USB patches for 4.7-rc1

Here's the big pull request for USB and PHY drivers for 4.7-rc1
 
 Full details in the shortlog, but it's the normal major gadget driver
 updates, phy updates, new usbip code, as well as a bit of lots of other
 stuff.
 
 All have been in linux-next with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlc/0P8ACgkQMUfUDdst+ykkFQCg0kJlxIiCU1FYBZYriqo4vX3F
 9N8AoM/8nO8Y6vMpF2LWnamafYgqscTE
 =ZuCh
 -----END PGP SIGNATURE-----

Merge tag 'usb-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB updates from Greg KH:
 "Here's the big pull request for USB and PHY drivers for 4.7-rc1

  Full details in the shortlog, but it's the normal major gadget driver
  updates, phy updates, new usbip code, as well as a bit of lots of
  other stuff.

  All have been in linux-next with no reported issues"

* tag 'usb-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (164 commits)
  USB: serial: ti_usb_3410_5052: add MOXA UPORT 11x0 support
  USB: serial: fix minor-number allocation
  USB: serial: quatech2: fix use-after-free in probe error path
  USB: serial: mxuport: fix use-after-free in probe error path
  USB: serial: keyspan: fix debug and error messages
  USB: serial: keyspan: fix URB unlink
  USB: serial: keyspan: fix use-after-free in probe error path
  USB: serial: io_edgeport: fix memory leaks in probe error path
  USB: serial: io_edgeport: fix memory leaks in attach error path
  usb: Remove unnecessary space before operator ','.
  usb: Remove unnecessary space before open square bracket.
  USB: FHCI: avoid redundant condition
  usb: host: xhci-rcar: Avoid long wait in xhci_reset()
  usb/host/fotg210: remove dead code in create_sysfs_files
  usb: wusbcore: Do not initialise statics to 0.
  usb: wusbcore: Remove space before ',' and '(' .
  USB: serial: cp210x: clean up CRTSCTS flag code
  USB: serial: cp210x: get rid of magic numbers in CRTSCTS flag code
  USB: serial: cp210x: fix hardware flow-control disable
  USB: serial: option: add even more ZTE device ids
  ...
This commit is contained in:
Linus Torvalds 2016-05-20 21:12:25 -07:00
commit 19e36ad292
182 changed files with 7633 additions and 2528 deletions

View File

@ -0,0 +1,35 @@
What: /sys/devices/platform/usbip-vudc.%d/dev_desc
Date: April 2016
KernelVersion: 4.6
Contact: Krzysztof Opasiak <k.opasiak@samsung.com>
Description:
This file allows to read device descriptor of
gadget driver which is currently bound to this
controller. It is possible to read this file
only if gadget driver is bound, otherwise error
is returned.
What: /sys/devices/platform/usbip-vudc.%d/usbip_status
Date: April 2016
KernelVersion: 4.6
Contact: Krzysztof Opasiak <k.opasiak@samsung.com>
Description:
Current status of the device.
Allowed values:
1 - Device is available and can be exported
2 - Device is currently exported
3 - Fatal error occurred during communication
with peer
What: /sys/devices/platform/usbip-vudc.%d/usbip_sockfd
Date: April 2016
KernelVersion: 4.6
Contact: Krzysztof Opasiak <k.opasiak@samsung.com>
Description:
This file allows to export usb device to
connection peer. It is done by writing to this
file socket fd (as a string for example "8")
associated with a connection to remote peer who
would like to use this device. It is possible to
close the connection by writing -1 instead of
socked fd.

View File

@ -0,0 +1,21 @@
Driver for Broadcom Northstar USB 2.0 PHY
Required properties:
- compatible: brcm,ns-usb2-phy
- reg: iomem address range of DMU (Device Management Unit)
- reg-names: "dmu", the only needed & supported reg right now
- clocks: USB PHY reference clock
- clock-names: "phy-ref-clk", the only needed & supported clock right now
To initialize USB 2.0 PHY driver needs to setup PLL correctly. To do this it
requires passing phandle to the USB PHY reference clock.
Example:
usb2-phy {
compatible = "brcm,ns-usb2-phy";
reg = <0x1800c000 0x1000>;
reg-names = "dmu";
#phy-cells = <0>;
clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>;
clock-names = "phy-ref-clk";
};

View File

@ -1,14 +1,17 @@
* Broadcom SATA3 PHY for STB
* Broadcom SATA3 PHY
Required properties:
- compatible: should be one or more of
"brcm,bcm7425-sata-phy"
"brcm,bcm7445-sata-phy"
"brcm,iproc-ns2-sata-phy"
"brcm,phy-sata3"
- address-cells: should be 1
- size-cells: should be 0
- reg: register range for the PHY PCB interface
- reg-names: should be "phy"
- reg: register ranges for the PHY PCB interface
- reg-names: should be "phy" and "phy-ctrl"
The "phy-ctrl" registers are only required for
"brcm,iproc-ns2-sata-phy".
Sub-nodes:
Each port's PHY should be represented as a sub-node.
@ -16,12 +19,12 @@ Sub-nodes:
Sub-nodes required properties:
- reg: the PHY number
- phy-cells: generic PHY binding; must be 0
Optional:
- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
Sub-nodes optional properties:
- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
This property is not applicable for "brcm,iproc-ns2-sata-phy".
Example:
sata-phy@f0458100 {
compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3";
reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>;

View File

@ -4,7 +4,9 @@ mt65xx USB3.0 PHY binding
This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC.
Required properties (controller (parent) node):
- compatible : should be "mediatek,mt8173-u3phy"
- compatible : should be one of
"mediatek,mt2701-u3phy"
"mediatek,mt8173-u3phy"
- reg : offset and length of register for phy, exclude port's
register.
- clocks : a list of phandle + clock-specifier pairs, one for each

View File

@ -7,6 +7,12 @@ Required properties:
- compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC.
"renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC.
"renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC.
"renesas,rcar-gen2-usb-phy" for a generic R-Car Gen2 compatible device.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
followed by the generic version.
- reg: offset and length of the register block.
- #address-cells: number of address cells for the USB channel subnodes, must
be <1>.
@ -34,7 +40,7 @@ the USB channel; see the selector meanings below:
Example (Lager board):
usb-phy@e6590100 {
compatible = "renesas,usb-phy-r8a7790";
compatible = "renesas,usb-phy-r8a7790", "renesas,rcar-gen2-usb-phy";
reg = <0 0xe6590100 0 0x100>;
#address-cells = <1>;
#size-cells = <0>;

View File

@ -6,6 +6,12 @@ This file provides information on what the device node for the R-Car generation
Required properties:
- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
SoC.
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
followed by the generic version.
- reg: offset and length of the partial USB 2.0 Host register block.
- clocks: clock phandle and specifier pair(s).
- #phy-cells: see phy-bindings.txt in the same directory, must be <0>.
@ -15,18 +21,20 @@ To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are
combined, the device tree node should set interrupt properties to use the
channel as USB OTG:
- interrupts: interrupt specifier for the PHY.
- vbus-supply: Phandle to a regulator that provides power to the VBUS. This
regulator will be managed during the PHY power on/off sequence.
Example (R-Car H3):
usb-phy@ee080200 {
compatible = "renesas,usb2-phy-r8a7795";
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0 0xee080200 0 0x700>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
};
usb-phy@ee0a0200 {
compatible = "renesas,usb2-phy-r8a7795";
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0 0xee0a0200 0 0x700>;
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
};

View File

@ -2,9 +2,20 @@ Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY
-------------------------------------------------
Required properties:
- compatible : should be "samsung,s5pv210-mipi-video-phy";
- compatible : should be one of the listed compatibles:
- "samsung,s5pv210-mipi-video-phy"
- "samsung,exynos5420-mipi-video-phy"
- "samsung,exynos5433-mipi-video-phy"
- #phy-cells : from the generic phy bindings, must be 1;
- syscon - phandle to the PMU system controller;
In case of s5pv210 and exynos5420 compatible PHYs:
- syscon - phandle to the PMU system controller
In case of exynos5433 compatible PHY:
- samsung,pmu-syscon - phandle to the PMU system controller
- samsung,disp-sysreg - phandle to the DISP system registers controller
- samsung,cam0-sysreg - phandle to the CAM0 system registers controller
- samsung,cam1-sysreg - phandle to the CAM1 system registers controller
For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in
the PHY specifier identifies the PHY and its meaning is as follows:
@ -12,6 +23,9 @@ the PHY specifier identifies the PHY and its meaning is as follows:
1 - MIPI DSIM 0,
2 - MIPI CSIS 1,
3 - MIPI DSIM 1.
"samsung,exynos5420-mipi-video-phy" and "samsung,exynos5433-mipi-video-phy"
supports additional fifth PHY:
4 - MIPI CSIS 2.
Samsung EXYNOS SoC series Display Port PHY
-------------------------------------------------

View File

@ -14,7 +14,6 @@ Optional properties:
the second element is expected to be a handle to the USB3/SS PHY
- phys: from the *Generic PHY* bindings
- phy-names: from the *Generic PHY* bindings
- tx-fifo-resize: determines if the FIFO *has* to be reallocated.
- snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
- snps,disable_scramble_quirk: true when SW should disable data scrambling.
Only really useful for FPGA builds.
@ -38,6 +37,8 @@ Optional properties:
- snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy.
- snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG,
disabling the suspend signal to the PHY.
- snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection
in PHY P3 power state.
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
utmi_l1_suspend_n, false when asserts utmi_sleep_n
- snps,hird-threshold: HIRD threshold
@ -47,6 +48,8 @@ Optional properties:
register for post-silicon frame length adjustment when the
fladj_30mhz_sdbnd signal is invalid or incorrect.
- <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated.
This is usually a subnode to DWC3 glue to which it is connected.
dwc3@4a030000 {
@ -54,5 +57,4 @@ dwc3@4a030000 {
reg = <0x4a030000 0xcfff>;
interrupts = <0 92 4>
usb-phy = <&usb2_phy>, <&usb3,phy>;
tx-fifo-resize;
};

View File

@ -59,7 +59,6 @@ Example device nodes:
interrupts = <0 205 0x4>;
phys = <&hs_phy>, <&ss_phy>;
phy-names = "usb2-phy", "usb3-phy";
tx-fifo-resize;
dr_mode = "host";
};
};

View File

@ -3,14 +3,17 @@
To show how to demo OTG HNP and SRP functions via sys input files
with 2 Freescale i.MX6Q sabre SD boards.
1.1 How to enable OTG FSM in menuconfig
1.1 How to enable OTG FSM
---------------------------------------
Select CONFIG_USB_OTG_FSM, rebuild kernel Image and modules.
If you want to check some internal variables for otg fsm,
mount debugfs, there are 2 files which can show otg fsm
variables and some controller registers value:
1.1.1 Select CONFIG_USB_OTG_FSM in menuconfig, rebuild kernel
Image and modules. If you want to check some internal
variables for otg fsm, mount debugfs, there are 2 files
which can show otg fsm variables and some controller registers value:
cat /sys/kernel/debug/ci_hdrc.0/otg
cat /sys/kernel/debug/ci_hdrc.0/registers
1.1.2 Add below entries in your dts file for your controller node
otg-rev = <0x0200>;
adp-disable;
1.2 Test operations
-------------------

View File

@ -15,6 +15,15 @@ config GENERIC_PHY
phy users can obtain reference to the PHY. All the users of this
framework should select this config.
config PHY_BCM_NS_USB2
tristate "Broadcom Northstar USB 2.0 PHY Driver"
depends on ARCH_BCM_IPROC || COMPILE_TEST
depends on HAS_IOMEM && OF
select GENERIC_PHY
help
Enable this to support Broadcom USB 2.0 PHY connected to the USB
controller on Northstar family.
config PHY_BERLIN_USB
tristate "Marvell Berlin USB PHY Driver"
depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF
@ -113,14 +122,15 @@ config PHY_MIPHY365X
config PHY_RCAR_GEN2
tristate "Renesas R-Car generation 2 USB PHY driver"
depends on ARCH_SHMOBILE
depends on ARCH_RENESAS
depends on GENERIC_PHY
help
Support for USB PHY found on Renesas R-Car generation 2 SoCs.
config PHY_RCAR_GEN3_USB2
tristate "Renesas R-Car generation 3 USB 2.0 PHY driver"
depends on OF && ARCH_SHMOBILE
depends on ARCH_RENESAS
depends on EXTCON
select GENERIC_PHY
help
Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs.
@ -218,9 +228,8 @@ config PHY_MT65XX_USB3
depends on ARCH_MEDIATEK && OF
select GENERIC_PHY
help
Say 'Y' here to add support for Mediatek USB3.0 PHY driver
for mt65xx SoCs. it supports two usb2.0 ports and
one usb3.0 port.
Say 'Y' here to add support for Mediatek USB3.0 PHY driver,
it supports multiple usb2.0 and usb3.0 ports.
config PHY_HI6220_USB
tristate "hi6220 USB PHY support"
@ -250,7 +259,8 @@ config PHY_SUN9I_USB
tristate "Allwinner sun9i SoC USB PHY driver"
depends on ARCH_SUNXI && HAS_IOMEM && OF
depends on RESET_CONTROLLER
depends on USB_COMMON
depends on USB_SUPPORT
select USB_COMMON
select GENERIC_PHY
help
Enable this to support the transceiver that is part of Allwinner
@ -403,14 +413,15 @@ config PHY_TUSB1210
help
Support for TI TUSB1210 USB ULPI PHY.
config PHY_BRCMSTB_SATA
tristate "Broadcom STB SATA PHY driver"
depends on ARCH_BRCMSTB || BMIPS_GENERIC
config PHY_BRCM_SATA
tristate "Broadcom SATA PHY driver"
depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST
depends on OF
select GENERIC_PHY
default ARCH_BCM_IPROC
help
Enable this to support the SATA3 PHY on 28nm or 40nm Broadcom STB SoCs.
Likely useful only with CONFIG_SATA_BRCMSTB enabled.
Enable this to support the Broadcom SATA PHY.
If unsure, say N.
config PHY_CYGNUS_PCIE
tristate "Broadcom Cygnus PCIe PHY driver"

View File

@ -3,6 +3,7 @@
#
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o
@ -49,7 +50,7 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o
obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o

View File

@ -0,0 +1,137 @@
/*
* Broadcom Northstar USB 2.0 PHY Driver
*
* Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.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/bcma/bcma.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
struct bcm_ns_usb2 {
struct device *dev;
struct clk *ref_clk;
struct phy *phy;
void __iomem *dmu;
};
static int bcm_ns_usb2_phy_init(struct phy *phy)
{
struct bcm_ns_usb2 *usb2 = phy_get_drvdata(phy);
struct device *dev = usb2->dev;
void __iomem *dmu = usb2->dmu;
u32 ref_clk_rate, usb2ctl, usb_pll_ndiv, usb_pll_pdiv;
int err = 0;
err = clk_prepare_enable(usb2->ref_clk);
if (err < 0) {
dev_err(dev, "Failed to prepare ref clock: %d\n", err);
goto err_out;
}
ref_clk_rate = clk_get_rate(usb2->ref_clk);
if (!ref_clk_rate) {
dev_err(dev, "Failed to get ref clock rate\n");
err = -EINVAL;
goto err_clk_off;
}
usb2ctl = readl(dmu + BCMA_DMU_CRU_USB2_CONTROL);
if (usb2ctl & BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK) {
usb_pll_pdiv = usb2ctl;
usb_pll_pdiv &= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK;
usb_pll_pdiv >>= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_SHIFT;
} else {
usb_pll_pdiv = 1 << 3;
}
/* Calculate ndiv based on a solid 1920 MHz that is for USB2 PHY */
usb_pll_ndiv = (1920000000 * usb_pll_pdiv) / ref_clk_rate;
/* Unlock DMU PLL settings with some magic value */
writel(0x0000ea68, dmu + BCMA_DMU_CRU_CLKSET_KEY);
/* Write USB 2.0 PLL control setting */
usb2ctl &= ~BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK;
usb2ctl |= usb_pll_ndiv << BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT;
writel(usb2ctl, dmu + BCMA_DMU_CRU_USB2_CONTROL);
/* Lock DMU PLL settings */
writel(0x00000000, dmu + BCMA_DMU_CRU_CLKSET_KEY);
err_clk_off:
clk_disable_unprepare(usb2->ref_clk);
err_out:
return err;
}
static const struct phy_ops ops = {
.init = bcm_ns_usb2_phy_init,
.owner = THIS_MODULE,
};
static int bcm_ns_usb2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct bcm_ns_usb2 *usb2;
struct resource *res;
struct phy_provider *phy_provider;
usb2 = devm_kzalloc(&pdev->dev, sizeof(*usb2), GFP_KERNEL);
if (!usb2)
return -ENOMEM;
usb2->dev = dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmu");
usb2->dmu = devm_ioremap_resource(dev, res);
if (IS_ERR(usb2->dmu)) {
dev_err(dev, "Failed to map DMU regs\n");
return PTR_ERR(usb2->dmu);
}
usb2->ref_clk = devm_clk_get(dev, "phy-ref-clk");
if (IS_ERR(usb2->ref_clk)) {
dev_err(dev, "Clock not defined\n");
return PTR_ERR(usb2->ref_clk);
}
usb2->phy = devm_phy_create(dev, NULL, &ops);
if (IS_ERR(dev))
return PTR_ERR(dev);
phy_set_drvdata(usb2->phy, usb2);
platform_set_drvdata(pdev, usb2);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id bcm_ns_usb2_id_table[] = {
{ .compatible = "brcm,ns-usb2-phy", },
{},
};
MODULE_DEVICE_TABLE(of, bcm_ns_usb2_id_table);
static struct platform_driver bcm_ns_usb2_driver = {
.probe = bcm_ns_usb2_probe,
.driver = {
.name = "bcm_ns_usb2",
.of_match_table = bcm_ns_usb2_id_table,
},
};
module_platform_driver(bcm_ns_usb2_driver);
MODULE_LICENSE("GPL v2");

412
drivers/phy/phy-brcm-sata.c Normal file
View File

@ -0,0 +1,412 @@
/*
* Broadcom SATA3 AHCI Controller PHY Driver
*
* Copyright (C) 2016 Broadcom
*
* 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, or (at your option)
* any later version.
*
* 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/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#define SATA_PCB_BANK_OFFSET 0x23c
#define SATA_PCB_REG_OFFSET(ofs) ((ofs) * 4)
#define MAX_PORTS 2
/* Register offset between PHYs in PCB space */
#define SATA_PCB_REG_28NM_SPACE_SIZE 0x1000
/* The older SATA PHY registers duplicated per port registers within the map,
* rather than having a separate map per port.
*/
#define SATA_PCB_REG_40NM_SPACE_SIZE 0x10
/* Register offset between PHYs in PHY control space */
#define SATA_PHY_CTRL_REG_28NM_SPACE_SIZE 0x8
enum brcm_sata_phy_version {
BRCM_SATA_PHY_STB_28NM,
BRCM_SATA_PHY_STB_40NM,
BRCM_SATA_PHY_IPROC_NS2,
};
struct brcm_sata_port {
int portnum;
struct phy *phy;
struct brcm_sata_phy *phy_priv;
bool ssc_en;
};
struct brcm_sata_phy {
struct device *dev;
void __iomem *phy_base;
void __iomem *ctrl_base;
enum brcm_sata_phy_version version;
struct brcm_sata_port phys[MAX_PORTS];
};
enum sata_phy_regs {
BLOCK0_REG_BANK = 0x000,
BLOCK0_XGXSSTATUS = 0x81,
BLOCK0_XGXSSTATUS_PLL_LOCK = BIT(12),
BLOCK0_SPARE = 0x8d,
BLOCK0_SPARE_OOB_CLK_SEL_MASK = 0x3,
BLOCK0_SPARE_OOB_CLK_SEL_REFBY2 = 0x1,
PLL_REG_BANK_0 = 0x050,
PLL_REG_BANK_0_PLLCONTROL_0 = 0x81,
PLL1_REG_BANK = 0x060,
PLL1_ACTRL2 = 0x82,
PLL1_ACTRL3 = 0x83,
PLL1_ACTRL4 = 0x84,
OOB_REG_BANK = 0x150,
OOB_CTRL1 = 0x80,
OOB_CTRL1_BURST_MAX_MASK = 0xf,
OOB_CTRL1_BURST_MAX_SHIFT = 12,
OOB_CTRL1_BURST_MIN_MASK = 0xf,
OOB_CTRL1_BURST_MIN_SHIFT = 8,
OOB_CTRL1_WAKE_IDLE_MAX_MASK = 0xf,
OOB_CTRL1_WAKE_IDLE_MAX_SHIFT = 4,
OOB_CTRL1_WAKE_IDLE_MIN_MASK = 0xf,
OOB_CTRL1_WAKE_IDLE_MIN_SHIFT = 0,
OOB_CTRL2 = 0x81,
OOB_CTRL2_SEL_ENA_SHIFT = 15,
OOB_CTRL2_SEL_ENA_RC_SHIFT = 14,
OOB_CTRL2_RESET_IDLE_MAX_MASK = 0x3f,
OOB_CTRL2_RESET_IDLE_MAX_SHIFT = 8,
OOB_CTRL2_BURST_CNT_MASK = 0x3,
OOB_CTRL2_BURST_CNT_SHIFT = 6,
OOB_CTRL2_RESET_IDLE_MIN_MASK = 0x3f,
OOB_CTRL2_RESET_IDLE_MIN_SHIFT = 0,
TXPMD_REG_BANK = 0x1a0,
TXPMD_CONTROL1 = 0x81,
TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0),
TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1),
TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82,
TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83,
TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff,
TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84,
TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff,
};
enum sata_phy_ctrl_regs {
PHY_CTRL_1 = 0x0,
PHY_CTRL_1_RESET = BIT(0),
};
static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port)
{
struct brcm_sata_phy *priv = port->phy_priv;
u32 size = 0;
switch (priv->version) {
case BRCM_SATA_PHY_STB_28NM:
case BRCM_SATA_PHY_IPROC_NS2:
size = SATA_PCB_REG_28NM_SPACE_SIZE;
break;
case BRCM_SATA_PHY_STB_40NM:
size = SATA_PCB_REG_40NM_SPACE_SIZE;
break;
default:
dev_err(priv->dev, "invalid phy version\n");
break;
};
return priv->phy_base + (port->portnum * size);
}
static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port)
{
struct brcm_sata_phy *priv = port->phy_priv;
u32 size = 0;
switch (priv->version) {
case BRCM_SATA_PHY_IPROC_NS2:
size = SATA_PHY_CTRL_REG_28NM_SPACE_SIZE;
break;
default:
dev_err(priv->dev, "invalid phy version\n");
break;
};
return priv->ctrl_base + (port->portnum * size);
}
static void brcm_sata_phy_wr(void __iomem *pcb_base, u32 bank,
u32 ofs, u32 msk, u32 value)
{
u32 tmp;
writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
tmp = readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
tmp = (tmp & msk) | value;
writel(tmp, pcb_base + SATA_PCB_REG_OFFSET(ofs));
}
static u32 brcm_sata_phy_rd(void __iomem *pcb_base, u32 bank, u32 ofs)
{
writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
return readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
}
/* These defaults were characterized by H/W group */
#define STB_FMIN_VAL_DEFAULT 0x3df
#define STB_FMAX_VAL_DEFAULT 0x3df
#define STB_FMAX_VAL_SSC 0x83
static int brcm_stb_sata_init(struct brcm_sata_port *port)
{
void __iomem *base = brcm_sata_pcb_base(port);
struct brcm_sata_phy *priv = port->phy_priv;
u32 tmp;
/* override the TX spread spectrum setting */
tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC;
brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
/* set fixed min freq */
brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK,
STB_FMIN_VAL_DEFAULT);
/* set fixed max freq depending on SSC config */
if (port->ssc_en) {
dev_info(priv->dev, "enabling SSC on port%d\n", port->portnum);
tmp = STB_FMAX_VAL_SSC;
} else {
tmp = STB_FMAX_VAL_DEFAULT;
}
brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
return 0;
}
/* NS2 SATA PLL1 defaults were characterized by H/W group */
#define NS2_PLL1_ACTRL2_MAGIC 0x1df8
#define NS2_PLL1_ACTRL3_MAGIC 0x2b00
#define NS2_PLL1_ACTRL4_MAGIC 0x8824
static int brcm_ns2_sata_init(struct brcm_sata_port *port)
{
int try;
unsigned int val;
void __iomem *base = brcm_sata_pcb_base(port);
void __iomem *ctrl_base = brcm_sata_ctrl_base(port);
struct device *dev = port->phy_priv->dev;
/* Configure OOB control */
val = 0x0;
val |= (0xc << OOB_CTRL1_BURST_MAX_SHIFT);
val |= (0x4 << OOB_CTRL1_BURST_MIN_SHIFT);
val |= (0x9 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT);
val |= (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT);
brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL1, 0x0, val);
val = 0x0;
val |= (0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT);
val |= (0x2 << OOB_CTRL2_BURST_CNT_SHIFT);
val |= (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT);
brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL2, 0x0, val);
/* Configure PHY PLL register bank 1 */
val = NS2_PLL1_ACTRL2_MAGIC;
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val);
val = NS2_PLL1_ACTRL3_MAGIC;
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val);
val = NS2_PLL1_ACTRL4_MAGIC;
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val);
/* Configure PHY BLOCK0 register bank */
/* Set oob_clk_sel to refclk/2 */
brcm_sata_phy_wr(base, BLOCK0_REG_BANK, BLOCK0_SPARE,
~BLOCK0_SPARE_OOB_CLK_SEL_MASK,
BLOCK0_SPARE_OOB_CLK_SEL_REFBY2);
/* Strobe PHY reset using PHY control register */
writel(PHY_CTRL_1_RESET, ctrl_base + PHY_CTRL_1);
mdelay(1);
writel(0x0, ctrl_base + PHY_CTRL_1);
mdelay(1);
/* Wait for PHY PLL lock by polling pll_lock bit */
try = 50;
while (try) {
val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
BLOCK0_XGXSSTATUS);
if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
break;
msleep(20);
try--;
}
if (!try) {
/* PLL did not lock; give up */
dev_err(dev, "port%d PLL did not lock\n", port->portnum);
return -ETIMEDOUT;
}
dev_dbg(dev, "port%d initialized\n", port->portnum);
return 0;
}
static int brcm_sata_phy_init(struct phy *phy)
{
int rc;
struct brcm_sata_port *port = phy_get_drvdata(phy);
switch (port->phy_priv->version) {
case BRCM_SATA_PHY_STB_28NM:
case BRCM_SATA_PHY_STB_40NM:
rc = brcm_stb_sata_init(port);
break;
case BRCM_SATA_PHY_IPROC_NS2:
rc = brcm_ns2_sata_init(port);
break;
default:
rc = -ENODEV;
};
return 0;
}
static const struct phy_ops phy_ops = {
.init = brcm_sata_phy_init,
.owner = THIS_MODULE,
};
static const struct of_device_id brcm_sata_phy_of_match[] = {
{ .compatible = "brcm,bcm7445-sata-phy",
.data = (void *)BRCM_SATA_PHY_STB_28NM },
{ .compatible = "brcm,bcm7425-sata-phy",
.data = (void *)BRCM_SATA_PHY_STB_40NM },
{ .compatible = "brcm,iproc-ns2-sata-phy",
.data = (void *)BRCM_SATA_PHY_IPROC_NS2 },
{},
};
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
static int brcm_sata_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *dn = dev->of_node, *child;
const struct of_device_id *of_id;
struct brcm_sata_phy *priv;
struct resource *res;
struct phy_provider *provider;
int ret, count = 0;
if (of_get_child_count(dn) == 0)
return -ENODEV;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dev_set_drvdata(dev, priv);
priv->dev = dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
priv->phy_base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->phy_base))
return PTR_ERR(priv->phy_base);
of_id = of_match_node(brcm_sata_phy_of_match, dn);
if (of_id)
priv->version = (enum brcm_sata_phy_version)of_id->data;
else
priv->version = BRCM_SATA_PHY_STB_28NM;
if (priv->version == BRCM_SATA_PHY_IPROC_NS2) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"phy-ctrl");
priv->ctrl_base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->ctrl_base))
return PTR_ERR(priv->ctrl_base);
}
for_each_available_child_of_node(dn, child) {
unsigned int id;
struct brcm_sata_port *port;
if (of_property_read_u32(child, "reg", &id)) {
dev_err(dev, "missing reg property in node %s\n",
child->name);
ret = -EINVAL;
goto put_child;
}
if (id >= MAX_PORTS) {
dev_err(dev, "invalid reg: %u\n", id);
ret = -EINVAL;
goto put_child;
}
if (priv->phys[id].phy) {
dev_err(dev, "already registered port %u\n", id);
ret = -EINVAL;
goto put_child;
}
port = &priv->phys[id];
port->portnum = id;
port->phy_priv = priv;
port->phy = devm_phy_create(dev, child, &phy_ops);
port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
if (IS_ERR(port->phy)) {
dev_err(dev, "failed to create PHY\n");
ret = PTR_ERR(port->phy);
goto put_child;
}
phy_set_drvdata(port->phy, port);
count++;
}
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(provider)) {
dev_err(dev, "could not register PHY provider\n");
return PTR_ERR(provider);
}
dev_info(dev, "registered %d port(s)\n", count);
return 0;
put_child:
of_node_put(child);
return ret;
}
static struct platform_driver brcm_sata_phy_driver = {
.probe = brcm_sata_phy_probe,
.driver = {
.of_match_table = brcm_sata_phy_of_match,
.name = "brcm-sata-phy",
}
};
module_platform_driver(brcm_sata_phy_driver);
MODULE_DESCRIPTION("Broadcom SATA PHY driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Carino");
MODULE_AUTHOR("Brian Norris");
MODULE_ALIAS("platform:phy-brcm-sata");

View File

@ -1,250 +0,0 @@
/*
* Broadcom SATA3 AHCI Controller PHY Driver
*
* Copyright © 2009-2015 Broadcom Corporation
*
* 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, or (at your option)
* any later version.
*
* 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/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#define SATA_MDIO_BANK_OFFSET 0x23c
#define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4)
#define MAX_PORTS 2
/* Register offset between PHYs in PCB space */
#define SATA_MDIO_REG_28NM_SPACE_SIZE 0x1000
/* The older SATA PHY registers duplicated per port registers within the map,
* rather than having a separate map per port.
*/
#define SATA_MDIO_REG_40NM_SPACE_SIZE 0x10
enum brcm_sata_phy_version {
BRCM_SATA_PHY_28NM,
BRCM_SATA_PHY_40NM,
};
struct brcm_sata_port {
int portnum;
struct phy *phy;
struct brcm_sata_phy *phy_priv;
bool ssc_en;
};
struct brcm_sata_phy {
struct device *dev;
void __iomem *phy_base;
enum brcm_sata_phy_version version;
struct brcm_sata_port phys[MAX_PORTS];
};
enum sata_mdio_phy_regs {
PLL_REG_BANK_0 = 0x50,
PLL_REG_BANK_0_PLLCONTROL_0 = 0x81,
TXPMD_REG_BANK = 0x1a0,
TXPMD_CONTROL1 = 0x81,
TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0),
TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1),
TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82,
TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83,
TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff,
TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84,
TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff,
};
static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port)
{
struct brcm_sata_phy *priv = port->phy_priv;
u32 offset = 0;
if (priv->version == BRCM_SATA_PHY_28NM)
offset = SATA_MDIO_REG_28NM_SPACE_SIZE;
else if (priv->version == BRCM_SATA_PHY_40NM)
offset = SATA_MDIO_REG_40NM_SPACE_SIZE;
else
dev_err(priv->dev, "invalid phy version\n");
return priv->phy_base + (port->portnum * offset);
}
static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs,
u32 msk, u32 value)
{
u32 tmp;
writel(bank, addr + SATA_MDIO_BANK_OFFSET);
tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs));
tmp = (tmp & msk) | value;
writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs));
}
/* These defaults were characterized by H/W group */
#define FMIN_VAL_DEFAULT 0x3df
#define FMAX_VAL_DEFAULT 0x3df
#define FMAX_VAL_SSC 0x83
static void brcm_sata_cfg_ssc(struct brcm_sata_port *port)
{
void __iomem *base = brcm_sata_phy_base(port);
struct brcm_sata_phy *priv = port->phy_priv;
u32 tmp;
/* override the TX spread spectrum setting */
tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC;
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
/* set fixed min freq */
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK,
FMIN_VAL_DEFAULT);
/* set fixed max freq depending on SSC config */
if (port->ssc_en) {
dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum);
tmp = FMAX_VAL_SSC;
} else {
tmp = FMAX_VAL_DEFAULT;
}
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
}
static int brcm_sata_phy_init(struct phy *phy)
{
struct brcm_sata_port *port = phy_get_drvdata(phy);
brcm_sata_cfg_ssc(port);
return 0;
}
static const struct phy_ops phy_ops = {
.init = brcm_sata_phy_init,
.owner = THIS_MODULE,
};
static const struct of_device_id brcm_sata_phy_of_match[] = {
{ .compatible = "brcm,bcm7445-sata-phy",
.data = (void *)BRCM_SATA_PHY_28NM },
{ .compatible = "brcm,bcm7425-sata-phy",
.data = (void *)BRCM_SATA_PHY_40NM },
{},
};
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
static int brcm_sata_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *dn = dev->of_node, *child;
const struct of_device_id *of_id;
struct brcm_sata_phy *priv;
struct resource *res;
struct phy_provider *provider;
int ret, count = 0;
if (of_get_child_count(dn) == 0)
return -ENODEV;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dev_set_drvdata(dev, priv);
priv->dev = dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
priv->phy_base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->phy_base))
return PTR_ERR(priv->phy_base);
of_id = of_match_node(brcm_sata_phy_of_match, dn);
if (of_id)
priv->version = (enum brcm_sata_phy_version)of_id->data;
else
priv->version = BRCM_SATA_PHY_28NM;
for_each_available_child_of_node(dn, child) {
unsigned int id;
struct brcm_sata_port *port;
if (of_property_read_u32(child, "reg", &id)) {
dev_err(dev, "missing reg property in node %s\n",
child->name);
ret = -EINVAL;
goto put_child;
}
if (id >= MAX_PORTS) {
dev_err(dev, "invalid reg: %u\n", id);
ret = -EINVAL;
goto put_child;
}
if (priv->phys[id].phy) {
dev_err(dev, "already registered port %u\n", id);
ret = -EINVAL;
goto put_child;
}
port = &priv->phys[id];
port->portnum = id;
port->phy_priv = priv;
port->phy = devm_phy_create(dev, child, &phy_ops);
port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
if (IS_ERR(port->phy)) {
dev_err(dev, "failed to create PHY\n");
ret = PTR_ERR(port->phy);
goto put_child;
}
phy_set_drvdata(port->phy, port);
count++;
}
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(provider)) {
dev_err(dev, "could not register PHY provider\n");
return PTR_ERR(provider);
}
dev_info(dev, "registered %d port(s)\n", count);
return 0;
put_child:
of_node_put(child);
return ret;
}
static struct platform_driver brcm_sata_phy_driver = {
.probe = brcm_sata_phy_probe,
.driver = {
.of_match_table = brcm_sata_phy_of_match,
.name = "brcmstb-sata-phy",
}
};
module_platform_driver(brcm_sata_phy_driver);
MODULE_DESCRIPTION("Broadcom STB SATA PHY driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Carino");
MODULE_AUTHOR("Brian Norris");
MODULE_ALIAS("platform:phy-brcmstb-sata");

View File

@ -1,7 +1,7 @@
/*
* Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Copyright (C) 2013,2016 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@ -13,96 +13,276 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon/exynos4-pmu.h>
#include <linux/mfd/syscon/exynos5-pmu.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spinlock.h>
#include <linux/mfd/syscon.h>
/* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */
#define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4)
enum exynos_mipi_phy_id {
EXYNOS_MIPI_PHY_ID_NONE = -1,
EXYNOS_MIPI_PHY_ID_CSIS0,
EXYNOS_MIPI_PHY_ID_DSIM0,
EXYNOS_MIPI_PHY_ID_CSIS1,
EXYNOS_MIPI_PHY_ID_DSIM1,
EXYNOS_MIPI_PHY_ID_CSIS2,
EXYNOS_MIPI_PHYS_NUM
};
#define is_mipi_dsim_phy_id(id) \
((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1)
enum exynos_mipi_phy_regmap_id {
EXYNOS_MIPI_REGMAP_PMU,
EXYNOS_MIPI_REGMAP_DISP,
EXYNOS_MIPI_REGMAP_CAM0,
EXYNOS_MIPI_REGMAP_CAM1,
EXYNOS_MIPI_REGMAPS_NUM
};
struct mipi_phy_device_desc {
int num_phys;
int num_regmaps;
const char *regmap_names[EXYNOS_MIPI_REGMAPS_NUM];
struct exynos_mipi_phy_desc {
enum exynos_mipi_phy_id coupled_phy_id;
u32 enable_val;
unsigned int enable_reg;
enum exynos_mipi_phy_regmap_id enable_map;
u32 resetn_val;
unsigned int resetn_reg;
enum exynos_mipi_phy_regmap_id resetn_map;
} phys[EXYNOS_MIPI_PHYS_NUM];
};
static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
.num_regmaps = 1,
.regmap_names = {"syscon"},
.num_phys = 4,
.phys = {
{
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
},
},
};
static const struct mipi_phy_device_desc exynos5420_mipi_phy = {
.num_regmaps = 1,
.regmap_names = {"syscon"},
.num_phys = 5,
.phys = {
{
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
},
},
};
#define EXYNOS5433_SYSREG_DISP_MIPI_PHY 0x100C
#define EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON 0x1014
#define EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON 0x1020
static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
.num_regmaps = 4,
.regmap_names = {
"samsung,pmu-syscon",
"samsung,disp-sysreg",
"samsung,cam0-sysreg",
"samsung,cam1-sysreg"
},
.num_phys = 5,
.phys = {
{
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(0),
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(0),
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
.resetn_map = EXYNOS_MIPI_REGMAP_DISP,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(1),
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(1),
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
.resetn_map = EXYNOS_MIPI_REGMAP_DISP,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY2_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(0),
.resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON,
.resetn_map = EXYNOS_MIPI_REGMAP_CAM1,
},
},
};
struct exynos_mipi_video_phy {
struct regmap *regmaps[EXYNOS_MIPI_REGMAPS_NUM];
int num_phys;
struct video_phy_desc {
struct phy *phy;
unsigned int index;
const struct exynos_mipi_phy_desc *data;
} phys[EXYNOS_MIPI_PHYS_NUM];
spinlock_t slock;
void __iomem *regs;
struct regmap *regmap;
};
static int __set_phy_state(struct exynos_mipi_video_phy *state,
enum exynos_mipi_phy_id id, unsigned int on)
static inline int __is_running(const struct exynos_mipi_phy_desc *data,
struct exynos_mipi_video_phy *state)
{
const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2);
void __iomem *addr;
u32 val, reset;
u32 val;
if (is_mipi_dsim_phy_id(id))
reset = EXYNOS4_MIPI_PHY_MRESETN;
else
reset = EXYNOS4_MIPI_PHY_SRESETN;
regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
return val & data->resetn_val;
}
static int __set_phy_state(const struct exynos_mipi_phy_desc *data,
struct exynos_mipi_video_phy *state, unsigned int on)
{
u32 val;
spin_lock(&state->slock);
if (!IS_ERR(state->regmap)) {
regmap_read(state->regmap, offset, &val);
if (on)
val |= reset;
else
val &= ~reset;
regmap_write(state->regmap, offset, val);
if (on)
val |= EXYNOS4_MIPI_PHY_ENABLE;
else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
val &= ~EXYNOS4_MIPI_PHY_ENABLE;
regmap_write(state->regmap, offset, val);
} else {
addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
/* disable in PMU sysreg */
if (!on && data->coupled_phy_id >= 0 &&
!__is_running(state->phys[data->coupled_phy_id].data, state)) {
regmap_read(state->regmaps[data->enable_map], data->enable_reg,
&val);
val &= ~data->enable_val;
regmap_write(state->regmaps[data->enable_map], data->enable_reg,
val);
}
val = readl(addr);
if (on)
val |= reset;
else
val &= ~reset;
writel(val, addr);
/* Clear ENABLE bit only if MRESETN, SRESETN bits are not set */
if (on)
val |= EXYNOS4_MIPI_PHY_ENABLE;
else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
val &= ~EXYNOS4_MIPI_PHY_ENABLE;
/* PHY reset */
regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
val = on ? (val | data->resetn_val) : (val & ~data->resetn_val);
regmap_write(state->regmaps[data->resetn_map], data->resetn_reg, val);
writel(val, addr);
/* enable in PMU sysreg */
if (on) {
regmap_read(state->regmaps[data->enable_map], data->enable_reg,
&val);
val |= data->enable_val;
regmap_write(state->regmaps[data->enable_map], data->enable_reg,
val);
}
spin_unlock(&state->slock);
return 0;
}
#define to_mipi_video_phy(desc) \
container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index]);
container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index])
static int exynos_mipi_video_phy_power_on(struct phy *phy)
{
struct video_phy_desc *phy_desc = phy_get_drvdata(phy);
struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);
return __set_phy_state(state, phy_desc->index, 1);
return __set_phy_state(phy_desc->data, state, 1);
}
static int exynos_mipi_video_phy_power_off(struct phy *phy)
@ -110,7 +290,7 @@ static int exynos_mipi_video_phy_power_off(struct phy *phy)
struct video_phy_desc *phy_desc = phy_get_drvdata(phy);
struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);
return __set_phy_state(state, phy_desc->index, 0);
return __set_phy_state(phy_desc->data, state, 0);
}
static struct phy *exynos_mipi_video_phy_xlate(struct device *dev,
@ -118,7 +298,7 @@ static struct phy *exynos_mipi_video_phy_xlate(struct device *dev,
{
struct exynos_mipi_video_phy *state = dev_get_drvdata(dev);
if (WARN_ON(args->args[0] >= EXYNOS_MIPI_PHYS_NUM))
if (WARN_ON(args->args[0] >= state->num_phys))
return ERR_PTR(-ENODEV);
return state->phys[args->args[0]].phy;
@ -132,32 +312,33 @@ static const struct phy_ops exynos_mipi_video_phy_ops = {
static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
{
const struct mipi_phy_device_desc *phy_dev;
struct exynos_mipi_video_phy *state;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct phy_provider *phy_provider;
unsigned int i;
phy_dev = of_device_get_match_data(dev);
if (!phy_dev)
return -ENODEV;
state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
if (IS_ERR(state->regmap)) {
struct resource *res;
dev_info(dev, "regmap lookup failed: %ld\n",
PTR_ERR(state->regmap));
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
state->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(state->regs))
return PTR_ERR(state->regs);
for (i = 0; i < phy_dev->num_regmaps; i++) {
state->regmaps[i] = syscon_regmap_lookup_by_phandle(np,
phy_dev->regmap_names[i]);
if (IS_ERR(state->regmaps[i]))
return PTR_ERR(state->regmaps[i]);
}
dev_set_drvdata(dev, state);
state->num_phys = phy_dev->num_phys;
spin_lock_init(&state->slock);
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
dev_set_drvdata(dev, state);
for (i = 0; i < state->num_phys; i++) {
struct phy *phy = devm_phy_create(dev, NULL,
&exynos_mipi_video_phy_ops);
if (IS_ERR(phy)) {
@ -167,6 +348,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
state->phys[i].phy = phy;
state->phys[i].index = i;
state->phys[i].data = &phy_dev->phys[i];
phy_set_drvdata(phy, &state->phys[i]);
}
@ -177,8 +359,17 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
}
static const struct of_device_id exynos_mipi_video_phy_of_match[] = {
{ .compatible = "samsung,s5pv210-mipi-video-phy" },
{ },
{
.compatible = "samsung,s5pv210-mipi-video-phy",
.data = &s5pv210_mipi_phy,
}, {
.compatible = "samsung,exynos5420-mipi-video-phy",
.data = &exynos5420_mipi_phy,
}, {
.compatible = "samsung,exynos5433-mipi-video-phy",
.data = &exynos5433_mipi_phy,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match);

View File

@ -134,6 +134,11 @@
#define U3P_SR_COEF_DIVISOR 1000
#define U3P_FM_DET_CYCLE_CNT 1024
struct mt65xx_phy_pdata {
/* avoid RX sensitivity level degradation only for mt8173 */
bool avoid_rx_sen_degradation;
};
struct mt65xx_phy_instance {
struct phy *phy;
void __iomem *port_base;
@ -145,6 +150,7 @@ struct mt65xx_u3phy {
struct device *dev;
void __iomem *sif_base; /* include sif2, but exclude port's */
struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
const struct mt65xx_phy_pdata *pdata;
struct mt65xx_phy_instance **phys;
int nphys;
};
@ -241,22 +247,26 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,
tmp = readl(port_base + U3P_U2PHYACR4);
tmp &= ~P2C_U2_GPIO_CTR_MSK;
writel(tmp, port_base + U3P_U2PHYACR4);
}
tmp = readl(port_base + U3P_USBPHYACR2);
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
writel(tmp, port_base + U3P_USBPHYACR2);
if (u3phy->pdata->avoid_rx_sen_degradation) {
if (!index) {
tmp = readl(port_base + U3P_USBPHYACR2);
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
writel(tmp, port_base + U3P_USBPHYACR2);
tmp = readl(port_base + U3D_U2PHYDCR0);
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0);
} else {
tmp = readl(port_base + U3D_U2PHYDCR0);
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0);
tmp = readl(port_base + U3D_U2PHYDCR0);
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0);
} else {
tmp = readl(port_base + U3D_U2PHYDCR0);
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0);
tmp = readl(port_base + U3P_U2PHYDTM0);
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
writel(tmp, port_base + U3P_U2PHYDTM0);
tmp = readl(port_base + U3P_U2PHYDTM0);
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
writel(tmp, port_base + U3P_U2PHYDTM0);
}
}
tmp = readl(port_base + U3P_USBPHYACR6);
@ -318,7 +328,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
writel(tmp, u3phy->sif_base + U3P_XTALCTL3);
/* [mt8173]switch 100uA current to SSUSB */
/* switch 100uA current to SSUSB */
tmp = readl(port_base + U3P_USBPHYACR5);
tmp |= PA5_RG_U2_HS_100U_U3_EN;
writel(tmp, port_base + U3P_USBPHYACR5);
@ -335,7 +345,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4);
writel(tmp, port_base + U3P_USBPHYACR5);
if (index) {
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
tmp = readl(port_base + U3D_U2PHYDCR0);
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0);
@ -386,7 +396,9 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
tmp = readl(port_base + U3P_U3_PHYA_REG0);
tmp &= ~P3A_RG_U3_VUSB10_ON;
writel(tmp, port_base + U3P_U3_PHYA_REG0);
} else {
}
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
tmp = readl(port_base + U3D_U2PHYDCR0);
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0);
@ -402,7 +414,7 @@ static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
u32 index = instance->index;
u32 tmp;
if (index) {
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
tmp = readl(port_base + U3D_U2PHYDCR0);
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0);
@ -502,8 +514,24 @@ static struct phy_ops mt65xx_u3phy_ops = {
.owner = THIS_MODULE,
};
static const struct mt65xx_phy_pdata mt2701_pdata = {
.avoid_rx_sen_degradation = false,
};
static const struct mt65xx_phy_pdata mt8173_pdata = {
.avoid_rx_sen_degradation = true,
};
static const struct of_device_id mt65xx_u3phy_id_table[] = {
{ .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata },
{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
{ },
};
MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table);
static int mt65xx_u3phy_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *child_np;
@ -513,10 +541,15 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
struct resource res;
int port, retval;
match = of_match_node(mt65xx_u3phy_id_table, pdev->dev.of_node);
if (!match)
return -EINVAL;
u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL);
if (!u3phy)
return -ENOMEM;
u3phy->pdata = match->data;
u3phy->nphys = of_get_child_count(np);
u3phy->phys = devm_kcalloc(dev, u3phy->nphys,
sizeof(*u3phy->phys), GFP_KERNEL);
@ -587,12 +620,6 @@ put_child:
return retval;
}
static const struct of_device_id mt65xx_u3phy_id_table[] = {
{ .compatible = "mediatek,mt8173-u3phy", },
{ },
};
MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table);
static struct platform_driver mt65xx_u3phy_driver = {
.probe = mt65xx_u3phy_probe,
.driver = {

View File

@ -195,6 +195,7 @@ static const struct of_device_id rcar_gen2_phy_match_table[] = {
{ .compatible = "renesas,usb-phy-r8a7790" },
{ .compatible = "renesas,usb-phy-r8a7791" },
{ .compatible = "renesas,usb-phy-r8a7794" },
{ .compatible = "renesas,rcar-gen2-usb-phy" },
{ }
};
MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table);

View File

@ -12,6 +12,7 @@
* published by the Free Software Foundation.
*/
#include <linux/extcon.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
@ -19,6 +20,7 @@
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
/******* USB2.0 Host registers (original offset is +0x200) *******/
#define USB2_INT_ENABLE 0x000
@ -74,20 +76,17 @@
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
#define USB2_ADPCTRL_DRVVBUS BIT(4)
struct rcar_gen3_data {
void __iomem *base;
struct clk *clk;
};
struct rcar_gen3_chan {
struct rcar_gen3_data usb2;
void __iomem *base;
struct extcon_dev *extcon;
struct phy *phy;
struct regulator *vbus;
bool has_otg;
};
static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
{
void __iomem *usb2_base = ch->usb2.base;
void __iomem *usb2_base = ch->base;
u32 val = readl(usb2_base + USB2_COMMCTRL);
dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host);
@ -100,7 +99,7 @@ static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
{
void __iomem *usb2_base = ch->usb2.base;
void __iomem *usb2_base = ch->base;
u32 val = readl(usb2_base + USB2_LINECTRL1);
dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm);
@ -114,7 +113,7 @@ static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
{
void __iomem *usb2_base = ch->usb2.base;
void __iomem *usb2_base = ch->base;
u32 val = readl(usb2_base + USB2_ADPCTRL);
dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus);
@ -130,6 +129,9 @@ static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
rcar_gen3_set_linectrl(ch, 1, 1);
rcar_gen3_set_host_mode(ch, 1);
rcar_gen3_enable_vbus_ctrl(ch, 1);
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
}
static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
@ -137,17 +139,20 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
rcar_gen3_set_linectrl(ch, 0, 1);
rcar_gen3_set_host_mode(ch, 0);
rcar_gen3_enable_vbus_ctrl(ch, 0);
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
}
static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch)
{
return !!(readl(ch->usb2.base + USB2_ADPCTRL) &
return !!(readl(ch->base + USB2_ADPCTRL) &
USB2_ADPCTRL_OTGSESSVLD);
}
static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
{
return !!(readl(ch->usb2.base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
}
static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch)
@ -166,7 +171,7 @@ static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch)
static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
{
void __iomem *usb2_base = ch->usb2.base;
void __iomem *usb2_base = ch->base;
u32 val;
val = readl(usb2_base + USB2_VBCTRL);
@ -187,7 +192,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
static int rcar_gen3_phy_usb2_init(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
void __iomem *usb2_base = channel->usb2.base;
void __iomem *usb2_base = channel->base;
/* Initialize USB2 part */
writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE);
@ -205,7 +210,7 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
writel(0, channel->usb2.base + USB2_INT_ENABLE);
writel(0, channel->base + USB2_INT_ENABLE);
return 0;
}
@ -213,8 +218,15 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
static int rcar_gen3_phy_usb2_power_on(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
void __iomem *usb2_base = channel->usb2.base;
void __iomem *usb2_base = channel->base;
u32 val;
int ret;
if (channel->vbus) {
ret = regulator_enable(channel->vbus);
if (ret)
return ret;
}
val = readl(usb2_base + USB2_USBCTR);
val |= USB2_USBCTR_PLL_RST;
@ -225,17 +237,29 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
return 0;
}
static int rcar_gen3_phy_usb2_power_off(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
int ret = 0;
if (channel->vbus)
ret = regulator_disable(channel->vbus);
return ret;
}
static struct phy_ops rcar_gen3_phy_usb2_ops = {
.init = rcar_gen3_phy_usb2_init,
.exit = rcar_gen3_phy_usb2_exit,
.power_on = rcar_gen3_phy_usb2_power_on,
.power_off = rcar_gen3_phy_usb2_power_off,
.owner = THIS_MODULE,
};
static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
{
struct rcar_gen3_chan *ch = _ch;
void __iomem *usb2_base = ch->usb2.base;
void __iomem *usb2_base = ch->base;
u32 status = readl(usb2_base + USB2_OBINTSTA);
irqreturn_t ret = IRQ_NONE;
@ -251,10 +275,17 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
{ .compatible = "renesas,usb2-phy-r8a7795" },
{ .compatible = "renesas,rcar-gen3-usb2-phy" },
{ }
};
MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table);
static const unsigned int rcar_gen3_phy_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
EXTCON_NONE,
};
static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -273,18 +304,30 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
channel->usb2.base = devm_ioremap_resource(dev, res);
if (IS_ERR(channel->usb2.base))
return PTR_ERR(channel->usb2.base);
channel->base = devm_ioremap_resource(dev, res);
if (IS_ERR(channel->base))
return PTR_ERR(channel->base);
/* call request_irq for OTG */
irq = platform_get_irq(pdev, 0);
if (irq >= 0) {
int ret;
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(dev), channel);
if (irq < 0)
dev_err(dev, "No irq handler (%d)\n", irq);
channel->has_otg = true;
channel->extcon = devm_extcon_dev_allocate(dev,
rcar_gen3_phy_cable);
if (IS_ERR(channel->extcon))
return PTR_ERR(channel->extcon);
ret = devm_extcon_dev_register(dev, channel->extcon);
if (ret < 0) {
dev_err(dev, "Failed to register extcon\n");
return ret;
}
}
/* devm_phy_create() will call pm_runtime_enable(dev); */
@ -294,6 +337,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
return PTR_ERR(channel->phy);
}
channel->vbus = devm_regulator_get_optional(dev, "vbus");
if (IS_ERR(channel->vbus)) {
if (PTR_ERR(channel->vbus) == -EPROBE_DEFER)
return PTR_ERR(channel->vbus);
channel->vbus = NULL;
}
phy_set_drvdata(channel->phy, channel);
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);

View File

@ -216,7 +216,7 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
init.parent_names = &clk_name;
init.num_parents = 1;
} else {
init.flags = CLK_IS_ROOT;
init.flags = 0;
init.parent_names = NULL;
init.num_parents = 0;
}

View File

@ -31,8 +31,6 @@ if USB_SUPPORT
config USB_COMMON
tristate
default y
depends on USB || USB_GADGET
config USB_ARCH_HAS_HCD
def_bool y
@ -41,6 +39,7 @@ config USB_ARCH_HAS_HCD
config USB
tristate "Support for Host-side USB"
depends on USB_ARCH_HAS_HCD
select USB_COMMON
select NLS # for UTF-8 strings
---help---
Universal Serial Bus (USB) is a specification for a serial bus

View File

@ -173,10 +173,10 @@ struct uea_softc {
const struct firmware *dsp_firm;
struct urb *urb_int;
void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
int (*stat) (struct uea_softc *);
int (*send_cmvs) (struct uea_softc *);
void (*dispatch_cmv)(struct uea_softc *, struct intr_pkt *);
void (*schedule_load_page)(struct uea_softc *, struct intr_pkt *);
int (*stat)(struct uea_softc *);
int (*send_cmvs)(struct uea_softc *);
/* keep in sync with eaglectl */
struct uea_stats {
@ -2454,7 +2454,7 @@ UEA_ATTR(firmid, 0);
/* Retrieve the device End System Identifier (MAC) */
static int uea_getesi(struct uea_softc *sc, u_char * esi)
static int uea_getesi(struct uea_softc *sc, u_char *esi)
{
unsigned char mac_str[2 * ETH_ALEN + 1];
int i;

View File

@ -292,10 +292,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
data->supports_runtime_pm = true;
ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (ret)
goto err_clk;
ret = imx_usbmisc_init(data->usbmisc_data);
if (ret) {
dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret);

View File

@ -61,8 +61,6 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
return 0;
}
static int state_changed;
/* Called when leaving a state. Do state clean up jobs here */
static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
{
@ -208,7 +206,6 @@ static void otg_start_hnp_polling(struct otg_fsm *fsm)
/* Called when entering a state */
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
{
state_changed = 1;
if (fsm->otg->state == new_state)
return 0;
VDBG("Set state: %s\n", usb_otg_state_string(new_state));
@ -324,6 +321,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
}
fsm->otg->state = new_state;
fsm->state_changed = 1;
return 0;
}
@ -335,7 +333,7 @@ int otg_statemachine(struct otg_fsm *fsm)
mutex_lock(&fsm->lock);
state = fsm->otg->state;
state_changed = 0;
fsm->state_changed = 0;
/* State machine state change judgement */
switch (state) {
@ -448,7 +446,7 @@ int otg_statemachine(struct otg_fsm *fsm)
}
mutex_unlock(&fsm->lock);
VDBG("quit statemachine, changed = %d\n", state_changed);
return state_changed;
VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
return fsm->state_changed;
}
EXPORT_SYMBOL_GPL(otg_statemachine);

View File

@ -122,6 +122,9 @@ void *hcd_buffer_alloc(
struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
if (size == 0)
return NULL;
/* some USB hosts just use PIO */
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
(!bus->controller->dma_mask &&

View File

@ -216,7 +216,7 @@ static void usbdev_vm_close(struct vm_area_struct *vma)
dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
}
struct vm_operations_struct usbdev_vm_ops = {
static struct vm_operations_struct usbdev_vm_ops = {
.open = usbdev_vm_open,
.close = usbdev_vm_close
};
@ -1316,10 +1316,11 @@ static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_connectinfo ci = {
.devnum = ps->dev->devnum,
.slow = ps->dev->speed == USB_SPEED_LOW
};
struct usbdevfs_connectinfo ci;
memset(&ci, 0, sizeof(ci));
ci.devnum = ps->dev->devnum;
ci.slow = ps->dev->speed == USB_SPEED_LOW;
if (copy_to_user(arg, &ci, sizeof(ci)))
return -EFAULT;

View File

@ -284,7 +284,7 @@ static int usb_probe_interface(struct device *dev)
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;
int lpm_disable_error;
int lpm_disable_error = -ENODEV;
dev_dbg(dev, "%s\n", __func__);
@ -336,12 +336,14 @@ static int usb_probe_interface(struct device *dev)
* setting during probe, that should also be fine. usb_set_interface()
* will attempt to disable LPM, and fail if it can't disable it.
*/
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
__func__, driver->name);
error = lpm_disable_error;
goto err;
if (driver->disable_hub_initiated_lpm) {
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (lpm_disable_error) {
dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
__func__, driver->name);
error = lpm_disable_error;
goto err;
}
}
/* Carry out a deferred switch to altsetting 0 */
@ -391,7 +393,8 @@ static int usb_unbind_interface(struct device *dev)
struct usb_interface *intf = to_usb_interface(dev);
struct usb_host_endpoint *ep, **eps = NULL;
struct usb_device *udev;
int i, j, error, r, lpm_disable_error;
int i, j, error, r;
int lpm_disable_error = -ENODEV;
intf->condition = USB_INTERFACE_UNBINDING;
@ -399,12 +402,13 @@ static int usb_unbind_interface(struct device *dev)
udev = interface_to_usbdev(intf);
error = usb_autoresume_device(udev);
/* Hub-initiated LPM policy may change, so attempt to disable LPM until
/* If hub-initiated LPM policy may change, attempt to disable LPM until
* the driver is unbound. If LPM isn't disabled, that's fine because it
* wouldn't be enabled unless all the bound interfaces supported
* hub-initiated LPM.
*/
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (driver->disable_hub_initiated_lpm)
lpm_disable_error = usb_unlocked_disable_lpm(udev);
/*
* Terminate all URBs for this interface unless the driver
@ -505,7 +509,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
struct device *dev;
struct usb_device *udev;
int retval = 0;
int lpm_disable_error;
int lpm_disable_error = -ENODEV;
if (!iface)
return -ENODEV;
@ -526,12 +530,14 @@ int usb_driver_claim_interface(struct usb_driver *driver,
iface->condition = USB_INTERFACE_BOUND;
/* Disable LPM until this driver is bound. */
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
__func__, driver->name);
return -ENOMEM;
/* See the comment about disabling LPM in usb_probe_interface(). */
if (driver->disable_hub_initiated_lpm) {
lpm_disable_error = usb_unlocked_disable_lpm(udev);
if (lpm_disable_error) {
dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
__func__, driver->name);
return -ENOMEM;
}
}
/* Claimed interfaces are initially inactive (suspended) and

View File

@ -994,7 +994,7 @@ static void usb_bus_init (struct usb_bus *bus)
bus->bandwidth_allocated = 0;
bus->bandwidth_int_reqs = 0;
bus->bandwidth_isoc_reqs = 0;
mutex_init(&bus->usb_address0_mutex);
mutex_init(&bus->devnum_next_mutex);
}
/*-------------------------------------------------------------------------*/
@ -1118,6 +1118,7 @@ static int register_root_hub(struct usb_hcd *hcd)
/* Did the HC die before the root hub was registered? */
if (HCD_DEAD(hcd))
usb_hc_died (hcd); /* This time clean up */
usb_dev->dev.of_node = parent_dev->of_node;
}
mutex_unlock(&usb_bus_idr_lock);
@ -2521,6 +2522,14 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
return NULL;
}
if (primary_hcd == NULL) {
hcd->address0_mutex = kmalloc(sizeof(*hcd->address0_mutex),
GFP_KERNEL);
if (!hcd->address0_mutex) {
kfree(hcd);
dev_dbg(dev, "hcd address0 mutex alloc failed\n");
return NULL;
}
mutex_init(hcd->address0_mutex);
hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
GFP_KERNEL);
if (!hcd->bandwidth_mutex) {
@ -2532,6 +2541,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
dev_set_drvdata(dev, hcd);
} else {
mutex_lock(&usb_port_peer_mutex);
hcd->address0_mutex = primary_hcd->address0_mutex;
hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
hcd->primary_hcd = primary_hcd;
primary_hcd->primary_hcd = primary_hcd;
@ -2598,8 +2608,10 @@ static void hcd_release(struct kref *kref)
struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
mutex_lock(&usb_port_peer_mutex);
if (usb_hcd_is_primary_hcd(hcd))
if (usb_hcd_is_primary_hcd(hcd)) {
kfree(hcd->address0_mutex);
kfree(hcd->bandwidth_mutex);
}
if (hcd->shared_hcd) {
struct usb_hcd *peer = hcd->shared_hcd;

View File

@ -104,6 +104,8 @@ static int usb_reset_and_verify_device(struct usb_device *udev);
static inline char *portspeed(struct usb_hub *hub, int portstatus)
{
if (hub_is_superspeedplus(hub->hdev))
return "10.0 Gb/s";
if (hub_is_superspeed(hub->hdev))
return "5.0 Gb/s";
if (portstatus & USB_PORT_STAT_HIGH_SPEED)
@ -2080,7 +2082,7 @@ static void choose_devnum(struct usb_device *udev)
struct usb_bus *bus = udev->bus;
/* be safe when more hub events are proceed in parallel */
mutex_lock(&bus->usb_address0_mutex);
mutex_lock(&bus->devnum_next_mutex);
if (udev->wusb) {
devnum = udev->portnum + 1;
BUG_ON(test_bit(devnum, bus->devmap.devicemap));
@ -2098,7 +2100,7 @@ static void choose_devnum(struct usb_device *udev)
set_bit(devnum, bus->devmap.devicemap);
udev->devnum = devnum;
}
mutex_unlock(&bus->usb_address0_mutex);
mutex_unlock(&bus->devnum_next_mutex);
}
static void release_devnum(struct usb_device *udev)
@ -4364,7 +4366,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
if (oldspeed == USB_SPEED_LOW)
delay = HUB_LONG_RESET_TIME;
mutex_lock(&hdev->bus->usb_address0_mutex);
mutex_lock(hcd->address0_mutex);
/* Reset the device; full speed may morph to high speed */
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
@ -4650,7 +4652,7 @@ fail:
hub_port_disable(hub, port1, 0);
update_devnum(udev, devnum); /* for disconnect processing */
}
mutex_unlock(&hdev->bus->usb_address0_mutex);
mutex_unlock(hcd->address0_mutex);
return retval;
}

View File

@ -302,9 +302,10 @@ static void sg_complete(struct urb *urb)
*/
spin_unlock(&io->lock);
for (i = 0, found = 0; i < io->entries; i++) {
if (!io->urbs[i] || !io->urbs[i]->dev)
if (!io->urbs[i])
continue;
if (found) {
usb_block_urb(io->urbs[i]);
retval = usb_unlink_urb(io->urbs[i]);
if (retval != -EINPROGRESS &&
retval != -ENODEV &&
@ -515,12 +516,10 @@ void usb_sg_wait(struct usb_sg_request *io)
int retval;
io->urbs[i]->dev = io->dev;
retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
/* after we submit, let completions or cancellations fire;
* we handshake using io->status.
*/
spin_unlock_irq(&io->lock);
retval = usb_submit_urb(io->urbs[i], GFP_NOIO);
switch (retval) {
/* maybe we retrying will recover */
case -ENXIO: /* hc didn't queue this one */
@ -578,31 +577,28 @@ EXPORT_SYMBOL_GPL(usb_sg_wait);
void usb_sg_cancel(struct usb_sg_request *io)
{
unsigned long flags;
int i, retval;
spin_lock_irqsave(&io->lock, flags);
/* shut everything down, if it didn't already */
if (!io->status) {
int i;
io->status = -ECONNRESET;
spin_unlock(&io->lock);
for (i = 0; i < io->entries; i++) {
int retval;
if (!io->urbs[i]->dev)
continue;
retval = usb_unlink_urb(io->urbs[i]);
if (retval != -EINPROGRESS
&& retval != -ENODEV
&& retval != -EBUSY
&& retval != -EIDRM)
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
__func__, retval);
}
spin_lock(&io->lock);
if (io->status) {
spin_unlock_irqrestore(&io->lock, flags);
return;
}
/* shut everything down */
io->status = -ECONNRESET;
spin_unlock_irqrestore(&io->lock, flags);
for (i = io->entries - 1; i >= 0; --i) {
usb_block_urb(io->urbs[i]);
retval = usb_unlink_urb(io->urbs[i]);
if (retval != -EINPROGRESS
&& retval != -ENODEV
&& retval != -EBUSY
&& retval != -EIDRM)
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
__func__, retval);
}
}
EXPORT_SYMBOL_GPL(usb_sg_cancel);

View File

@ -466,7 +466,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->route = 0;
dev->dev.parent = bus->controller;
dev->dev.of_node = bus->controller->of_node;
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
} else {

View File

@ -2425,6 +2425,9 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
u32 gintsts;
u32 gintmsk;
if (!dwc2_is_device_mode(hsotg))
return IRQ_NONE;
spin_lock(&hsotg->lock);
irq_retry:
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
@ -2631,7 +2634,10 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
desc->wMaxPacketSize, desc->bInterval);
/* not to be called for EP0 */
WARN_ON(index == 0);
if (index == 0) {
dev_err(hsotg->dev, "%s: called for EP 0\n", __func__);
return -EINVAL;
}
dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
if (dir_in != hs_ep->dir_in) {

View File

@ -4703,6 +4703,7 @@ fail2:
spin_unlock_irqrestore(&hsotg->lock, flags);
urb->hcpriv = NULL;
kfree(qtd);
qtd = NULL;
fail1:
if (qh_allocated) {
struct dwc2_qtd *qtd2, *qtd2_tmp;

View File

@ -552,6 +552,7 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
{
list_del(&qtd->qtd_list_entry);
kfree(qtd);
qtd = NULL;
}
/* Descriptor DMA support functions */

View File

@ -1709,7 +1709,8 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
dwc2_deschedule_periodic(hsotg, qh);
hsotg->periodic_qh_count--;
if (!hsotg->periodic_qh_count) {
if (!hsotg->periodic_qh_count &&
hsotg->core_params->dma_desc_enable <= 0) {
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
intr_mask &= ~GINTSTS_SOF;
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);

View File

@ -562,7 +562,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
retval = dwc2_get_dr_mode(hsotg);
if (retval)
return retval;
goto error;
/*
* Reset before dwc2_get_hwparams() then it could get power-on real

View File

@ -60,6 +60,20 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
{
struct dwc3 *dwc = dep->dwc;
u32 reg;
dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
DWC3_GDBGFIFOSPACE_NUM(dep->number) |
DWC3_GDBGFIFOSPACE_TYPE(type));
reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
}
/**
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
* @dwc: pointer to our context structure
@ -203,13 +217,10 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
static void dwc3_free_event_buffers(struct dwc3 *dwc)
{
struct dwc3_event_buffer *evt;
int i;
for (i = 0; i < dwc->num_event_buffers; i++) {
evt = dwc->ev_buffs[i];
if (evt)
dwc3_free_one_event_buffer(dwc, evt);
}
evt = dwc->ev_buf;
if (evt)
dwc3_free_one_event_buffer(dwc, evt);
}
/**
@ -222,27 +233,14 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
*/
static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
{
int num;
int i;
struct dwc3_event_buffer *evt;
num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
dwc->num_event_buffers = num;
dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
GFP_KERNEL);
if (!dwc->ev_buffs)
return -ENOMEM;
for (i = 0; i < num; i++) {
struct dwc3_event_buffer *evt;
evt = dwc3_alloc_one_event_buffer(dwc, length);
if (IS_ERR(evt)) {
dev_err(dwc->dev, "can't allocate event buffer\n");
return PTR_ERR(evt);
}
dwc->ev_buffs[i] = evt;
evt = dwc3_alloc_one_event_buffer(dwc, length);
if (IS_ERR(evt)) {
dev_err(dwc->dev, "can't allocate event buffer\n");
return PTR_ERR(evt);
}
dwc->ev_buf = evt;
return 0;
}
@ -256,25 +254,22 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
static int dwc3_event_buffers_setup(struct dwc3 *dwc)
{
struct dwc3_event_buffer *evt;
int n;
for (n = 0; n < dwc->num_event_buffers; n++) {
evt = dwc->ev_buffs[n];
dwc3_trace(trace_dwc3_core,
"Event buf %p dma %08llx length %d\n",
evt->buf, (unsigned long long) evt->dma,
evt->length);
evt = dwc->ev_buf;
dwc3_trace(trace_dwc3_core,
"Event buf %p dma %08llx length %d\n",
evt->buf, (unsigned long long) evt->dma,
evt->length);
evt->lpos = 0;
evt->lpos = 0;
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
lower_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
upper_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
DWC3_GEVNTSIZ_SIZE(evt->length));
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
}
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
lower_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
upper_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
DWC3_GEVNTSIZ_SIZE(evt->length));
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
return 0;
}
@ -282,19 +277,16 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc)
static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
{
struct dwc3_event_buffer *evt;
int n;
for (n = 0; n < dwc->num_event_buffers; n++) {
evt = dwc->ev_buffs[n];
evt = dwc->ev_buf;
evt->lpos = 0;
evt->lpos = 0;
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
| DWC3_GEVNTSIZ_SIZE(0));
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
}
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
| DWC3_GEVNTSIZ_SIZE(0));
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
}
static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
@ -434,6 +426,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->u2ss_inp3_quirk)
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
if (dwc->dis_rxdet_inp3_quirk)
reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
if (dwc->req_p1p2p3_quirk)
reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
@ -882,9 +877,6 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->usb3_lpm_capable = device_property_read_bool(dev,
"snps,usb3_lpm_capable");
dwc->needs_fifo_resize = device_property_read_bool(dev,
"tx-fifo-resize");
dwc->disable_scramble_quirk = device_property_read_bool(dev,
"snps,disable_scramble_quirk");
dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
@ -907,6 +899,8 @@ static int dwc3_probe(struct platform_device *pdev)
"snps,dis_u2_susphy_quirk");
dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
"snps,dis_enblslpm_quirk");
dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
"snps,dis_rxdet_inp3_quirk");
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
"snps,tx_de_emphasis_quirk");
@ -926,7 +920,6 @@ static int dwc3_probe(struct platform_device *pdev)
if (pdata->hird_threshold)
hird_threshold = pdata->hird_threshold;
dwc->needs_fifo_resize = pdata->tx_fifo_resize;
dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
dwc->dr_mode = pdata->dr_mode;
@ -941,6 +934,7 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
if (pdata->tx_de_emphasis)
@ -1050,19 +1044,11 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret)
goto err5;
ret = dwc3_debugfs_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize debugfs\n");
goto err6;
}
dwc3_debugfs_init(dwc);
pm_runtime_allow(dev);
return 0;
err6:
dwc3_core_exit_mode(dwc);
err5:
dwc3_event_buffers_cleanup(dwc);

View File

@ -152,6 +152,24 @@
/* Bit fields */
/* Global Debug Queue/FIFO Space Available Register */
#define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f)
#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0)
#define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff)
#define DWC3_TXFIFOQ 1
#define DWC3_RXFIFOQ 3
#define DWC3_TXREQQ 5
#define DWC3_RXREQQ 7
#define DWC3_RXINFOQ 9
#define DWC3_DESCFETCHQ 13
#define DWC3_EVENTQ 15
/* Global RX Threshold Configuration Register */
#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
#define DWC3_GRXTHRCFG_PKTCNTSEL (1 << 29)
/* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
#define DWC3_GCTL_U2RSTECN (1 << 16)
@ -193,6 +211,7 @@
/* Global USB3 PIPE Control Register */
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
#define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29)
#define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28)
#define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24)
#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19)
#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7)
@ -257,6 +276,9 @@
#define DWC3_DCFG_LOWSPEED (2 << 0)
#define DWC3_DCFG_FULLSPEED1 (3 << 0)
#define DWC3_DCFG_NUMP_SHIFT 17
#define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f)
#define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT)
#define DWC3_DCFG_LPM_CAP (1 << 22)
/* Device Control Register */
@ -438,18 +460,17 @@ struct dwc3_event_buffer {
#define DWC3_EP_DIRECTION_TX true
#define DWC3_EP_DIRECTION_RX false
#define DWC3_TRB_NUM 32
#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1)
#define DWC3_TRB_NUM 256
/**
* struct dwc3_ep - device side endpoint representation
* @endpoint: usb endpoint
* @request_list: list of requests for this endpoint
* @req_queued: list of requests on this ep which have TRBs setup
* @pending_list: list of pending requests for this endpoint
* @started_list: list of started requests on this endpoint
* @trb_pool: array of transaction buffers
* @trb_pool_dma: dma address of @trb_pool
* @free_slot: next slot which is going to be used
* @busy_slot: first slot which is owned by HW
* @trb_enqueue: enqueue 'pointer' into TRB array
* @trb_dequeue: dequeue 'pointer' into TRB array
* @desc: usb_endpoint_descriptor pointer
* @dwc: pointer to DWC controller
* @saved_state: ep state saved during hibernation
@ -464,13 +485,11 @@ struct dwc3_event_buffer {
*/
struct dwc3_ep {
struct usb_ep endpoint;
struct list_head request_list;
struct list_head req_queued;
struct list_head pending_list;
struct list_head started_list;
struct dwc3_trb *trb_pool;
dma_addr_t trb_pool_dma;
u32 free_slot;
u32 busy_slot;
const struct usb_ss_ep_comp_descriptor *comp_desc;
struct dwc3 *dwc;
@ -486,6 +505,18 @@ struct dwc3_ep {
/* This last one is specific to EP0 */
#define DWC3_EP0_DIR_IN (1 << 31)
/*
* IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will
* use a u8 type here. If anybody decides to increase number of TRBs to
* anything larger than 256 - I can't see why people would want to do
* this though - then this type needs to be changed.
*
* By using u8 types we ensure that our % operator when incrementing
* enqueue and dequeue get optimized away by the compiler.
*/
u8 trb_enqueue;
u8 trb_dequeue;
u8 number;
u8 type;
u8 resource_index;
@ -557,6 +588,7 @@ enum dwc3_link_state {
#define DWC3_TRB_CTRL_IOC (1 << 11)
#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4))
#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1)
#define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2)
#define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3)
@ -623,19 +655,32 @@ struct dwc3_hwparams {
/* HWPARAMS7 */
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
/**
* struct dwc3_request - representation of a transfer request
* @request: struct usb_request to be transferred
* @list: a list_head used for request queueing
* @dep: struct dwc3_ep owning this request
* @first_trb_index: index to first trb used by this request
* @epnum: endpoint number to which this request refers
* @trb: pointer to struct dwc3_trb
* @trb_dma: DMA address of @trb
* @direction: IN or OUT direction flag
* @mapped: true when request has been dma-mapped
* @queued: true when request has been queued to HW
*/
struct dwc3_request {
struct usb_request request;
struct list_head list;
struct dwc3_ep *dep;
u32 start_slot;
u8 first_trb_index;
u8 epnum;
struct dwc3_trb *trb;
dma_addr_t trb_dma;
unsigned direction:1;
unsigned mapped:1;
unsigned queued:1;
unsigned started:1;
};
/*
@ -667,7 +712,6 @@ struct dwc3_scratchpad_array {
* @regs: base address for our registers
* @regs_size: address space size
* @nr_scratch: number of scratch buffers
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents
@ -709,9 +753,7 @@ struct dwc3_scratchpad_array {
* 0 - utmi_sleep_n
* 1 - utmi_l1_suspend_n
* @is_fpga: true when we are using the FPGA board
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @pullups_connected: true when Run/Stop bit is set
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @start_config_issued: true when StartConfig command has been issued
* @three_stage_setup: set if we perform a three phase setup
@ -756,7 +798,7 @@ struct dwc3 {
struct platform_device *xhci;
struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
struct dwc3_event_buffer **ev_buffs;
struct dwc3_event_buffer *ev_buf;
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
struct usb_gadget gadget;
@ -780,7 +822,6 @@ struct dwc3 {
u32 gctl;
u32 nr_scratch;
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@ -855,9 +896,7 @@ struct dwc3 {
unsigned has_lpm_erratum:1;
unsigned is_utmi_l1_suspend:1;
unsigned is_fpga:1;
unsigned needs_fifo_resize:1;
unsigned pullups_connected:1;
unsigned resize_fifos:1;
unsigned setup_packet_pending:1;
unsigned three_stage_setup:1;
unsigned usb3_lpm_capable:1;
@ -873,6 +912,7 @@ struct dwc3 {
unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1;
unsigned dis_rxdet_inp3_quirk:1;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
@ -938,6 +978,10 @@ struct dwc3_event_depevt {
#define DEPEVT_STATUS_CONTROL_DATA 1
#define DEPEVT_STATUS_CONTROL_STATUS 2
/* In response to Start Transfer */
#define DEPEVT_TRANSFER_NO_RESOURCE 1
#define DEPEVT_TRANSFER_BUS_EXPIRY 2
u32 parameters:16;
} __packed;
@ -1025,7 +1069,7 @@ struct dwc3_gadget_ep_cmd_params {
/* prototypes */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
/* check whether we are on the DWC_usb31 core */
static inline bool dwc3_is_usb31(struct dwc3 *dwc)

View File

@ -217,11 +217,11 @@ static inline const char *dwc3_gadget_event_type_string(u8 event)
void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...);
#ifdef CONFIG_DEBUG_FS
extern int dwc3_debugfs_init(struct dwc3 *);
extern void dwc3_debugfs_init(struct dwc3 *);
extern void dwc3_debugfs_exit(struct dwc3 *);
#else
static inline int dwc3_debugfs_init(struct dwc3 *d)
{ return 0; }
static inline void dwc3_debugfs_init(struct dwc3 *d)
{ }
static inline void dwc3_debugfs_exit(struct dwc3 *d)
{ }
#endif

View File

@ -618,24 +618,323 @@ static const struct file_operations dwc3_link_state_fops = {
.release = single_release,
};
int dwc3_debugfs_init(struct dwc3 *dwc)
{
struct dentry *root;
struct dentry *file;
int ret;
struct dwc3_ep_file_map {
char name[25];
int (*show)(struct seq_file *s, void *unused);
};
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
if (!root) {
ret = -ENOMEM;
goto err0;
static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_TXREQQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXREQQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_event_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_EVENTQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_ep_transfer_type_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
if (!(dep->flags & DWC3_EP_ENABLED) ||
!dep->endpoint.desc) {
seq_printf(s, "--\n");
goto out;
}
switch (usb_endpoint_type(dep->endpoint.desc)) {
case USB_ENDPOINT_XFER_CONTROL:
seq_printf(s, "control\n");
break;
case USB_ENDPOINT_XFER_ISOC:
seq_printf(s, "isochronous\n");
break;
case USB_ENDPOINT_XFER_BULK:
seq_printf(s, "bulk\n");
break;
case USB_ENDPOINT_XFER_INT:
seq_printf(s, "interrupt\n");
break;
default:
seq_printf(s, "--\n");
}
out:
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static inline const char *dwc3_trb_type_string(struct dwc3_trb *trb)
{
switch (DWC3_TRBCTL_TYPE(trb->ctrl)) {
case DWC3_TRBCTL_NORMAL:
return "normal";
case DWC3_TRBCTL_CONTROL_SETUP:
return "control-setup";
case DWC3_TRBCTL_CONTROL_STATUS2:
return "control-status2";
case DWC3_TRBCTL_CONTROL_STATUS3:
return "control-status3";
case DWC3_TRBCTL_CONTROL_DATA:
return "control-data";
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
return "isoc-first";
case DWC3_TRBCTL_ISOCHRONOUS:
return "isoc";
case DWC3_TRBCTL_LINK_TRB:
return "link";
default:
return "UNKNOWN";
}
}
static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
int i;
spin_lock_irqsave(&dwc->lock, flags);
if (dep->number <= 1) {
seq_printf(s, "--\n");
goto out;
}
seq_printf(s, "enqueue pointer %d\n", dep->trb_enqueue);
seq_printf(s, "dequeue pointer %d\n", dep->trb_dequeue);
seq_printf(s, "\n--------------------------------------------------\n\n");
seq_printf(s, "buffer_addr,size,type,ioc,isp_imi,csp,chn,lst,hwo\n");
for (i = 0; i < DWC3_TRB_NUM; i++) {
struct dwc3_trb *trb = &dep->trb_pool[i];
seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n",
trb->bph, trb->bpl, trb->size,
dwc3_trb_type_string(trb),
!!(trb->ctrl & DWC3_TRB_CTRL_IOC),
!!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
!!(trb->ctrl & DWC3_TRB_CTRL_CSP),
!!(trb->ctrl & DWC3_TRB_CTRL_CHN),
!!(trb->ctrl & DWC3_TRB_CTRL_LST),
!!(trb->ctrl & DWC3_TRB_CTRL_HWO));
}
out:
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static struct dwc3_ep_file_map map[] = {
{ "tx_fifo_queue", dwc3_tx_fifo_queue_show, },
{ "rx_fifo_queue", dwc3_rx_fifo_queue_show, },
{ "tx_request_queue", dwc3_tx_request_queue_show, },
{ "rx_request_queue", dwc3_rx_request_queue_show, },
{ "rx_info_queue", dwc3_rx_info_queue_show, },
{ "descriptor_fetch_queue", dwc3_descriptor_fetch_queue_show, },
{ "event_queue", dwc3_event_queue_show, },
{ "transfer_type", dwc3_ep_transfer_type_show, },
{ "trb_ring", dwc3_ep_trb_ring_show, },
};
static int dwc3_endpoint_open(struct inode *inode, struct file *file)
{
const char *file_name = file_dentry(file)->d_iname;
struct dwc3_ep_file_map *f_map;
int i;
for (i = 0; i < ARRAY_SIZE(map); i++) {
f_map = &map[i];
if (strcmp(f_map->name, file_name) == 0)
break;
}
return single_open(file, f_map->show, inode->i_private);
}
static const struct file_operations dwc3_endpoint_fops = {
.open = dwc3_endpoint_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void dwc3_debugfs_create_endpoint_file(struct dwc3_ep *dep,
struct dentry *parent, int type)
{
struct dentry *file;
struct dwc3_ep_file_map *ep_file = &map[type];
file = debugfs_create_file(ep_file->name, S_IRUGO, parent, dep,
&dwc3_endpoint_fops);
}
static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
struct dentry *parent)
{
int i;
for (i = 0; i < ARRAY_SIZE(map); i++)
dwc3_debugfs_create_endpoint_file(dep, parent, i);
}
static void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep,
struct dentry *parent)
{
struct dentry *dir;
dir = debugfs_create_dir(dep->name, parent);
if (IS_ERR_OR_NULL(dir))
return;
dwc3_debugfs_create_endpoint_files(dep, dir);
}
static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc,
struct dentry *parent)
{
int i;
for (i = 0; i < dwc->num_in_eps; i++) {
u8 epnum = (i << 1) | 1;
struct dwc3_ep *dep = dwc->eps[epnum];
if (!dep)
continue;
dwc3_debugfs_create_endpoint_dir(dep, parent);
}
for (i = 0; i < dwc->num_out_eps; i++) {
u8 epnum = (i << 1);
struct dwc3_ep *dep = dwc->eps[epnum];
if (!dep)
continue;
dwc3_debugfs_create_endpoint_dir(dep, parent);
}
}
void dwc3_debugfs_init(struct dwc3 *dwc)
{
struct dentry *root;
struct dentry *file;
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
if (IS_ERR_OR_NULL(root)) {
if (!root)
dev_err(dwc->dev, "Can't create debugfs root\n");
return;
}
dwc->root = root;
dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL);
if (!dwc->regset) {
ret = -ENOMEM;
goto err1;
debugfs_remove_recursive(root);
return;
}
dwc->regset->regs = dwc3_regs;
@ -643,47 +942,30 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
dwc->regset->base = dwc->regs;
file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
if (!file) {
ret = -ENOMEM;
goto err2;
}
if (!file)
dev_dbg(dwc->dev, "Can't create debugfs regdump\n");
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_mode_fops);
if (!file) {
ret = -ENOMEM;
goto err2;
}
if (!file)
dev_dbg(dwc->dev, "Can't create debugfs mode\n");
}
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_testmode_fops);
if (!file) {
ret = -ENOMEM;
goto err2;
}
if (!file)
dev_dbg(dwc->dev, "Can't create debugfs testmode\n");
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_link_state_fops);
if (!file) {
ret = -ENOMEM;
goto err2;
}
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR,
root, dwc, &dwc3_link_state_fops);
if (!file)
dev_dbg(dwc->dev, "Can't create debugfs link_state\n");
dwc3_debugfs_create_endpoint_dirs(dwc, root);
}
return 0;
err2:
kfree(dwc->regset);
err1:
debugfs_remove_recursive(root);
err0:
return ret;
}
void dwc3_debugfs_exit(struct dwc3 *dwc)

View File

@ -126,8 +126,6 @@ struct dwc3_omap {
u32 debug_offset;
u32 irq0_offset;
u32 dma_status:1;
struct extcon_dev *edev;
struct notifier_block vbus_nb;
struct notifier_block id_nb;
@ -277,9 +275,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
reg = dwc3_omap_read_irqmisc_status(omap);
if (reg & USBOTGSS_IRQMISC_DMADISABLECLR)
omap->dma_status = false;
dwc3_omap_write_irqmisc_status(omap, reg);
reg = dwc3_omap_read_irq0_status(omap);
@ -331,8 +326,6 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
dwc3_omap_write_irqmisc_clr(omap, reg);
}
static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
static int dwc3_omap_id_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
@ -490,7 +483,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
omap->irq = irq;
omap->base = base;
omap->vbus_reg = vbus_reg;
dev->dma_mask = &dwc3_omap_dma_mask;
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
@ -504,7 +496,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
/* check the DMA Status */
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);

View File

@ -47,7 +47,7 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
{ },
};
static int dwc3_pci_quirks(struct pci_dev *pdev)
static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3)
{
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
@ -77,8 +77,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
pdata.dis_u3_susphy_quirk = true;
pdata.dis_u2_susphy_quirk = true;
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
sizeof(pdata));
return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
@ -123,8 +122,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
pdata.has_lpm_erratum = true;
pdata.dis_enblslpm_quirk = true;
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
sizeof(pdata));
return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
}
return 0;
@ -169,20 +167,20 @@ static int dwc3_pci_probe(struct pci_dev *pci,
return ret;
}
pci_set_drvdata(pci, dwc3);
ret = dwc3_pci_quirks(pci);
if (ret)
goto err;
dwc3->dev.parent = dev;
ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev));
ret = dwc3_pci_quirks(pci, dwc3);
if (ret)
goto err;
ret = platform_device_add(dwc3);
if (ret) {
dev_err(dev, "failed to register dwc3 device\n");
goto err;
}
pci_set_drvdata(pci, dwc3);
return 0;
err:
platform_device_put(dwc3);

View File

@ -70,10 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
return 0;
}
trb = &dwc->ep0_trb[dep->free_slot];
trb = &dwc->ep0_trb[dep->trb_enqueue];
if (chain)
dep->free_slot++;
dep->trb_enqueue++;
trb->bpl = lower_32_bits(buf_dma);
trb->bph = upper_32_bits(buf_dma);
@ -124,7 +124,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
req->request.status = -EINPROGRESS;
req->epnum = dep->number;
list_add_tail(&req->list, &dep->request_list);
list_add_tail(&req->list, &dep->pending_list);
/*
* Gadget driver might not be quick enough to queue a request
@ -240,7 +240,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
}
/* we share one TRB for ep0/1 */
if (!list_empty(&dep->request_list)) {
if (!list_empty(&dep->pending_list)) {
ret = -EBUSY;
goto out;
}
@ -272,10 +272,10 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
dep->flags = DWC3_EP_ENABLED;
dwc->delayed_status = false;
if (!list_empty(&dep->request_list)) {
if (!list_empty(&dep->pending_list)) {
struct dwc3_request *req;
req = next_request(&dep->request_list);
req = next_request(&dep->pending_list);
dwc3_gadget_giveback(dep, req, -ECONNRESET);
}
@ -463,8 +463,18 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
if (!set)
return -EINVAL;
dwc->test_mode_nr = wIndex >> 8;
dwc->test_mode = true;
switch (wIndex >> 8) {
case TEST_J:
case TEST_K:
case TEST_SE0_NAK:
case TEST_PACKET:
case TEST_FORCE_EN:
dwc->test_mode_nr = wIndex >> 8;
dwc->test_mode = true;
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
@ -586,9 +596,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->resize_fifos = true;
dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");
}
break;
@ -809,7 +816,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
trace_dwc3_complete_trb(ep0, trb);
r = next_request(&ep0->request_list);
r = next_request(&ep0->pending_list);
if (!r)
return;
@ -848,7 +855,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
trb++;
length = trb->size & DWC3_TRB_SIZE_MASK;
ep0->free_slot = 0;
ep0->trb_enqueue = 0;
}
transfer_size = roundup((ur->length - transfer_size),
@ -897,8 +904,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
trace_dwc3_complete_trb(dep, trb);
if (!list_empty(&dep->request_list)) {
r = next_request(&dep->request_list);
if (!list_empty(&dep->pending_list)) {
r = next_request(&dep->pending_list);
dwc3_gadget_giveback(dep, r, 0);
}
@ -1027,12 +1034,6 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
{
if (dwc->resize_fifos) {
dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
dwc3_gadget_resize_tx_fifos(dwc);
dwc->resize_fifos = 0;
}
WARN_ON(dwc3_ep0_start_control_status(dep));
}

View File

@ -145,90 +145,21 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
return -ETIMEDOUT;
}
/**
* dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
* @dwc: pointer to our context structure
*
* This function will a best effort FIFO allocation in order
* to improve FIFO usage and throughput, while still allowing
* us to enable as many endpoints as possible.
*
* Keep in mind that this operation will be highly dependent
* on the configured size for RAM1 - which contains TxFifo -,
* the amount of endpoints enabled on coreConsultant tool, and
* the width of the Master Bus.
*
* In the ideal world, we would always be able to satisfy the
* following equation:
*
* ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
* (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
*
* Unfortunately, due to many variables that's not always the case.
*/
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
static void dwc3_ep_inc_enq(struct dwc3_ep *dep)
{
int last_fifo_depth = 0;
int ram1_depth;
int fifo_size;
int mdwidth;
int num;
dep->trb_enqueue++;
dep->trb_enqueue %= DWC3_TRB_NUM;
}
if (!dwc->needs_fifo_resize)
return 0;
static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
{
dep->trb_dequeue++;
dep->trb_dequeue %= DWC3_TRB_NUM;
}
ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
/* MDWIDTH is represented in bits, we need it in bytes */
mdwidth >>= 3;
/*
* FIXME For now we will only allocate 1 wMaxPacketSize space
* for each enabled endpoint, later patches will come to
* improve this algorithm so that we better use the internal
* FIFO space
*/
for (num = 0; num < dwc->num_in_eps; num++) {
/* bit0 indicates direction; 1 means IN ep */
struct dwc3_ep *dep = dwc->eps[(num << 1) | 1];
int mult = 1;
int tmp;
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
if (usb_endpoint_xfer_bulk(dep->endpoint.desc)
|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
mult = 3;
/*
* REVISIT: the following assumes we will always have enough
* space available on the FIFO RAM for all possible use cases.
* Make sure that's true somehow and change FIFO allocation
* accordingly.
*
* If we have Bulk or Isochronous endpoints, we want
* them to be able to be very, very fast. So we're giving
* those endpoints a fifo_size which is enough for 3 full
* packets
*/
tmp = mult * (dep->endpoint.maxpacket + mdwidth);
tmp += mdwidth;
fifo_size = DIV_ROUND_UP(tmp, mdwidth);
fifo_size |= (last_fifo_depth << 16);
dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
dep->name, last_fifo_depth, fifo_size & 0xffff);
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
last_fifo_depth += (fifo_size & 0xffff);
}
return 0;
static int dwc3_ep_is_last_trb(unsigned int index)
{
return index == DWC3_TRB_NUM - 1;
}
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
@ -237,21 +168,19 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
struct dwc3 *dwc = dep->dwc;
int i;
if (req->queued) {
if (req->started) {
i = 0;
do {
dep->busy_slot++;
dwc3_ep_inc_deq(dep);
/*
* Skip LINK TRB. We can't use req->trb and check for
* DWC3_TRBCTL_LINK_TRB because it points the TRB we
* just completed (not the LINK TRB).
*/
if (((dep->busy_slot & DWC3_TRB_MASK) ==
DWC3_TRB_NUM- 1) &&
usb_endpoint_xfer_isoc(dep->endpoint.desc))
dep->busy_slot++;
if (dwc3_ep_is_last_trb(dep->trb_dequeue))
dwc3_ep_inc_deq(dep);
} while(++i < req->request.num_mapped_sgs);
req->queued = false;
req->started = false;
}
list_del(&req->list);
req->trb = NULL;
@ -307,6 +236,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
} while (1);
}
static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
{
@ -314,8 +245,40 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
u32 timeout = 500;
u32 reg;
int susphy = false;
int ret = -EINVAL;
trace_dwc3_gadget_ep_cmd(dep, cmd, params);
/*
* Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if
* we're issuing an endpoint command, we must check if
* GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it.
*
* We will also set SUSPHY bit to what it was before returning as stated
* by the same section on Synopsys databook.
*/
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
susphy = true;
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
if (cmd == DWC3_DEPCMD_STARTTRANSFER) {
int needs_wakeup;
needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 ||
dwc->link_state == DWC3_LINK_STATE_U2 ||
dwc->link_state == DWC3_LINK_STATE_U3);
if (unlikely(needs_wakeup)) {
ret = __dwc3_gadget_wakeup(dwc);
dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
ret);
}
}
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
@ -324,12 +287,40 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
do {
reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
if (!(reg & DWC3_DEPCMD_CMDACT)) {
int cmd_status = DWC3_DEPCMD_STATUS(reg);
dwc3_trace(trace_dwc3_gadget,
"Command Complete --> %d",
DWC3_DEPCMD_STATUS(reg));
if (DWC3_DEPCMD_STATUS(reg))
return -EINVAL;
return 0;
cmd_status);
switch (cmd_status) {
case 0:
ret = 0;
break;
case DEPEVT_TRANSFER_NO_RESOURCE:
dwc3_trace(trace_dwc3_gadget, "%s: no resource available");
ret = -EINVAL;
break;
case DEPEVT_TRANSFER_BUS_EXPIRY:
/*
* SW issues START TRANSFER command to
* isochronous ep with future frame interval. If
* future interval time has already passed when
* core receives the command, it will respond
* with an error status of 'Bus Expiry'.
*
* Instead of always returning -EINVAL, let's
* give a hint to the gadget driver that this is
* the case by returning -EAGAIN.
*/
dwc3_trace(trace_dwc3_gadget, "%s: bus expiry");
ret = -EAGAIN;
break;
default:
dev_WARN(dwc->dev, "UNKNOWN cmd status\n");
}
break;
}
/*
@ -340,11 +331,20 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
if (!timeout) {
dwc3_trace(trace_dwc3_gadget,
"Command Timed Out");
return -ETIMEDOUT;
ret = -ETIMEDOUT;
break;
}
udelay(1);
} while (1);
if (unlikely(susphy)) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
return ret;
}
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
@ -464,9 +464,19 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
/* Burst size is only needed in SuperSpeed mode */
if (dwc->gadget.speed >= USB_SPEED_SUPER) {
u32 burst = dep->endpoint.maxburst - 1;
u32 burst = dep->endpoint.maxburst;
u32 nump;
u32 reg;
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
/* update NumP */
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
nump = DWC3_DCFG_NUMP(reg);
nump = max(nump, burst);
reg &= ~DWC3_DCFG_NUMP_MASK;
reg |= nump << DWC3_DCFG_NUMP_SHIFT;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1);
}
if (ignore)
@ -567,10 +577,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
reg |= DWC3_DALEPENA_EP(dep->number);
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
if (!usb_endpoint_xfer_isoc(desc))
if (usb_endpoint_xfer_control(desc))
goto out;
/* Link TRB for ISOC. The HWO bit is never reset */
/* Link TRB. The HWO bit is never reset */
trb_st_hw = &dep->trb_pool[0];
trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
@ -608,19 +618,19 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
{
struct dwc3_request *req;
if (!list_empty(&dep->req_queued)) {
if (!list_empty(&dep->started_list)) {
dwc3_stop_active_transfer(dwc, dep->number, true);
/* - giveback all requests to gadget driver */
while (!list_empty(&dep->req_queued)) {
req = next_request(&dep->req_queued);
while (!list_empty(&dep->started_list)) {
req = next_request(&dep->started_list);
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
}
}
while (!list_empty(&dep->request_list)) {
req = next_request(&dep->request_list);
while (!list_empty(&dep->pending_list)) {
req = next_request(&dep->pending_list);
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
}
@ -783,20 +793,19 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
chain ? " chain" : "");
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
trb = &dep->trb_pool[dep->trb_enqueue];
if (!req->trb) {
dwc3_gadget_move_request_queued(req);
dwc3_gadget_move_started_request(req);
req->trb = trb;
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
req->start_slot = dep->free_slot & DWC3_TRB_MASK;
req->first_trb_index = dep->trb_enqueue;
}
dep->free_slot++;
/* Skip the LINK-TRB on ISOC */
if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
usb_endpoint_xfer_isoc(dep->endpoint.desc))
dep->free_slot++;
dwc3_ep_inc_enq(dep);
/* Skip the LINK-TRB */
if (dwc3_ep_is_last_trb(dep->trb_enqueue))
dwc3_ep_inc_enq(dep);
trb->size = DWC3_TRB_SIZE_LENGTH(length);
trb->bpl = lower_32_bits(dma);
@ -812,6 +821,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
else
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
/* always enable Interrupt on Missed ISOC */
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
break;
case USB_ENDPOINT_XFER_BULK:
@ -826,15 +838,14 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
BUG();
}
if (!req->request.no_interrupt && !chain)
trb->ctrl |= DWC3_TRB_CTRL_IOC;
/* always enable Continue on Short Packet */
trb->ctrl |= DWC3_TRB_CTRL_CSP;
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
trb->ctrl |= DWC3_TRB_CTRL_CSP;
} else if (last) {
if (!req->request.no_interrupt && !chain)
trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI;
if (last)
trb->ctrl |= DWC3_TRB_CTRL_LST;
}
if (chain)
trb->ctrl |= DWC3_TRB_CTRL_CHN;
@ -860,55 +871,29 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
{
struct dwc3_request *req, *n;
u32 trbs_left;
u32 max;
unsigned int last_one = 0;
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
/* the first request must not be queued */
trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
/* Can't wrap around on a non-isoc EP since there's no link TRB */
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
if (trbs_left > max)
trbs_left = max;
}
trbs_left = dep->trb_dequeue - dep->trb_enqueue;
/*
* If busy & slot are equal than it is either full or empty. If we are
* starting to process requests then we are empty. Otherwise we are
* If enqueue & dequeue are equal than it is either full or empty. If we
* are starting to process requests then we are empty. Otherwise we are
* full and don't do anything
*/
if (!trbs_left) {
if (!starting)
return;
trbs_left = DWC3_TRB_NUM;
/*
* In case we start from scratch, we queue the ISOC requests
* starting from slot 1. This is done because we use ring
* buffer and have no LST bit to stop us. Instead, we place
* IOC bit every TRB_NUM/4. We try to avoid having an interrupt
* after the first request so we start at slot 1 and have
* 7 requests proceed before we hit the first IOC.
* Other transfer types don't use the ring buffer and are
* processed from the first TRB until the last one. Since we
* don't wrap around we have to start at the beginning.
*/
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dep->busy_slot = 1;
dep->free_slot = 1;
} else {
dep->busy_slot = 0;
dep->free_slot = 0;
}
}
/* The last TRB is a link TRB, not used for xfer */
if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
if (trbs_left <= 1)
return;
list_for_each_entry_safe(req, n, &dep->request_list, list) {
list_for_each_entry_safe(req, n, &dep->pending_list, list) {
unsigned length;
dma_addr_t dma;
last_one = false;
@ -927,7 +912,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
if (i == (request->num_mapped_sgs - 1) ||
sg_is_last(s)) {
if (list_empty(&dep->request_list))
if (list_empty(&dep->pending_list))
last_one = true;
chain = false;
}
@ -957,7 +942,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
last_one = 1;
/* Is this the last request? */
if (list_is_last(&req->list, &dep->request_list))
if (list_is_last(&req->list, &dep->pending_list))
last_one = 1;
dwc3_prepare_one_trb(dep, req, dma, length,
@ -988,18 +973,18 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
* new requests as we try to set the IOC bit only on the last request.
*/
if (start_new) {
if (list_empty(&dep->req_queued))
if (list_empty(&dep->started_list))
dwc3_prepare_trbs(dep, start_new);
/* req points to the first request which will be sent */
req = next_request(&dep->req_queued);
req = next_request(&dep->started_list);
} else {
dwc3_prepare_trbs(dep, start_new);
/*
* req points to the first request where HWO changed from 0 to 1
*/
req = next_request(&dep->req_queued);
req = next_request(&dep->started_list);
}
if (!req) {
dep->flags |= DWC3_EP_PENDING_REQUEST;
@ -1046,7 +1031,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
{
u32 uf;
if (list_empty(&dep->request_list)) {
if (list_empty(&dep->pending_list)) {
dwc3_trace(trace_dwc3_gadget,
"ISOC ep %s run out for requests",
dep->name);
@ -1114,7 +1099,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
if (ret)
return ret;
list_add_tail(&req->list, &dep->request_list);
list_add_tail(&req->list, &dep->pending_list);
/*
* If there are no pending requests and the endpoint isn't already
@ -1149,7 +1134,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
* notion of current microframe.
*/
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
if (list_empty(&dep->req_queued)) {
if (list_empty(&dep->started_list)) {
dwc3_stop_active_transfer(dwc, dep->number, true);
dep->flags = DWC3_EP_ENABLED;
}
@ -1267,13 +1252,13 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
spin_lock_irqsave(&dwc->lock, flags);
list_for_each_entry(r, &dep->request_list, list) {
list_for_each_entry(r, &dep->pending_list, list) {
if (r == req)
break;
}
if (r != req) {
list_for_each_entry(r, &dep->req_queued, list) {
list_for_each_entry(r, &dep->started_list, list) {
if (r == req)
break;
}
@ -1313,10 +1298,10 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
if (value) {
if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
(!list_empty(&dep->req_queued) ||
!list_empty(&dep->request_list)))) {
(!list_empty(&dep->started_list) ||
!list_empty(&dep->pending_list)))) {
dwc3_trace(trace_dwc3_gadget,
"%s: pending request, cannot halt\n",
"%s: pending request, cannot halt",
dep->name);
return -EAGAIN;
}
@ -1417,22 +1402,16 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g)
return DWC3_DSTS_SOFFN(reg);
}
static int dwc3_gadget_wakeup(struct usb_gadget *g)
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long timeout;
unsigned long flags;
int ret;
u32 reg;
int ret = 0;
u8 link_state;
u8 speed;
spin_lock_irqsave(&dwc->lock, flags);
/*
* According to the Databook Remote wakeup request should
* be issued only when the device is in early suspend state.
@ -1445,8 +1424,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
if ((speed == DWC3_DSTS_SUPERSPEED) ||
(speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n");
ret = -EINVAL;
goto out;
return -EINVAL;
}
link_state = DWC3_DSTS_USBLNKST(reg);
@ -1459,14 +1437,13 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
dwc3_trace(trace_dwc3_gadget,
"can't wakeup from '%s'\n",
dwc3_gadget_link_string(link_state));
ret = -EINVAL;
goto out;
return -EINVAL;
}
ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
if (ret < 0) {
dev_err(dwc->dev, "failed to put link in Recovery\n");
goto out;
return ret;
}
/* Recent versions do this automatically */
@ -1490,10 +1467,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
dev_err(dwc->dev, "failed to send remote wakeup\n");
ret = -EINVAL;
return -EINVAL;
}
out:
return 0;
}
static int dwc3_gadget_wakeup(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
int ret;
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_wakeup(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
@ -1620,7 +1607,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
IRQF_SHARED, "dwc3", dwc);
IRQF_SHARED, "dwc3", dwc->ev_buf);
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
@ -1682,6 +1669,17 @@ static int dwc3_gadget_start(struct usb_gadget *g,
}
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
/*
* We are telling dwc3 that we want to use DCFG.NUMP as ACK TP's NUMP
* field instead of letting dwc3 itself calculate that automatically.
*
* This way, we maximize the chances that we'll be able to get several
* bursts of data without going through any sort of endpoint throttling.
*/
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
/* Start with SuperSpeed Default */
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
@ -1720,7 +1718,7 @@ err2:
err1:
spin_unlock_irqrestore(&dwc->lock, flags);
free_irq(irq, dwc);
free_irq(irq, dwc->ev_buf);
err0:
return ret;
@ -1743,7 +1741,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
spin_unlock_irqrestore(&dwc->lock, flags);
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
free_irq(irq, dwc);
free_irq(irq, dwc->ev_buf);
return 0;
}
@ -1815,8 +1813,8 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
dep->endpoint.caps.dir_in = !!direction;
dep->endpoint.caps.dir_out = !direction;
INIT_LIST_HEAD(&dep->request_list);
INIT_LIST_HEAD(&dep->req_queued);
INIT_LIST_HEAD(&dep->pending_list);
INIT_LIST_HEAD(&dep->started_list);
}
return 0;
@ -1913,11 +1911,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
* If there are still queued request
* then wait, do not issue either END
* or UPDATE TRANSFER, just attach next
* request in request_list during
* request in pending_list during
* giveback.If any future queued request
* is successfully transferred then we
* will issue UPDATE TRANSFER for all
* request in the request_list.
* request in the pending_list.
*/
dep->flags |= DWC3_EP_MISSED_ISOC;
} else {
@ -1963,15 +1961,14 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
int ret;
do {
req = next_request(&dep->req_queued);
req = next_request(&dep->started_list);
if (WARN_ON_ONCE(!req))
return 1;
i = 0;
do {
slot = req->start_slot + i;
if ((slot == DWC3_TRB_NUM - 1) &&
usb_endpoint_xfer_isoc(dep->endpoint.desc))
slot = req->first_trb_index + i;
if (slot == DWC3_TRB_NUM - 1)
slot++;
slot %= DWC3_TRB_NUM;
trb = &dep->trb_pool[slot];
@ -1989,8 +1986,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
} while (1);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
if (list_empty(&dep->request_list)) {
list_empty(&dep->started_list)) {
if (list_empty(&dep->pending_list)) {
/*
* If there is no entry in request list then do
* not issue END TRANSFER now. Just set PENDING
@ -2039,7 +2036,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
if (!list_empty(&dep->req_queued))
if (!list_empty(&dep->started_list))
return;
}
@ -2686,14 +2683,13 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
}
}
static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
{
struct dwc3_event_buffer *evt;
struct dwc3 *dwc = evt->dwc;
irqreturn_t ret = IRQ_NONE;
int left;
u32 reg;
evt = dwc->ev_buffs[buf];
left = evt->count;
if (!(evt->flags & DWC3_EVENT_PENDING))
@ -2718,7 +2714,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
left -= 4;
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 4);
}
evt->count = 0;
@ -2726,39 +2722,34 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
ret = IRQ_HANDLED;
/* Unmask interrupt */
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
reg &= ~DWC3_GEVNTSIZ_INTMASK;
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
return ret;
}
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt)
{
struct dwc3 *dwc = _dwc;
struct dwc3_event_buffer *evt = _evt;
struct dwc3 *dwc = evt->dwc;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
int i;
spin_lock_irqsave(&dwc->lock, flags);
for (i = 0; i < dwc->num_event_buffers; i++)
ret |= dwc3_process_event_buf(dwc, i);
ret = dwc3_process_event_buf(evt);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
{
struct dwc3_event_buffer *evt;
struct dwc3 *dwc = evt->dwc;
u32 count;
u32 reg;
evt = dwc->ev_buffs[buf];
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
count &= DWC3_GEVNTCOUNT_MASK;
if (!count)
return IRQ_NONE;
@ -2767,28 +2758,18 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
evt->flags |= DWC3_EVENT_PENDING;
/* Mask interrupt */
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
reg |= DWC3_GEVNTSIZ_INTMASK;
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
return IRQ_WAKE_THREAD;
}
static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
static irqreturn_t dwc3_interrupt(int irq, void *_evt)
{
struct dwc3 *dwc = _dwc;
int i;
irqreturn_t ret = IRQ_NONE;
struct dwc3_event_buffer *evt = _evt;
for (i = 0; i < dwc->num_event_buffers; i++) {
irqreturn_t status;
status = dwc3_check_event_buf(dwc, i);
if (status == IRQ_WAKE_THREAD)
ret = status;
}
return ret;
return dwc3_check_event_buf(evt);
}
/**

View File

@ -68,12 +68,12 @@ static inline struct dwc3_request *next_request(struct list_head *list)
return list_first_entry(list, struct dwc3_request, list);
}
static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
{
struct dwc3_ep *dep = req->dep;
req->queued = true;
list_move_tail(&req->list, &dep->req_queued);
req->started = true;
list_move_tail(&req->list, &dep->started_list);
}
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,

View File

@ -23,7 +23,6 @@
struct dwc3_platform_data {
enum usb_device_speed maximum_speed;
enum usb_dr_mode dr_mode;
bool tx_fifo_resize;
bool usb3_lpm_capable;
unsigned is_utmi_l1_suspend:1;
@ -43,6 +42,7 @@ struct dwc3_platform_data {
unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1;
unsigned dis_rxdet_inp3_quirk:1;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;

View File

@ -15,6 +15,7 @@
menuconfig USB_GADGET
tristate "USB Gadget Support"
select USB_COMMON
select NLS
help
USB is a master/slave protocol, organized with one master

View File

@ -66,20 +66,36 @@ function_descriptors(struct usb_function *f,
{
struct usb_descriptor_header **descriptors;
/*
* NOTE: we try to help gadget drivers which might not be setting
* max_speed appropriately.
*/
switch (speed) {
case USB_SPEED_SUPER_PLUS:
descriptors = f->ssp_descriptors;
break;
if (descriptors)
break;
/* FALLTHROUGH */
case USB_SPEED_SUPER:
descriptors = f->ss_descriptors;
break;
if (descriptors)
break;
/* FALLTHROUGH */
case USB_SPEED_HIGH:
descriptors = f->hs_descriptors;
break;
if (descriptors)
break;
/* FALLTHROUGH */
default:
descriptors = f->fs_descriptors;
}
/*
* if we can't find any descriptors at all, then this gadget deserves to
* Oops with a NULL pointer dereference
*/
return descriptors;
}

View File

@ -651,7 +651,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
if (io_data->read && ret > 0) {
use_mm(io_data->mm);
ret = copy_to_iter(io_data->buf, ret, &io_data->data);
if (iov_iter_count(&io_data->data))
if (ret != io_data->req->actual && iov_iter_count(&io_data->data))
ret = -EFAULT;
unuse_mm(io_data->mm);
}

View File

@ -2977,25 +2977,6 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
}
EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string);
int fsg_common_run_thread(struct fsg_common *common)
{
common->state = FSG_STATE_IDLE;
/* Tell the thread to start working */
common->thread_task =
kthread_create(fsg_main_thread, common, "file-storage");
if (IS_ERR(common->thread_task)) {
common->state = FSG_STATE_TERMINATED;
return PTR_ERR(common->thread_task);
}
DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
wake_up_process(common->thread_task);
return 0;
}
EXPORT_SYMBOL_GPL(fsg_common_run_thread);
static void fsg_common_release(struct kref *ref)
{
struct fsg_common *common = container_of(ref, struct fsg_common, ref);
@ -3005,6 +2986,7 @@ static void fsg_common_release(struct kref *ref)
if (common->state != FSG_STATE_TERMINATED) {
raise_exception(common, FSG_STATE_EXIT);
wait_for_completion(&common->thread_notifier);
common->thread_task = NULL;
}
for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
@ -3050,9 +3032,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
if (ret)
return ret;
fsg_common_set_inquiry_string(fsg->common, NULL, NULL);
ret = fsg_common_run_thread(fsg->common);
if (ret)
}
if (!common->thread_task) {
common->state = FSG_STATE_IDLE;
common->thread_task =
kthread_create(fsg_main_thread, common, "file-storage");
if (IS_ERR(common->thread_task)) {
int ret = PTR_ERR(common->thread_task);
common->thread_task = NULL;
common->state = FSG_STATE_TERMINATED;
return ret;
}
DBG(common, "I/O thread pid: %d\n",
task_pid_nr(common->thread_task));
wake_up_process(common->thread_task);
}
fsg->gadget = gadget;

View File

@ -153,8 +153,6 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg);
void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
const char *pn);
int fsg_common_run_thread(struct fsg_common *common);
void fsg_config_from_params(struct fsg_config *cfg,
const struct fsg_module_parameters *params,
unsigned int fsg_num_buffers);

View File

@ -133,10 +133,6 @@ static int acm_ms_do_config(struct usb_configuration *c)
if (status < 0)
goto put_msg;
status = fsg_common_run_thread(opts->common);
if (status)
goto remove_acm;
status = usb_add_function(c, f_msg);
if (status)
goto remove_acm;

View File

@ -132,10 +132,6 @@ static int msg_do_config(struct usb_configuration *c)
if (IS_ERR(f_msg))
return PTR_ERR(f_msg);
ret = fsg_common_run_thread(opts->common);
if (ret)
goto put_func;
ret = usb_add_function(c, f_msg);
if (ret)
goto put_func;

View File

@ -137,7 +137,6 @@ static struct usb_function *f_msg_rndis;
static int rndis_do_config(struct usb_configuration *c)
{
struct fsg_opts *fsg_opts;
int ret;
if (gadget_is_otg(c->cdev->gadget)) {
@ -169,11 +168,6 @@ static int rndis_do_config(struct usb_configuration *c)
goto err_fsg;
}
fsg_opts = fsg_opts_from_func_inst(fi_msg);
ret = fsg_common_run_thread(fsg_opts->common);
if (ret)
goto err_run;
ret = usb_add_function(c, f_msg_rndis);
if (ret)
goto err_run;
@ -225,7 +219,6 @@ static struct usb_function *f_msg_multi;
static int cdc_do_config(struct usb_configuration *c)
{
struct fsg_opts *fsg_opts;
int ret;
if (gadget_is_otg(c->cdev->gadget)) {
@ -258,11 +251,6 @@ static int cdc_do_config(struct usb_configuration *c)
goto err_fsg;
}
fsg_opts = fsg_opts_from_func_inst(fi_msg);
ret = fsg_common_run_thread(fsg_opts->common);
if (ret)
goto err_run;
ret = usb_add_function(c, f_msg_multi);
if (ret)
goto err_run;

View File

@ -152,7 +152,6 @@ static int nokia_bind_config(struct usb_configuration *c)
struct usb_function *f_ecm;
struct usb_function *f_obex2 = NULL;
struct usb_function *f_msg;
struct fsg_opts *fsg_opts;
int status = 0;
int obex1_stat = -1;
int obex2_stat = -1;
@ -222,12 +221,6 @@ static int nokia_bind_config(struct usb_configuration *c)
goto err_ecm;
}
fsg_opts = fsg_opts_from_func_inst(fi_msg);
status = fsg_common_run_thread(fsg_opts->common);
if (status)
goto err_msg;
status = usb_add_function(c, f_msg);
if (status)
goto err_msg;

View File

@ -1726,10 +1726,7 @@ static int at91sam9261_udc_init(struct at91_udc *udc)
udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node,
"atmel,matrix");
if (IS_ERR(udc->matrix))
return PTR_ERR(udc->matrix);
return 0;
return PTR_ERR_OR_ZERO(udc->matrix);
}
static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on)

View File

@ -325,11 +325,8 @@ struct pch_vbus_gpio_data {
* @pdev: reference to the PCI device
* @ep: array of endpoints
* @lock: protects all state
* @active: enabled the PCI device
* @stall: stall requested
* @prot_stall: protcol stall requested
* @irq_registered: irq registered with system
* @mem_region: device memory mapped
* @registered: driver registered with system
* @suspended: driver in suspended state
* @connected: gadget driver associated
@ -339,12 +336,8 @@ struct pch_vbus_gpio_data {
* @data_requests: DMA pool for data requests
* @stp_requests: DMA pool for setup requests
* @dma_addr: DMA pool for received
* @ep0out_buf: Buffer for DMA
* @setup_data: Received setup data
* @phys_addr: of device memory
* @base_addr: for mapped device memory
* @bar: Indicates which PCI BAR for USB regs
* @irq: IRQ line for the device
* @cfg_data: current cfg, intf, and alt in use
* @vbus_gpio: GPIO informaton for detecting VBUS
*/
@ -354,11 +347,9 @@ struct pch_udc_dev {
struct pci_dev *pdev;
struct pch_udc_ep ep[PCH_UDC_EP_NUM];
spinlock_t lock; /* protects all state */
unsigned active:1,
unsigned
stall:1,
prot_stall:1,
irq_registered:1,
mem_region:1,
suspended:1,
connected:1,
vbus_session:1,
@ -367,12 +358,8 @@ struct pch_udc_dev {
struct pci_pool *data_requests;
struct pci_pool *stp_requests;
dma_addr_t dma_addr;
void *ep0out_buf;
struct usb_ctrlrequest setup_data;
unsigned long phys_addr;
void __iomem *base_addr;
unsigned bar;
unsigned irq;
struct pch_udc_cfg_data cfg_data;
struct pch_vbus_gpio_data vbus_gpio;
};
@ -380,8 +367,10 @@ struct pch_udc_dev {
#define PCH_UDC_PCI_BAR_QUARK_X1000 0
#define PCH_UDC_PCI_BAR 1
#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
#define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC 0x0939
#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
#define PCI_VENDOR_ID_ROHM 0x10DB
#define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D
#define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808
@ -1732,14 +1721,12 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
{
struct pch_udc_ep *ep;
struct pch_udc_dev *dev;
unsigned long iflags;
if (!usbep)
return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
if ((usbep->name == ep0_string) || !ep->ep.desc)
return -EINVAL;
@ -1770,12 +1757,10 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
struct pch_udc_request *req;
struct pch_udc_ep *ep;
struct pch_udc_data_dma_desc *dma_desc;
struct pch_udc_dev *dev;
if (!usbep)
return NULL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
req = kzalloc(sizeof *req, gfp);
if (!req)
return NULL;
@ -1948,12 +1933,10 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
{
struct pch_udc_ep *ep;
struct pch_udc_request *req;
struct pch_udc_dev *dev;
unsigned long flags;
int ret = -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
if (!usbep || !usbreq || (!ep->ep.desc && ep->num))
return ret;
req = container_of(usbreq, struct pch_udc_request, req);
@ -1985,14 +1968,12 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
{
struct pch_udc_ep *ep;
struct pch_udc_dev *dev;
unsigned long iflags;
int ret;
if (!usbep)
return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
if (!ep->ep.desc && !ep->num)
return -EINVAL;
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
@ -2030,14 +2011,12 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
static int pch_udc_pcd_set_wedge(struct usb_ep *usbep)
{
struct pch_udc_ep *ep;
struct pch_udc_dev *dev;
unsigned long iflags;
int ret;
if (!usbep)
return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
if (!ep->ep.desc && !ep->num)
return -EINVAL;
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
@ -2647,7 +2626,7 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
{
u32 reg, dev_stat = 0;
int i, ret;
int i;
dev_stat = pch_udc_read_device_status(dev);
dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
@ -2676,7 +2655,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
}
dev->stall = 0;
spin_lock(&dev->lock);
ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
dev->driver->setup(&dev->gadget, &dev->setup_data);
spin_unlock(&dev->lock);
}
@ -2687,7 +2666,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
*/
static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
{
int i, ret;
int i;
u32 reg, dev_stat = 0;
dev_stat = pch_udc_read_device_status(dev);
@ -2713,7 +2692,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
/* call gadget zero with setup data received */
spin_lock(&dev->lock);
ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
dev->driver->setup(&dev->gadget, &dev->setup_data);
spin_unlock(&dev->lock);
}
@ -2855,17 +2834,6 @@ static void pch_udc_setup_ep0(struct pch_udc_dev *dev)
UDC_DEVINT_SI | UDC_DEVINT_SC);
}
/**
* gadget_release() - Free the gadget driver private data
* @pdev reference to struct pci_dev
*/
static void gadget_release(struct device *pdev)
{
struct pch_udc_dev *dev = dev_get_drvdata(pdev);
kfree(dev);
}
/**
* pch_udc_pcd_reinit() - This API initializes the endpoint structures
* @dev: Reference to the driver structure
@ -2949,6 +2917,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
{
struct pch_udc_stp_dma_desc *td_stp;
struct pch_udc_data_dma_desc *td_data;
void *ep0out_buf;
/* DMA setup */
dev->data_requests = pci_pool_create("data_requests", dev->pdev,
@ -2991,10 +2960,11 @@ static int init_dma_pools(struct pch_udc_dev *dev)
dev->ep[UDC_EP0IN_IDX].td_data = NULL;
dev->ep[UDC_EP0IN_IDX].td_data_phys = 0;
dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL);
if (!dev->ep0out_buf)
ep0out_buf = devm_kzalloc(&dev->pdev->dev, UDC_EP0OUT_BUFF_SIZE * 4,
GFP_KERNEL);
if (!ep0out_buf)
return -ENOMEM;
dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf,
dev->dma_addr = dma_map_single(&dev->pdev->dev, ep0out_buf,
UDC_EP0OUT_BUFF_SIZE * 4,
DMA_FROM_DEVICE);
return 0;
@ -3078,129 +3048,80 @@ static void pch_udc_remove(struct pci_dev *pdev)
if (dev->dma_addr)
dma_unmap_single(&dev->pdev->dev, dev->dma_addr,
UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
kfree(dev->ep0out_buf);
pch_vbus_gpio_free(dev);
pch_udc_exit(dev);
if (dev->irq_registered)
free_irq(pdev->irq, dev);
if (dev->base_addr)
iounmap(dev->base_addr);
if (dev->mem_region)
release_mem_region(dev->phys_addr,
pci_resource_len(pdev, dev->bar));
if (dev->active)
pci_disable_device(pdev);
kfree(dev);
}
#ifdef CONFIG_PM
static int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state)
#ifdef CONFIG_PM_SLEEP
static int pch_udc_suspend(struct device *d)
{
struct pci_dev *pdev = to_pci_dev(d);
struct pch_udc_dev *dev = pci_get_drvdata(pdev);
pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL);
pci_disable_device(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
if (pci_save_state(pdev)) {
dev_err(&pdev->dev,
"%s: could not save PCI config state\n", __func__);
return -ENOMEM;
}
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
static int pch_udc_resume(struct pci_dev *pdev)
static int pch_udc_resume(struct device *d)
{
int ret;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
ret = pci_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__);
return ret;
}
pci_enable_wake(pdev, PCI_D3hot, 0);
return 0;
}
static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume);
#define PCH_UDC_PM_OPS (&pch_udc_pm)
#else
#define pch_udc_suspend NULL
#define pch_udc_resume NULL
#endif /* CONFIG_PM */
#define PCH_UDC_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static int pch_udc_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
unsigned long resource;
unsigned long len;
int bar;
int retval;
struct pch_udc_dev *dev;
/* init */
dev = kzalloc(sizeof *dev, GFP_KERNEL);
if (!dev) {
pr_err("%s: no memory for device structure\n", __func__);
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
}
/* pci setup */
if (pci_enable_device(pdev) < 0) {
kfree(dev);
pr_err("%s: pci_enable_device failed\n", __func__);
return -ENODEV;
}
dev->active = 1;
retval = pcim_enable_device(pdev);
if (retval)
return retval;
pci_set_drvdata(pdev, dev);
/* Determine BAR based on PCI ID */
if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC)
dev->bar = PCH_UDC_PCI_BAR_QUARK_X1000;
bar = PCH_UDC_PCI_BAR_QUARK_X1000;
else
dev->bar = PCH_UDC_PCI_BAR;
bar = PCH_UDC_PCI_BAR;
/* PCI resource allocation */
resource = pci_resource_start(pdev, dev->bar);
len = pci_resource_len(pdev, dev->bar);
retval = pcim_iomap_regions(pdev, 1 << bar, pci_name(pdev));
if (retval)
return retval;
if (!request_mem_region(resource, len, KBUILD_MODNAME)) {
dev_err(&pdev->dev, "%s: pci device used already\n", __func__);
retval = -EBUSY;
goto finished;
}
dev->phys_addr = resource;
dev->mem_region = 1;
dev->base_addr = pcim_iomap_table(pdev)[bar];
dev->base_addr = ioremap_nocache(resource, len);
if (!dev->base_addr) {
pr_err("%s: device memory cannot be mapped\n", __func__);
retval = -ENOMEM;
goto finished;
}
if (!pdev->irq) {
dev_err(&pdev->dev, "%s: irq not set\n", __func__);
retval = -ENODEV;
goto finished;
}
/* initialize the hardware */
if (pch_udc_pcd_init(dev)) {
retval = -ENODEV;
goto finished;
}
if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME,
dev)) {
if (pch_udc_pcd_init(dev))
return -ENODEV;
pci_enable_msi(pdev);
retval = devm_request_irq(&pdev->dev, pdev->irq, pch_udc_isr,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (retval) {
dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__,
pdev->irq);
retval = -ENODEV;
goto finished;
}
dev->irq = pdev->irq;
dev->irq_registered = 1;
pci_set_master(pdev);
pci_try_set_mwi(pdev);
@ -3219,8 +3140,7 @@ static int pch_udc_probe(struct pci_dev *pdev,
/* Put the device in disconnected state till a driver is bound */
pch_udc_set_disconnect(dev);
retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
gadget_release);
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
if (retval)
goto finished;
return 0;
@ -3262,9 +3182,10 @@ static struct pci_driver pch_udc_driver = {
.id_table = pch_udc_pcidev_id,
.probe = pch_udc_probe,
.remove = pch_udc_remove,
.suspend = pch_udc_suspend,
.resume = pch_udc_resume,
.shutdown = pch_udc_shutdown,
.driver = {
.pm = PCH_UDC_PM_OPS,
},
};
module_pci_driver(pch_udc_driver);

View File

@ -296,7 +296,7 @@ static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum,
} while ((tmp & mask) != loop);
}
static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
static void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
{
struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum];

View File

@ -61,11 +61,9 @@ static int udc_bind_to_driver(struct usb_udc *udc,
#ifdef CONFIG_HAS_DMA
int usb_gadget_map_request(struct usb_gadget *gadget,
int usb_gadget_map_request_by_dev(struct device *dev,
struct usb_request *req, int is_in)
{
struct device *dev = gadget->dev.parent;
if (req->length == 0)
return 0;
@ -75,7 +73,7 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
mapped = dma_map_sg(dev, req->sg, req->num_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (mapped == 0) {
dev_err(&gadget->dev, "failed to map SGs\n");
dev_err(dev, "failed to map SGs\n");
return -EFAULT;
}
@ -92,24 +90,38 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
return 0;
}
EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev);
int usb_gadget_map_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in);
}
EXPORT_SYMBOL_GPL(usb_gadget_map_request);
void usb_gadget_unmap_request(struct usb_gadget *gadget,
void usb_gadget_unmap_request_by_dev(struct device *dev,
struct usb_request *req, int is_in)
{
if (req->length == 0)
return;
if (req->num_mapped_sgs) {
dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs,
dma_unmap_sg(dev, req->sg, req->num_mapped_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->num_mapped_sgs = 0;
} else {
dma_unmap_single(gadget->dev.parent, req->dma, req->length,
dma_unmap_single(dev, req->dma, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
}
}
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev);
void usb_gadget_unmap_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in);
}
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
#endif /* CONFIG_HAS_DMA */

View File

@ -35,6 +35,7 @@ config USB_XHCI_PCI
config USB_XHCI_PLATFORM
tristate "Generic xHCI driver for a platform device"
select USB_XHCI_RCAR if ARCH_RENESAS
---help---
Adds an xHCI host driver for a generic platform device, which
provides a memory space and an irq.
@ -63,7 +64,7 @@ config USB_XHCI_MVEBU
config USB_XHCI_RCAR
tristate "xHCI support for Renesas R-Car SoCs"
select USB_XHCI_PLATFORM
depends on USB_XHCI_PLATFORM
depends on ARCH_RENESAS || COMPILE_TEST
---help---
Say 'Y' to enable the support for the xHCI host controller

View File

@ -352,10 +352,8 @@ static int bcma_hcd_probe(struct bcma_device *core)
usb_dev->core = core;
if (core->dev.of_node)
usb_dev->gpio_desc = devm_get_gpiod_from_child(&core->dev, "vcc",
&core->dev.of_node->fwnode);
if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
gpiod_direction_output(usb_dev->gpio_desc, 1);
usb_dev->gpio_desc = devm_gpiod_get(&core->dev, "vcc",
GPIOD_OUT_HIGH);
switch (core->id.id) {
case BCMA_CORE_USB20_HOST:

View File

@ -52,13 +52,6 @@ static void dbg_hcs_params(struct ehci_hcd *ehci, char *label)
ehci_dbg(ehci, "%s portroute %s\n", label, buf);
}
}
#else
static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) {}
#endif
#ifdef CONFIG_DYNAMIC_DEBUG
/*
* check the values in the HCCPARAMS register
@ -92,13 +85,6 @@ static void dbg_hcc_params(struct ehci_hcd *ehci, char *label)
" 32 periodic list" : "");
}
}
#else
static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) {}
#endif
#ifdef CONFIG_DYNAMIC_DEBUG
static void __maybe_unused
dbg_qtd(const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
@ -281,37 +267,6 @@ dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
(status & PORT_CONNECT) ? " CONNECT" : "");
}
#else
static inline void __maybe_unused
dbg_qh(char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{}
static inline int __maybe_unused
dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
{
return 0;
}
static inline int __maybe_unused
dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
{
return 0;
}
static inline int __maybe_unused
dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
{
return 0;
}
static inline int __maybe_unused
dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
{
return 0;
}
#endif /* CONFIG_DYNAMIC_DEBUG */
static inline void
dbg_status(struct ehci_hcd *ehci, const char *label, u32 status)
{
@ -341,13 +296,6 @@ dbg_port(struct ehci_hcd *ehci, const char *label, int port, u32 status)
/*-------------------------------------------------------------------------*/
#ifndef CONFIG_DYNAMIC_DEBUG
static inline void create_debug_files(struct ehci_hcd *bus) { }
static inline void remove_debug_files(struct ehci_hcd *bus) { }
#else
/* troubleshooting help: expose state in debugfs */
static int debug_async_open(struct inode *, struct file *);
@ -1120,4 +1068,38 @@ static inline void remove_debug_files(struct ehci_hcd *ehci)
debugfs_remove_recursive(ehci->debug_dir);
}
#else /* CONFIG_DYNAMIC_DEBUG */
static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) { }
static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) { }
static inline void __maybe_unused dbg_qh(const char *label,
struct ehci_hcd *ehci, struct ehci_qh *qh) { }
static inline int __maybe_unused dbg_status_buf(const char *buf,
unsigned int len, const char *label, u32 status)
{ return 0; }
static inline int __maybe_unused dbg_command_buf(const char *buf,
unsigned int len, const char *label, u32 command)
{ return 0; }
static inline int __maybe_unused dbg_intr_buf(const char *buf,
unsigned int len, const char *label, u32 enable)
{ return 0; }
static inline int __maybe_unused dbg_port_buf(char *buf,
unsigned int len, const char *label, int port, u32 status)
{ return 0; }
static inline void dbg_status(struct ehci_hcd *ehci, const char *label,
u32 status) { }
static inline void dbg_cmd(struct ehci_hcd *ehci, const char *label,
u32 command) { }
static inline void dbg_port(struct ehci_hcd *ehci, const char *label,
int port, u32 status) { }
static inline void create_debug_files(struct ehci_hcd *bus) { }
static inline void remove_debug_files(struct ehci_hcd *bus) { }
#endif /* CONFIG_DYNAMIC_DEBUG */

View File

@ -321,7 +321,7 @@ static struct platform_driver exynos_ehci_driver = {
.of_match_table = of_match_ptr(exynos_ehci_match),
}
};
static const struct ehci_driver_overrides exynos_overrides __initdata = {
static const struct ehci_driver_overrides exynos_overrides __initconst = {
.extra_priv_size = sizeof(struct exynos_ehci_hcd),
};

View File

@ -229,7 +229,7 @@ static struct platform_driver ehci_msm_driver = {
},
};
static const struct ehci_driver_overrides msm_overrides __initdata = {
static const struct ehci_driver_overrides msm_overrides __initconst = {
.reset = ehci_msm_reset,
};

View File

@ -86,7 +86,7 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
static struct hc_driver __read_mostly ehci_omap_hc_driver;
static const struct ehci_driver_overrides ehci_omap_overrides __initdata = {
static const struct ehci_driver_overrides ehci_omap_overrides __initconst = {
.extra_priv_size = sizeof(struct omap_hcd),
};

View File

@ -163,7 +163,7 @@ static struct platform_driver spear_ehci_hcd_driver = {
}
};
static const struct ehci_driver_overrides spear_overrides __initdata = {
static const struct ehci_driver_overrides spear_overrides __initconst = {
.extra_priv_size = sizeof(struct spear_ehci),
};

View File

@ -288,7 +288,7 @@ static int scan_ed_list(struct fhci_usb *usb,
list_for_each_entry(ed, list, node) {
td = ed->td_head;
if (!td || (td && td->status == USB_TD_INPROGRESS))
if (!td || td->status == USB_TD_INPROGRESS)
continue;
if (ed->state != FHCI_ED_OPER) {

View File

@ -4795,14 +4795,8 @@ static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max,
static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
{
struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
int i = 0;
if (i)
goto out;
i = device_create_file(controller, &dev_attr_uframe_periodic_max);
out:
return i;
return device_create_file(controller, &dev_attr_uframe_periodic_max);
}
static inline void remove_sysfs_files(struct fotg210_hcd *fotg210)

View File

@ -257,14 +257,14 @@ static int whc_probe(struct umc_dev *umc)
ret = whc_init(whc);
if (ret)
goto error;
goto error_whc_init;
wusbhc->dev = dev;
wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
if (!wusbhc->uwb_rc) {
ret = -ENODEV;
dev_err(dev, "cannot get radio controller\n");
goto error;
goto error_uwb_rc;
}
if (whc->n_devices > USB_MAXCHILDREN) {
@ -311,8 +311,9 @@ error_usb_add_hcd:
wusbhc_destroy(wusbhc);
error_wusbhc_create:
uwb_rc_put(wusbhc->uwb_rc);
error:
error_uwb_rc:
whc_clean_up(whc);
error_whc_init:
usb_put_hcd(usb_hcd);
return ret;
}

View File

@ -314,7 +314,7 @@ void qset_free_std(struct whc *whc, struct whc_std *std)
kfree(std->bounce_buf);
}
if (std->pl_virt) {
if (std->dma_addr)
if (!dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
dma_unmap_single(whc->wusbhc.dev, std->dma_addr,
std->num_pointers * sizeof(struct whc_page_list_entry),
DMA_TO_DEVICE);
@ -535,9 +535,11 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
list_for_each_entry(std, &qset->stds, list_node) {
if (std->ntds_remaining == -1) {
pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
std->ntds_remaining = ntds--;
std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt,
pl_len, DMA_TO_DEVICE);
if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
return -EFAULT;
std->ntds_remaining = ntds--;
}
}
return 0;
@ -618,6 +620,8 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len,
is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (dma_mapping_error(&whc->umc->dev, std->dma_addr))
return -EFAULT;
if (qset_fill_page_list(whc, std, mem_flags) < 0)
return -ENOMEM;

View File

@ -12,6 +12,9 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include "xhci-mvebu.h"
#define USB3_MAX_WINDOWS 4
@ -41,8 +44,10 @@ static void xhci_mvebu_mbus_config(void __iomem *base,
}
}
int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev)
int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
struct platform_device *pdev = to_platform_device(dev);
struct resource *res;
void __iomem *base;
const struct mbus_dram_target_info *dram;

View File

@ -10,10 +10,13 @@
#ifndef __LINUX_XHCI_MVEBU_H
#define __LINUX_XHCI_MVEBU_H
struct usb_hcd;
#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev);
int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
#else
static inline int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev)
static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
{
return 0;
}

View File

@ -37,27 +37,32 @@ static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
.start = xhci_plat_start,
};
static void xhci_priv_plat_start(struct usb_hcd *hcd)
{
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
if (priv->plat_start)
priv->plat_start(hcd);
}
static int xhci_priv_init_quirk(struct usb_hcd *hcd)
{
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
if (!priv->init_quirk)
return 0;
return priv->init_quirk(hcd);
}
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
{
struct usb_hcd *hcd = xhci_to_hcd(xhci);
/*
* As of now platform drivers don't provide MSI support so we ensure
* here that the generic code does not try to make a pci_dev from our
* dev struct in order to setup MSI
*/
xhci->quirks |= XHCI_PLAT;
/*
* On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
* to 1. However, these SoCs don't support 64-bit address memory
* pointers. So, this driver clears the AC64 bit of xhci->hcc_params
* to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
* xhci_gen_setup().
*/
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3))
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
}
/* called during probe() after chip reset completes */
@ -65,38 +70,35 @@ static int xhci_plat_setup(struct usb_hcd *hcd)
{
int ret;
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3)) {
ret = xhci_rcar_init_quirk(hcd);
if (ret)
return ret;
}
ret = xhci_priv_init_quirk(hcd);
if (ret)
return ret;
return xhci_gen_setup(hcd, xhci_plat_quirks);
}
static int xhci_plat_start(struct usb_hcd *hcd)
{
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3))
xhci_rcar_start(hcd);
xhci_priv_plat_start(hcd);
return xhci_run(hcd);
}
#ifdef CONFIG_OF
static const struct xhci_plat_priv xhci_plat_marvell_armada = {
.type = XHCI_PLAT_TYPE_MARVELL_ARMADA,
.init_quirk = xhci_mvebu_mbus_init_quirk,
};
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
.type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2,
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1,
.init_quirk = xhci_rcar_init_quirk,
.plat_start = xhci_rcar_start,
};
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
.type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3,
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2,
.init_quirk = xhci_rcar_init_quirk,
.plat_start = xhci_rcar_start,
};
static const struct of_device_id usb_xhci_of_match[] = {
@ -207,12 +209,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
*priv = *priv_match;
}
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_MARVELL_ARMADA)) {
ret = xhci_mvebu_mbus_init_quirk(pdev);
if (ret)
goto disable_clk;
}
device_wakeup_enable(hcd->self.controller);
xhci->clk = clk;

View File

@ -13,27 +13,11 @@
#include "xhci.h" /* for hcd_to_xhci() */
enum xhci_plat_type {
XHCI_PLAT_TYPE_MARVELL_ARMADA = 1,
XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2,
XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3,
};
struct xhci_plat_priv {
enum xhci_plat_type type;
const char *firmware_name;
void (*plat_start)(struct usb_hcd *);
int (*init_quirk)(struct usb_hcd *);
};
#define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
static inline bool xhci_plat_type_is(struct usb_hcd *hcd,
enum xhci_plat_type type)
{
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
if (priv && priv->type == type)
return true;
else
return false;
}
#endif /* _XHCI_PLAT_H */

View File

@ -11,6 +11,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/usb/phy.h>
#include "xhci.h"
@ -76,6 +77,24 @@ static void xhci_rcar_start_gen2(struct usb_hcd *hcd)
writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL);
}
static int xhci_rcar_is_gen2(struct device *dev)
{
struct device_node *node = dev->of_node;
return of_device_is_compatible(node, "renesas,xhci-r8a7790") ||
of_device_is_compatible(node, "renesas,xhci-r8a7791") ||
of_device_is_compatible(node, "renesas,xhci-r8a7793") ||
of_device_is_compatible(node, "renensas,rcar-gen2-xhci");
}
static int xhci_rcar_is_gen3(struct device *dev)
{
struct device_node *node = dev->of_node;
return of_device_is_compatible(node, "renesas,xhci-r8a7795") ||
of_device_is_compatible(node, "renesas,rcar-gen3-xhci");
}
void xhci_rcar_start(struct usb_hcd *hcd)
{
u32 temp;
@ -85,7 +104,7 @@ void xhci_rcar_start(struct usb_hcd *hcd)
temp = readl(hcd->regs + RCAR_USB3_INT_ENA);
temp |= RCAR_USB3_INT_ENA_VAL;
writel(temp, hcd->regs + RCAR_USB3_INT_ENA);
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2))
if (xhci_rcar_is_gen2(hcd->self.controller))
xhci_rcar_start_gen2(hcd);
}
}
@ -156,9 +175,22 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd)
/* This function needs to initialize a "phy" of usb before */
int xhci_rcar_init_quirk(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
/* If hcd->regs is NULL, we don't just call the following function */
if (!hcd->regs)
return 0;
/*
* On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
* to 1. However, these SoCs don't support 64-bit address memory
* pointers. So, this driver clears the AC64 bit of xhci->hcc_params
* to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
* xhci_gen_setup().
*/
if (xhci_rcar_is_gen2(hcd->self.controller) ||
xhci_rcar_is_gen3(hcd->self.controller))
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
return xhci_rcar_download_firmware(hcd);
}

View File

@ -373,7 +373,11 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
}
}
static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
/* Get the right ring for the given slot_id, ep_index and stream_id.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
*/
struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id)
{
@ -405,17 +409,6 @@ static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
return NULL;
}
/* Get the right ring for the given URB.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
*/
static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb)
{
return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id);
}
/*
* Move the xHC's endpoint ring dequeue pointer past cur_td.
* Record the new state of the xHC's endpoint ring dequeue segment,
@ -1768,7 +1761,7 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
if (trb_comp_code == COMP_TX_ERR ||
trb_comp_code == COMP_BABBLE ||
trb_comp_code == COMP_SPLIT_ERR)
/* The 0.96 spec says a babbling control endpoint
/* The 0.95 spec says a babbling control endpoint
* is not halted. The 0.96 spec says it is. Some HW
* claims to be 0.95 compliant, but it halts the control
* endpoint anyway. Check if a babble halted the
@ -2938,46 +2931,55 @@ static int prepare_transfer(struct xhci_hcd *xhci,
return 0;
}
static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
static unsigned int count_trbs(u64 addr, u64 len)
{
int num_sgs, num_trbs, running_total, temp, i;
struct scatterlist *sg;
unsigned int num_trbs;
sg = NULL;
num_sgs = urb->num_mapped_sgs;
temp = urb->transfer_buffer_length;
num_trbs = DIV_ROUND_UP(len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
TRB_MAX_BUFF_SIZE);
if (num_trbs == 0)
num_trbs++;
num_trbs = 0;
for_each_sg(urb->sg, sg, num_sgs, i) {
unsigned int len = sg_dma_len(sg);
/* Scatter gather list entries may cross 64KB boundaries */
running_total = TRB_MAX_BUFF_SIZE -
(sg_dma_address(sg) & (TRB_MAX_BUFF_SIZE - 1));
running_total &= TRB_MAX_BUFF_SIZE - 1;
if (running_total != 0)
num_trbs++;
/* How many more 64KB chunks to transfer, how many more TRBs? */
while (running_total < sg_dma_len(sg) && running_total < temp) {
num_trbs++;
running_total += TRB_MAX_BUFF_SIZE;
}
len = min_t(int, len, temp);
temp -= len;
if (temp == 0)
break;
}
return num_trbs;
}
static void check_trb_math(struct urb *urb, int num_trbs, int running_total)
static inline unsigned int count_trbs_needed(struct urb *urb)
{
if (num_trbs != 0)
dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated number of "
"TRBs, %d left\n", __func__,
urb->ep->desc.bEndpointAddress, num_trbs);
if (running_total != urb->transfer_buffer_length)
return count_trbs(urb->transfer_dma, urb->transfer_buffer_length);
}
static unsigned int count_sg_trbs_needed(struct urb *urb)
{
struct scatterlist *sg;
unsigned int i, len, full_len, num_trbs = 0;
full_len = urb->transfer_buffer_length;
for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
len = sg_dma_len(sg);
num_trbs += count_trbs(sg_dma_address(sg), len);
len = min_t(unsigned int, len, full_len);
full_len -= len;
if (full_len == 0)
break;
}
return num_trbs;
}
static unsigned int count_isoc_trbs_needed(struct urb *urb, int i)
{
u64 addr, len;
addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
len = urb->iso_frame_desc[i].length;
return count_trbs(addr, len);
}
static void check_trb_math(struct urb *urb, int running_total)
{
if (unlikely(running_total != urb->transfer_buffer_length))
dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, "
"queued %#x (%d), asked for %#x (%d)\n",
__func__,
@ -3003,26 +3005,20 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
}
/*
* xHCI uses normal TRBs for both bulk and interrupt. When the interrupt
* endpoint is to be serviced, the xHC will consume (at most) one TD. A TD
* (comprised of sg list entries) can take several service intervals to
* transmit.
*/
int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
static void check_interval(struct xhci_hcd *xhci, struct urb *urb,
struct xhci_ep_ctx *ep_ctx)
{
struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci,
xhci->devs[slot_id]->out_ctx, ep_index);
int xhci_interval;
int ep_interval;
xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info));
ep_interval = urb->interval;
/* Convert to microframes */
if (urb->dev->speed == USB_SPEED_LOW ||
urb->dev->speed == USB_SPEED_FULL)
ep_interval *= 8;
/* FIXME change this to a warning and a suggestion to use the new API
* to set the polling interval (once the API is added).
*/
@ -3037,6 +3033,22 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
urb->dev->speed == USB_SPEED_FULL)
urb->interval /= 8;
}
}
/*
* xHCI uses normal TRBs for both bulk and interrupt. When the interrupt
* endpoint is to be serviced, the xHC will consume (at most) one TD. A TD
* (comprised of sg list entries) can take several service intervals to
* transmit.
*/
int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
{
struct xhci_ep_ctx *ep_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, xhci->devs[slot_id]->out_ctx, ep_index);
check_interval(xhci, urb, ep_ctx);
return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index);
}
@ -3086,177 +3098,6 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
return (total_packet_count - ((transferred + trb_buff_len) / maxp));
}
static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
{
struct xhci_ring *ep_ring;
unsigned int num_trbs;
struct urb_priv *urb_priv;
struct xhci_td *td;
struct scatterlist *sg;
int num_sgs;
int trb_buff_len, this_sg_len, running_total, ret;
unsigned int total_packet_count;
bool zero_length_needed;
bool first_trb;
int last_trb_num;
u64 addr;
bool more_trbs_coming;
struct xhci_generic_trb *start_trb;
int start_cycle;
ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
if (!ep_ring)
return -EINVAL;
num_trbs = count_sg_trbs_needed(xhci, urb);
num_sgs = urb->num_mapped_sgs;
total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length,
usb_endpoint_maxp(&urb->ep->desc));
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
num_trbs, urb, 0, mem_flags);
if (ret < 0)
return ret;
urb_priv = urb->hcpriv;
/* Deal with URB_ZERO_PACKET - need one more td/trb */
zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET &&
urb_priv->length == 2;
if (zero_length_needed) {
num_trbs++;
xhci_dbg(xhci, "Creating zero length td.\n");
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
1, urb, 1, mem_flags);
if (ret < 0)
return ret;
}
td = urb_priv->td[0];
/*
* Don't give the first TRB to the hardware (by toggling the cycle bit)
* until we've finished creating all the other TRBs. The ring's cycle
* state may change as we enqueue the other TRBs, so save it too.
*/
start_trb = &ep_ring->enqueue->generic;
start_cycle = ep_ring->cycle_state;
running_total = 0;
/*
* How much data is in the first TRB?
*
* There are three forces at work for TRB buffer pointers and lengths:
* 1. We don't want to walk off the end of this sg-list entry buffer.
* 2. The transfer length that the driver requested may be smaller than
* the amount of memory allocated for this scatter-gather list.
* 3. TRBs buffers can't cross 64KB boundaries.
*/
sg = urb->sg;
addr = (u64) sg_dma_address(sg);
this_sg_len = sg_dma_len(sg);
trb_buff_len = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
if (trb_buff_len > urb->transfer_buffer_length)
trb_buff_len = urb->transfer_buffer_length;
first_trb = true;
last_trb_num = zero_length_needed ? 2 : 1;
/* Queue the first TRB, even if it's zero-length */
do {
u32 field = 0;
u32 length_field = 0;
u32 remainder = 0;
/* Don't change the cycle bit of the first TRB until later */
if (first_trb) {
first_trb = false;
if (start_cycle == 0)
field |= 0x1;
} else
field |= ep_ring->cycle_state;
/* Chain all the TRBs together; clear the chain bit in the last
* TRB to indicate it's the last TRB in the chain.
*/
if (num_trbs > last_trb_num) {
field |= TRB_CHAIN;
} else if (num_trbs == last_trb_num) {
td->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
} else if (zero_length_needed && num_trbs == 1) {
trb_buff_len = 0;
urb_priv->td[1]->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
}
/* Only set interrupt on short packet for IN endpoints */
if (usb_urb_dir_in(urb))
field |= TRB_ISP;
if (TRB_MAX_BUFF_SIZE -
(addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) {
xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n");
xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n",
(unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
(unsigned int) addr + trb_buff_len);
}
/* Set the TRB length, TD size, and interrupter fields. */
remainder = xhci_td_remainder(xhci, running_total, trb_buff_len,
urb->transfer_buffer_length,
urb, num_trbs - 1);
length_field = TRB_LEN(trb_buff_len) |
TRB_TD_SIZE(remainder) |
TRB_INTR_TARGET(0);
if (num_trbs > 1)
more_trbs_coming = true;
else
more_trbs_coming = false;
queue_trb(xhci, ep_ring, more_trbs_coming,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
field | TRB_TYPE(TRB_NORMAL));
--num_trbs;
running_total += trb_buff_len;
/* Calculate length for next transfer --
* Are we done queueing all the TRBs for this sg entry?
*/
this_sg_len -= trb_buff_len;
if (this_sg_len == 0) {
--num_sgs;
if (num_sgs == 0)
break;
sg = sg_next(sg);
addr = (u64) sg_dma_address(sg);
this_sg_len = sg_dma_len(sg);
} else {
addr += trb_buff_len;
}
trb_buff_len = TRB_MAX_BUFF_SIZE -
(addr & (TRB_MAX_BUFF_SIZE - 1));
trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
if (running_total + trb_buff_len > urb->transfer_buffer_length)
trb_buff_len =
urb->transfer_buffer_length - running_total;
} while (num_trbs > 0);
check_trb_math(urb, num_trbs, running_total);
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
start_cycle, start_trb);
return 0;
}
/* This is very similar to what ehci-q.c qtd_fill() does */
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
@ -3264,51 +3105,40 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct xhci_ring *ep_ring;
struct urb_priv *urb_priv;
struct xhci_td *td;
int num_trbs;
struct xhci_generic_trb *start_trb;
bool first_trb;
int last_trb_num;
struct scatterlist *sg = NULL;
bool more_trbs_coming;
bool zero_length_needed;
int start_cycle;
u32 field, length_field;
int running_total, trb_buff_len, ret;
unsigned int total_packet_count;
unsigned int num_trbs, last_trb_num, i;
unsigned int start_cycle, num_sgs = 0;
unsigned int running_total, block_len, trb_buff_len;
unsigned int full_len;
int ret;
u32 field, length_field, remainder;
u64 addr;
if (urb->num_sgs)
return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index);
ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
if (!ep_ring)
return -EINVAL;
num_trbs = 0;
/* How much data is (potentially) left before the 64KB boundary? */
running_total = TRB_MAX_BUFF_SIZE -
(urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
running_total &= TRB_MAX_BUFF_SIZE - 1;
/* If there's some data on this 64KB chunk, or we have to send a
* zero-length transfer, we need at least one TRB
*/
if (running_total != 0 || urb->transfer_buffer_length == 0)
num_trbs++;
/* How many more 64KB chunks to transfer, how many more TRBs? */
while (running_total < urb->transfer_buffer_length) {
num_trbs++;
running_total += TRB_MAX_BUFF_SIZE;
}
/* If we have scatter/gather list, we use it. */
if (urb->num_sgs) {
num_sgs = urb->num_mapped_sgs;
sg = urb->sg;
num_trbs = count_sg_trbs_needed(urb);
} else
num_trbs = count_trbs_needed(urb);
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
num_trbs, urb, 0, mem_flags);
if (ret < 0)
if (unlikely(ret < 0))
return ret;
urb_priv = urb->hcpriv;
last_trb_num = num_trbs - 1;
/* Deal with URB_ZERO_PACKET - need one more td/trb */
zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET &&
urb_priv->length == 2;
@ -3318,7 +3148,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
1, urb, 1, mem_flags);
if (ret < 0)
if (unlikely(ret < 0))
return ret;
}
@ -3332,43 +3162,58 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
start_trb = &ep_ring->enqueue->generic;
start_cycle = ep_ring->cycle_state;
full_len = urb->transfer_buffer_length;
running_total = 0;
total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length,
usb_endpoint_maxp(&urb->ep->desc));
/* How much data is in the first TRB? */
addr = (u64) urb->transfer_dma;
trb_buff_len = TRB_MAX_BUFF_SIZE -
(urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
if (trb_buff_len > urb->transfer_buffer_length)
trb_buff_len = urb->transfer_buffer_length;
block_len = 0;
first_trb = true;
last_trb_num = zero_length_needed ? 2 : 1;
/* Queue the first TRB, even if it's zero-length */
do {
u32 remainder = 0;
field = 0;
/* Queue the TRBs, even if they are zero-length */
for (i = 0; i < num_trbs; i++) {
field = TRB_TYPE(TRB_NORMAL);
if (block_len == 0) {
/* A new contiguous block. */
if (sg) {
addr = (u64) sg_dma_address(sg);
block_len = sg_dma_len(sg);
} else {
addr = (u64) urb->transfer_dma;
block_len = full_len;
}
/* TRB buffer should not cross 64KB boundaries */
trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
trb_buff_len = min_t(unsigned int,
trb_buff_len,
block_len);
} else {
/* Further through the contiguous block. */
trb_buff_len = block_len;
if (trb_buff_len > TRB_MAX_BUFF_SIZE)
trb_buff_len = TRB_MAX_BUFF_SIZE;
}
if (running_total + trb_buff_len > full_len)
trb_buff_len = full_len - running_total;
/* Don't change the cycle bit of the first TRB until later */
if (first_trb) {
first_trb = false;
if (i == 0) {
if (start_cycle == 0)
field |= 0x1;
field |= TRB_CYCLE;
} else
field |= ep_ring->cycle_state;
/* Chain all the TRBs together; clear the chain bit in the last
* TRB to indicate it's the last TRB in the chain.
*/
if (num_trbs > last_trb_num) {
if (i < last_trb_num) {
field |= TRB_CHAIN;
} else if (num_trbs == last_trb_num) {
td->last_trb = ep_ring->enqueue;
field |= TRB_IOC;
} else if (zero_length_needed && num_trbs == 1) {
trb_buff_len = 0;
urb_priv->td[1]->last_trb = ep_ring->enqueue;
} else {
field |= TRB_IOC;
if (i == last_trb_num)
td->last_trb = ep_ring->enqueue;
else if (zero_length_needed) {
trb_buff_len = 0;
urb_priv->td[1]->last_trb = ep_ring->enqueue;
}
}
/* Only set interrupt on short packet for IN endpoints */
@ -3376,15 +3221,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field |= TRB_ISP;
/* Set the TRB length, TD size, and interrupter fields. */
remainder = xhci_td_remainder(xhci, running_total, trb_buff_len,
urb->transfer_buffer_length,
urb, num_trbs - 1);
remainder = xhci_td_remainder(xhci, running_total,
trb_buff_len, full_len,
urb, num_trbs - i - 1);
length_field = TRB_LEN(trb_buff_len) |
TRB_TD_SIZE(remainder) |
TRB_INTR_TARGET(0);
if (num_trbs > 1)
if (i < num_trbs - 1)
more_trbs_coming = true;
else
more_trbs_coming = false;
@ -3392,18 +3237,24 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
field | TRB_TYPE(TRB_NORMAL));
--num_trbs;
field);
running_total += trb_buff_len;
/* Calculate length for next transfer */
addr += trb_buff_len;
trb_buff_len = urb->transfer_buffer_length - running_total;
if (trb_buff_len > TRB_MAX_BUFF_SIZE)
trb_buff_len = TRB_MAX_BUFF_SIZE;
} while (num_trbs > 0);
block_len -= trb_buff_len;
check_trb_math(urb, num_trbs, running_total);
if (sg) {
if (block_len == 0) {
/* New sg entry */
--num_sgs;
if (num_sgs == 0)
break;
sg = sg_next(sg);
}
}
}
check_trb_math(urb, running_total);
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
start_cycle, start_trb);
return 0;
@ -3532,23 +3383,6 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
return 0;
}
static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
struct urb *urb, int i)
{
int num_trbs = 0;
u64 addr, td_len;
addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
td_len = urb->iso_frame_desc[i].length;
num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
TRB_MAX_BUFF_SIZE);
if (num_trbs == 0)
num_trbs++;
return num_trbs;
}
/*
* The transfer burst count field of the isochronous TRB defines the number of
* bursts that are required to move all packets in this TD. Only SuperSpeed
@ -3746,7 +3580,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
last_burst_pkt_count = xhci_get_last_burst_packet_count(xhci,
urb, total_pkt_count);
trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
trbs_per_td = count_isoc_trbs_needed(urb, i);
ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
urb->stream_id, trbs_per_td, urb, i, mem_flags);
@ -3807,8 +3641,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field |= TRB_BEI;
}
/* Calculate TRB length */
trb_buff_len = TRB_MAX_BUFF_SIZE -
(addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
if (trb_buff_len > td_remain_len)
trb_buff_len = td_remain_len;
@ -3897,8 +3730,6 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
struct xhci_ring *ep_ring;
struct xhci_ep_ctx *ep_ctx;
int start_frame;
int xhci_interval;
int ep_interval;
int num_tds, num_trbs, i;
int ret;
struct xhci_virt_ep *xep;
@ -3912,7 +3743,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
num_trbs = 0;
num_tds = urb->number_of_packets;
for (i = 0; i < num_tds; i++)
num_trbs += count_isoc_trbs_needed(xhci, urb, i);
num_trbs += count_isoc_trbs_needed(urb, i);
/* Check the ring to guarantee there is enough room for the whole urb.
* Do not insert any td of the urb to the ring if the check failed.
@ -3926,26 +3757,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
* Check interval value. This should be done before we start to
* calculate the start frame value.
*/
xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info));
ep_interval = urb->interval;
/* Convert to microframes */
if (urb->dev->speed == USB_SPEED_LOW ||
urb->dev->speed == USB_SPEED_FULL)
ep_interval *= 8;
/* FIXME change this to a warning and a suggestion to use the new API
* to set the polling interval (once the API is added).
*/
if (xhci_interval != ep_interval) {
dev_dbg_ratelimited(&urb->dev->dev,
"Driver uses different interval (%d microframe%s) than xHCI (%d microframe%s)\n",
ep_interval, ep_interval == 1 ? "" : "s",
xhci_interval, xhci_interval == 1 ? "" : "s");
urb->interval = xhci_interval;
/* Convert back to frames for LS/FS devices */
if (urb->dev->speed == USB_SPEED_LOW ||
urb->dev->speed == USB_SPEED_FULL)
urb->interval /= 8;
}
check_interval(xhci, urb, ep_ctx);
/* Calculate the start frame and put it in urb->start_frame. */
if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) {

View File

@ -1459,47 +1459,6 @@ free_priv:
return ret;
}
/* Get the right ring for the given URB.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
*/
static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb)
{
unsigned int slot_id;
unsigned int ep_index;
unsigned int stream_id;
struct xhci_virt_ep *ep;
slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
stream_id = urb->stream_id;
ep = &xhci->devs[slot_id]->eps[ep_index];
/* Common case: no streams */
if (!(ep->ep_state & EP_HAS_STREAMS))
return ep->ring;
if (stream_id == 0) {
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has streams, "
"but URB has no stream ID.\n",
slot_id, ep_index);
return NULL;
}
if (stream_id < ep->stream_info->num_streams)
return ep->stream_info->stream_rings[stream_id];
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has "
"stream IDs 1 to %u allocated, "
"but stream ID %u is requested.\n",
slot_id, ep_index,
ep->stream_info->num_streams - 1,
stream_id);
return NULL;
}
/*
* Remove the URB's TD from the endpoint ring. This may cause the HC to stop
* USB transfers, potentially stopping in the middle of a TRB buffer. The HC

View File

@ -1338,6 +1338,9 @@ union xhci_trb {
/* TRB buffer pointers can't cross 64KB boundaries */
#define TRB_MAX_BUFF_SHIFT 16
#define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT)
/* How much data is left before the 64KB boundary? */
#define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \
(addr & (TRB_MAX_BUFF_SIZE - 1)))
struct xhci_segment {
union xhci_trb *trbs;
@ -1965,4 +1968,15 @@ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_container_
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id);
static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb)
{
return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
xhci_get_endpoint_index(&urb->ep->desc),
urb->stream_id);
}
#endif /* __LINUX_XHCI_HCD_H */

View File

@ -163,7 +163,7 @@ static void isp1761_pci_shutdown(struct pci_dev *dev)
printk(KERN_ERR "ips1761_pci_shutdown\n");
}
static const struct pci_device_id isp1760_plx [] = {
static const struct pci_device_id isp1760_plx[] = {
{
.class = PCI_CLASS_BRIDGE_OTHER << 8,
.class_mask = ~0,

View File

@ -268,3 +268,29 @@ config USB_CHAOSKEY
To compile this driver as a module, choose M here: the
module will be called chaoskey.
config UCSI
tristate "USB Type-C Connector System Software Interface driver"
depends on ACPI
help
UCSI driver is meant to be used as a convenience tool for desktop and
server systems that are not equipped to handle USB in device mode. It
will always select USB host role for the USB Type-C ports on systems
that provide UCSI interface.
USB Type-C Connector System Software Interface (UCSI) is a
specification for an interface that allows the Operating System to
control the USB Type-C ports on a system. Things the need controlling
include the USB Data Role (host or device), and when USB Power
Delivery is supported, the Power Role (source or sink). With USB
Type-C connectors, when two dual role capable devices are attached
together, the data role is selected randomly. Therefore it is
important to give the OS a way to select the role. Otherwise the user
would have to unplug and replug in order in order to attempt to swap
the data and power roles.
The UCSI specification can be downloaded from:
http://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-ucsi-spec.html
To compile the driver as a module, choose M here: the module will be
called ucsi.

View File

@ -26,6 +26,7 @@ obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o
obj-$(CONFIG_USB_YUREX) += yurex.o
obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o
obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o
obj-$(CONFIG_UCSI) += ucsi.o
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o

View File

@ -2420,7 +2420,7 @@ static int sisusb_open(struct inode *inode, struct file *file)
if (!sisusb->devinit) {
if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH ||
sisusb->sisusb_dev->speed == USB_SPEED_SUPER) {
sisusb->sisusb_dev->speed >= USB_SPEED_SUPER) {
if (sisusb_init_gfxdevice(sisusb, 0)) {
mutex_unlock(&sisusb->lock);
dev_err(&sisusb->sisusb_dev->dev,
@ -3127,7 +3127,7 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->present = 1;
if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) {
if (dev->speed == USB_SPEED_HIGH || dev->speed >= USB_SPEED_SUPER) {
int initscreen = 1;
#ifdef INCL_SISUSB_CON
if (sisusb_first_vc > 0 && sisusb_last_vc > 0 &&

478
drivers/usb/misc/ucsi.c Normal file
View File

@ -0,0 +1,478 @@
/*
* USB Type-C Connector System Software Interface driver
*
* Copyright (C) 2016, Intel Corporation
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.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/platform_device.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/acpi.h>
#include "ucsi.h"
/* Double the time defined by MIN_TIME_TO_RESPOND_WITH_BUSY */
#define UCSI_TIMEOUT_MS 20
enum ucsi_status {
UCSI_IDLE = 0,
UCSI_BUSY,
UCSI_ERROR,
};
struct ucsi_connector {
int num;
struct ucsi *ucsi;
struct work_struct work;
struct ucsi_connector_capability cap;
};
struct ucsi {
struct device *dev;
struct ucsi_data __iomem *data;
enum ucsi_status status;
struct completion complete;
struct ucsi_capability cap;
struct ucsi_connector *connector;
/* device lock */
spinlock_t dev_lock;
/* PPM Communication lock */
struct mutex ppm_lock;
/* PPM communication flags */
unsigned long flags;
#define EVENT_PENDING 0
#define COMMAND_PENDING 1
};
static int ucsi_acpi_cmd(struct ucsi *ucsi, struct ucsi_control *ctrl)
{
uuid_le uuid = UUID_LE(0x6f8398c2, 0x7ca4, 0x11e4,
0xad, 0x36, 0x63, 0x10, 0x42, 0xb5, 0x00, 0x8f);
union acpi_object *obj;
ucsi->data->ctrl.raw_cmd = ctrl->raw_cmd;
obj = acpi_evaluate_dsm(ACPI_HANDLE(ucsi->dev), uuid.b, 1, 1, NULL);
if (!obj) {
dev_err(ucsi->dev, "%s: failed to evaluate _DSM\n", __func__);
return -EIO;
}
ACPI_FREE(obj);
return 0;
}
static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
{
struct ucsi *ucsi = data;
struct ucsi_cci *cci;
spin_lock(&ucsi->dev_lock);
ucsi->status = UCSI_IDLE;
cci = &ucsi->data->cci;
/*
* REVISIT: This is not documented behavior, but all known PPMs ACK
* asynchronous events by sending notification with cleared CCI.
*/
if (!ucsi->data->raw_cci) {
if (test_bit(EVENT_PENDING, &ucsi->flags))
complete(&ucsi->complete);
else
dev_WARN(ucsi->dev, "spurious notification\n");
goto out_unlock;
}
if (test_bit(COMMAND_PENDING, &ucsi->flags)) {
if (cci->busy) {
ucsi->status = UCSI_BUSY;
complete(&ucsi->complete);
goto out_unlock;
} else if (cci->ack_complete || cci->cmd_complete) {
/* Error Indication is only valid with commands */
if (cci->error && cci->cmd_complete)
ucsi->status = UCSI_ERROR;
ucsi->data->ctrl.raw_cmd = 0;
complete(&ucsi->complete);
}
}
if (cci->connector_change) {
struct ucsi_connector *con;
/*
* This is workaround for buggy PPMs that create asynchronous
* event notifications before OPM has enabled them.
*/
if (!ucsi->connector)
goto out_unlock;
con = ucsi->connector + (cci->connector_change - 1);
/*
* PPM will not clear the connector specific bit in Connector
* Change Indication field of CCI until the driver has ACK it,
* and the driver can not ACK it before it has been processed.
* The PPM will not generate new events before the first has
* been acknowledged, even if they are for an other connector.
* So only one event at a time.
*/
if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags))
schedule_work(&con->work);
}
out_unlock:
spin_unlock(&ucsi->dev_lock);
}
static int ucsi_ack(struct ucsi *ucsi, u8 cmd)
{
struct ucsi_control ctrl;
int ret;
ctrl.cmd.cmd = UCSI_ACK_CC_CI;
ctrl.cmd.length = 0;
ctrl.cmd.data = cmd;
ret = ucsi_acpi_cmd(ucsi, &ctrl);
if (ret)
return ret;
/* Waiting for ACK also with ACK CMD for now */
ret = wait_for_completion_timeout(&ucsi->complete,
msecs_to_jiffies(UCSI_TIMEOUT_MS));
if (!ret)
return -ETIMEDOUT;
return 0;
}
static int ucsi_run_cmd(struct ucsi *ucsi, struct ucsi_control *ctrl,
void *data, size_t size)
{
u16 err_value = 0;
int ret;
set_bit(COMMAND_PENDING, &ucsi->flags);
ret = ucsi_acpi_cmd(ucsi, ctrl);
if (ret)
goto err_clear_flag;
ret = wait_for_completion_timeout(&ucsi->complete,
msecs_to_jiffies(UCSI_TIMEOUT_MS));
if (!ret) {
ret = -ETIMEDOUT;
goto err_clear_flag;
}
switch (ucsi->status) {
case UCSI_IDLE:
if (data)
memcpy(data, ucsi->data->message_in, size);
ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
break;
case UCSI_BUSY:
/* The caller decides whether to cancel or not */
ret = -EBUSY;
goto err_clear_flag;
case UCSI_ERROR:
ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
if (ret)
goto err_clear_flag;
ctrl->cmd.cmd = UCSI_GET_ERROR_STATUS;
ctrl->cmd.length = 0;
ctrl->cmd.data = 0;
ret = ucsi_acpi_cmd(ucsi, ctrl);
if (ret)
goto err_clear_flag;
ret = wait_for_completion_timeout(&ucsi->complete,
msecs_to_jiffies(UCSI_TIMEOUT_MS));
if (!ret) {
ret = -ETIMEDOUT;
goto err_clear_flag;
}
memcpy(&err_value, ucsi->data->message_in, sizeof(err_value));
/* Something has really gone wrong */
if (WARN_ON(ucsi->status == UCSI_ERROR)) {
ret = -ENODEV;
goto err_clear_flag;
}
ret = ucsi_ack(ucsi, UCSI_ACK_CMD);
if (ret)
goto err_clear_flag;
switch (err_value) {
case UCSI_ERROR_INCOMPATIBLE_PARTNER:
ret = -EOPNOTSUPP;
break;
case UCSI_ERROR_CC_COMMUNICATION_ERR:
ret = -ECOMM;
break;
case UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL:
ret = -EIO;
break;
case UCSI_ERROR_DEAD_BATTERY:
dev_warn(ucsi->dev, "Dead battery condition!\n");
ret = -EPERM;
break;
/* The following mean a bug in this driver */
case UCSI_ERROR_INVALID_CON_NUM:
case UCSI_ERROR_UNREGONIZED_CMD:
case UCSI_ERROR_INVALID_CMD_ARGUMENT:
default:
dev_warn(ucsi->dev,
"%s: possible UCSI driver bug - error %hu\n",
__func__, err_value);
ret = -EINVAL;
break;
}
break;
}
ctrl->raw_cmd = 0;
err_clear_flag:
clear_bit(COMMAND_PENDING, &ucsi->flags);
return ret;
}
static void ucsi_connector_change(struct work_struct *work)
{
struct ucsi_connector *con = container_of(work, struct ucsi_connector,
work);
struct ucsi_connector_status constat;
struct ucsi *ucsi = con->ucsi;
struct ucsi_control ctrl;
int ret;
mutex_lock(&ucsi->ppm_lock);
ctrl.cmd.cmd = UCSI_GET_CONNECTOR_STATUS;
ctrl.cmd.length = 0;
ctrl.cmd.data = con->num;
ret = ucsi_run_cmd(con->ucsi, &ctrl, &constat, sizeof(constat));
if (ret) {
dev_err(ucsi->dev, "%s: failed to read connector status (%d)\n",
__func__, ret);
goto out_ack_event;
}
/* Ignoring disconnections and Alternate Modes */
if (!constat.connected || !(constat.change &
(UCSI_CONSTAT_PARTNER_CHANGE | UCSI_CONSTAT_CONNECT_CHANGE)) ||
constat.partner_flags & UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE)
goto out_ack_event;
/* If the partner got USB Host role, attempting swap */
if (constat.partner_type & UCSI_CONSTAT_PARTNER_TYPE_DFP) {
ctrl.uor.cmd = UCSI_SET_UOR;
ctrl.uor.con_num = con->num;
ctrl.uor.role = UCSI_UOR_ROLE_DFP;
ret = ucsi_run_cmd(con->ucsi, &ctrl, NULL, 0);
if (ret)
dev_err(ucsi->dev, "%s: failed to swap role (%d)\n",
__func__, ret);
}
out_ack_event:
ucsi_ack(ucsi, UCSI_ACK_EVENT);
clear_bit(EVENT_PENDING, &ucsi->flags);
mutex_unlock(&ucsi->ppm_lock);
}
static int ucsi_reset_ppm(struct ucsi *ucsi)
{
int timeout = UCSI_TIMEOUT_MS;
struct ucsi_control ctrl;
int ret;
memset(&ctrl, 0, sizeof(ctrl));
ctrl.cmd.cmd = UCSI_PPM_RESET;
ret = ucsi_acpi_cmd(ucsi, &ctrl);
if (ret)
return ret;
/* There is no quarantee the PPM will ever set the RESET_COMPLETE bit */
while (!ucsi->data->cci.reset_complete && timeout--)
usleep_range(1000, 2000);
return 0;
}
static int ucsi_init(struct ucsi *ucsi)
{
struct ucsi_connector *con;
struct ucsi_control ctrl;
int ret;
int i;
init_completion(&ucsi->complete);
spin_lock_init(&ucsi->dev_lock);
mutex_init(&ucsi->ppm_lock);
/* Reset the PPM */
ret = ucsi_reset_ppm(ucsi);
if (ret)
return ret;
/*
* REVISIT: Executing second reset to WA an issue seen on some of the
* Broxton based platforms, where the first reset puts the PPM into a
* state where it's unable to recognise some of the commands.
*/
ret = ucsi_reset_ppm(ucsi);
if (ret)
return ret;
mutex_lock(&ucsi->ppm_lock);
/* Enable basic notifications */
ctrl.cmd.cmd = UCSI_SET_NOTIFICATION_ENABLE;
ctrl.cmd.length = 0;
ctrl.cmd.data = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR;
ret = ucsi_run_cmd(ucsi, &ctrl, NULL, 0);
if (ret)
goto err_reset;
/* Get PPM capabilities */
ctrl.cmd.cmd = UCSI_GET_CAPABILITY;
ret = ucsi_run_cmd(ucsi, &ctrl, &ucsi->cap, sizeof(ucsi->cap));
if (ret)
goto err_reset;
if (!ucsi->cap.num_connectors) {
ret = -ENODEV;
goto err_reset;
}
ucsi->connector = devm_kcalloc(ucsi->dev, ucsi->cap.num_connectors,
sizeof(*ucsi->connector), GFP_KERNEL);
if (!ucsi->connector) {
ret = -ENOMEM;
goto err_reset;
}
for (i = 1, con = ucsi->connector; i < ucsi->cap.num_connectors + 1;
i++, con++) {
/* Get connector capability */
ctrl.cmd.cmd = UCSI_GET_CONNECTOR_CAPABILITY;
ctrl.cmd.data = i;
ret = ucsi_run_cmd(ucsi, &ctrl, &con->cap, sizeof(con->cap));
if (ret)
goto err_reset;
con->num = i;
con->ucsi = ucsi;
INIT_WORK(&con->work, ucsi_connector_change);
}
/* Enable all notifications */
ctrl.cmd.cmd = UCSI_SET_NOTIFICATION_ENABLE;
ctrl.cmd.data = UCSI_ENABLE_NTFY_ALL;
ret = ucsi_run_cmd(ucsi, &ctrl, NULL, 0);
if (ret < 0)
goto err_reset;
mutex_unlock(&ucsi->ppm_lock);
return 0;
err_reset:
ucsi_reset_ppm(ucsi);
mutex_unlock(&ucsi->ppm_lock);
return ret;
}
static int ucsi_acpi_probe(struct platform_device *pdev)
{
struct resource *res;
acpi_status status;
struct ucsi *ucsi;
int ret;
ucsi = devm_kzalloc(&pdev->dev, sizeof(*ucsi), GFP_KERNEL);
if (!ucsi)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "missing memory resource\n");
return -ENODEV;
}
/*
* NOTE: ACPI has claimed the memory region as it's also an Operation
* Region. It's not possible to request it in the driver.
*/
ucsi->data = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!ucsi->data)
return -ENOMEM;
ucsi->dev = &pdev->dev;
status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev),
ACPI_ALL_NOTIFY,
ucsi_acpi_notify, ucsi);
if (ACPI_FAILURE(status))
return -ENODEV;
ret = ucsi_init(ucsi);
if (ret) {
acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
ACPI_ALL_NOTIFY,
ucsi_acpi_notify);
return ret;
}
platform_set_drvdata(pdev, ucsi);
return 0;
}
static int ucsi_acpi_remove(struct platform_device *pdev)
{
struct ucsi *ucsi = platform_get_drvdata(pdev);
acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
ACPI_ALL_NOTIFY, ucsi_acpi_notify);
/* Make sure there are no events in the middle of being processed */
if (wait_on_bit_timeout(&ucsi->flags, EVENT_PENDING,
TASK_UNINTERRUPTIBLE,
msecs_to_jiffies(UCSI_TIMEOUT_MS)))
dev_WARN(ucsi->dev, "%s: Events still pending\n", __func__);
ucsi_reset_ppm(ucsi);
return 0;
}
static const struct acpi_device_id ucsi_acpi_match[] = {
{ "PNP0CA0", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, ucsi_acpi_match);
static struct platform_driver ucsi_acpi_platform_driver = {
.driver = {
.name = "ucsi_acpi",
.acpi_match_table = ACPI_PTR(ucsi_acpi_match),
},
.probe = ucsi_acpi_probe,
.remove = ucsi_acpi_remove,
};
module_platform_driver(ucsi_acpi_platform_driver);
MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("USB Type-C System Software Interface (UCSI) driver");

215
drivers/usb/misc/ucsi.h Normal file
View File

@ -0,0 +1,215 @@
#include <linux/types.h>
/* -------------------------------------------------------------------------- */
/* Command Status and Connector Change Indication (CCI) data structure */
struct ucsi_cci {
unsigned int RESERVED1:1;
unsigned int connector_change:7;
u8 data_length;
unsigned int RESERVED9:9;
unsigned int not_supported:1;
unsigned int cancel_complete:1;
unsigned int reset_complete:1;
unsigned int busy:1;
unsigned int ack_complete:1;
unsigned int error:1;
unsigned int cmd_complete:1;
} __packed;
/* Default fields in CONTROL data structure */
struct ucsi_command {
u8 cmd;
u8 length;
u64 data:48;
} __packed;
/* Set USB Operation Mode Command structure */
struct ucsi_uor_cmd {
u8 cmd;
u8 length;
u64 con_num:7;
u64 role:3;
#define UCSI_UOR_ROLE_DFP BIT(0)
#define UCSI_UOR_ROLE_UFP BIT(1)
#define UCSI_UOR_ROLE_DRP BIT(2)
u64 data:38;
} __packed;
struct ucsi_control {
union {
u64 raw_cmd;
struct ucsi_command cmd;
struct ucsi_uor_cmd uor;
};
};
struct ucsi_data {
u16 version;
u16 RESERVED;
union {
u32 raw_cci;
struct ucsi_cci cci;
};
struct ucsi_control ctrl;
u32 message_in[4];
u32 message_out[4];
} __packed;
/* Commands */
#define UCSI_PPM_RESET 0x01
#define UCSI_CANCEL 0x02
#define UCSI_CONNECTOR_RESET 0x03
#define UCSI_ACK_CC_CI 0x04
#define UCSI_SET_NOTIFICATION_ENABLE 0x05
#define UCSI_GET_CAPABILITY 0x06
#define UCSI_GET_CONNECTOR_CAPABILITY 0x07
#define UCSI_SET_UOM 0x08
#define UCSI_SET_UOR 0x09
#define UCSI_SET_PDM 0x0A
#define UCSI_SET_PDR 0x0B
#define UCSI_GET_ALTERNATE_MODES 0x0C
#define UCSI_GET_CAM_SUPPORTED 0x0D
#define UCSI_GET_CURRENT_CAM 0x0E
#define UCSI_SET_NEW_CAM 0x0F
#define UCSI_GET_PDOS 0x10
#define UCSI_GET_CABLE_PROPERTY 0x11
#define UCSI_GET_CONNECTOR_STATUS 0x12
#define UCSI_GET_ERROR_STATUS 0x13
/* ACK_CC_CI commands */
#define UCSI_ACK_EVENT 1
#define UCSI_ACK_CMD 2
/* Bits for SET_NOTIFICATION_ENABLE command */
#define UCSI_ENABLE_NTFY_CMD_COMPLETE BIT(0)
#define UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE BIT(1)
#define UCSI_ENABLE_NTFY_PWR_OPMODE_CHANGE BIT(2)
#define UCSI_ENABLE_NTFY_CAP_CHANGE BIT(5)
#define UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE BIT(6)
#define UCSI_ENABLE_NTFY_PD_RESET_COMPLETE BIT(7)
#define UCSI_ENABLE_NTFY_CAM_CHANGE BIT(8)
#define UCSI_ENABLE_NTFY_BAT_STATUS_CHANGE BIT(9)
#define UCSI_ENABLE_NTFY_PARTNER_CHANGE BIT(11)
#define UCSI_ENABLE_NTFY_PWR_DIR_CHANGE BIT(12)
#define UCSI_ENABLE_NTFY_CONNECTOR_CHANGE BIT(14)
#define UCSI_ENABLE_NTFY_ERROR BIT(15)
#define UCSI_ENABLE_NTFY_ALL 0xdbe7
/* Error information returned by PPM in response to GET_ERROR_STATUS command. */
#define UCSI_ERROR_UNREGONIZED_CMD BIT(0)
#define UCSI_ERROR_INVALID_CON_NUM BIT(1)
#define UCSI_ERROR_INVALID_CMD_ARGUMENT BIT(2)
#define UCSI_ERROR_INCOMPATIBLE_PARTNER BIT(3)
#define UCSI_ERROR_CC_COMMUNICATION_ERR BIT(4)
#define UCSI_ERROR_DEAD_BATTERY BIT(5)
#define UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL BIT(6)
/* Data structure filled by PPM in response to GET_CAPABILITY command. */
struct ucsi_capability {
u32 attributes;
#define UCSI_CAP_ATTR_DISABLE_STATE BIT(0)
#define UCSI_CAP_ATTR_BATTERY_CHARGING BIT(1)
#define UCSI_CAP_ATTR_USB_PD BIT(2)
#define UCSI_CAP_ATTR_TYPEC_CURRENT BIT(6)
#define UCSI_CAP_ATTR_POWER_AC_SUPPLY BIT(8)
#define UCSI_CAP_ATTR_POWER_OTHER BIT(10)
#define UCSI_CAP_ATTR_POWER_VBUS BIT(14)
u8 num_connectors;
u32 features:24;
#define UCSI_CAP_SET_UOM BIT(0)
#define UCSI_CAP_SET_PDM BIT(1)
#define UCSI_CAP_ALT_MODE_DETAILS BIT(2)
#define UCSI_CAP_ALT_MODE_OVERRIDE BIT(3)
#define UCSI_CAP_PDO_DETAILS BIT(4)
#define UCSI_CAP_CABLE_DETAILS BIT(5)
#define UCSI_CAP_EXT_SUPPLY_NOTIFICATIONS BIT(6)
#define UCSI_CAP_PD_RESET BIT(7)
u8 num_alt_modes;
u8 RESERVED;
u16 bc_version;
u16 pd_version;
u16 typec_version;
} __packed;
/* Data structure filled by PPM in response to GET_CONNECTOR_CAPABILITY cmd. */
struct ucsi_connector_capability {
u8 op_mode;
#define UCSI_CONCAP_OPMODE_DFP BIT(0)
#define UCSI_CONCAP_OPMODE_UFP BIT(1)
#define UCSI_CONCAP_OPMODE_DRP BIT(2)
#define UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY BIT(3)
#define UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY BIT(4)
#define UCSI_CONCAP_OPMODE_USB2 BIT(5)
#define UCSI_CONCAP_OPMODE_USB3 BIT(6)
#define UCSI_CONCAP_OPMODE_ALT_MODE BIT(7)
u8 provider:1;
u8 consumer:1;
} __packed;
/* Data structure filled by PPM in response to GET_CABLE_PROPERTY command. */
struct ucsi_cable_property {
u16 speed_supported;
u8 current_capability;
u8 vbus_in_cable:1;
u8 active_cable:1;
u8 directionality:1;
u8 plug_type:2;
#define UCSI_CABLE_PROPERTY_PLUG_TYPE_A 0
#define UCSI_CABLE_PROPERTY_PLUG_TYPE_B 1
#define UCSI_CABLE_PROPERTY_PLUG_TYPE_C 2
#define UCSI_CABLE_PROPERTY_PLUG_OTHER 3
u8 mode_support:1;
u8 RESERVED_2:2;
u8 latency:4;
u8 RESERVED_4:4;
} __packed;
/* Data structure filled by PPM in response to GET_CONNECTOR_STATUS command. */
struct ucsi_connector_status {
u16 change;
#define UCSI_CONSTAT_EXT_SUPPLY_CHANGE BIT(1)
#define UCSI_CONSTAT_POWER_OPMODE_CHANGE BIT(2)
#define UCSI_CONSTAT_PDOS_CHANGE BIT(5)
#define UCSI_CONSTAT_POWER_LEVEL_CHANGE BIT(6)
#define UCSI_CONSTAT_PD_RESET_COMPLETE BIT(7)
#define UCSI_CONSTAT_CAM_CHANGE BIT(8)
#define UCSI_CONSTAT_BC_CHANGE BIT(9)
#define UCSI_CONSTAT_PARTNER_CHANGE BIT(11)
#define UCSI_CONSTAT_POWER_DIR_CHANGE BIT(12)
#define UCSI_CONSTAT_CONNECT_CHANGE BIT(14)
#define UCSI_CONSTAT_ERROR BIT(15)
u16 pwr_op_mode:3;
#define UCSI_CONSTAT_PWR_OPMODE_NONE 0
#define UCSI_CONSTAT_PWR_OPMODE_DEFAULT 1
#define UCSI_CONSTAT_PWR_OPMODE_BC 2
#define UCSI_CONSTAT_PWR_OPMODE_PD 3
#define UCSI_CONSTAT_PWR_OPMODE_TYPEC1_3 4
#define UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0 5
u16 connected:1;
u16 pwr_dir:1;
u16 partner_flags:8;
#define UCSI_CONSTAT_PARTNER_FLAG_USB BIT(0)
#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE BIT(1)
u16 partner_type:3;
#define UCSI_CONSTAT_PARTNER_TYPE_DFP 1
#define UCSI_CONSTAT_PARTNER_TYPE_UFP 2
#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_NO_UFP 3 /* Powered Cable */
#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */
#define UCSI_CONSTAT_PARTNER_TYPE_DEBUG 5
#define UCSI_CONSTAT_PARTNER_TYPE_AUDIO 6
u32 request_data_obj;
u8 bc_status:2;
#define UCSI_CONSTAT_BC_NOT_CHARGING 0
#define UCSI_CONSTAT_BC_NOMINAL_CHARGING 1
#define UCSI_CONSTAT_BC_SLOW_CHARGING 2
#define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3
u8 provider_cap_limit_reason:4;
#define UCSI_CONSTAT_CAP_PWR_LOWERED 0
#define UCSI_CONSTAT_CAP_PWR_BUDGET_LIMIT 1
u8 RESERVED:2;
} __packed;
/* -------------------------------------------------------------------------- */

View File

@ -287,6 +287,9 @@ static struct urb *usbtest_alloc_urb(
if (usb_pipein(pipe))
urb->transfer_flags |= URB_SHORT_NOT_OK;
if ((bytes + offset) == 0)
return urb;
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
urb->transfer_buffer = usb_alloc_coherent(udev, bytes + offset,
GFP_KERNEL, &urb->transfer_dma);
@ -529,6 +532,7 @@ static struct scatterlist *
alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe)
{
struct scatterlist *sg;
unsigned int n_size = 0;
unsigned i;
unsigned size = max;
unsigned maxpacket =
@ -561,7 +565,8 @@ alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe)
break;
case 1:
for (j = 0; j < size; j++)
*buf++ = (u8) ((j % maxpacket) % 63);
*buf++ = (u8) (((j + n_size) % maxpacket) % 63);
n_size += size;
break;
}

View File

@ -240,10 +240,7 @@ static int phy_8x16_read_devicetree(struct phy_8x16 *qphy)
qphy->switch_gpio = devm_gpiod_get_optional(dev, "switch",
GPIOD_OUT_LOW);
if (IS_ERR(qphy->switch_gpio))
return PTR_ERR(qphy->switch_gpio);
return 0;
return PTR_ERR_OR_ZERO(qphy->switch_gpio);
}
static int phy_8x16_reboot_notify(struct notifier_block *this,

View File

@ -155,13 +155,13 @@ static int twl6030_start_srp(struct phy_companion *comparator)
static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
{
/* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_BACKUP_REG);
/* Program CFG_LDO_PD2 register and set VUSB bit */
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2);
twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_CFG_LDO_PD2);
/* Program MISC2 register and set bit VUSB_IN_VBAT */
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x10, TWL6030_MISC2);
twl->usb3v3 = regulator_get(twl->dev, twl->regulator);
if (IS_ERR(twl->usb3v3))
@ -301,10 +301,10 @@ static void otg_set_vbus_work(struct work_struct *data)
*/
if (twl->vbus_enable)
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40,
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x40,
CHARGERUSB_CTRL1);
else
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00,
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x00,
CHARGERUSB_CTRL1);
}

View File

@ -799,8 +799,10 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt);
return info->dma_map_ctrl(pkt, map);
return info->dma_map_ctrl(chan->device->dev, pkt, map);
}
static void usbhsf_dma_complete(void *arg);
@ -881,12 +883,12 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
if (!fifo)
goto usbhsf_pio_prepare_push;
if (usbhsf_dma_map(pkt) < 0)
goto usbhsf_pio_prepare_push;
ret = usbhsf_fifo_select(pipe, fifo, 0);
if (ret < 0)
goto usbhsf_pio_prepare_push_unmap;
goto usbhsf_pio_prepare_push;
if (usbhsf_dma_map(pkt) < 0)
goto usbhsf_pio_prepare_push_unselect;
pkt->trans = len;
@ -896,8 +898,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
return 0;
usbhsf_pio_prepare_push_unmap:
usbhsf_dma_unmap(pkt);
usbhsf_pio_prepare_push_unselect:
usbhsf_fifo_unselect(pipe, fifo);
usbhsf_pio_prepare_push:
/*
* change handler to PIO

View File

@ -191,13 +191,12 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep,
/*
* dma map/unmap
*/
static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
static int usbhsg_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt,
int map)
{
struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
struct usb_request *req = &ureq->req;
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
enum dma_data_direction dir;
int ret = 0;
@ -207,13 +206,13 @@ static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
/* it can not use scatter/gather */
WARN_ON(req->num_sgs);
ret = usb_gadget_map_request(&gpriv->gadget, req, dir);
ret = usb_gadget_map_request_by_dev(dma_dev, req, dir);
if (ret < 0)
return ret;
pkt->dma = req->dma;
} else {
usb_gadget_unmap_request(&gpriv->gadget, req, dir);
usb_gadget_unmap_request_by_dev(dma_dev, req, dir);
}
return ret;

View File

@ -929,7 +929,8 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,
/*
* dma map functions
*/
static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
static int usbhsh_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt,
int map)
{
if (map) {
struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);

View File

@ -391,9 +391,8 @@ void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len)
/*
* pipe setup
*/
static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
int is_host,
int dir_in)
static int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host,
int dir_in, u16 *pipecfg)
{
u16 type = 0;
u16 bfre = 0;
@ -451,14 +450,14 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
/* EPNUM */
epnum = 0; /* see usbhs_pipe_config_update() */
return type |
bfre |
dblb |
cntmd |
dir |
shtnak |
epnum;
*pipecfg = type |
bfre |
dblb |
cntmd |
dir |
shtnak |
epnum;
return 0;
}
static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe)
@ -655,7 +654,8 @@ static void usbhsp_put_pipe(struct usbhs_pipe *pipe)
}
void usbhs_pipe_init(struct usbhs_priv *priv,
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map))
int (*dma_map_ctrl)(struct device *dma_dev,
struct usbhs_pkt *pkt, int map))
{
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
struct usbhs_pipe *pipe;
@ -702,7 +702,11 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
return NULL;
}
pipecfg = usbhsp_setup_pipecfg(pipe, is_host, dir_in);
if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) {
dev_err(dev, "can't setup pipe\n");
return NULL;
}
pipebuf = usbhsp_setup_pipebuff(pipe);
usbhsp_pipe_select(pipe);

View File

@ -47,7 +47,8 @@ struct usbhs_pipe_info {
struct usbhs_pipe *pipe;
int size; /* array size of "pipe" */
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map);
int (*dma_map_ctrl)(struct device *dma_dev, struct usbhs_pkt *pkt,
int map);
};
/*
@ -84,7 +85,8 @@ int usbhs_pipe_is_running(struct usbhs_pipe *pipe);
void usbhs_pipe_running(struct usbhs_pipe *pipe, int running);
void usbhs_pipe_init(struct usbhs_priv *priv,
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map));
int (*dma_map_ctrl)(struct device *dma_dev,
struct usbhs_pkt *pkt, int map));
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
void usbhs_pipe_clear(struct usbhs_pipe *pipe);
int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);

View File

@ -331,6 +331,42 @@ struct cp210x_comm_status {
*/
#define PURGE_ALL 0x000f
/* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */
struct cp210x_flow_ctl {
__le32 ulControlHandshake;
__le32 ulFlowReplace;
__le32 ulXonLimit;
__le32 ulXoffLimit;
} __packed;
/* cp210x_flow_ctl::ulControlHandshake */
#define CP210X_SERIAL_DTR_MASK GENMASK(1, 0)
#define CP210X_SERIAL_DTR_SHIFT(_mode) (_mode)
#define CP210X_SERIAL_CTS_HANDSHAKE BIT(3)
#define CP210X_SERIAL_DSR_HANDSHAKE BIT(4)
#define CP210X_SERIAL_DCD_HANDSHAKE BIT(5)
#define CP210X_SERIAL_DSR_SENSITIVITY BIT(6)
/* values for cp210x_flow_ctl::ulControlHandshake::CP210X_SERIAL_DTR_MASK */
#define CP210X_SERIAL_DTR_INACTIVE 0
#define CP210X_SERIAL_DTR_ACTIVE 1
#define CP210X_SERIAL_DTR_FLOW_CTL 2
/* cp210x_flow_ctl::ulFlowReplace */
#define CP210X_SERIAL_AUTO_TRANSMIT BIT(0)
#define CP210X_SERIAL_AUTO_RECEIVE BIT(1)
#define CP210X_SERIAL_ERROR_CHAR BIT(2)
#define CP210X_SERIAL_NULL_STRIPPING BIT(3)
#define CP210X_SERIAL_BREAK_CHAR BIT(4)
#define CP210X_SERIAL_RTS_MASK GENMASK(7, 6)
#define CP210X_SERIAL_RTS_SHIFT(_mode) (_mode << 6)
#define CP210X_SERIAL_XOFF_CONTINUE BIT(31)
/* values for cp210x_flow_ctl::ulFlowReplace::CP210X_SERIAL_RTS_MASK */
#define CP210X_SERIAL_RTS_INACTIVE 0
#define CP210X_SERIAL_RTS_ACTIVE 1
#define CP210X_SERIAL_RTS_FLOW_CTL 2
/*
* Reads a variable-sized block of CP210X_ registers, identified by req.
* Returns data into buf in native USB byte order.
@ -698,9 +734,10 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
{
struct device *dev = &port->dev;
unsigned int cflag;
u8 modem_ctl[16];
struct cp210x_flow_ctl flow_ctl;
u32 baud;
u16 bits;
u32 ctl_hs;
cp210x_read_u32_reg(port, CP210X_GET_BAUDRATE, &baud);
@ -796,9 +833,10 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
break;
}
cp210x_read_reg_block(port, CP210X_GET_FLOW, modem_ctl,
sizeof(modem_ctl));
if (modem_ctl[0] & 0x08) {
cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
sizeof(flow_ctl));
ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
if (ctl_hs & CP210X_SERIAL_CTS_HANDSHAKE) {
dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
cflag |= CRTSCTS;
} else {
@ -867,7 +905,6 @@ static void cp210x_set_termios(struct tty_struct *tty,
struct device *dev = &port->dev;
unsigned int cflag, old_cflag;
u16 bits;
u8 modem_ctl[16];
cflag = tty->termios.c_cflag;
old_cflag = old_termios->c_cflag;
@ -951,35 +988,44 @@ static void cp210x_set_termios(struct tty_struct *tty,
}
if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
struct cp210x_flow_ctl flow_ctl;
u32 ctl_hs;
u32 flow_repl;
/* Only bytes 0, 4 and 7 out of first 8 have functional bits */
cp210x_read_reg_block(port, CP210X_GET_FLOW, modem_ctl,
sizeof(modem_ctl));
dev_dbg(dev, "%s - read modem controls = %02x .. .. .. %02x .. .. %02x\n",
__func__, modem_ctl[0], modem_ctl[4], modem_ctl[7]);
cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
sizeof(flow_ctl));
ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
dev_dbg(dev, "%s - read ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
__func__, ctl_hs, flow_repl);
ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE;
ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
if (cflag & CRTSCTS) {
modem_ctl[0] &= ~0x7B;
modem_ctl[0] |= 0x09;
modem_ctl[4] = 0x80;
/* FIXME - why clear reserved bits just read? */
modem_ctl[5] = 0;
modem_ctl[6] = 0;
modem_ctl[7] = 0;
ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
flow_repl |= CP210X_SERIAL_RTS_SHIFT(
CP210X_SERIAL_RTS_FLOW_CTL);
dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);
} else {
modem_ctl[0] &= ~0x7B;
modem_ctl[0] |= 0x01;
/* FIXME - OR here instead of assignment looks wrong */
modem_ctl[4] |= 0x40;
ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
flow_repl |= CP210X_SERIAL_RTS_SHIFT(
CP210X_SERIAL_RTS_ACTIVE);
dev_dbg(dev, "%s - flow control = NONE\n", __func__);
}
dev_dbg(dev, "%s - write modem controls = %02x .. .. .. %02x .. .. %02x\n",
__func__, modem_ctl[0], modem_ctl[4], modem_ctl[7]);
cp210x_write_reg_block(port, CP210X_SET_FLOW, modem_ctl,
sizeof(modem_ctl));
dev_dbg(dev, "%s - write ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
__func__, ctl_hs, flow_repl);
flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
sizeof(flow_ctl));
}
}

View File

@ -93,27 +93,27 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial);
static void ftdi_USB_UIRT_setup(struct ftdi_private *priv);
static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
static struct ftdi_sio_quirk ftdi_jtag_quirk = {
static const struct ftdi_sio_quirk ftdi_jtag_quirk = {
.probe = ftdi_jtag_probe,
};
static struct ftdi_sio_quirk ftdi_NDI_device_quirk = {
static const struct ftdi_sio_quirk ftdi_NDI_device_quirk = {
.probe = ftdi_NDI_device_setup,
};
static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
static const struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
.port_probe = ftdi_USB_UIRT_setup,
};
static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
static const struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
.port_probe = ftdi_HE_TIRA1_setup,
};
static struct ftdi_sio_quirk ftdi_stmclite_quirk = {
static const struct ftdi_sio_quirk ftdi_stmclite_quirk = {
.probe = ftdi_stmclite_probe,
};
static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
static const struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
.probe = ftdi_8u2232c_probe,
};
@ -1775,7 +1775,7 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
static int ftdi_sio_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
struct ftdi_sio_quirk *quirk =
const struct ftdi_sio_quirk *quirk =
(struct ftdi_sio_quirk *)id->driver_info;
if (quirk && quirk->probe) {
@ -1792,7 +1792,7 @@ static int ftdi_sio_probe(struct usb_serial *serial,
static int ftdi_sio_port_probe(struct usb_serial_port *port)
{
struct ftdi_private *priv;
struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);

View File

@ -2849,14 +2849,16 @@ static int edge_startup(struct usb_serial *serial)
/* not set up yet, so do it now */
edge_serial->interrupt_read_urb =
usb_alloc_urb(0, GFP_KERNEL);
if (!edge_serial->interrupt_read_urb)
return -ENOMEM;
if (!edge_serial->interrupt_read_urb) {
response = -ENOMEM;
break;
}
edge_serial->interrupt_in_buffer =
kmalloc(buffer_size, GFP_KERNEL);
if (!edge_serial->interrupt_in_buffer) {
usb_free_urb(edge_serial->interrupt_read_urb);
return -ENOMEM;
response = -ENOMEM;
break;
}
edge_serial->interrupt_in_endpoint =
endpoint->bEndpointAddress;
@ -2884,14 +2886,16 @@ static int edge_startup(struct usb_serial *serial)
/* not set up yet, so do it now */
edge_serial->read_urb =
usb_alloc_urb(0, GFP_KERNEL);
if (!edge_serial->read_urb)
return -ENOMEM;
if (!edge_serial->read_urb) {
response = -ENOMEM;
break;
}
edge_serial->bulk_in_buffer =
kmalloc(buffer_size, GFP_KERNEL);
if (!edge_serial->bulk_in_buffer) {
usb_free_urb(edge_serial->read_urb);
return -ENOMEM;
response = -ENOMEM;
break;
}
edge_serial->bulk_in_endpoint =
endpoint->bEndpointAddress;
@ -2917,9 +2921,22 @@ static int edge_startup(struct usb_serial *serial)
}
}
if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) {
dev_err(ddev, "Error - the proper endpoints were not found!\n");
return -ENODEV;
if (response || !interrupt_in_found || !bulk_in_found ||
!bulk_out_found) {
if (!response) {
dev_err(ddev, "expected endpoints not found\n");
response = -ENODEV;
}
usb_free_urb(edge_serial->interrupt_read_urb);
kfree(edge_serial->interrupt_in_buffer);
usb_free_urb(edge_serial->read_urb);
kfree(edge_serial->bulk_in_buffer);
kfree(edge_serial);
return response;
}
/* start interrupt read for this edgeport this interrupt will
@ -2942,16 +2959,9 @@ static void edge_disconnect(struct usb_serial *serial)
{
struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
/* stop reads and writes on all ports */
/* free up our endpoint stuff */
if (edge_serial->is_epic) {
usb_kill_urb(edge_serial->interrupt_read_urb);
usb_free_urb(edge_serial->interrupt_read_urb);
kfree(edge_serial->interrupt_in_buffer);
usb_kill_urb(edge_serial->read_urb);
usb_free_urb(edge_serial->read_urb);
kfree(edge_serial->bulk_in_buffer);
}
}
@ -2964,6 +2974,16 @@ static void edge_release(struct usb_serial *serial)
{
struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
if (edge_serial->is_epic) {
usb_kill_urb(edge_serial->interrupt_read_urb);
usb_free_urb(edge_serial->interrupt_read_urb);
kfree(edge_serial->interrupt_in_buffer);
usb_kill_urb(edge_serial->read_urb);
usb_free_urb(edge_serial->read_urb);
kfree(edge_serial->bulk_in_buffer);
}
kfree(edge_serial);
}

View File

@ -255,7 +255,7 @@ static int keyspan_write(struct tty_struct *tty,
return count;
}
dev_dbg(&port->dev, "%s - endpoint %d flip %d\n",
dev_dbg(&port->dev, "%s - endpoint %x flip %d\n",
__func__, usb_pipeendpoint(this_urb->pipe), flip);
if (this_urb->status == -EINPROGRESS) {
@ -300,7 +300,7 @@ static void usa26_indat_callback(struct urb *urb)
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
__func__, status, endpoint);
return;
}
@ -393,7 +393,8 @@ static void usa26_instat_callback(struct urb *urb)
serial = urb->context;
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
__func__, status);
return;
}
if (urb->actual_length != 9) {
@ -452,7 +453,7 @@ static void usa28_indat_callback(struct urb *urb)
do {
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
__func__, status, usb_pipeendpoint(urb->pipe));
return;
}
@ -511,7 +512,8 @@ static void usa28_instat_callback(struct urb *urb)
serial = urb->context;
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
__func__, status);
return;
}
@ -591,7 +593,8 @@ static void usa49_instat_callback(struct urb *urb)
serial = urb->context;
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
__func__, status);
return;
}
@ -646,7 +649,7 @@ static void usa49_indat_callback(struct urb *urb)
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
__func__, status, endpoint);
return;
}
@ -698,7 +701,8 @@ static void usa49wg_indat_callback(struct urb *urb)
serial = urb->context;
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
__func__, status);
return;
}
@ -774,8 +778,8 @@ static void usa90_indat_callback(struct urb *urb)
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
__func__, status, endpoint);
dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
__func__, status, endpoint);
return;
}
@ -847,7 +851,8 @@ static void usa90_instat_callback(struct urb *urb)
serial = urb->context;
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
__func__, status);
return;
}
if (urb->actual_length < 14) {
@ -912,7 +917,8 @@ static void usa67_instat_callback(struct urb *urb)
serial = urb->context;
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status);
dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
__func__, status);
return;
}
@ -1082,12 +1088,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
return 0;
}
static inline void stop_urb(struct urb *urb)
{
if (urb && urb->status == -EINPROGRESS)
usb_kill_urb(urb);
}
static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
{
struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
@ -1114,10 +1114,10 @@ static void keyspan_close(struct usb_serial_port *port)
p_priv->out_flip = 0;
p_priv->in_flip = 0;
stop_urb(p_priv->inack_urb);
usb_kill_urb(p_priv->inack_urb);
for (i = 0; i < 2; i++) {
stop_urb(p_priv->in_urbs[i]);
stop_urb(p_priv->out_urbs[i]);
usb_kill_urb(p_priv->in_urbs[i]);
usb_kill_urb(p_priv->out_urbs[i]);
}
}
@ -1221,8 +1221,8 @@ static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *se
if (ep->bEndpointAddress == endpoint)
return ep;
}
dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
"endpoint %x\n", endpoint);
dev_warn(&serial->interface->dev, "found no endpoint descriptor for endpoint %x\n",
endpoint);
return NULL;
}
@ -1237,7 +1237,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
if (endpoint == -1)
return NULL; /* endpoint not needed */
dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %x\n",
__func__, endpoint);
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
if (!urb)
return NULL;
@ -1572,7 +1573,8 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
return -1;
}
dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
dev_dbg(&port->dev, "%s - endpoint %x\n",
__func__, usb_pipeendpoint(this_urb->pipe));
/* Save reset port val for resend.
Don't overwrite resend for open/close condition. */
@ -1838,7 +1840,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
return -1;
}
dev_dbg(&port->dev, "%s - endpoint %d (%d)\n",
dev_dbg(&port->dev, "%s - endpoint %x (%d)\n",
__func__, usb_pipeendpoint(this_urb->pipe), device_port);
/* Save reset port val for resend.
@ -2365,9 +2367,9 @@ static void keyspan_disconnect(struct usb_serial *serial)
s_priv = usb_get_serial_data(serial);
stop_urb(s_priv->instat_urb);
stop_urb(s_priv->glocont_urb);
stop_urb(s_priv->indat_urb);
usb_kill_urb(s_priv->instat_urb);
usb_kill_urb(s_priv->glocont_urb);
usb_kill_urb(s_priv->indat_urb);
}
static void keyspan_release(struct usb_serial *serial)
@ -2376,6 +2378,10 @@ static void keyspan_release(struct usb_serial *serial)
s_priv = usb_get_serial_data(serial);
/* Make sure to unlink the URBs submitted in attach. */
usb_kill_urb(s_priv->instat_urb);
usb_kill_urb(s_priv->indat_urb);
usb_free_urb(s_priv->instat_urb);
usb_free_urb(s_priv->indat_urb);
usb_free_urb(s_priv->glocont_urb);
@ -2491,11 +2497,11 @@ static int keyspan_port_remove(struct usb_serial_port *port)
p_priv = usb_get_serial_port_data(port);
stop_urb(p_priv->inack_urb);
stop_urb(p_priv->outcont_urb);
usb_kill_urb(p_priv->inack_urb);
usb_kill_urb(p_priv->outcont_urb);
for (i = 0; i < 2; i++) {
stop_urb(p_priv->in_urbs[i]);
stop_urb(p_priv->out_urbs[i]);
usb_kill_urb(p_priv->in_urbs[i]);
usb_kill_urb(p_priv->out_urbs[i]);
}
usb_free_urb(p_priv->inack_urb);

View File

@ -1259,6 +1259,15 @@ static int mxuport_attach(struct usb_serial *serial)
return 0;
}
static void mxuport_release(struct usb_serial *serial)
{
struct usb_serial_port *port0 = serial->port[0];
struct usb_serial_port *port1 = serial->port[1];
usb_serial_generic_close(port1);
usb_serial_generic_close(port0);
}
static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct mxuport_port *mxport = usb_get_serial_port_data(port);
@ -1361,6 +1370,7 @@ static struct usb_serial_driver mxuport_device = {
.probe = mxuport_probe,
.port_probe = mxuport_port_probe,
.attach = mxuport_attach,
.release = mxuport_release,
.calc_num_ports = mxuport_calc_num_ports,
.open = mxuport_open,
.close = mxuport_close,

View File

@ -375,18 +375,22 @@ static void option_instat_callback(struct urb *urb);
#define HAIER_PRODUCT_CE81B 0x10f8
#define HAIER_PRODUCT_CE100 0x2009
/* Cinterion (formerly Siemens) products */
#define SIEMENS_VENDOR_ID 0x0681
#define CINTERION_VENDOR_ID 0x1e2d
/* Gemalto's Cinterion products (formerly Siemens) */
#define SIEMENS_VENDOR_ID 0x0681
#define CINTERION_VENDOR_ID 0x1e2d
#define CINTERION_PRODUCT_HC25_MDMNET 0x0040
#define CINTERION_PRODUCT_HC25_MDM 0x0047
#define CINTERION_PRODUCT_HC25_MDMNET 0x0040
#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */
#define CINTERION_PRODUCT_HC28_MDM 0x004C
#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */
#define CINTERION_PRODUCT_EU3_E 0x0051
#define CINTERION_PRODUCT_EU3_P 0x0052
#define CINTERION_PRODUCT_PH8 0x0053
#define CINTERION_PRODUCT_AHXX 0x0055
#define CINTERION_PRODUCT_PLXX 0x0060
#define CINTERION_PRODUCT_PH8_2RMNET 0x0082
#define CINTERION_PRODUCT_PH8_AUDIO 0x0083
#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084
#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085
/* Olivetti products */
#define OLIVETTI_VENDOR_ID 0x0b3c
@ -633,6 +637,10 @@ static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = {
.reserved = BIT(1) | BIT(2) | BIT(3),
};
static const struct option_blacklist_info cinterion_rmnet2_blacklist = {
.reserved = BIT(4) | BIT(5),
};
static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@ -1602,7 +1610,79 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff42, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff43, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff44, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff45, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff46, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff47, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff48, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff49, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4a, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4b, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4c, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4d, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4e, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4f, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff50, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff51, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff52, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff53, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff54, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff55, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff56, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff57, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff58, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff59, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5a, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5b, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5c, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5d, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5e, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5f, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff60, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff61, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff62, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff63, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff64, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff65, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff66, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff67, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff68, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff69, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6a, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6b, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6c, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6d, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6e, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6f, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff70, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff71, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff72, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff73, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff74, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff75, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff76, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff77, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff78, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff79, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7a, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7b, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7c, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7d, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7e, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7f, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff80, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff81, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff82, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff83, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff84, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff85, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff86, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff87, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff88, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff89, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8a, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8b, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8c, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8d, 0xff, 0xff, 0xff) },
@ -1613,6 +1693,61 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff92, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff9f, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa0, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa1, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa2, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa3, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa4, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa5, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa6, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa7, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa8, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa9, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffaa, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffab, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffac, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffae, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffaf, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb0, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb1, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb2, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb3, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb4, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb5, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb6, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb7, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb8, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb9, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffba, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbb, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbc, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbd, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbe, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbf, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc0, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc1, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc2, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc3, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc4, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc5, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc6, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc7, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc8, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc9, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffca, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcb, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcc, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcd, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffce, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcf, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd0, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd1, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd2, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd3, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd4, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd5, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffec, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffee, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xfff6, 0xff, 0xff, 0xff) },
@ -1712,7 +1847,13 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_2RMNET, 0xff),
.driver_info = (kernel_ulong_t)&cinterion_rmnet2_blacklist },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_AUDIO, 0xff),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },

View File

@ -141,6 +141,7 @@ static void qt2_release(struct usb_serial *serial)
serial_priv = usb_get_serial_data(serial);
usb_kill_urb(serial_priv->read_urb);
usb_free_urb(serial_priv->read_urb);
kfree(serial_priv->read_buffer);
kfree(serial_priv);

View File

@ -80,6 +80,7 @@ struct ti_device {
int td_open_port_count;
struct usb_serial *td_serial;
int td_is_3410;
bool td_rs485_only;
int td_urb_error;
};
@ -160,6 +161,11 @@ static const struct usb_device_id ti_id_table_3410[] = {
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
{ } /* terminator */
};
@ -193,6 +199,11 @@ static const struct usb_device_id ti_id_table_combined[] = {
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
{ } /* terminator */
};
@ -277,6 +288,11 @@ MODULE_FIRMWARE("mts_gsm.fw");
MODULE_FIRMWARE("mts_edge.fw");
MODULE_FIRMWARE("mts_mt9234mu.fw");
MODULE_FIRMWARE("mts_mt9234zba.fw");
MODULE_FIRMWARE("moxa/moxa-1110.fw");
MODULE_FIRMWARE("moxa/moxa-1130.fw");
MODULE_FIRMWARE("moxa/moxa-1131.fw");
MODULE_FIRMWARE("moxa/moxa-1150.fw");
MODULE_FIRMWARE("moxa/moxa-1151.fw");
module_param(closing_wait, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(closing_wait,
@ -292,6 +308,9 @@ static int ti_startup(struct usb_serial *serial)
{
struct ti_device *tdev;
struct usb_device *dev = serial->dev;
struct usb_host_interface *cur_altsetting;
int num_endpoints;
u16 vid, pid;
int status;
dev_dbg(&dev->dev,
@ -315,8 +334,22 @@ static int ti_startup(struct usb_serial *serial)
dev_dbg(&dev->dev, "%s - device type is %s\n", __func__,
tdev->td_is_3410 ? "3410" : "5052");
/* if we have only 1 configuration, download firmware */
if (dev->descriptor.bNumConfigurations == 1) {
vid = le16_to_cpu(dev->descriptor.idVendor);
pid = le16_to_cpu(dev->descriptor.idProduct);
if (vid == MXU1_VENDOR_ID) {
switch (pid) {
case MXU1_1130_PRODUCT_ID:
case MXU1_1131_PRODUCT_ID:
tdev->td_rs485_only = true;
break;
}
}
cur_altsetting = serial->interface->cur_altsetting;
num_endpoints = cur_altsetting->desc.bNumEndpoints;
/* if we have only 1 configuration and 1 endpoint, download firmware */
if (dev->descriptor.bNumConfigurations == 1 && num_endpoints == 1) {
status = ti_download_firmware(tdev);
if (status != 0)
@ -371,7 +404,11 @@ static int ti_port_probe(struct usb_serial_port *port)
port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
tport->tp_port = port;
tport->tp_tdev = usb_get_serial_data(port->serial);
tport->tp_uart_mode = 0; /* default is RS232 */
if (tport->tp_tdev->td_rs485_only)
tport->tp_uart_mode = TI_UART_485_RECEIVER_DISABLED;
else
tport->tp_uart_mode = TI_UART_232;
usb_set_serial_port_data(port, tport);
@ -1450,6 +1487,16 @@ static int ti_download_firmware(struct ti_device *tdev)
const struct firmware *fw_p;
char buf[32];
if (le16_to_cpu(dev->descriptor.idVendor) == MXU1_VENDOR_ID) {
snprintf(buf,
sizeof(buf),
"moxa/moxa-%04x.fw",
le16_to_cpu(dev->descriptor.idProduct));
status = request_firmware(&fw_p, buf, &dev->dev);
goto check_firmware;
}
/* try ID specific firmware first, then try generic firmware */
sprintf(buf, "ti_usb-v%04x-p%04x.fw",
le16_to_cpu(dev->descriptor.idVendor),
@ -1487,6 +1534,8 @@ static int ti_download_firmware(struct ti_device *tdev)
}
status = request_firmware(&fw_p, buf, &dev->dev);
}
check_firmware:
if (status) {
dev_err(&dev->dev, "%s - firmware not found\n", __func__);
return -ENOENT;

Some files were not shown because too many files have changed in this diff Show More