diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-06 16:48:27 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-06 16:48:27 -0800 |
commit | f90d64483ebd394958841f67f8794ab203b319a7 (patch) | |
tree | 3da8638603681adfe9bea7897c03ea27b40ef4f4 /drivers | |
parent | 67e79a6dc2664a3ef85113440e60f7aaca3c7815 (diff) | |
parent | 1c7cf3d5e1c181caca75012b65252288c18a25f2 (diff) |
Merge tag 'usb-5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY updates from Greg KH:
"Here is the big USB/PHY driver pull request for 5.1-rc1.
The usual set of gadget driver updates, phy driver updates, xhci
updates, and typec additions. Also included in here are a lot of small
cleanups and fixes and driver updates where needed.
All of these have been in linux-next for a while with no reported
issues"
* tag 'usb-5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (167 commits)
wusb: Remove unnecessary static function ckhdid_printf
usb: core: make default autosuspend delay configurable
usb: core: Fix typo in description of "authorized_default"
usb: chipidea: Refactor USB PHY selection and keep a single PHY
usb: chipidea: Grab the (legacy) USB PHY by phandle first
usb: chipidea: imx: set power polarity
dt-bindings: usb: ci-hdrc-usb2: add property power-active-high
usb: chipidea: imx: remove unused header files
usb: chipidea: tegra: Fix missed ci_hdrc_remove_device()
usb: core: add option of only authorizing internal devices
usb: typec: tps6598x: handle block writes separately with plain-I2C adapters
usb: xhci: Fix for Enabling USB ROLE SWITCH QUIRK on INTEL_SUNRISEPOINT_LP_XHCI
usb: xhci: fix build warning - missing prototype
usb: xhci: dbc: Fixing typo error.
usb: xhci: remove unused member 'parent' in xhci_regset struct
xhci: tegra: Prevent error pointer dereference
USB: serial: option: add Telit ME910 ECM composition
usb: core: Replace hardcoded check with inline function from usb.h
usb: core: skip interfaces disabled in devicetree
usb: typec: mux: remove redundant check on variable match
...
Diffstat (limited to 'drivers')
173 files changed, 2743 insertions, 1036 deletions
diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c index d427e806cd73..04db9ae235e4 100644 --- a/drivers/base/devcon.c +++ b/drivers/base/devcon.c @@ -7,10 +7,37 @@ */ #include <linux/device.h> +#include <linux/property.h> static DEFINE_MUTEX(devcon_lock); static LIST_HEAD(devcon_list); +typedef void *(*devcon_match_fn_t)(struct device_connection *con, int ep, + void *data); + +static void * +fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id, + void *data, devcon_match_fn_t match) +{ + struct device_connection con = { .id = con_id }; + struct fwnode_handle *ep; + void *ret; + + fwnode_graph_for_each_endpoint(fwnode, ep) { + con.fwnode = fwnode_graph_get_remote_port_parent(ep); + if (!fwnode_device_is_available(con.fwnode)) + continue; + + ret = match(&con, -1, data); + fwnode_handle_put(con.fwnode); + if (ret) { + fwnode_handle_put(ep); + return ret; + } + } + return NULL; +} + /** * device_connection_find_match - Find physical connection to a device * @dev: Device with the connection @@ -23,10 +50,9 @@ static LIST_HEAD(devcon_list); * caller is expecting to be returned. */ void *device_connection_find_match(struct device *dev, const char *con_id, - void *data, - void *(*match)(struct device_connection *con, - int ep, void *data)) + void *data, devcon_match_fn_t match) { + struct fwnode_handle *fwnode = dev_fwnode(dev); const char *devname = dev_name(dev); struct device_connection *con; void *ret = NULL; @@ -35,6 +61,12 @@ void *device_connection_find_match(struct device *dev, const char *con_id, if (!match) return NULL; + if (fwnode) { + ret = fwnode_graph_devcon_match(fwnode, con_id, data, match); + if (ret) + return ret; + } + mutex_lock(&devcon_lock); list_for_each_entry(con, &devcon_list, list) { @@ -75,12 +107,36 @@ static struct bus_type *generic_match_buses[] = { NULL, }; +static int device_fwnode_match(struct device *dev, void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} + +static void *device_connection_fwnode_match(struct device_connection *con) +{ + struct bus_type *bus; + struct device *dev; + + for (bus = generic_match_buses[0]; bus; bus++) { + dev = bus_find_device(bus, NULL, (void *)con->fwnode, + device_fwnode_match); + if (dev && !strncmp(dev_name(dev), con->id, strlen(con->id))) + return dev; + + put_device(dev); + } + return NULL; +} + /* This tries to find the device from the most common bus types by name. */ static void *generic_match(struct device_connection *con, int ep, void *data) { struct bus_type *bus; struct device *dev; + if (con->fwnode) + return device_connection_fwnode_match(con); + for (bus = generic_match_buses[0]; bus; bus++) { dev = bus_find_device_by_name(bus, NULL, con->endpoint[ep]); if (dev) diff --git a/drivers/phy/broadcom/phy-bcm-sr-pcie.c b/drivers/phy/broadcom/phy-bcm-sr-pcie.c index c10e95f86de5..96a3af126a78 100644 --- a/drivers/phy/broadcom/phy-bcm-sr-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-sr-pcie.c @@ -78,8 +78,8 @@ struct sr_pcie_phy_core { static const u8 pipemux_table[] = { /* PIPEMUX = 0, EP 1x16 */ 0x00, - /* PIPEMUX = 1, EP 2x8 */ - 0x00, + /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ + 0x80, /* PIPEMUX = 2, EP 4x4 */ 0x00, /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ diff --git a/drivers/phy/cadence/Kconfig b/drivers/phy/cadence/Kconfig index 2b8c0851ff33..31f18b67dd7c 100644 --- a/drivers/phy/cadence/Kconfig +++ b/drivers/phy/cadence/Kconfig @@ -1,6 +1,7 @@ # # Phy drivers for Cadence PHYs # + config PHY_CADENCE_DP tristate "Cadence MHDP DisplayPort PHY driver" depends on OF @@ -9,9 +10,19 @@ config PHY_CADENCE_DP help Support for Cadence MHDP DisplayPort PHY. +config PHY_CADENCE_DPHY + tristate "Cadence D-PHY Support" + depends on HAS_IOMEM && OF + select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + help + Choose this option if you have a Cadence D-PHY in your + system. If M is selected, the module will be called + cdns-dphy. + config PHY_CADENCE_SIERRA tristate "Cadence Sierra PHY Driver" depends on OF && HAS_IOMEM && RESET_CONTROLLER select GENERIC_PHY help - Enable this to support the Cadence Sierra PHY driver
\ No newline at end of file + Enable this to support the Cadence Sierra PHY driver diff --git a/drivers/phy/cadence/Makefile b/drivers/phy/cadence/Makefile index 412349af0492..2f9e3457b954 100644 --- a/drivers/phy/cadence/Makefile +++ b/drivers/phy/cadence/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_PHY_CADENCE_DP) += phy-cadence-dp.o +obj-$(CONFIG_PHY_CADENCE_DPHY) += cdns-dphy.o obj-$(CONFIG_PHY_CADENCE_SIERRA) += phy-cadence-sierra.o diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c new file mode 100644 index 000000000000..90c4e9b5aac8 --- /dev/null +++ b/drivers/phy/cadence/cdns-dphy.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright: 2017-2018 Cadence Design Systems, Inc. + */ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include <linux/phy/phy.h> +#include <linux/phy/phy-mipi-dphy.h> + +#define REG_WAKEUP_TIME_NS 800 +#define DPHY_PLL_RATE_HZ 108000000 + +/* DPHY registers */ +#define DPHY_PMA_CMN(reg) (reg) +#define DPHY_PMA_LCLK(reg) (0x100 + (reg)) +#define DPHY_PMA_LDATA(lane, reg) (0x200 + ((lane) * 0x100) + (reg)) +#define DPHY_PMA_RCLK(reg) (0x600 + (reg)) +#define DPHY_PMA_RDATA(lane, reg) (0x700 + ((lane) * 0x100) + (reg)) +#define DPHY_PCS(reg) (0xb00 + (reg)) + +#define DPHY_CMN_SSM DPHY_PMA_CMN(0x20) +#define DPHY_CMN_SSM_EN BIT(0) +#define DPHY_CMN_TX_MODE_EN BIT(9) + +#define DPHY_CMN_PWM DPHY_PMA_CMN(0x40) +#define DPHY_CMN_PWM_DIV(x) ((x) << 20) +#define DPHY_CMN_PWM_LOW(x) ((x) << 10) +#define DPHY_CMN_PWM_HIGH(x) (x) + +#define DPHY_CMN_FBDIV DPHY_PMA_CMN(0x4c) +#define DPHY_CMN_FBDIV_VAL(low, high) (((high) << 11) | ((low) << 22)) +#define DPHY_CMN_FBDIV_FROM_REG (BIT(10) | BIT(21)) + +#define DPHY_CMN_OPIPDIV DPHY_PMA_CMN(0x50) +#define DPHY_CMN_IPDIV_FROM_REG BIT(0) +#define DPHY_CMN_IPDIV(x) ((x) << 1) +#define DPHY_CMN_OPDIV_FROM_REG BIT(6) +#define DPHY_CMN_OPDIV(x) ((x) << 7) + +#define DPHY_PSM_CFG DPHY_PCS(0x4) +#define DPHY_PSM_CFG_FROM_REG BIT(0) +#define DPHY_PSM_CLK_DIV(x) ((x) << 1) + +#define DSI_HBP_FRAME_OVERHEAD 12 +#define DSI_HSA_FRAME_OVERHEAD 14 +#define DSI_HFP_FRAME_OVERHEAD 6 +#define DSI_HSS_VSS_VSE_FRAME_OVERHEAD 4 +#define DSI_BLANKING_FRAME_OVERHEAD 6 +#define DSI_NULL_FRAME_OVERHEAD 6 +#define DSI_EOT_PKT_SIZE 4 + +struct cdns_dphy_cfg { + u8 pll_ipdiv; + u8 pll_opdiv; + u16 pll_fbdiv; + unsigned int nlanes; +}; + +enum cdns_dphy_clk_lane_cfg { + DPHY_CLK_CFG_LEFT_DRIVES_ALL = 0, + DPHY_CLK_CFG_LEFT_DRIVES_RIGHT = 1, + DPHY_CLK_CFG_LEFT_DRIVES_LEFT = 2, + DPHY_CLK_CFG_RIGHT_DRIVES_ALL = 3, +}; + +struct cdns_dphy; +struct cdns_dphy_ops { + int (*probe)(struct cdns_dphy *dphy); + void (*remove)(struct cdns_dphy *dphy); + void (*set_psm_div)(struct cdns_dphy *dphy, u8 div); + void (*set_clk_lane_cfg)(struct cdns_dphy *dphy, + enum cdns_dphy_clk_lane_cfg cfg); + void (*set_pll_cfg)(struct cdns_dphy *dphy, + const struct cdns_dphy_cfg *cfg); + unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy); +}; + +struct cdns_dphy { + struct cdns_dphy_cfg cfg; + void __iomem *regs; + struct clk *psm_clk; + struct clk *pll_ref_clk; + const struct cdns_dphy_ops *ops; + struct phy *phy; +}; + +static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy, + struct cdns_dphy_cfg *cfg, + struct phy_configure_opts_mipi_dphy *opts, + unsigned int *dsi_hfp_ext) +{ + unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk); + u64 dlane_bps; + + memset(cfg, 0, sizeof(*cfg)); + + if (pll_ref_hz < 9600000 || pll_ref_hz >= 150000000) + return -EINVAL; + else if (pll_ref_hz < 19200000) + cfg->pll_ipdiv = 1; + else if (pll_ref_hz < 38400000) + cfg->pll_ipdiv = 2; + else if (pll_ref_hz < 76800000) + cfg->pll_ipdiv = 4; + else + cfg->pll_ipdiv = 8; + + dlane_bps = opts->hs_clk_rate; + + if (dlane_bps > 2500000000UL || dlane_bps < 160000000UL) + return -EINVAL; + else if (dlane_bps >= 1250000000) + cfg->pll_opdiv = 1; + else if (dlane_bps >= 630000000) + cfg->pll_opdiv = 2; + else if (dlane_bps >= 320000000) + cfg->pll_opdiv = 4; + else if (dlane_bps >= 160000000) + cfg->pll_opdiv = 8; + + cfg->pll_fbdiv = DIV_ROUND_UP_ULL(dlane_bps * 2 * cfg->pll_opdiv * + cfg->pll_ipdiv, + pll_ref_hz); + + return 0; +} + +static int cdns_dphy_setup_psm(struct cdns_dphy *dphy) +{ + unsigned long psm_clk_hz = clk_get_rate(dphy->psm_clk); + unsigned long psm_div; + + if (!psm_clk_hz || psm_clk_hz > 100000000) + return -EINVAL; + + psm_div = DIV_ROUND_CLOSEST(psm_clk_hz, 1000000); + if (dphy->ops->set_psm_div) + dphy->ops->set_psm_div(dphy, psm_div); + + return 0; +} + +static void cdns_dphy_set_clk_lane_cfg(struct cdns_dphy *dphy, + enum cdns_dphy_clk_lane_cfg cfg) +{ + if (dphy->ops->set_clk_lane_cfg) + dphy->ops->set_clk_lane_cfg(dphy, cfg); +} + +static void cdns_dphy_set_pll_cfg(struct cdns_dphy *dphy, + const struct cdns_dphy_cfg *cfg) +{ + if (dphy->ops->set_pll_cfg) + dphy->ops->set_pll_cfg(dphy, cfg); +} + +static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy) +{ + return dphy->ops->get_wakeup_time_ns(dphy); +} + +static unsigned long cdns_dphy_ref_get_wakeup_time_ns(struct cdns_dphy *dphy) +{ + /* Default wakeup time is 800 ns (in a simulated environment). */ + return 800; +} + +static void cdns_dphy_ref_set_pll_cfg(struct cdns_dphy *dphy, + const struct cdns_dphy_cfg *cfg) +{ + u32 fbdiv_low, fbdiv_high; + + fbdiv_low = (cfg->pll_fbdiv / 4) - 2; + fbdiv_high = cfg->pll_fbdiv - fbdiv_low - 2; + + writel(DPHY_CMN_IPDIV_FROM_REG | DPHY_CMN_OPDIV_FROM_REG | + DPHY_CMN_IPDIV(cfg->pll_ipdiv) | + DPHY_CMN_OPDIV(cfg->pll_opdiv), + dphy->regs + DPHY_CMN_OPIPDIV); + writel(DPHY_CMN_FBDIV_FROM_REG | + DPHY_CMN_FBDIV_VAL(fbdiv_low, fbdiv_high), + dphy->regs + DPHY_CMN_FBDIV); + writel(DPHY_CMN_PWM_HIGH(6) | DPHY_CMN_PWM_LOW(0x101) | + DPHY_CMN_PWM_DIV(0x8), + dphy->regs + DPHY_CMN_PWM); +} + +static void cdns_dphy_ref_set_psm_div(struct cdns_dphy *dphy, u8 div) +{ + writel(DPHY_PSM_CFG_FROM_REG | DPHY_PSM_CLK_DIV(div), + dphy->regs + DPHY_PSM_CFG); +} + +/* + * This is the reference implementation of DPHY hooks. Specific integration of + * this IP may have to re-implement some of them depending on how they decided + * to wire things in the SoC. + */ +static const struct cdns_dphy_ops ref_dphy_ops = { + .get_wakeup_time_ns = cdns_dphy_ref_get_wakeup_time_ns, + .set_pll_cfg = cdns_dphy_ref_set_pll_cfg, + .set_psm_div = cdns_dphy_ref_set_psm_div, +}; + +static int cdns_dphy_config_from_opts(struct phy *phy, + struct phy_configure_opts_mipi_dphy *opts, + struct cdns_dphy_cfg *cfg) +{ + struct cdns_dphy *dphy = phy_get_drvdata(phy); + unsigned int dsi_hfp_ext = 0; + int ret; + + ret = phy_mipi_dphy_config_validate(opts); + if (ret) + return ret; + + ret = cdns_dsi_get_dphy_pll_cfg(dphy, cfg, + opts, &dsi_hfp_ext); + if (ret) + return ret; + + opts->wakeup = cdns_dphy_get_wakeup_time_ns(dphy) / 1000; + + return 0; +} + +static int cdns_dphy_validate(struct phy *phy, enum phy_mode mode, int submode, + union phy_configure_opts *opts) +{ + struct cdns_dphy_cfg cfg = { 0 }; + + if (mode != PHY_MODE_MIPI_DPHY) + return -EINVAL; + + return cdns_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg); +} + +static int cdns_dphy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + struct cdns_dphy *dphy = phy_get_drvdata(phy); + struct cdns_dphy_cfg cfg = { 0 }; + int ret; + + ret = cdns_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg); + if (ret) + return ret; + + /* + * Configure the internal PSM clk divider so that the DPHY has a + * 1MHz clk (or something close). + */ + ret = cdns_dphy_setup_psm(dphy); + if (ret) + return ret; + + /* + * Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes + * and 8 data lanes, each clk lane can be attache different set of + * data lanes. The 2 groups are named 'left' and 'right', so here we + * just say that we want the 'left' clk lane to drive the 'left' data + * lanes. + */ + cdns_dphy_set_clk_lane_cfg(dphy, DPHY_CLK_CFG_LEFT_DRIVES_LEFT); + + /* + * Configure the DPHY PLL that will be used to generate the TX byte + * clk. + */ + cdns_dphy_set_pll_cfg(dphy, &cfg); + + return 0; +} + +static int cdns_dphy_power_on(struct phy *phy) +{ + struct cdns_dphy *dphy = phy_get_drvdata(phy); + + clk_prepare_enable(dphy->psm_clk); + clk_prepare_enable(dphy->pll_ref_clk); + + /* Start TX state machine. */ + writel(DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN, + dphy->regs + DPHY_CMN_SSM); + + return 0; +} + +static int cdns_dphy_power_off(struct phy *phy) +{ + struct cdns_dphy *dphy = phy_get_drvdata(phy); + + clk_disable_unprepare(dphy->pll_ref_clk); + clk_disable_unprepare(dphy->psm_clk); + + return 0; +} + +static const struct phy_ops cdns_dphy_ops = { + .configure = cdns_dphy_configure, + .validate = cdns_dphy_validate, + .power_on = cdns_dphy_power_on, + .power_off = cdns_dphy_power_off, +}; + +static int cdns_dphy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct cdns_dphy *dphy; + struct resource *res; + int ret; + + dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); + if (!dphy) + return -ENOMEM; + dev_set_drvdata(&pdev->dev, dphy); + + dphy->ops = of_device_get_match_data(&pdev->dev); + if (!dphy->ops) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dphy->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dphy->regs)) + return PTR_ERR(dphy->regs); + + dphy->psm_clk = devm_clk_get(&pdev->dev, "psm"); + if (IS_ERR(dphy->psm_clk)) + return PTR_ERR(dphy->psm_clk); + + dphy->pll_ref_clk = devm_clk_get(&pdev->dev, "pll_ref"); + if (IS_ERR(dphy->pll_ref_clk)) + return PTR_ERR(dphy->pll_ref_clk); + + if (dphy->ops->probe) { + ret = dphy->ops->probe(dphy); + if (ret) + return ret; + } + + dphy->phy = devm_phy_create(&pdev->dev, NULL, &cdns_dphy_ops); + if (IS_ERR(dphy->phy)) { + dev_err(&pdev->dev, "failed to create PHY\n"); + if (dphy->ops->remove) + dphy->ops->remove(dphy); + return PTR_ERR(dphy->phy); + } + + phy_set_drvdata(dphy->phy, dphy); + phy_provider = devm_of_phy_provider_register(&pdev->dev, + of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static int cdns_dphy_remove(struct platform_device *pdev) +{ + struct cdns_dphy *dphy = dev_get_drvdata(&pdev->dev); + + if (dphy->ops->remove) + dphy->ops->remove(dphy); + + return 0; +} + +static const struct of_device_id cdns_dphy_of_match[] = { + { .compatible = "cdns,dphy", .data = &ref_dphy_ops }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, cdns_dphy_of_match); + +static struct platform_driver cdns_dphy_platform_driver = { + .probe = cdns_dphy_probe, + .remove = cdns_dphy_remove, + .driver = { + .name = "cdns-mipi-dphy", + .of_match_table = cdns_dphy_of_match, + }, +}; +module_platform_driver(cdns_dphy_platform_driver); + +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>"); +MODULE_DESCRIPTION("Cadence MIPI D-PHY Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index f050bd4e97e0..832670b4952b 100644 --- a/drivers/phy/freescale/Kconfig +++ b/drivers/phy/freescale/Kconfig @@ -2,4 +2,4 @@ config PHY_FSL_IMX8MQ_USB tristate "Freescale i.MX8M USB3 PHY" depends on OF && HAS_IOMEM select GENERIC_PHY - default SOC_IMX8MQ + default ARCH_MXC && ARM64 diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig index 224ea4e6a46d..9ba872325dad 100644 --- a/drivers/phy/marvell/Kconfig +++ b/drivers/phy/marvell/Kconfig @@ -21,6 +21,27 @@ config PHY_BERLIN_USB help Enable this to support the USB PHY on Marvell Berlin SoCs. +config PHY_MVEBU_A3700_COMPHY + tristate "Marvell A3700 comphy driver" + depends on ARCH_MVEBU || COMPILE_TEST + depends on OF + depends on HAVE_ARM_SMCCC + default y + select GENERIC_PHY + help + This driver allows to control the comphy, a hardware block providing + shared serdes PHYs on Marvell Armada 3700. Its serdes lanes can be + used by various controllers: Ethernet, SATA, USB3, PCIe. + +config PHY_MVEBU_A3700_UTMI + tristate "Marvell A3700 UTMI driver" + depends on ARCH_MVEBU || COMPILE_TEST + depends on OF + default y + select GENERIC_PHY + help + Enable this to support Marvell A3700 UTMI PHY driver. + config PHY_MVEBU_A38X_COMPHY tristate "Marvell Armada 38x comphy driver" depends on ARCH_MVEBU || COMPILE_TEST diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile index 59b6c03ef756..434eb9ca6cc3 100644 --- a/drivers/phy/marvell/Makefile +++ b/drivers/phy/marvell/Makefile @@ -2,6 +2,8 @@ obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o +obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY) += phy-mvebu-a3700-comphy.o +obj-$(CONFIG_PHY_MVEBU_A3700_UTMI) += phy-mvebu-a3700-utmi.o obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY) += phy-armada38x-comphy.o obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o diff --git a/drivers/phy/marvell/phy-armada375-usb2.c b/drivers/phy/marvell/phy-armada375-usb2.c index 1a3db288c0a9..fa5dc9462d09 100644 --- a/drivers/phy/marvell/phy-armada375-usb2.c +++ b/drivers/phy/marvell/phy-armada375-usb2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * USB cluster support for Armada 375 platform. * @@ -5,10 +6,6 @@ * * Gregory CLEMENT <gregory.clement@free-electrons.com> * - * This file is licensed under the terms of the GNU General Public - * License version 2 or later. This program is licensed "as is" - * without any warranty of any kind, whether express or implied. - * * Armada 375 comes with an USB2 host and device controller and an * USB3 controller. The USB cluster control register allows to manage * common features of both USB controllers. @@ -18,7 +15,6 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/kernel.h> -#include <linux/module.h> #include <linux/of_address.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> @@ -142,7 +138,6 @@ static const struct of_device_id of_usb_cluster_table[] = { { .compatible = "marvell,armada-375-usb-cluster", }, { /* end of list */ }, }; -MODULE_DEVICE_TABLE(of, of_usb_cluster_table); static struct platform_driver armada375_usb_phy_driver = { .probe = armada375_usb_phy_probe, @@ -151,8 +146,4 @@ static struct platform_driver armada375_usb_phy_driver = { .name = "armada-375-usb-cluster", } }; -module_platform_driver(armada375_usb_phy_driver); - -MODULE_DESCRIPTION("Armada 375 USB cluster driver"); -MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(armada375_usb_phy_driver); diff --git a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c new file mode 100644 index 000000000000..8812a104c233 --- /dev/null +++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Marvell + * + * Authors: + * Evan Wang <xswang@marvell.com> + * Miquèl Raynal <miquel.raynal@bootlin.com> + * + * Structure inspired from phy-mvebu-cp110-comphy.c written by Antoine Tenart. + * SMC call initial support done by Grzegorz Jaszczyk. + */ + +#include <linux/arm-smccc.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/phy.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> + +#define MVEBU_A3700_COMPHY_LANES 3 +#define MVEBU_A3700_COMPHY_PORTS 2 + +/* COMPHY Fast SMC function identifiers */ +#define COMPHY_SIP_POWER_ON 0x82000001 +#define COMPHY_SIP_POWER_OFF 0x82000002 +#define COMPHY_SIP_PLL_LOCK 0x82000003 + +#define COMPHY_FW_MODE_SATA 0x1 +#define COMPHY_FW_MODE_SGMII 0x2 +#define COMPHY_FW_MODE_HS_SGMII 0x3 +#define COMPHY_FW_MODE_USB3H 0x4 +#define COMPHY_FW_MODE_USB3D 0x5 +#define COMPHY_FW_MODE_PCIE 0x6 +#define COMPHY_FW_MODE_RXAUI 0x7 +#define COMPHY_FW_MODE_XFI 0x8 +#define COMPHY_FW_MODE_SFI 0x9 +#define COMPHY_FW_MODE_USB3 0xa + +#define COMPHY_FW_SPEED_1_25G 0 /* SGMII 1G */ +#define COMPHY_FW_SPEED_2_5G 1 +#define COMPHY_FW_SPEED_3_125G 2 /* SGMII 2.5G */ +#define COMPHY_FW_SPEED_5G 3 +#define COMPHY_FW_SPEED_5_15625G 4 /* XFI 5G */ +#define COMPHY_FW_SPEED_6G 5 +#define COMPHY_FW_SPEED_10_3125G 6 /* XFI 10G */ +#define COMPHY_FW_SPEED_MAX 0x3F + +#define COMPHY_FW_MODE(mode) ((mode) << 12) +#define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \ + ((idx) << 8) | \ + ((speed) << 2)) +#define COMPHY_FW_PCIE(mode, idx, speed, width) (COMPHY_FW_NET(mode, idx, speed) | \ + ((width) << 18)) + +struct mvebu_a3700_comphy_conf { + unsigned int lane; + enum phy_mode mode; + int submode; + unsigned int port; + u32 fw_mode; +}; + +#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw) \ + { \ + .lane = _lane, \ + .mode = _mode, \ + .submode = _smode, \ + .port = _port, \ + .fw_mode = _fw, \ + } + +#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \ + MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _port, _fw) + +#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \ + MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw) + +static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = { + /* lane 0 */ + MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0, + COMPHY_FW_MODE_USB3H), + MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1, + COMPHY_FW_MODE_SGMII), + MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, 1, + COMPHY_FW_MODE_HS_SGMII), + /* lane 1 */ + MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0, + COMPHY_FW_MODE_PCIE), + MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0, + COMPHY_FW_MODE_SGMII), + MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, 0, + COMPHY_FW_MODE_HS_SGMII), + /* lane 2 */ + MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0, + COMPHY_FW_MODE_SATA), + MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0, + COMPHY_FW_MODE_USB3H), +}; + +struct mvebu_a3700_comphy_lane { + struct device *dev; + unsigned int id; + enum phy_mode mode; + int submode; + int port; +}; + +static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane, + unsigned long mode) +{ + struct arm_smccc_res res; + + arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res); + + return res.a0; +} + +static int mvebu_a3700_comphy_get_fw_mode(int lane, int port, + enum phy_mode mode, + int submode) +{ + int i, n = ARRAY_SIZE(mvebu_a3700_comphy_modes); + + /* Unused PHY mux value is 0x0 */ + if (mode == PHY_MODE_INVALID) + return -EINVAL; + + for (i = 0; i < n; i++) { + if (mvebu_a3700_comphy_modes[i].lane == lane && + mvebu_a3700_comphy_modes[i].port == port && + mvebu_a3700_comphy_modes[i].mode == mode && + mvebu_a3700_comphy_modes[i].submode == submode) + break; + } + + if (i == n) + return -EINVAL; + + return mvebu_a3700_comphy_modes[i].fw_mode; +} + +static int mvebu_a3700_comphy_set_mode(struct phy *phy, enum phy_mode mode, + int submode) +{ + struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); + int fw_mode; + + if (submode == PHY_INTERFACE_MODE_1000BASEX) + submode = PHY_INTERFACE_MODE_SGMII; + + fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode, + submode); + if (fw_mode < 0) { + dev_err(lane->dev, "invalid COMPHY mode\n"); + return fw_mode; + } + + /* Just remember the mode, ->power_on() will do the real setup */ + lane->mode = mode; + lane->submode = submode; + + return 0; +} + +static int mvebu_a3700_comphy_power_on(struct phy *phy) +{ + struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); + u32 fw_param; + int fw_mode; + + fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, + lane->mode, lane->submode); + if (fw_mode < 0) { + dev_err(lane->dev, "invalid COMPHY mode\n"); + return fw_mode; + } + + switch (lane->mode) { + case PHY_MODE_USB_HOST_SS: + dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id); + fw_param = COMPHY_FW_MODE(fw_mode); + break; + case PHY_MODE_SATA: + dev_dbg(lane->dev, "set lane %d to SATA mode\n", lane->id); + fw_param = COMPHY_FW_MODE(fw_mode); + break; + case PHY_MODE_ETHERNET: + switch (lane->submode) { + case PHY_INTERFACE_MODE_SGMII: + dev_dbg(lane->dev, "set lane %d to SGMII mode\n", + lane->id); + fw_param = COMPHY_FW_NET(fw_mode, lane->port, + COMPHY_FW_SPEED_1_25G); + break; + case PHY_INTERFACE_MODE_2500BASEX: + dev_dbg(lane->dev, "set lane %d to HS SGMII mode\n", + lane->id); + fw_param = COMPHY_FW_NET(fw_mode, lane->port, + COMPHY_FW_SPEED_3_125G); + break; + default: + dev_err(lane->dev, "unsupported PHY submode (%d)\n", + lane->submode); + return -ENOTSUPP; + } + break; + case PHY_MODE_PCIE: + dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id); + fw_param = COMPHY_FW_PCIE(fw_mode, lane->port, + COMPHY_FW_SPEED_5G, + phy->attrs.bus_width); + break; + default: + dev_err(lane->dev, "unsupported PHY mode (%d)\n", lane->mode); + return -ENOTSUPP; + } + + return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param); +} + +static int mvebu_a3700_comphy_power_off(struct phy *phy) +{ + struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); + + return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_OFF, lane->id, 0); +} + +static const struct phy_ops mvebu_a3700_comphy_ops = { + .power_on = mvebu_a3700_comphy_power_on, + .power_off = mvebu_a3700_comphy_power_off, + .set_mode = mvebu_a3700_comphy_set_mode, + .owner = THIS_MODULE, +}; + +static struct phy *mvebu_a3700_comphy_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct mvebu_a3700_comphy_lane *lane; + struct phy *phy; + + if (WARN_ON(args->args[0] >= MVEBU_A3700_COMPHY_PORTS)) + return ERR_PTR(-EINVAL); + + phy = of_phy_simple_xlate(dev, args); + if (IS_ERR(phy)) + return phy; + + lane = phy_get_drvdata(phy); + lane->port = args->args[0]; + + return phy; +} + +static int mvebu_a3700_comphy_probe(struct platform_device *pdev) +{ + struct phy_provider *provider; + struct device_node *child; + + for_each_available_child_of_node(pdev->dev.of_node, child) { + struct mvebu_a3700_comphy_lane *lane; + struct phy *phy; + int ret; + u32 lane_id; + + ret = of_property_read_u32(child, "reg", &lane_id); + if (ret < 0) { + dev_err(&pdev->dev, "missing 'reg' property (%d)\n", + ret); + continue; + } + + if (lane_id >= MVEBU_A3700_COMPHY_LANES) { + dev_err(&pdev->dev, "invalid 'reg' property\n"); + continue; + } + + lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL); + if (!lane) + return -ENOMEM; + + phy = devm_phy_create(&pdev->dev, child, + &mvebu_a3700_comphy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + lane->dev = &pdev->dev; + lane->mode = PHY_MODE_INVALID; + lane->submode = PHY_INTERFACE_MODE_NA; + lane->id = lane_id; + lane->port = -1; + phy_set_drvdata(phy, lane); + } + + provider = devm_of_phy_provider_register(&pdev->dev, + mvebu_a3700_comphy_xlate); + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id mvebu_a3700_comphy_of_match_table[] = { + { .compatible = "marvell,comphy-a3700" }, + { }, +}; +MODULE_DEVICE_TABLE(of, mvebu_a3700_comphy_of_match_table); + +static struct platform_driver mvebu_a3700_comphy_driver = { + .probe = mvebu_a3700_comphy_probe, + .driver = { + .name = "mvebu-a3700-comphy", + .of_match_table = mvebu_a3700_comphy_of_match_table, + }, +}; +module_platform_driver(mvebu_a3700_comphy_driver); + +MODULE_AUTHOR("Miquèl Raynal <miquel.raynal@bootlin.com>"); +MODULE_DESCRIPTION("Common PHY driver for A3700"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/marvell/phy-mvebu-a3700-utmi.c b/drivers/phy/marvell/phy-mvebu-a3700-utmi.c new file mode 100644 index 000000000000..94a29dea57af --- /dev/null +++ b/drivers/phy/marvell/phy-mvebu-a3700-utmi.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Marvell + * + * Authors: + * Igal Liberman <igall@marvell.com> + * Miquèl Raynal <miquel.raynal@bootlin.com> + * + * Marvell A3700 UTMI PHY driver + */ + +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +/* Armada 3700 UTMI PHY registers */ +#define USB2_PHY_PLL_CTRL_REG0 0x0 +#define PLL_REF_DIV_OFF 0 +#define PLL_REF_DIV_MASK GENMASK(6, 0) +#define PLL_REF_DIV_5 5 +#define PLL_FB_DIV_OFF 16 +#define PLL_FB_DIV_MASK GENMASK(24, 16) +#define PLL_FB_DIV_96 96 +#define PLL_SEL_LPFR_OFF 28 +#define PLL_SEL_LPFR_MASK GENMASK(29, 28) +#define PLL_READY BIT(31) +#define USB2_PHY_CAL_CTRL 0x8 +#define PHY_PLLCAL_DONE BIT(31) +#define PHY_IMPCAL_DONE BIT(23) +#define USB2_RX_CHAN_CTRL1 0x18 +#define USB2PHY_SQCAL_DONE BIT(31) +#define USB2_PHY_OTG_CTRL 0x34 +#define PHY_PU_OTG BIT(4) +#define USB2_PHY_CHRGR_DETECT 0x38 +#define PHY_CDP_EN BIT(2) +#define PHY_DCP_EN BIT(3) +#define PHY_PD_EN BIT(4) +#define PHY_PU_CHRG_DTC BIT(5) +#define PHY_CDP_DM_AUTO BIT(7) +#define PHY_ENSWITCH_DP BIT(12) +#define PHY_ENSWITCH_DM BIT(13) + +/* Armada 3700 USB miscellaneous registers */ +#define USB2_PHY_CTRL(usb32) (usb32 ? 0x20 : 0x4) +#define RB_USB2PHY_PU BIT(0) +#define USB2_DP_PULLDN_DEV_MODE BIT(5) +#define USB2_DM_PULLDN_DEV_MODE BIT(6) +#define RB_USB2PHY_SUSPM(usb32) (usb32 ? BIT(14) : BIT(7)) + +#define PLL_LOCK_DELAY_US 10000 +#define PLL_LOCK_TIMEOUT_US 1000000 + +/** + * struct mvebu_a3700_utmi_caps - PHY capabilities + * + * @usb32: Flag indicating which PHY is in use (impacts the register map): + * - The UTMI PHY wired to the USB3/USB2 controller (otg) + * - The UTMI PHY wired to the USB2 controller (host only) + * @ops: PHY operations + */ +struct mvebu_a3700_utmi_caps { + int usb32; + const struct phy_ops *ops; +}; + +/** + * struct mvebu_a3700_utmi - PHY driver data + * + * @regs: PHY registers + * @usb_mis: Regmap with USB miscellaneous registers including PHY ones + * @caps: PHY capabilities + * @phy: PHY handle + */ +struct mvebu_a3700_utmi { + void __iomem *regs; + struct regmap *usb_misc; + const struct mvebu_a3700_utmi_caps *caps; + struct phy *phy; +}; + +static int mvebu_a3700_utmi_phy_power_on(struct phy *phy) +{ + struct mvebu_a3700_utmi *utmi = phy_get_drvdata(phy); + struct device *dev = &phy->dev; + int usb32 = utmi->caps->usb32; + int ret = 0; + u32 reg; + + /* + * Setup PLL. 40MHz clock used to be the default, being 25MHz now. + * See "PLL Settings for Typical REFCLK" table. + */ + reg = readl(utmi->regs + USB2_PHY_PLL_CTRL_REG0); + reg &= ~(PLL_REF_DIV_MASK | PLL_FB_DIV_MASK | PLL_SEL_LPFR_MASK); + reg |= (PLL_REF_DIV_5 << PLL_REF_DIV_OFF) | + (PLL_FB_DIV_96 << PLL_FB_DIV_OFF); + writel(reg, utmi->regs + USB2_PHY_PLL_CTRL_REG0); + + /* Enable PHY pull up and disable USB2 suspend */ + regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32), + RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU, + RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU); + + if (usb32) { + /* Power up OTG module */ + reg = readl(utmi->regs + USB2_PHY_OTG_CTRL); + reg |= PHY_PU_OTG; + writel(reg, utmi->regs + USB2_PHY_OTG_CTRL); + + /* Disable PHY charger detection */ + reg = readl(utmi->regs + USB2_PHY_CHRGR_DETECT); + reg &= ~(PHY_CDP_EN | PHY_DCP_EN | PHY_PD_EN | PHY_PU_CHRG_DTC | + PHY_CDP_DM_AUTO | PHY_ENSWITCH_DP | PHY_ENSWITCH_DM); + writel(reg, utmi->regs + USB2_PHY_CHRGR_DETECT); + + /* Disable PHY DP/DM pull-down (used for device mode) */ + regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32), + USB2_DP_PULLDN_DEV_MODE | + USB2_DM_PULLDN_DEV_MODE, 0); + } + + /* Wait for PLL calibration */ + ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg, + reg & PHY_PLLCAL_DONE, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + dev_err(dev, "Failed to end USB2 PLL calibration\n"); + return ret; + } + + /* Wait for impedance calibration */ + ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg, + reg & PHY_IMPCAL_DONE, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + dev_err(dev, "Failed to end USB2 impedance calibration\n"); + return ret; + } + + /* Wait for squelch calibration */ + ret = readl_poll_timeout(utmi->regs + USB2_RX_CHAN_CTRL1, reg, + reg & USB2PHY_SQCAL_DONE, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + dev_err(dev, "Failed to end USB2 unknown calibration\n"); + return ret; + } + + /* Wait for PLL to be locked */ + ret = readl_poll_timeout(utmi->regs + USB2_PHY_PLL_CTRL_REG0, reg, + reg & PLL_READY, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) + dev_err(dev, "Failed to lock USB2 PLL\n"); + + return ret; +} + +static int mvebu_a3700_utmi_phy_power_off(struct phy *phy) +{ + struct mvebu_a3700_utmi *utmi = phy_get_drvdata(phy); + int usb32 = utmi->caps->usb32; + u32 reg; + + /* Disable PHY pull-up and enable USB2 suspend */ + reg = readl(utmi->regs + USB2_PHY_CTRL(usb32)); + reg &= ~(RB_USB2PHY_PU | RB_USB2PHY_SUSPM(usb32)); + writel(reg, utmi->regs + USB2_PHY_CTRL(usb32)); + + /* Power down OTG module */ + if (usb32) { + reg = readl(utmi->regs + USB2_PHY_OTG_CTRL); + reg &= ~PHY_PU_OTG; + writel(reg, utmi->regs + USB2_PHY_OTG_CTRL); + } + + return 0; +} + +static const struct phy_ops mvebu_a3700_utmi_phy_ops = { + .power_on = mvebu_a3700_utmi_phy_power_on, + .power_off = mvebu_a3700_utmi_phy_power_off, + .owner = THIS_MODULE, +}; + +static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_otg_phy_caps = { + .usb32 = true, + .ops = &mvebu_a3700_utmi_phy_ops, +}; + +static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_host_phy_caps = { + .usb32 = false, + .ops = &mvebu_a3700_utmi_phy_ops, +}; + +static const struct of_device_id mvebu_a3700_utmi_of_match[] = { + { + .compatible = "marvell,a3700-utmi-otg-phy", + .data = &mvebu_a3700_utmi_otg_phy_caps, + }, + { + .compatible = "marvell,a3700-utmi-host-phy", + .data = &mvebu_a3700_utmi_host_phy_caps, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, mvebu_a3700_utmi_of_match); + +static int mvebu_a3700_utmi_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mvebu_a3700_utmi *utmi; + struct phy_provider *provider; + struct resource *res; + + utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL); + if (!utmi) + return -ENOMEM; + + /* Get UTMI memory region */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Missing UTMI PHY memory resource\n"); + return -ENODEV; + } + + utmi->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(utmi->regs)) + return PTR_ERR(utmi->regs); + + /* Get miscellaneous Host/PHY region */ + utmi->usb_misc = syscon_regmap_lookup_by_phandle(dev->of_node, + "marvell,usb-misc-reg"); + if (IS_ERR(utmi->usb_misc)) { + dev_err(dev, + "Missing USB misc purpose system controller\n"); + return PTR_ERR(utmi->usb_misc); + } + + /* Retrieve PHY capabilities */ + utmi->caps = of_device_get_match_data(dev); + + /* Instantiate the PHY */ + utmi->phy = devm_phy_create(dev, NULL, utmi->caps->ops); + if (IS_ERR(utmi->phy)) { + dev_err(dev, "Failed to create the UTMI PHY\n"); + return PTR_ERR(utmi->phy); + } + + phy_set_drvdata(utmi->phy, utmi); + + /* Ensure the PHY is powered off */ + utmi->caps->ops->power_off(utmi->phy); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static struct platform_driver mvebu_a3700_utmi_driver = { + .probe = mvebu_a3700_utmi_phy_probe, + .driver = { + .name = "mvebu-a3700-utmi-phy", + .owner = THIS_MODULE, + .of_match_table = mvebu_a3700_utmi_of_match, + }, +}; +module_platform_driver(mvebu_a3700_utmi_driver); + +MODULE_AUTHOR("Igal Liberman <igall@marvell.com>"); +MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>"); +MODULE_DESCRIPTION("Marvell EBU A3700 UTMI PHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c index 187cccde53b5..d98e0451f6a1 100644 --- a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c +++ b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c @@ -580,8 +580,6 @@ static struct phy *mvebu_comphy_xlate(struct device *dev, return phy; lane = phy_get_drvdata(phy); - if (lane->port >= 0) - return ERR_PTR(-EBUSY); lane->port = args->args[0]; return phy; diff --git a/drivers/phy/marvell/phy-mvebu-sata.c b/drivers/phy/marvell/phy-mvebu-sata.c index 768ce92e81ce..369fece2be7a 100644 --- a/drivers/phy/marvell/phy-mvebu-sata.c +++ b/drivers/phy/marvell/phy-mvebu-sata.c @@ -10,7 +10,7 @@ */ #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/clk.h> #include <linux/phy/phy.h> #include <linux/io.h> @@ -122,7 +122,6 @@ static const struct of_device_id phy_mvebu_sata_of_match[] = { { .compatible = "marvell,mvebu-sata-phy" }, { }, }; -MODULE_DEVICE_TABLE(of, phy_mvebu_sata_of_match); static struct platform_driver phy_mvebu_sata_driver = { .probe = phy_mvebu_sata_probe, @@ -131,8 +130,4 @@ static struct platform_driver phy_mvebu_sata_driver = { .of_match_table = phy_mvebu_sata_of_match, } }; -module_platform_driver(phy_mvebu_sata_driver); - -MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); -MODULE_DESCRIPTION("Marvell MVEBU SATA PHY driver"); -MODULE_LICENSE("GPL v2"); +builtin_platform_driver(phy_mvebu_sata_driver); diff --git a/drivers/phy/phy-core-mipi-dphy.c b/drivers/phy/phy-core-mipi-dphy.c index 465fa1b91a5f..14e0551cd319 100644 --- a/drivers/phy/phy-core-mipi-dphy.c +++ b/drivers/phy/phy-core-mipi-dphy.c @@ -65,12 +65,12 @@ int phy_mipi_dphy_get_default_config(unsigned long pixel_clock, */ cfg->hs_trail = max(4 * 8 * ui, 60000 + 4 * 4 * ui); - cfg->init = 100000000; + cfg->init = 100; cfg->lpx = 60000; cfg->ta_get = 5 * cfg->lpx; cfg->ta_go = 4 * cfg->lpx; cfg->ta_sure = 2 * cfg->lpx; - cfg->wakeup = 1000000000; + cfg->wakeup = 1000; cfg->hs_clk_rate = hs_clk_rate; cfg->lanes = lanes; @@ -143,7 +143,7 @@ int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy *cfg) if (cfg->hs_trail < max(8 * ui, 60000 + 4 * ui)) return -EINVAL; - if (cfg->init < 100000000) + if (cfg->init < 100) return -EINVAL; if (cfg->lpx < 50000) @@ -158,7 +158,7 @@ int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy *cfg) if (cfg->ta_sure < cfg->lpx || cfg->ta_sure > (2 * cfg->lpx)) return -EINVAL; - if (cfg->wakeup < 1000000000) + if (cfg->wakeup < 1000) return -EINVAL; return 0; diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 19b05e824ee4..cb38f6e8614c 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -1112,14 +1112,4 @@ static int __init phy_core_init(void) return 0; } -module_init(phy_core_init); - -static void __exit phy_core_exit(void) -{ - class_destroy(phy_class); -} -module_exit(phy_core_exit); - -MODULE_DESCRIPTION("Generic PHY Framework"); -MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); -MODULE_LICENSE("GPL v2"); +device_initcall(phy_core_init); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index b4006818e1b6..08d6f6f7f039 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -687,6 +687,116 @@ static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_MULTI_LANE_CTRL1, 0x02), }; +static const struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07), +}; + +static const struct qmp_phy_init_tbl msm8998_usb3_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), +}; + +static const struct qmp_phy_init_tbl msm8998_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05), +}; + +static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x8a), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), +}; + + /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { /* phy-type - PCIE/UFS/USB */ @@ -1036,6 +1146,33 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .no_pcs_sw_reset = true, }; +static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { + .type = PHY_TYPE_USB3, + .nlanes = 1, + + .serdes_tbl = msm8998_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl), + .tx_tbl = msm8998_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(msm8998_usb3_tx_tbl), + .rx_tbl = msm8998_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), + .pcs_tbl = msm8998_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), + .clk_list = msm8996_phy_clk_l, + .num_clks = ARRAY_SIZE(msm8996_phy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout, + + .start_ctrl = SERDES_START | PCS_START, + .pwrdn_ctrl = SW_PWRDN, + .mask_pcs_ready = PHYSTATUS, + + .is_dual_lane_phy = true, +}; + static void qcom_qmp_phy_configure(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], @@ -1736,6 +1873,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { .compatible = "qcom,msm8996-qmp-usb3-phy", .data = &msm8996_usb3phy_cfg, }, { + .compatible = "qcom,msm8998-qmp-ufs-phy", + .data = &sdm845_ufsphy_cfg, + }, { .compatible = "qcom,ipq8074-qmp-pcie-phy", .data = &ipq8074_pciephy_cfg, }, { @@ -1747,6 +1887,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { }, { .compatible = "qcom,sdm845-qmp-ufs-phy", .data = &sdm845_ufsphy_cfg, + }, { + .compatible = "qcom,msm8998-qmp-usb3-phy", + .data = &msm8998_usb3phy_cfg, }, { }, }; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index d201cc307151..a1b6cdee9a08 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -174,6 +174,7 @@ #define QSERDES_V3_COM_DIV_FRAC_START1_MODE1 0x0c4 #define QSERDES_V3_COM_DIV_FRAC_START2_MODE1 0x0c8 #define QSERDES_V3_COM_DIV_FRAC_START3_MODE1 0x0cc +#define QSERDES_V3_COM_INTEGLOOP_INITVAL 0x0d0 #define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0 0x0d8 #define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0 0x0dc #define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1 0x0e0 @@ -201,6 +202,7 @@ #define QSERDES_V3_COM_DEBUG_BUS2 0x170 #define QSERDES_V3_COM_DEBUG_BUS3 0x174 #define QSERDES_V3_COM_DEBUG_BUS_SEL 0x178 +#define QSERDES_V3_COM_CMN_MODE 0x184 /* Only for QMP V3 PHY - TX registers */ #define QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX 0x044 @@ -211,6 +213,7 @@ #define QSERDES_V3_TX_RCV_DETECT_LVL_2 0x0a4 /* Only for QMP V3 PHY - RX registers */ +#define QSERDES_V3_RX_UCDR_FO_GAIN 0x008 #define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c #define QSERDES_V3_RX_UCDR_SO_GAIN 0x014 #define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF 0x024 @@ -219,6 +222,7 @@ #define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030 #define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 #define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c +#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040 #define QSERDES_V3_RX_UCDR_PI_CONTROLS 0x044 #define QSERDES_V3_RX_RX_TERM_BW 0x07c #define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index 9177989f22d1..8fd7ce139772 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c @@ -152,6 +152,31 @@ static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = { QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00), }; +static const unsigned int msm8998_regs_layout[] = { + [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8, + [QUSB2PHY_PLL_STATUS] = 0x1a0, + [QUSB2PHY_PORT_TUNE1] = 0x23c, + [QUSB2PHY_PORT_TUNE2] = 0x240, + [QUSB2PHY_PORT_TUNE3] = 0x244, + [QUSB2PHY_PORT_TUNE4] = 0x248, + [QUSB2PHY_PORT_TEST1] = 0x24c, + [QUSB2PHY_PORT_TEST2] = 0x250, + [QUSB2PHY_PORT_POWERDOWN] = 0x210, + [QUSB2PHY_INTR_CTRL] = 0x22c, +}; + +static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = { + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x13), + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c), + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80), + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a), + + QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xa5), + QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x09), + + QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19), +}; + static const unsigned int sdm845_regs_layout[] = { [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8, [QUSB2PHY_PLL_STATUS] = 0x1a0, @@ -221,6 +246,18 @@ static const struct qusb2_phy_cfg msm8996_phy_cfg = { .autoresume_en = BIT(3), }; +static const struct qusb2_phy_cfg msm8998_phy_cfg = { + .tbl = msm8998_init_tbl, + .tbl_num = ARRAY_SIZE(msm8998_init_tbl), + .regs = msm8998_regs_layout, + + .disable_ctrl = POWER_DOWN, + .mask_core_ready = CORE_READY_STATUS, + .has_pll_override = true, + .autoresume_en = BIT(0), + .update_tune1_with_efuse = true, +}; + static const struct qusb2_phy_cfg sdm845_phy_cfg = { .tbl = sdm845_init_tbl, .tbl_num = ARRAY_SIZE(sdm845_init_tbl), @@ -734,6 +771,9 @@ static const struct of_device_id qusb2_phy_of_match_table[] = { .compatible = "qcom,msm8996-qusb2-phy", .data = &msm8996_phy_cfg, }, { + .compatible = "qcom,msm8998-qusb2-phy", + .data = &msm8998_phy_cfg, + }, { .compatible = "qcom,sdm845-qusb2-phy", .data = &sdm845_phy_cfg, }, diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h b/drivers/phy/qualcomm/phy-qcom-ufs-i.h index 681644e43248..f798fb64de94 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h @@ -23,24 +23,7 @@ #include <linux/platform_device.h> #include <linux/io.h> #include <linux/delay.h> - -#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ -({ \ - ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ - might_sleep_if(timeout_us); \ - for (;;) { \ - (val) = readl(addr); \ - if (cond) \ - break; \ - if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \ - (val) = readl(addr); \ - break; \ - } \ - if (sleep_us) \ - usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \ - } \ - (cond) ? 0 : -ETIMEDOUT; \ -}) +#include <linux/iopoll.h> #define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ { \ diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 91fba60267a0..ba07121c3eff 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -55,16 +55,16 @@ enum rockchip_usb2phy_host_state { }; /** - * Different states involved in USB charger detection. - * USB_CHG_STATE_UNDEFINED USB charger is not connected or detection + * enum usb_chg_state - Different states involved in USB charger detection. + * @USB_CHG_STATE_UNDEFINED: USB charger is not connected or detection * process is not yet started. - * USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact. - * USB_CHG_STATE_DCD_DONE Data pin contact is detected. - * USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects + * @USB_CHG_STATE_WAIT_FOR_DCD: Waiting for Data pins contact. + * @USB_CHG_STATE_DCD_DONE: Data pin contact is detected. + * @USB_CHG_STATE_PRIMARY_DONE: Primary detection is completed (Detects * between SDP and DCP/CDP). - * USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects - * between DCP and CDP). - * USB_CHG_STATE_DETECTED USB charger type is determined. + * @USB_CHG_STATE_SECONDARY_DONE: Secondary detection is completed (Detects + * between DCP and CDP). + * @USB_CHG_STATE_DETECTED: USB charger type is determined. */ enum usb_chg_state { USB_CHG_STATE_UNDEFINED = 0, @@ -94,7 +94,7 @@ struct usb2phy_reg { }; /** - * struct rockchip_chg_det_reg: usb charger detect registers + * struct rockchip_chg_det_reg - usb charger detect registers * @cp_det: charging port detected successfully. * @dcp_det: dedicated charging port detected successfully. * @dp_det: assert data pin connect successfully. @@ -120,7 +120,7 @@ struct rockchip_chg_det_reg { }; /** - * struct rockchip_usb2phy_port_cfg: usb-phy port configuration. + * struct rockchip_usb2phy_port_cfg - usb-phy port configuration. * @phy_sus: phy suspend register. * @bvalid_det_en: vbus valid rise detection enable register. * @bvalid_det_st: vbus valid rise detection status register. @@ -148,10 +148,11 @@ struct rockchip_usb2phy_port_cfg { }; /** - * struct rockchip_usb2phy_cfg: usb-phy configuration. + * struct rockchip_usb2phy_cfg - usb-phy configuration. * @reg: the address offset of grf for usb-phy config. * @num_ports: specify how many ports that the phy has. * @clkout_ctl: keep on/turn off output clk of phy. + * @port_cfgs: usb-phy port configurations. * @chg_det: charger detection registers. */ struct rockchip_usb2phy_cfg { @@ -163,12 +164,10 @@ struct rockchip_usb2phy_cfg { }; /** - * struct rockchip_usb2phy_port: usb-phy port data. + * struct rockchip_usb2phy_port - usb-phy port data. + * @phy: generic phy. * @port_id: flag for otg port or host port. * @suspended: phy suspended flag. - * @utmi_avalid: utmi avalid status usage flag. - * true - use avalid to get vbus status - * flase - use bvalid to get vbus status * @vbus_attached: otg device vbus status. * @bvalid_irq: IRQ number assigned for vbus valid rise detection. * @ls_irq: IRQ number assigned for linestate detection. @@ -178,7 +177,7 @@ struct rockchip_usb2phy_cfg { * @chg_work: charge detect work. * @otg_sm_work: OTG state machine work. * @sm_work: HOST state machine work. - * @phy_cfg: port register configuration, assigned by driver data. + * @port_cfg: port register configuration, assigned by driver data. * @event_nb: hold event notification callback. * @state: define OTG enumeration states before device reset. * @mode: the dr_mode of the controller. @@ -187,7 +186,6 @@ struct rockchip_usb2phy_port { struct phy *phy; unsigned int port_id; bool suspended; - bool utmi_avalid; bool vbus_attached; int bvalid_irq; int ls_irq; @@ -203,12 +201,13 @@ struct rockchip_usb2phy_port { }; /** - * struct rockchip_usb2phy: usb2.0 phy driver data. + * struct rockchip_usb2phy - usb2.0 phy driver data. + * @dev: pointer to device. * @grf: General Register Files regmap. * @usbgrf: USB General Register Files regmap. * @clk: clock struct of phy input clk. * @clk480m: clock struct of phy output clk. - * @clk_hw: clock struct of phy output clk management. + * @clk480m_hw: clock struct of phy output clk management. * @chg_state: states involved in USB charger detection. * @chg_type: USB charger types. * @dcd_retries: The retry count used to track Data contact @@ -542,12 +541,8 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) unsigned long delay; bool vbus_attach, sch_work, notify_charger; - if (rport->utmi_avalid) - vbus_attach = property_enabled(rphy->grf, - &rport->port_cfg->utmi_avalid); - else - vbus_attach = property_enabled(rphy->grf, - &rport->port_cfg->utmi_bvalid); + vbus_attach = property_enabled(rphy->grf, + &rport->port_cfg->utmi_bvalid); sch_work = false; notify_charger = false; @@ -1021,9 +1016,6 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work); INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work); - rport->utmi_avalid = - of_property_read_bool(child_np, "rockchip,utmi-avalid"); - /* * Some SoCs use one interrupt with otg-id/otg-bvalid/linestate * interrupts muxed together, so probe the otg-mux interrupt first, diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig index c4709ed7fb0e..103efc456a12 100644 --- a/drivers/phy/ti/Kconfig +++ b/drivers/phy/ti/Kconfig @@ -33,12 +33,11 @@ config OMAP_CONTROL_PHY config OMAP_USB2 tristate "OMAP USB2 PHY Driver" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || ARCH_K3 depends on USB_SUPPORT select GENERIC_PHY select USB_PHY - select OMAP_CONTROL_PHY - depends on OMAP_OCP2SCP + select OMAP_CONTROL_PHY if ARCH_OMAP2PLUS help Enable this to support the transceiver that is part of SOC. This driver takes care of all the PHY functionality apart from comparator. @@ -50,7 +49,6 @@ config TI_PIPE3 depends on ARCH_OMAP2PLUS || COMPILE_TEST select GENERIC_PHY select OMAP_CONTROL_PHY - depends on OMAP_OCP2SCP help Enable this to support the PIPE3 PHY that is part of TI SOCs. This driver takes care of all the PHY functionality apart from comparator. diff --git a/drivers/phy/ti/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c index fe909fd8144f..e871f2983a0e 100644 --- a/drivers/phy/ti/phy-omap-usb2.c +++ b/drivers/phy/ti/phy-omap-usb2.c @@ -36,6 +36,10 @@ #define USB2PHY_DISCON_BYP_LATCH (1 << 31) #define USB2PHY_ANA_CONFIG1 0x4c +#define AM654_USB2_OTG_PD BIT(8) +#define AM654_USB2_VBUS_DET_EN BIT(5) +#define AM654_USB2_VBUSVALID_DET_EN BIT(4) + /** * omap_usb2_set_comparator - links the comparator present in the sytem with * this phy @@ -135,9 +139,9 @@ static int omap_usb_power_on(struct phy *x) static int omap_usb2_disable_clocks(struct omap_usb *phy) { - clk_disable(phy->wkupclk); + clk_disable_unprepare(phy->wkupclk); if (!IS_ERR(phy->optclk)) - clk_disable(phy->optclk); + clk_disable_unprepare(phy->optclk); return 0; } @@ -146,14 +150,14 @@ static int omap_usb2_enable_clocks(struct omap_usb *phy) { int ret; - ret = clk_enable(phy->wkupclk); + ret = clk_prepare_enable(phy->wkupclk); if (ret < 0) { dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); goto err0; } if (!IS_ERR(phy->optclk)) { - ret = clk_enable(phy->optclk); + ret = clk_prepare_enable(phy->optclk); if (ret < 0) { dev_err(phy->dev, "Failed to enable optclk %d\n", ret); goto err1; @@ -245,6 +249,15 @@ static const struct usb_phy_data am437x_usb2_data = { .power_off = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD, }; +static const struct usb_phy_data am654_usb2_data = { + .label = "am654_usb2", + .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT, + .mask = AM654_USB2_OTG_PD | AM654_USB2_VBUS_DET_EN | + AM654_USB2_VBUSVALID_DET_EN, + .power_on = AM654_USB2_VBUS_DET_EN | AM654_USB2_VBUSVALID_DET_EN, + .power_off = AM654_USB2_OTG_PD, +}; + static const struct of_device_id omap_usb2_id_table[] = { { .compatible = "ti,omap-usb2", @@ -266,6 +279,10 @@ static const struct of_device_id omap_usb2_id_table[] = { .compatible = "ti,am437x-usb2", .data = &am437x_usb2_data, }, + { + .compatible = "ti,am654-usb2", + .data = &am654_usb2_data, + }, {}, }; MODULE_DEVICE_TABLE(of, omap_usb2_id_table); @@ -346,63 +363,72 @@ static int omap_usb2_probe(struct platform_device *pdev) } } - otg->set_host = omap_usb_set_host; - otg->set_peripheral = omap_usb_set_peripheral; - if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS) - otg->set_vbus = omap_usb_set_vbus; - if (phy_data->flags & OMAP_USB2_HAS_START_SRP) - otg->start_srp = omap_usb_start_srp; - otg->usb_phy = &phy->phy; - - platform_set_drvdata(pdev, phy); - pm_runtime_enable(phy->dev); - - generic_phy = devm_phy_create(phy->dev, NULL, &ops); - if (IS_ERR(generic_phy)) { - pm_runtime_disable(phy->dev); - return PTR_ERR(generic_phy); - } - - phy_set_drvdata(generic_phy, phy); - omap_usb_power_off(generic_phy); - - phy_provider = devm_of_phy_provider_register(phy->dev, - of_phy_simple_xlate); - if (IS_ERR(phy_provider)) { - pm_runtime_disable(phy->dev); - return PTR_ERR(phy_provider); - } phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); if (IS_ERR(phy->wkupclk)) { - dev_warn(&pdev->dev, "unable to get wkupclk, trying old name\n"); + if (PTR_ERR(phy->wkupclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(&pdev->dev, "unable to get wkupclk %ld, trying old name\n", + PTR_ERR(phy->wkupclk)); phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); + if (IS_ERR(phy->wkupclk)) { - dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); - pm_runtime_disable(phy->dev); + if (PTR_ERR(phy->wkupclk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); return PTR_ERR(phy->wkupclk); } else { dev_warn(&pdev->dev, "found usb_phy_cm_clk32k, please fix DTS\n"); } } - clk_prepare(phy->wkupclk); phy->optclk = devm_clk_get(phy->dev, "refclk"); if (IS_ERR(phy->optclk)) { + if (PTR_ERR(phy->optclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_dbg(&pdev->dev, "unable to get refclk, trying old name\n"); phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); + if (IS_ERR(phy->optclk)) { - dev_dbg(&pdev->dev, - "unable to get usb_otg_ss_refclk960m\n"); + if (PTR_ERR(phy->optclk) != -EPROBE_DEFER) { + dev_dbg(&pdev->dev, + "unable to get usb_otg_ss_refclk960m\n"); + } } else { dev_warn(&pdev->dev, "found usb_otg_ss_refclk960m, please fix DTS\n"); } } - if (!IS_ERR(phy->optclk)) - clk_prepare(phy->optclk); + otg->set_host = omap_usb_set_host; + otg->set_peripheral = omap_usb_set_peripheral; + if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS) + otg->set_vbus = omap_usb_set_vbus; + if (phy_data->flags & OMAP_USB2_HAS_START_SRP) + otg->start_srp = omap_usb_start_srp; + otg->usb_phy = &phy->phy; + + platform_set_drvdata(pdev, phy); + pm_runtime_enable(phy->dev); + + generic_phy = devm_phy_create(phy->dev, NULL, &ops); + if (IS_ERR(generic_phy)) { + pm_runtime_disable(phy->dev); + return PTR_ERR(generic_phy); + } + + phy_set_drvdata(generic_phy, phy); + omap_usb_power_off(generic_phy); + + phy_provider = devm_of_phy_provider_register(phy->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + pm_runtime_disable(phy->dev); + return PTR_ERR(phy_provider); + } + usb_add_phy_dev(&phy->phy); @@ -413,9 +439,6 @@ static int omap_usb2_remove(struct platform_device *pdev) { struct omap_usb *phy = platform_get_drvdata(pdev); - clk_unprepare(phy->wkupclk); - if (!IS_ERR(phy->optclk)) - clk_unprepare(phy->optclk); usb_remove_phy(&phy->phy); pm_runtime_disable(phy->dev); diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 02bc74608cf3..6fa3cced6f8e 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -32,7 +32,7 @@ struct cht_int33fe_data { struct i2c_client *fusb302; struct i2c_client *pi3usb30532; /* Contain a list-head must be per device */ - struct device_connection connections[5]; + struct device_connection connections[4]; }; /* @@ -174,16 +174,13 @@ static int cht_int33fe_probe(struct platform_device *pdev) data->connections[0].endpoint[0] = "port0"; data->connections[0].endpoint[1] = "i2c-pi3usb30532"; - data->connections[0].id = "typec-switch"; + data->connections[0].id = "orientation-switch"; data->connections[1].endpoint[0] = "port0"; data->connections[1].endpoint[1] = "i2c-pi3usb30532"; - data->connections[1].id = "typec-mux"; - data->connections[2].endpoint[0] = "port0"; - data->connections[2].endpoint[1] = "i2c-pi3usb30532"; - data->connections[2].id = "idff01m01"; - data->connections[3].endpoint[0] = "i2c-fusb302"; - data->connections[3].endpoint[1] = "intel_xhci_usb_sw-role-switch"; - data->connections[3].id = "usb-role-switch"; + data->connections[1].id = "mode-switch"; + data->connections[2].endpoint[0] = "i2c-fusb302"; + data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch"; + data->connections[2].id = "usb-role-switch"; device_connections_add(data->connections); diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 70e6c956c23c..e4b27413f528 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB device configuration # diff --git a/drivers/usb/README b/drivers/usb/README deleted file mode 100644 index 2144e7dbfa41..000000000000 --- a/drivers/usb/README +++ /dev/null @@ -1,54 +0,0 @@ -To understand all the Linux-USB framework, you'll use these resources: - - * This source code. This is necessarily an evolving work, and - includes kerneldoc that should help you get a current overview. - ("make pdfdocs", and then look at "usb.pdf" for host side and - "gadget.pdf" for peripheral side.) Also, Documentation/usb has - more information. - - * The USB 2.0 specification (from www.usb.org), with supplements - such as those for USB OTG and the various device classes. - The USB specification has a good overview chapter, and USB - peripherals conform to the widely known "Chapter 9". - - * Chip specifications for USB controllers. Examples include - host controllers (on PCs, servers, and more); peripheral - controllers (in devices with Linux firmware, like printers or - cell phones); and hard-wired peripherals like Ethernet adapters. - - * Specifications for other protocols implemented by USB peripheral - functions. Some are vendor-specific; others are vendor-neutral - but just standardized outside of the www.usb.org team. - -Here is a list of what each subdirectory here is, and what is contained in -them. - -core/ - This is for the core USB host code, including the - usbfs files and the hub class driver ("hub_wq"). - -host/ - This is for USB host controller drivers. This - includes UHCI, OHCI, EHCI, and others that might - be used with more specialized "embedded" systems. - -gadget/ - This is for USB peripheral controller drivers and - the various gadget drivers which talk to them. - - -Individual USB driver directories. A new driver should be added to the -first subdirectory in the list below that it fits into. - -image/ - This is for still image drivers, like scanners or - digital cameras. -../input/ - This is for any driver that uses the input subsystem, - like keyboard, mice, touchscreens, tablets, etc. -../media/ - This is for multimedia drivers, like video cameras, - radios, and any other drivers that talk to the v4l - subsystem. -../net/ - This is for network drivers. -serial/ - This is for USB to serial drivers. -storage/ - This is for USB mass-storage drivers. -class/ - This is for all USB device drivers that do not fit - into any of the above categories, and work for a range - of USB Class specified devices. -misc/ - This is for all USB device drivers that do not fit - into any of the above categories. diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig index 0f922942a07a..989aaa3b080d 100644 --- a/drivers/usb/atm/Kconfig +++ b/drivers/usb/atm/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB/ATM DSL configuration # diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index ee34e9046f7e..eb37ebfcb123 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_CHIPIDEA tristate "ChipIdea Highspeed Dual Role Controller" depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 9b45aa422e69..ceec8d5985d4 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -7,10 +7,8 @@ #include <linux/module.h> #include <linux/of_platform.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/dma-mapping.h> #include <linux/usb/chipidea.h> #include <linux/usb/of.h> #include <linux/clk.h> @@ -152,8 +150,8 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) dev_warn(dev, "No over current polarity defined\n"); } - if (of_find_property(np, "external-vbus-divider", NULL)) - data->evdo = 1; + data->pwr_pol = of_property_read_bool(np, "power-active-high"); + data->evdo = of_property_read_bool(np, "external-vbus-divider"); if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) data->ulpi = 1; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 7cc53e2ce564..c842e03f8767 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -18,6 +18,7 @@ struct imx_usbmisc_data { /* true if dt specifies polarity */ unsigned int oc_pol_configured:1; + unsigned int pwr_pol:1; /* power polarity */ unsigned int evdo:1; /* set external vbus divider option */ unsigned int ulpi:1; /* connected to an ULPI phy */ unsigned int hsic:1; /* HSIC controlller */ diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 772851bee99b..12025358bb3c 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -130,6 +130,7 @@ static int tegra_udc_remove(struct platform_device *pdev) { struct tegra_udc *udc = platform_get_drvdata(pdev); + ci_hdrc_remove_device(udc->dev); usb_phy_set_suspend(udc->phy, 1); clk_disable_unprepare(udc->clk); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 7bfcbb23c2a4..27749ace2d93 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -954,25 +954,47 @@ static int ci_hdrc_probe(struct platform_device *pdev) } else if (ci->platdata->usb_phy) { ci->usb_phy = ci->platdata->usb_phy; } else { + /* Look for a generic PHY first */ ci->phy = devm_phy_get(dev->parent, "usb-phy"); - ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2); - /* if both generic PHY and USB PHY layers aren't enabled */ - if (PTR_ERR(ci->phy) == -ENOSYS && - PTR_ERR(ci->usb_phy) == -ENXIO) { - ret = -ENXIO; + if (PTR_ERR(ci->phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; goto ulpi_exit; + } else if (IS_ERR(ci->phy)) { + ci->phy = NULL; } - if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) { - ret = -EPROBE_DEFER; - goto ulpi_exit; + /* Look for a legacy USB PHY from device-tree next */ + if (!ci->phy) { + ci->usb_phy = devm_usb_get_phy_by_phandle(dev->parent, + "phys", 0); + + if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto ulpi_exit; + } else if (IS_ERR(ci->usb_phy)) { + ci->usb_phy = NULL; + } } - if (IS_ERR(ci->phy)) - ci->phy = NULL; - else if (IS_ERR(ci->usb_phy)) - ci->usb_phy = NULL; + /* Look for any registered legacy USB PHY as last resort */ + if (!ci->phy && !ci->usb_phy) { + ci->usb_phy = devm_usb_get_phy(dev->parent, + USB_PHY_TYPE_USB2); + + if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto ulpi_exit; + } else if (IS_ERR(ci->usb_phy)) { + ci->usb_phy = NULL; + } + } + + /* No USB PHY was found in the end */ + if (!ci->phy && !ci->usb_phy) { + ret = -ENXIO; + goto ulpi_exit; + } } ret = ci_usb_phy_init(ci); diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 097ffbca0bd9..d8b67e150b12 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -63,6 +63,7 @@ #define MX6_BM_NON_BURST_SETTING BIT(1) #define MX6_BM_OVER_CUR_DIS BIT(7) #define MX6_BM_OVER_CUR_POLARITY BIT(8) +#define MX6_BM_PWR_POLARITY BIT(9) #define MX6_BM_WAKEUP_ENABLE BIT(10) #define MX6_BM_UTMI_ON_CLOCK BIT(13) #define MX6_BM_ID_WAKEUP BIT(16) @@ -383,6 +384,9 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) else if (data->oc_pol_configured) reg &= ~MX6_BM_OVER_CUR_POLARITY; } + /* If the polarity is not set keep it as setup by the bootlader */ + if (data->pwr_pol == 1) + reg |= MX6_BM_PWR_POLARITY; writel(reg, usbmisc->base + data->index * 4); /* SoC non-burst setting */ @@ -585,6 +589,9 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data) else if (data->oc_pol_configured) reg &= ~MX6_BM_OVER_CUR_POLARITY; } + /* If the polarity is not set keep it as setup by the bootlader */ + if (data->pwr_pol == 1) + reg |= MX6_BM_PWR_POLARITY; writel(reg, usbmisc->base); reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig index 971385fe9abc..52f3a531a82f 100644 --- a/drivers/usb/class/Kconfig +++ b/drivers/usb/class/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Class driver configuration # diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index bec581fb7c63..9e9caff905d5 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -1099,7 +1099,7 @@ static int wdm_post_reset(struct usb_interface *intf) rv = recover_from_urb_loss(desc); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); - return 0; + return rv; } static struct usb_driver wdm_driver = { diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 4d75d9a80001..bdb6bd0b63a6 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Core configuration # @@ -90,3 +91,15 @@ config USB_LEDS_TRIGGER_USBPORT This driver allows LEDs to be controlled by USB events. Enabling this trigger allows specifying list of USB ports that should turn on LED when some USB device gets connected. + +config USB_AUTOSUSPEND_DELAY + int "Default autosuspend delay" + depends on USB + default 2 + help + The default autosuspend delay in seconds. Can be overridden + with the usbcore.autosuspend command line or module parameter. + + The default value Linux has always had is 2 seconds. Change + this value if you want a different delay and cannot modify + the command line or module parameter. diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 7b5cb28ffb35..20ff036b4c22 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -552,7 +552,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, unsigned char *buffer2; int size2; struct usb_descriptor_header *header; - int len, retval; + int retval; u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES]; unsigned iad_num = 0; @@ -707,8 +707,8 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, nalts[i] = j = USB_MAXALTSETTING; } - len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j; - config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL); + intfc = kzalloc(struct_size(intfc, altsetting, j), GFP_KERNEL); + config->intf_cache[i] = intfc; if (!intfc) return -ENOMEM; kref_init(&intfc->ref); @@ -800,13 +800,11 @@ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = 0; + int result = -ENOMEM; unsigned int cfgno, length; unsigned char *bigbuffer; struct usb_config_descriptor *desc; - cfgno = 0; - result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); @@ -832,8 +830,7 @@ int usb_get_configuration(struct usb_device *dev) if (!desc) goto err2; - result = 0; - for (; cfgno < ncfg; cfgno++) { + for (cfgno = 0; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, @@ -889,7 +886,6 @@ int usb_get_configuration(struct usb_device *dev) goto err; } } - result = 0; err: kfree(desc); diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index d65566341dd1..fa783531ee88 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -604,7 +604,7 @@ static void async_completed(struct urb *urb) snoop(&urb->dev->dev, "urb complete\n"); snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, as->status, COMPLETE, NULL, 0); - if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN) + if (usb_urb_dir_in(urb)) snoop_urb_data(urb, urb->actual_length); if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && @@ -1564,12 +1564,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb } for (totlen = u = 0; u < number_of_packets; u++) { /* - * arbitrary limit need for USB 3.0 - * bMaxBurst (0~15 allowed, 1~16 packets) - * bmAttributes (bit 1:0, mult 0~2, 1~3 packets) - * sizemax: 1024 * 16 * 3 = 49152 + * arbitrary limit need for USB 3.1 Gen2 + * sizemax: 96 DPs at SSP, 96 * 1024 = 98304 */ - if (isopkt[u].length > 49152) { + if (isopkt[u].length > 98304) { ret = -EINVAL; goto error; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 53564386ed57..8987cec9549d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1896,14 +1896,11 @@ int usb_runtime_idle(struct device *dev) return -EBUSY; } -int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) { struct usb_hcd *hcd = bus_to_hcd(udev->bus); int ret = -EPERM; - if (enable && !udev->usb2_hw_lpm_allowed) - return 0; - if (hcd->driver->set_usb2_hw_lpm) { ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); if (!ret) @@ -1913,6 +1910,24 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) return ret; } +int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + if (!udev->usb2_hw_lpm_capable || + !udev->usb2_hw_lpm_allowed || + udev->usb2_hw_lpm_enabled) + return 0; + + return usb_set_usb2_hardware_lpm(udev, 1); +} + +int usb_disable_usb2_hardware_lpm(struct usb_device *udev) +{ + if (!udev->usb2_hw_lpm_enabled) + return 0; + + return usb_set_usb2_hardware_lpm(udev, 0); +} + #endif /* CONFIG_PM */ struct bus_type usb_bus_type = { diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index f713cecc1f41..1ac9c1e5f773 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -118,6 +118,31 @@ int usb_choose_configuration(struct usb_device *udev) continue; } + /* + * Select first configuration as default for audio so that + * devices that don't comply with UAC3 protocol are supported. + * But, still iterate through other configurations and + * select UAC3 compliant config if present. + */ + if (desc && is_audio(desc)) { + /* Always prefer the first found UAC3 config */ + if (is_uac3_config(desc)) { + best = c; + break; + } + + /* If there is no UAC3 config, prefer the first config */ + else if (i == 0) + best = c; + + /* Unconditional continue, because the rest of the code + * in the loop is irrelevant for audio devices, and + * because it can reassign best, which for audio devices + * we don't want. + */ + continue; + } + /* When the first config's first interface is one of Microsoft's * pet nonstandard Ethernet-over-USB protocols, ignore it unless * this kernel has enabled the necessary host side driver. @@ -132,25 +157,6 @@ int usb_choose_configuration(struct usb_device *udev) #endif } - /* - * Select first configuration as default for audio so that - * devices that don't comply with UAC3 protocol are supported. - * But, still iterate through other configurations and - * select UAC3 compliant config if present. - */ - if (i == 0 && num_configs > 1 && desc && is_audio(desc)) { - best = c; - continue; - } - - if (i > 0 && desc && is_audio(desc)) { - if (is_uac3_config(desc)) { - best = c; - break; - } - continue; - } - /* From the remaining configs, choose the first one whose * first interface is for a non-vendor-specific class. * Reason: Linux is more likely to have a class driver diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 015b126ce455..3189181bb628 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -373,13 +373,19 @@ static const u8 ss_rh_config_descriptor[] = { * -1 is authorized for all devices except wireless (old behaviour) * 0 is unauthorized for all devices * 1 is authorized for all devices + * 2 is authorized for internal devices */ -static int authorized_default = -1; +#define USB_AUTHORIZE_WIRED -1 +#define USB_AUTHORIZE_NONE 0 +#define USB_AUTHORIZE_ALL 1 +#define USB_AUTHORIZE_INTERNAL 2 + +static int authorized_default = USB_AUTHORIZE_WIRED; module_param(authorized_default, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(authorized_default, "Default USB device authorization: 0 is not authorized, 1 is " - "authorized, -1 is authorized except for wireless USB (default, " - "old behaviour"); + "authorized, 2 is authorized for internal devices, -1 is " + "authorized except for wireless USB (default, old behaviour)"); /*-------------------------------------------------------------------------*/ /** @@ -884,7 +890,7 @@ static ssize_t authorized_default_show(struct device *dev, struct usb_hcd *hcd; hcd = bus_to_hcd(usb_bus); - return snprintf(buf, PAGE_SIZE, "%u\n", !!HCD_DEV_AUTHORIZED(hcd)); + return snprintf(buf, PAGE_SIZE, "%u\n", hcd->dev_policy); } static ssize_t authorized_default_store(struct device *dev, @@ -900,11 +906,8 @@ static ssize_t authorized_default_store(struct device *dev, hcd = bus_to_hcd(usb_bus); result = sscanf(buf, "%u\n", &val); if (result == 1) { - if (val) - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - + hcd->dev_policy = val <= USB_DEVICE_AUTHORIZE_INTERNAL ? + val : USB_DEVICE_AUTHORIZE_ALL; result = size; } else { result = -EINVAL; @@ -2736,6 +2739,11 @@ int usb_add_hcd(struct usb_hcd *hcd, if (retval) return retval; + retval = usb_phy_roothub_set_mode(hcd->phy_roothub, + PHY_MODE_USB_HOST_SS); + if (retval) + goto err_usb_phy_roothub_power_on; + retval = usb_phy_roothub_power_on(hcd->phy_roothub); if (retval) goto err_usb_phy_roothub_power_on; @@ -2743,18 +2751,26 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); - /* Keep old behaviour if authorized_default is not in [0, 1]. */ - if (authorized_default < 0 || authorized_default > 1) { - if (hcd->wireless) - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - } else { - if (authorized_default) - set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); - else - clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags); + switch (authorized_default) { + case USB_AUTHORIZE_NONE: + hcd->dev_policy = USB_DEVICE_AUTHORIZE_NONE; + break; + + case USB_AUTHORIZE_ALL: + hcd->dev_policy = USB_DEVICE_AUTHORIZE_ALL; + break; + + case USB_AUTHORIZE_INTERNAL: + hcd->dev_policy = USB_DEVICE_AUTHORIZE_INTERNAL; + break; + + case USB_AUTHORIZE_WIRED: + default: + hcd->dev_policy = hcd->wireless ? + USB_DEVICE_AUTHORIZE_NONE : USB_DEVICE_AUTHORIZE_ALL; + break; } + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* per default all interfaces are authorized */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1d1e61e980f3..8d4631c81b9f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -108,6 +108,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); static void hub_release(struct kref *kref); static int usb_reset_and_verify_device(struct usb_device *udev); static int hub_port_disable(struct usb_hub *hub, int port1, int set_state); +static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1, + u16 portstatus); static inline char *portspeed(struct usb_hub *hub, int portstatus) { @@ -607,6 +609,36 @@ static int hub_port_status(struct usb_hub *hub, int port1, status, change, NULL); } +static void hub_resubmit_irq_urb(struct usb_hub *hub) +{ + unsigned long flags; + int status; + + spin_lock_irqsave(&hub->irq_urb_lock, flags); + + if (hub->quiescing) { + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); + return; + } + + status = usb_submit_urb(hub->urb, GFP_ATOMIC); + if (status && status != -ENODEV && status != -EPERM && + status != -ESHUTDOWN) { + dev_err(hub->intfdev, "resubmit --> %d\n", status); + mod_timer(&hub->irq_urb_retry, jiffies + HZ); + } + + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); +} + +static void hub_retry_irq_urb(struct timer_list *t) +{ + struct usb_hub *hub = from_timer(hub, t, irq_urb_retry); + + hub_resubmit_irq_urb(hub); +} + + static void kick_hub_wq(struct usb_hub *hub) { struct usb_interface *intf; @@ -709,12 +741,7 @@ static void hub_irq(struct urb *urb) kick_hub_wq(hub); resubmit: - if (hub->quiescing) - return; - - status = usb_submit_urb(hub->urb, GFP_ATOMIC); - if (status != 0 && status != -ENODEV && status != -EPERM) - dev_err(hub->intfdev, "resubmit --> %d\n", status); + hub_resubmit_irq_urb(hub); } /* USB 2.0 spec Section 11.24.2.3 */ @@ -1112,6 +1139,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) USB_PORT_FEAT_ENABLE); } + /* Make sure a warm-reset request is handled by port_event */ + if (type == HUB_RESUME && + hub_port_warm_reset_required(hub, port1, portstatus)) + set_bit(port1, hub->event_bits); + /* * Add debounce if USB3 link is in polling/link training state. * Link will automatically transition to Enabled state after @@ -1264,10 +1296,13 @@ enum hub_quiescing_type { static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) { struct usb_device *hdev = hub->hdev; + unsigned long flags; int i; /* hub_wq and related activity won't re-trigger */ + spin_lock_irqsave(&hub->irq_urb_lock, flags); hub->quiescing = 1; + spin_unlock_irqrestore(&hub->irq_urb_lock, flags); if (type != HUB_SUSPEND) { /* Disconnect all the children */ @@ -1278,6 +1313,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) } /* Stop hub_wq and related activity */ + del_timer_sync(&hub->irq_urb_retry); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work_sync(&hub->leds); @@ -1810,6 +1846,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); INIT_WORK(&hub->events, hub_event); + spin_lock_init(&hub->irq_urb_lock); + timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0); usb_get_intf(intf); usb_get_dev(hdev); @@ -3220,8 +3258,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) } /* disable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); if (usb_disable_ltm(udev)) { dev_err(&udev->dev, "Failed to disable LTM before suspend\n"); @@ -3259,8 +3296,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_enable_ltm(udev); err_ltm: /* Try to enable USB2 hardware LPM again */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); if (udev->do_remote_wakeup) (void) usb_disable_remote_wakeup(udev); @@ -3543,8 +3579,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) hub_port_logical_disconnect(hub, port1); } else { /* Try to enable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); /* Try to enable USB3 LTM */ usb_enable_ltm(udev); @@ -4435,7 +4470,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { udev->usb2_hw_lpm_allowed = 1; - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); } } @@ -5649,8 +5684,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) /* Disable USB2 hardware LPM. * It will be re-enabled by the enumeration process. */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); + usb_disable_usb2_hardware_lpm(udev); /* Disable LPM while we reset the device and reinstall the alt settings. * Device-initiated LPM, and system exit latency settings are cleared @@ -5753,7 +5787,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) done: /* Now that the alt settings are re-installed, enable LTM and LPM. */ - usb_set_usb2_hardware_lpm(udev, 1); + usb_enable_usb2_hardware_lpm(udev); usb_unlocked_enable_lpm(udev); usb_enable_ltm(udev); usb_release_bos_descriptor(udev); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 4accfb63f7dc..a9e24e4b8df1 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -69,6 +69,8 @@ struct usb_hub { struct delayed_work leds; struct delayed_work init_work; struct work_struct events; + spinlock_t irq_urb_lock; + struct timer_list irq_urb_retry; struct usb_port **ports; }; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index bfa5eda0cc26..82239f27c4cc 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1243,8 +1243,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev->actconfig->interface[i] = NULL; } - if (dev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(dev, 0); + usb_disable_usb2_hardware_lpm(dev); usb_unlocked_disable_lpm(dev); usb_disable_ltm(dev); @@ -2007,6 +2006,13 @@ free_interfaces: for (i = 0; i < nintf; ++i) { struct usb_interface *intf = cp->interface[i]; + if (intf->dev.of_node && + !of_device_is_available(intf->dev.of_node)) { + dev_info(&dev->dev, "skipping disabled interface %d\n", + intf->cur_altsetting->desc.bInterfaceNumber); + continue; + } + dev_dbg(&dev->dev, "adding %s (config #%d, interface %d)\n", dev_name(&intf->dev), configuration, diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 38b2c776c4b4..7580493b867a 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -123,6 +123,34 @@ int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub) } EXPORT_SYMBOL_GPL(usb_phy_roothub_exit); +int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub, + enum phy_mode mode) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_set_mode(roothub_entry->phy, mode); + if (err) + goto err_out; + } + + return 0; + +err_out: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_power_off(roothub_entry->phy); + + return err; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode); + int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub) { struct usb_phy_roothub *roothub_entry; diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h index 88a3c037e9df..dad564e2d2d4 100644 --- a/drivers/usb/core/phy.h +++ b/drivers/usb/core/phy.h @@ -16,6 +16,8 @@ struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev); int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub); int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); +int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub, + enum phy_mode mode); int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index ea18284dfa9a..7e88fdfe3cf5 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -528,7 +528,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, if (!ret) { udev->usb2_hw_lpm_allowed = value; - ret = usb_set_usb2_hardware_lpm(udev, value); + if (value) + ret = usb_enable_usb2_hardware_lpm(udev); + else + ret = usb_disable_usb2_hardware_lpm(udev); } usb_unlock_device(udev); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index f51750bcd152..0eab79f82ce4 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -70,9 +70,8 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { struct urb *urb; - urb = kmalloc(sizeof(struct urb) + - iso_packets * sizeof(struct usb_iso_packet_descriptor), - mem_flags); + urb = kmalloc(struct_size(urb, iso_frame_desc, iso_packets), + mem_flags); if (!urb) return NULL; usb_init_urb(urb); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4ebfbd737905..7fcb9f782931 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -46,8 +46,7 @@ #include <linux/mm.h> #include <linux/dma-mapping.h> -#include "usb.h" - +#include "hub.h" const char *usbcore_name = "usbcore"; @@ -65,8 +64,8 @@ int usb_disabled(void) EXPORT_SYMBOL_GPL(usb_disabled); #ifdef CONFIG_PM -static int usb_autosuspend_delay = 2; /* Default delay value, - * in seconds */ +/* Default delay value, in seconds */ +static int usb_autosuspend_delay = CONFIG_USB_AUTOSUSPEND_DELAY; module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); @@ -536,6 +535,27 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus) return hcd->wireless; } +static bool usb_dev_authorized(struct usb_device *dev, struct usb_hcd *hcd) +{ + struct usb_hub *hub; + + if (!dev->parent) + return true; /* Root hub always ok [and always wired] */ + + switch (hcd->dev_policy) { + case USB_DEVICE_AUTHORIZE_NONE: + default: + return false; + + case USB_DEVICE_AUTHORIZE_ALL: + return true; + + case USB_DEVICE_AUTHORIZE_INTERNAL: + hub = usb_hub_to_struct_hub(dev->parent); + return hub->ports[dev->portnum - 1]->connect_type == + USB_PORT_CONNECT_TYPE_HARD_WIRED; + } +} /** * usb_alloc_dev - usb device constructor (usbcore-internal) @@ -663,12 +683,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->connect_time = jiffies; dev->active_duration = -jiffies; #endif - if (root_hub) /* Root hub always ok [and always wired] */ - dev->authorized = 1; - else { - dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd); + + dev->authorized = usb_dev_authorized(dev, usb_hcd); + if (!root_hub) dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0; - } + return dev; } EXPORT_SYMBOL_GPL(usb_alloc_dev); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 546a2219454b..d95a5358f73d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -92,7 +92,8 @@ extern int usb_remote_wakeup(struct usb_device *dev); extern int usb_runtime_suspend(struct device *dev); extern int usb_runtime_resume(struct device *dev); extern int usb_runtime_idle(struct device *dev); -extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable); +extern int usb_enable_usb2_hardware_lpm(struct usb_device *udev); +extern int usb_disable_usb2_hardware_lpm(struct usb_device *udev); #else @@ -112,7 +113,12 @@ static inline int usb_autoresume_device(struct usb_device *udev) return 0; } -static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) +static inline int usb_enable_usb2_hardware_lpm(struct usb_device *udev) +{ + return 0; +} + +static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev) { return 0; } diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index b6a495e98fd8..68d095ae2865 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_DWC2 tristate "DesignWare USB2 DRD Core Support" depends on HAS_DMA diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 55ef3cc2701b..6812a8a3a98b 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -768,22 +768,13 @@ static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) return desc_size; } -/* - * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. - * @hs_ep: The endpoint - * @dma_buff: DMA address to use - * @len: Length of the transfer - * - * This function will iterate over descriptor chain and fill its entries - * with corresponding information based on transfer data. - */ -static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, +static void dwc2_gadget_fill_nonisoc_xfer_ddma_one(struct dwc2_hsotg_ep *hs_ep, + struct dwc2_dma_desc **desc, dma_addr_t dma_buff, - unsigned int len) + unsigned int len, + bool true_last) { - struct dwc2_hsotg *hsotg = hs_ep->parent; int dir_in = hs_ep->dir_in; - struct dwc2_dma_desc *desc = hs_ep->desc_list; u32 mps = hs_ep->ep.maxpacket; u32 maxsize = 0; u32 offset = 0; @@ -798,39 +789,77 @@ static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, hs_ep->desc_count = 1; for (i = 0; i < hs_ep->desc_count; ++i) { - desc->status = 0; - desc->status |= (DEV_DMA_BUFF_STS_HBUSY + (*desc)->status = 0; + (*desc)->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT); if (len > maxsize) { if (!hs_ep->index && !dir_in) - desc->status |= (DEV_DMA_L | DEV_DMA_IOC); + (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); - desc->status |= (maxsize << - DEV_DMA_NBYTES_SHIFT & mask); - desc->buf = dma_buff + offset; + (*desc)->status |= + maxsize << DEV_DMA_NBYTES_SHIFT & mask; + (*desc)->buf = dma_buff + offset; len -= maxsize; offset += maxsize; } else { - desc->status |= (DEV_DMA_L | DEV_DMA_IOC); + if (true_last) + (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); if (dir_in) - desc->status |= (len % mps) ? DEV_DMA_SHORT : - ((hs_ep->send_zlp) ? DEV_DMA_SHORT : 0); - if (len > maxsize) - dev_err(hsotg->dev, "wrong len %d\n", len); + (*desc)->status |= (len % mps) ? DEV_DMA_SHORT : + ((hs_ep->send_zlp && true_last) ? + DEV_DMA_SHORT : 0); - desc->status |= + (*desc)->status |= len << DEV_DMA_NBYTES_SHIFT & mask; - desc->buf = dma_buff + offset; + (*desc)->buf = dma_buff + offset; } - desc->status &= ~DEV_DMA_BUFF_STS_MASK; - desc->status |= (DEV_DMA_BUFF_STS_HREADY + (*desc)->status &= ~DEV_DMA_BUFF_STS_MASK; + (*desc)->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); - desc++; + (*desc)++; + } +} + +/* + * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. + * @hs_ep: The endpoint + * @ureq: Request to transfer + * @offset: offset in bytes + * @len: Length of the transfer + * + * This function will iterate over descriptor chain and fill its entries + * with corresponding information based on transfer data. + */ +static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, + struct usb_request *ureq, + unsigned int offset, + unsigned int len) +{ + struct dwc2_dma_desc *desc = hs_ep->desc_list; + struct scatterlist *sg; + int i; + u8 desc_count = 0; + + /* non-DMA sg buffer */ + if (!ureq->num_sgs) { + dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, + ureq->dma + offset, len, true); + return; } + + /* DMA sg buffer */ + for_each_sg(ureq->sg, sg, ureq->num_sgs, i) { + dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, + sg_dma_address(sg) + sg->offset, sg_dma_len(sg), + sg_is_last(sg)); + desc_count += hs_ep->desc_count; + } + + hs_ep->desc_count = desc_count; } /* @@ -944,7 +973,13 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) hs_ep->next_desc = 0; list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { - ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, + dma_addr_t dma_addr = hs_req->req.dma; + + if (hs_req->req.num_sgs) { + WARN_ON(hs_req->req.num_sgs > 1); + dma_addr = sg_dma_address(hs_req->req.sg); + } + ret = dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, hs_req->req.length); if (ret) break; @@ -1100,7 +1135,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, offset = ureq->actual; /* Fill DDMA chain entries */ - dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset, + dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq, offset, length); /* write descriptor chain address to control register */ @@ -1399,7 +1434,13 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, */ if (using_desc_dma(hs) && hs_ep->isochronous) { if (hs_ep->target_frame != TARGET_FRAME_INITIAL) { - dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma, + dma_addr_t dma_addr = hs_req->req.dma; + + if (hs_req->req.num_sgs) { + WARN_ON(hs_req->req.num_sgs > 1); + dma_addr = sg_dma_address(hs_req->req.sg); + } + dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, hs_req->req.length); } return 0; @@ -1987,13 +2028,12 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", index); if (using_desc_dma(hsotg)) { - /* Not specific buffer needed for ep0 ZLP */ - dma_addr_t dma = hs_ep->desc_list_dma; - if (!index) dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); - dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0); + /* Not specific buffer needed for ep0 ZLP */ + dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &hs_ep->desc_list, + hs_ep->desc_list_dma, 0, true); } else { dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | DXEPTSIZ_XFERSIZE(0), @@ -4005,6 +4045,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, ret = -ENOMEM; goto error1; } + epctrl &= ~(DXEPCTL_TXFNUM_LIMIT << DXEPCTL_TXFNUM_SHIFT); hsotg->fifo_map |= 1 << fifo_index; epctrl |= DXEPCTL_TXFNUM(fifo_index); hs_ep->fifo_index = fifo_index; @@ -4385,6 +4426,7 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, hsotg->enabled = 0; spin_unlock_irqrestore(&hsotg->lock, flags); + gadget->sg_supported = using_desc_dma(hsotg); dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); return 0; diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index dd82fa516f3f..3f087962f498 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3981,10 +3981,8 @@ static struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags) { struct dwc2_hcd_urb *urb; - u32 size = sizeof(*urb) + iso_desc_count * - sizeof(struct dwc2_hcd_iso_packet_desc); - urb = kzalloc(size, mem_flags); + urb = kzalloc(struct_size(urb, iso_descs, iso_desc_count), mem_flags); if (urb) urb->packet_count = iso_desc_count; return urb; diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 1a0404fda596..2b1494460d0c 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" depends on (USB || USB_GADGET) && HAS_DMA @@ -86,11 +88,11 @@ config USB_DWC3_HAPS platform, please say 'Y' or 'M' here. config USB_DWC3_KEYSTONE - tristate "Texas Instruments Keystone2 Platforms" - depends on ARCH_KEYSTONE || COMPILE_TEST + tristate "Texas Instruments Keystone2/AM654 Platforms" + depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST default USB_DWC3 help - Support of USB2/3 functionality in TI Keystone2 platforms. + Support of USB2/3 functionality in TI Keystone2 and AM654 platforms. Say 'Y' or 'M' here if you have one such device config USB_DWC3_OF_SIMPLE diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index df876418cb78..1528d395b156 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -692,7 +692,6 @@ struct dwc3_ep { #define DWC3_EP_WEDGE BIT(2) #define DWC3_EP_TRANSFER_STARTED BIT(3) #define DWC3_EP_PENDING_REQUEST BIT(5) -#define DWC3_EP_END_TRANSFER_PENDING BIT(7) /* This last one is specific to EP0 */ #define DWC3_EP0_DIR_IN BIT(31) @@ -863,6 +862,7 @@ struct dwc3_hwparams { * @num_pending_sgs: counter to pending sgs * @num_queued_sgs: counter to the number of sgs which already got queued * @remaining: amount of data remaining + * @status: internal dwc3 request status tracking * @epnum: endpoint number to which this request refers * @trb: pointer to struct dwc3_trb * @trb_dma: DMA address of @trb @@ -871,7 +871,6 @@ struct dwc3_hwparams { * or unaligned OUT) * @direction: IN or OUT direction flag * @mapped: true when request has been dma-mapped - * @started: request is started */ struct dwc3_request { struct usb_request request; @@ -883,6 +882,14 @@ struct dwc3_request { unsigned num_pending_sgs; unsigned int num_queued_sgs; unsigned remaining; + + unsigned int status; +#define DWC3_REQUEST_STATUS_QUEUED 0 +#define DWC3_REQUEST_STATUS_STARTED 1 +#define DWC3_REQUEST_STATUS_CANCELLED 2 +#define DWC3_REQUEST_STATUS_COMPLETED 3 +#define DWC3_REQUEST_STATUS_UNKNOWN -1 + u8 epnum; struct dwc3_trb *trb; dma_addr_t trb_dma; @@ -892,7 +899,6 @@ struct dwc3_request { unsigned needs_extra_trb:1; unsigned direction:1; unsigned mapped:1; - unsigned started:1; }; /* diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 4f75ab3505b7..6759a7efd8d5 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -193,65 +193,69 @@ static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) * dwc3_gadget_event_string - returns event name * @event: the event code */ -static inline const char * -dwc3_gadget_event_string(char *str, const struct dwc3_event_devt *event) +static inline const char *dwc3_gadget_event_string(char *str, size_t size, + const struct dwc3_event_devt *event) { enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK; switch (event->type) { case DWC3_DEVICE_EVENT_DISCONNECT: - sprintf(str, "Disconnect: [%s]", + snprintf(str, size, "Disconnect: [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_RESET: - sprintf(str, "Reset [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "Reset [%s]", + dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_CONNECT_DONE: - sprintf(str, "Connection Done [%s]", + snprintf(str, size, "Connection Done [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: - sprintf(str, "Link Change [%s]", + snprintf(str, size, "Link Change [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_WAKEUP: - sprintf(str, "WakeUp [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "WakeUp [%s]", + dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_EOPF: - sprintf(str, "End-Of-Frame [%s]", + snprintf(str, size, "End-Of-Frame [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_SOF: - sprintf(str, "Start-Of-Frame [%s]", + snprintf(str, size, "Start-Of-Frame [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - sprintf(str, "Erratic Error [%s]", + snprintf(str, size, "Erratic Error [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_CMD_CMPL: - sprintf(str, "Command Complete [%s]", + snprintf(str, size, "Command Complete [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_OVERFLOW: - sprintf(str, "Overflow [%s]", dwc3_gadget_link_string(state)); + snprintf(str, size, "Overflow [%s]", + dwc3_gadget_link_string(state)); break; default: - sprintf(str, "UNKNOWN"); + snprintf(str, size, "UNKNOWN"); } return str; } -static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str) +static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str, + size_t size) { switch (t & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: - sprintf(str, "Get Interface Status(Intf = %d, Length = %d)", - i, l); + snprintf(str, size, "Get Interface Status(Intf = %d, Length = %d)", + i, l); break; case USB_RECIP_ENDPOINT: - sprintf(str, "Get Endpoint Status(ep%d%s)", + snprintf(str, size, "Get Endpoint Status(ep%d%s)", i & ~USB_DIR_IN, i & USB_DIR_IN ? "in" : "out"); break; @@ -259,11 +263,11 @@ static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str) } static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, - __u16 i, char *str) + __u16 i, char *str, size_t size) { switch (t & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - sprintf(str, "%s Device Feature(%s%s)", + snprintf(str, size, "%s Device Feature(%s%s)", b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", ({char *s; switch (v) { @@ -311,13 +315,13 @@ static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, } s; }) : ""); break; case USB_RECIP_INTERFACE: - sprintf(str, "%s Interface Feature(%s)", + snprintf(str, size, "%s Interface Feature(%s)", b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", v == USB_INTRF_FUNC_SUSPEND ? "Function Suspend" : "UNKNOWN"); break; case USB_RECIP_ENDPOINT: - sprintf(str, "%s Endpoint Feature(%s ep%d%s)", + snprintf(str, size, "%s Endpoint Feature(%s ep%d%s)", b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", v == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN", i & ~USB_DIR_IN, @@ -326,15 +330,15 @@ static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v, } } -static inline void dwc3_decode_set_address(__u16 v, char *str) +static inline void dwc3_decode_set_address(__u16 v, char *str, size_t size) { - sprintf(str, "Set Address(Addr = %02x)", v); + snprintf(str, size, "Set Address(Addr = %02x)", v); } static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v, - __u16 i, __u16 l, char *str) + __u16 i, __u16 l, char *str, size_t size) { - sprintf(str, "%s %s Descriptor(Index = %d, Length = %d)", + snprintf(str, size, "%s %s Descriptor(Index = %d, Length = %d)", b == USB_REQ_GET_DESCRIPTOR ? "Get" : "Set", ({ char *s; switch (v >> 8) { @@ -393,87 +397,92 @@ static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v, } -static inline void dwc3_decode_get_configuration(__u16 l, char *str) +static inline void dwc3_decode_get_configuration(__u16 l, char *str, + size_t size) { - sprintf(str, "Get Configuration(Length = %d)", l); + snprintf(str, size, "Get Configuration(Length = %d)", l); } -static inline void dwc3_decode_set_configuration(__u8 v, char *str) +static inline void dwc3_decode_set_configuration(__u8 v, char *str, size_t size) { - sprintf(str, "Set Configuration(Config = %d)", v); + snprintf(str, size, "Set Configuration(Config = %d)", v); } -static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str) +static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str, + size_t size) { - sprintf(str, "Get Interface(Intf = %d, Length = %d)", i, l); + snprintf(str, size, "Get Interface(Intf = %d, Length = %d)", i, l); } -static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str) +static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str, size_t size) { - sprintf(str, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v); + snprintf(str, size, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v); } -static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str) +static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str, + size_t size) { - sprintf(str, "Synch Frame(Endpoint = %d, Length = %d)", i, l); + snprintf(str, size, "Synch Frame(Endpoint = %d, Length = %d)", i, l); } -static inline void dwc3_decode_set_sel(__u16 l, char *str) +static inline void dwc3_decode_set_sel(__u16 l, char *str, size_t size) { - sprintf(str, "Set SEL(Length = %d)", l); + snprintf(str, size, "Set SEL(Length = %d)", l); } -static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str) +static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str, size_t size) { - sprintf(str, "Set Isochronous Delay(Delay = %d ns)", v); + snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", v); } /** * dwc3_decode_ctrl - returns a string represetion of ctrl request */ -static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType, - __u8 bRequest, __u16 wValue, __u16 wIndex, __u16 wLength) +static inline const char *dwc3_decode_ctrl(char *str, size_t size, + __u8 bRequestType, __u8 bRequest, __u16 wValue, __u16 wIndex, + __u16 wLength) { switch (bRequest) { case USB_REQ_GET_STATUS: - dwc3_decode_get_status(bRequestType, wIndex, wLength, str); + dwc3_decode_get_status(bRequestType, wIndex, wLength, str, + size); break; case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: dwc3_decode_set_clear_feature(bRequestType, bRequest, wValue, - wIndex, str); + wIndex, str, size); break; case USB_REQ_SET_ADDRESS: - dwc3_decode_set_address(wValue, str); + dwc3_decode_set_address(wValue, str, size); break; case USB_REQ_GET_DESCRIPTOR: case USB_REQ_SET_DESCRIPTOR: dwc3_decode_get_set_descriptor(bRequestType, bRequest, wValue, - wIndex, wLength, str); + wIndex, wLength, str, size); break; case USB_REQ_GET_CONFIGURATION: - dwc3_decode_get_configuration(wLength, str); + dwc3_decode_get_configuration(wLength, str, size); break; case USB_REQ_SET_CONFIGURATION: - dwc3_decode_set_configuration(wValue, str); + dwc3_decode_set_configuration(wValue, str, size); break; case USB_REQ_GET_INTERFACE: - dwc3_decode_get_intf(wIndex, wLength, str); + dwc3_decode_get_intf(wIndex, wLength, str, size); break; case USB_REQ_SET_INTERFACE: - dwc3_decode_set_intf(wValue, wIndex, str); + dwc3_decode_set_intf(wValue, wIndex, str, size); break; case USB_REQ_SYNCH_FRAME: - dwc3_decode_synch_frame(wIndex, wLength, str); + dwc3_decode_synch_frame(wIndex, wLength, str, size); break; case USB_REQ_SET_SEL: - dwc3_decode_set_sel(wLength, str); + dwc3_decode_set_sel(wLength, str, size); break; case USB_REQ_SET_ISOCH_DELAY: - dwc3_decode_set_isoch_delay(wValue, str); + dwc3_decode_set_isoch_delay(wValue, str, size); break; default: - sprintf(str, "%02x %02x %02x %02x %02x %02x %02x %02x", + snprintf(str, size, "%02x %02x %02x %02x %02x %02x %02x %02x", bRequestType, bRequest, cpu_to_le16(wValue) & 0xff, cpu_to_le16(wValue) >> 8, @@ -490,16 +499,15 @@ static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType, * dwc3_ep_event_string - returns event name * @event: then event code */ -static inline const char * -dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, - u32 ep0state) +static inline const char *dwc3_ep_event_string(char *str, size_t size, + const struct dwc3_event_depevt *event, u32 ep0state) { u8 epnum = event->endpoint_number; size_t len; int status; int ret; - ret = sprintf(str, "ep%d%s: ", epnum >> 1, + ret = snprintf(str, size, "ep%d%s: ", epnum >> 1, (epnum & 1) ? "in" : "out"); if (ret < 0) return "UNKNOWN"; @@ -509,7 +517,7 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, switch (event->endpoint_event) { case DWC3_DEPEVT_XFERCOMPLETE: len = strlen(str); - sprintf(str + len, "Transfer Complete (%c%c%c)", + snprintf(str + len, size - len, "Transfer Complete (%c%c%c)", status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_IOC ? 'I' : 'i', status & DEPEVT_STATUS_LST ? 'L' : 'l'); @@ -517,12 +525,13 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, len = strlen(str); if (epnum <= 1) - sprintf(str + len, " [%s]", dwc3_ep0_state_string(ep0state)); + snprintf(str + len, size - len, " [%s]", + dwc3_ep0_state_string(ep0state)); break; case DWC3_DEPEVT_XFERINPROGRESS: len = strlen(str); - sprintf(str + len, "Transfer In Progress [%d] (%c%c%c)", + snprintf(str + len, size - len, "Transfer In Progress [%d] (%c%c%c)", event->parameters, status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_IOC ? 'I' : 'i', @@ -531,47 +540,51 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event, case DWC3_DEPEVT_XFERNOTREADY: len = strlen(str); - sprintf(str + len, "Transfer Not Ready [%d]%s", + snprintf(str + len, size - len, "Transfer Not Ready [%d]%s", event->parameters, status & DEPEVT_STATUS_TRANSFER_ACTIVE ? " (Active)" : " (Not Active)"); + len = strlen(str); + /* Control Endpoints */ if (epnum <= 1) { int phase = DEPEVT_STATUS_CONTROL_PHASE(event->status); switch (phase) { case DEPEVT_STATUS_CONTROL_DATA: - strcat(str, " [Data Phase]"); + snprintf(str + ret, size - ret, + " [Data Phase]"); break; case DEPEVT_STATUS_CONTROL_STATUS: - strcat(str, " [Status Phase]"); + snprintf(str + ret, size - ret, + " [Status Phase]"); } } break; case DWC3_DEPEVT_RXTXFIFOEVT: - strcat(str, "FIFO"); + snprintf(str + ret, size - ret, "FIFO"); break; case DWC3_DEPEVT_STREAMEVT: status = event->status; switch (status) { case DEPEVT_STREAMEVT_FOUND: - sprintf(str + ret, " Stream %d Found", + snprintf(str + ret, size - ret, " Stream %d Found", event->parameters); break; case DEPEVT_STREAMEVT_NOTFOUND: default: - strcat(str, " Stream Not Found"); + snprintf(str + ret, size - ret, " Stream Not Found"); break; } break; case DWC3_DEPEVT_EPCMDCMPLT: - strcat(str, "Endpoint Command Complete"); + snprintf(str + ret, size - ret, "Endpoint Command Complete"); break; default: - sprintf(str, "UNKNOWN"); + snprintf(str, size, "UNKNOWN"); } return str; @@ -611,14 +624,15 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) } } -static inline const char *dwc3_decode_event(char *str, u32 event, u32 ep0state) +static inline const char *dwc3_decode_event(char *str, size_t size, u32 event, + u32 ep0state) { const union dwc3_event evt = (union dwc3_event) event; if (evt.type.is_devspec) - return dwc3_gadget_event_string(str, &evt.devt); + return dwc3_gadget_event_string(str, size, &evt.devt); else - return dwc3_ep_event_string(str, &evt.depevt, ep0state); + return dwc3_ep_event_string(str, size, &evt.depevt, ep0state); } static inline const char *dwc3_ep_cmd_status_string(int status) diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 869725d15c74..726100d1ac0d 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -457,8 +457,13 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) * This device property is for kernel internal use only and * is expected to be set by the glue code. */ - if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) - return extcon_get_extcon_dev(name); + if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) { + edev = extcon_get_extcon_dev(name); + if (!edev) + return ERR_PTR(-EPROBE_DEFER); + + return edev; + } np_phy = of_parse_phandle(dev->of_node, "phys", 0); np_conn = of_graph_get_remote_node(np_phy, -1, -1); diff --git a/drivers/usb/dwc3/dwc3-haps.c b/drivers/usb/dwc3/dwc3-haps.c index 02d57d98ef9b..3cecbf169452 100644 --- a/drivers/usb/dwc3/dwc3-haps.c +++ b/drivers/usb/dwc3/dwc3-haps.c @@ -106,6 +106,15 @@ static const struct pci_device_id dwc3_haps_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), + /* + * i.MX6QP and i.MX7D platform use a PCIe controller with the + * same VID and PID as this USB controller. The system may + * incorrectly match this driver to that PCIe controller. To + * workaround this, specifically use class type USB to prevent + * incorrect driver matching. + */ + .class = (PCI_CLASS_SERIAL_USB << 8), + .class_mask = 0xffff00, }, { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 193a9a88222a..cbee5fb9b9fb 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -106,6 +106,10 @@ static int kdwc3_probe(struct platform_device *pdev) goto err_irq; } + /* IRQ processing not required currently for AM65 */ + if (of_device_is_compatible(node, "ti,am654-dwc3")) + goto skip_irq; + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "missing irq\n"); @@ -123,6 +127,7 @@ static int kdwc3_probe(struct platform_device *pdev) kdwc3_enable_irqs(kdwc); +skip_irq: error = of_platform_populate(node, NULL, NULL, dev); if (error) { dev_err(&pdev->dev, "failed to create dwc3 core\n"); @@ -152,8 +157,11 @@ static int kdwc3_remove_core(struct device *dev, void *c) static int kdwc3_remove(struct platform_device *pdev) { struct dwc3_keystone *kdwc = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + if (!of_device_is_compatible(node, "ti,am654-dwc3")) + kdwc3_disable_irqs(kdwc); - kdwc3_disable_irqs(kdwc); device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core); pm_runtime_put_sync(kdwc->dev); pm_runtime_disable(kdwc->dev); @@ -165,6 +173,7 @@ static int kdwc3_remove(struct platform_device *pdev) static const struct of_device_id kdwc3_of_match[] = { { .compatible = "ti,keystone-dwc3", }, + { .compatible = "ti,am654-dwc3" }, {}, }; MODULE_DEVICE_TABLE(of, kdwc3_of_match); diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index a6d0203e40b6..184df4daa590 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -595,6 +595,7 @@ static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = { static const struct of_device_id dwc3_qcom_of_match[] = { { .compatible = "qcom,dwc3" }, { .compatible = "qcom,msm8996-dwc3" }, + { .compatible = "qcom,msm8998-dwc3" }, { .compatible = "qcom,sdm845-dwc3" }, { } }; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6c9b76bcc2e1..e293400cc6e9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -174,7 +174,6 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, { struct dwc3 *dwc = dep->dwc; - req->started = false; list_del(&req->list); req->remaining = 0; req->needs_extra_trb = false; @@ -209,6 +208,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, struct dwc3 *dwc = dep->dwc; dwc3_gadget_del_and_unmap_request(dep, req, status); + req->status = DWC3_REQUEST_STATUS_COMPLETED; spin_unlock(&dwc->lock); usb_gadget_giveback_request(&dep->endpoint, &req->request); @@ -384,19 +384,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status); - if (ret == 0) { - switch (DWC3_DEPCMD_CMD(cmd)) { - case DWC3_DEPCMD_STARTTRANSFER: - dep->flags |= DWC3_EP_TRANSFER_STARTED; - dwc3_gadget_ep_get_transfer_index(dep); - break; - case DWC3_DEPCMD_ENDTRANSFER: - dep->flags &= ~DWC3_EP_TRANSFER_STARTED; - break; - default: - /* nothing */ - break; - } + if (ret == 0 && DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { + dep->flags |= DWC3_EP_TRANSFER_STARTED; + dwc3_gadget_ep_get_transfer_index(dep); } if (saved_config) { @@ -642,7 +632,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) dep->type = usb_endpoint_type(desc); dep->flags |= DWC3_EP_ENABLED; - dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg |= DWC3_DALEPENA_EP(dep->number); @@ -698,12 +687,13 @@ out: return 0; } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force); +static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, + bool interrupt); static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, false); /* - giveback all requests to gadget driver */ while (!list_empty(&dep->started_list)) { @@ -748,7 +738,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dep->stream_capable = false; dep->type = 0; - dep->flags &= DWC3_EP_END_TRANSFER_PENDING; + dep->flags = 0; /* Clear out the ep descriptors for non-ep0 */ if (dep->number > 1) { @@ -847,6 +837,7 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep, req->direction = dep->direction; req->epnum = dep->number; req->dep = dep; + req->status = DWC3_REQUEST_STATUS_UNKNOWN; trace_dwc3_alloc_request(req); @@ -1360,7 +1351,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) * to wait for the next XferNotReady to test the command again */ if (cmd_status == 0) { - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, true); return 0; } } @@ -1435,6 +1426,11 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) &req->request, req->dep->name)) return -EINVAL; + if (WARN(req->status < DWC3_REQUEST_STATUS_COMPLETED, + "%s: request %pK already in flight\n", + dep->name, &req->request)) + return -EINVAL; + pm_runtime_get(dwc->dev); req->request.actual = 0; @@ -1443,6 +1439,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) trace_dwc3_ep_queue(req); list_add_tail(&req->list, &dep->pending_list); + req->status = DWC3_REQUEST_STATUS_QUEUED; /* * NOTICE: Isochronous endpoints should NEVER be prestarted. We must @@ -1506,6 +1503,8 @@ static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *r trb->ctrl &= ~DWC3_TRB_CTRL_HWO; dwc3_ep_inc_deq(dep); } + + req->num_trbs = 0; } static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep) @@ -1547,13 +1546,16 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, } if (r == req) { /* wait until it is processed */ - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, true); if (!r->trb) goto out0; dwc3_gadget_move_cancelled_request(req); - goto out0; + if (dep->flags & DWC3_EP_TRANSFER_STARTED) + goto out0; + else + goto out1; } dev_err(dwc->dev, "request %pK was not queued to %s\n", request, ep->name); @@ -1561,6 +1563,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, goto out0; } +out1: dwc3_gadget_giveback(dep, req, -ECONNRESET); out0: @@ -2500,7 +2503,7 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, dwc3_gadget_ep_cleanup_completed_requests(dep, event, status); if (stop) { - dwc3_stop_active_transfer(dep, true); + dwc3_stop_active_transfer(dep, true, true); dep->flags = DWC3_EP_ENABLED; } @@ -2547,7 +2550,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dep = dwc->eps[epnum]; if (!(dep->flags & DWC3_EP_ENABLED)) { - if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) + if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) return; /* Handle only EPCMDCMPLT when EP disabled */ @@ -2571,7 +2574,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, cmd = DEPEVT_PARAMETER_CMD(event->parameters); if (cmd == DWC3_DEPCMD_ENDTRANSFER) { - dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; + dep->flags &= ~DWC3_EP_TRANSFER_STARTED; dwc3_gadget_ep_cleanup_cancelled_requests(dep); } break; @@ -2621,15 +2624,15 @@ static void dwc3_reset_gadget(struct dwc3 *dwc) } } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force) +static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, + bool interrupt) { struct dwc3 *dwc = dep->dwc; struct dwc3_gadget_ep_cmd_params params; u32 cmd; int ret; - if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) || - !dep->resource_index) + if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) return; /* @@ -2665,17 +2668,15 @@ static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force) cmd = DWC3_DEPCMD_ENDTRANSFER; cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0; - cmd |= DWC3_DEPCMD_CMDIOC; + cmd |= interrupt ? DWC3_DEPCMD_CMDIOC : 0; cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); memset(¶ms, 0, sizeof(params)); ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); WARN_ON_ONCE(ret); dep->resource_index = 0; - if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) { - dep->flags |= DWC3_EP_END_TRANSFER_PENDING; + if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) udelay(100); - } } static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) @@ -3339,6 +3340,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err4; } + dwc3_gadget_set_speed(&dwc->gadget, dwc->maximum_speed); + return 0; err4: diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 023a473648eb..3ed738e86ea7 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -75,7 +75,7 @@ static inline void dwc3_gadget_move_started_request(struct dwc3_request *req) { struct dwc3_ep *dep = req->dep; - req->started = true; + req->status = DWC3_REQUEST_STATUS_STARTED; list_move_tail(&req->list, &dep->started_list); } @@ -90,7 +90,7 @@ static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req) { struct dwc3_ep *dep = req->dep; - req->started = false; + req->status = DWC3_REQUEST_STATUS_CANCELLED; list_move_tail(&req->list, &dep->cancelled_list); } diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index e97a00593dda..818a63da1a44 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -59,8 +59,8 @@ DECLARE_EVENT_CLASS(dwc3_log_event, __entry->ep0state = dwc->ep0state; ), TP_printk("event (%08x): %s", __entry->event, - dwc3_decode_event(__get_str(str), __entry->event, - __entry->ep0state)) + dwc3_decode_event(__get_str(str), DWC3_MSG_MAX, + __entry->event, __entry->ep0state)) ); DEFINE_EVENT(dwc3_log_event, dwc3_event, @@ -86,7 +86,8 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", dwc3_decode_ctrl(__get_str(str), __entry->bRequestType, + TP_printk("%s", dwc3_decode_ctrl(__get_str(str), DWC3_MSG_MAX, + __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) ) @@ -305,7 +306,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ep, __entry->trb_enqueue = dep->trb_enqueue; __entry->trb_dequeue = dep->trb_dequeue; ), - TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c:%c", + TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c", __get_str(name), __entry->maxpacket, __entry->maxpacket_limit, __entry->max_streams, __entry->maxburst, __entry->trb_enqueue, @@ -315,7 +316,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ep, __entry->flags & DWC3_EP_WEDGE ? 'W' : 'w', __entry->flags & DWC3_EP_TRANSFER_STARTED ? 'B' : 'b', __entry->flags & DWC3_EP_PENDING_REQUEST ? 'P' : 'p', - __entry->flags & DWC3_EP_END_TRANSFER_PENDING ? 'E' : 'e', __entry->direction ? '<' : '>' ) ); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 31cce7805eb2..ec189d7855a0 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Gadget support on a system involves # (a) a peripheral controller, and diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 71b15c65b90f..1eb4fa2e623f 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -67,9 +67,6 @@ struct usb_ep *usb_ep_autoconfig_ss( ) { struct usb_ep *ep; - u8 type; - - type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; if (gadget->ops->match_ep) { ep = gadget->ops->match_ep(gadget, desc, ep_comp); @@ -109,16 +106,6 @@ found_ep: desc->bEndpointAddress |= gadget->out_epnum; } - /* report (variable) full speed bulk maxpacket */ - if ((type == USB_ENDPOINT_XFER_BULK) && !ep_comp) { - int size = ep->maxpacket_limit; - - /* min() doesn't work on bitfields with gcc-3.5 */ - if (size > 64) - size = 64; - desc->wMaxPacketSize = cpu_to_le16(size); - } - ep->address = desc->bEndpointAddress; ep->desc = NULL; ep->comp_desc = NULL; @@ -152,9 +139,10 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss); * * On success, this returns an claimed usb_ep, and modifies the endpoint * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value - * is initialized as if the endpoint were used at full speed. To prevent - * the endpoint from being returned by a later autoconfig call, claims it - * by assigning ep->claimed to true. + * is initialized as if the endpoint were used at full speed. Because of + * that the users must consider adjusting the autoconfigured descriptor. + * To prevent the endpoint from being returned by a later autoconfig call, + * claims it by assigning ep->claimed to true. * * On failure, this returns a null endpoint descriptor. */ @@ -163,7 +151,26 @@ struct usb_ep *usb_ep_autoconfig( struct usb_endpoint_descriptor *desc ) { - return usb_ep_autoconfig_ss(gadget, desc, NULL); + struct usb_ep *ep; + u8 type; + + ep = usb_ep_autoconfig_ss(gadget, desc, NULL); + if (!ep) + return NULL; + + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + /* report (variable) full speed bulk maxpacket */ + if (type == USB_ENDPOINT_XFER_BULK) { + int size = ep->maxpacket_limit; + + /* min() doesn't work on bitfields with gcc-3.5 */ + if (size > 64) + size = 64; + desc->wMaxPacketSize = cpu_to_le16(size); + } + + return ep; } EXPORT_SYMBOL_GPL(usb_ep_autoconfig); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 1e5430438703..20413c276c61 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1082,6 +1082,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * condition with req->complete callback. */ usb_ep_dequeue(ep->ep, req); + wait_for_completion(&done); interrupted = ep->status < 0; } @@ -2843,12 +2844,18 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, struct usb_request *req; struct usb_ep *ep; u8 bEndpointAddress; + u16 wMaxPacketSize; /* * We back up bEndpointAddress because autoconfig overwrites * it with physical endpoint address. */ bEndpointAddress = ds->bEndpointAddress; + /* + * We back up wMaxPacketSize because autoconfig treats + * endpoint descriptors as if they were full speed. + */ + wMaxPacketSize = ds->wMaxPacketSize; pr_vdebug("autoconfig\n"); ep = usb_ep_autoconfig(func->gadget, ds); if (unlikely(!ep)) @@ -2869,6 +2876,11 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, */ if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) ds->bEndpointAddress = bEndpointAddress; + /* + * Restore wMaxPacketSize which was potentially + * overwritten by autoconfig. + */ + ds->wMaxPacketSize = wMaxPacketSize; } ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength); diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 2746a926a8d9..00d346965f7a 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -459,10 +459,10 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } else if (intf == uac1->as_in_intf) { uac1->as_in_alt = alt; - if (alt) - ret = u_audio_start_playback(&uac1->g_audio); - else - u_audio_stop_playback(&uac1->g_audio); + if (alt) + ret = u_audio_start_playback(&uac1->g_audio); + else + u_audio_stop_playback(&uac1->g_audio); } else { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); return -EINVAL; @@ -568,6 +568,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) goto fail; as_out_interface_alt_0_desc.bInterfaceNumber = status; as_out_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc.baInterfaceNr[0] = status; uac1->as_out_intf = status; uac1->as_out_alt = 0; @@ -576,6 +577,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) goto fail; as_in_interface_alt_0_desc.bInterfaceNumber = status; as_in_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc.baInterfaceNr[1] = status; uac1->as_in_intf = status; uac1->as_in_alt = 0; diff --git a/drivers/usb/gadget/function/u_ecm.h b/drivers/usb/gadget/function/u_ecm.h index 050aa672ee7f..098ece573a5e 100644 --- a/drivers/usb/gadget/function/u_ecm.h +++ b/drivers/usb/gadget/function/u_ecm.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_ECM_H diff --git a/drivers/usb/gadget/function/u_eem.h b/drivers/usb/gadget/function/u_eem.h index de3828d3e8f0..921386a375cf 100644 --- a/drivers/usb/gadget/function/u_eem.h +++ b/drivers/usb/gadget/function/u_eem.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_EEM_H diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index cd33cee4d78b..d8b92485b727 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __U_ETHER_CONFIGFS_H diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index c3aba4dfa958..f9b0cf67360d 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_FFS_H diff --git a/drivers/usb/gadget/function/u_gether.h b/drivers/usb/gadget/function/u_gether.h index 5b7e2eb90336..ce4f07626f96 100644 --- a/drivers/usb/gadget/function/u_gether.h +++ b/drivers/usb/gadget/function/u_gether.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_GETHER_H diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h index 2f5ca4bfa7ff..1594bfa312eb 100644 --- a/drivers/usb/gadget/function/u_hid.h +++ b/drivers/usb/gadget/function/u_hid.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_HID_H diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h index 5599aa5fc977..29bf006c0a13 100644 --- a/drivers/usb/gadget/function/u_midi.h +++ b/drivers/usb/gadget/function/u_midi.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_MIDI_H diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index 67324f983343..d483e45c0f77 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_NCM_H diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h index 6088ff744194..78797764f478 100644 --- a/drivers/usb/gadget/function/u_printer.h +++ b/drivers/usb/gadget/function/u_printer.h @@ -7,7 +7,7 @@ * Copyright (c) 2015 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_PRINTER_H diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index d65fb4ebac3c..1e148b76f339 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_RNDIS_H diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 29436f75bbe0..65f634ec7fc2 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -16,7 +16,6 @@ #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/interrupt.h> #include <linux/device.h> #include <linux/delay.h> #include <linux/tty.h> @@ -26,6 +25,7 @@ #include <linux/module.h> #include <linux/console.h> #include <linux/kthread.h> +#include <linux/workqueue.h> #include <linux/kfifo.h> #include "u_serial.h" @@ -110,7 +110,7 @@ struct gs_port { int read_allocated; struct list_head read_queue; unsigned n_read; - struct tasklet_struct push; + struct delayed_work push; struct list_head write_pool; int write_started; @@ -352,9 +352,10 @@ __acquires(&port->port_lock) * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) * can be buffered before the TTY layer's buffers (currently 64 KB). */ -static void gs_rx_push(unsigned long _port) +static void gs_rx_push(struct work_struct *work) { - struct gs_port *port = (void *)_port; + struct delayed_work *w = to_delayed_work(work); + struct gs_port *port = container_of(w, struct gs_port, push); struct tty_struct *tty; struct list_head *queue = &port->read_queue; bool disconnect = false; @@ -429,21 +430,13 @@ static void gs_rx_push(unsigned long _port) /* We want our data queue to become empty ASAP, keeping data * in the tty and ldisc (not here). If we couldn't push any - * this time around, there may be trouble unless there's an - * implicit tty_unthrottle() call on its way... + * this time around, RX may be starved, so wait until next jiffy. * - * REVISIT we should probably add a timer to keep the tasklet - * from starving ... but it's not clear that case ever happens. + * We may leave non-empty queue only when there is a tty, and + * either it is throttled or there is no more room in flip buffer. */ - if (!list_empty(queue) && tty) { - if (!tty_throttled(tty)) { - if (do_push) - tasklet_schedule(&port->push); - else - pr_warn("ttyGS%d: RX not scheduled?\n", - port->port_num); - } - } + if (!list_empty(queue) && !tty_throttled(tty)) + schedule_delayed_work(&port->push, 1); /* If we're still connected, refill the USB RX queue. */ if (!disconnect && port->port_usb) @@ -459,7 +452,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) /* Queue all received data until the tty layer is ready for it. */ spin_lock(&port->port_lock); list_add_tail(&req->list, &port->read_queue); - tasklet_schedule(&port->push); + schedule_delayed_work(&port->push, 0); spin_unlock(&port->port_lock); } @@ -854,8 +847,8 @@ static void gs_unthrottle(struct tty_struct *tty) * rts/cts, or other handshaking with the host, but if the * read queue backs up enough we'll be NAKing OUT packets. */ - tasklet_schedule(&port->push); pr_vdebug("ttyGS%d: unthrottle\n", port->port_num); + schedule_delayed_work(&port->push, 0); } spin_unlock_irqrestore(&port->port_lock, flags); } @@ -1159,7 +1152,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) init_waitqueue_head(&port->drain_wait); init_waitqueue_head(&port->close_wait); - tasklet_init(&port->push, gs_rx_push, (unsigned long) port); + INIT_DELAYED_WORK(&port->push, gs_rx_push); INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queue); @@ -1186,7 +1179,7 @@ static int gs_closed(struct gs_port *port) static void gserial_free_port(struct gs_port *port) { - tasklet_kill(&port->push); + cancel_delayed_work_sync(&port->push); /* wait for old opens to finish */ wait_event(port->close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h index 8362ee572e1e..82048791eb6e 100644 --- a/drivers/usb/gadget/function/u_uac2.h +++ b/drivers/usb/gadget/function/u_uac2.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_UAC2_H diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 5242d489e20a..16da49a2fcf2 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -7,7 +7,7 @@ * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef U_UVC_H diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 099d650082e5..1473d25ff17a 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -56,6 +56,8 @@ extern unsigned int uvc_gadget_trace_param; dev_dbg(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) #define uvcg_info(f, fmt, args...) \ dev_info(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) +#define uvcg_warn(f, fmt, args...) \ + dev_warn(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) #define uvcg_err(f, fmt, args...) \ dev_err(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index bc1e2af566c3..00fb58e50a15 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #include <linux/sort.h> @@ -1570,10 +1570,6 @@ uvcg_uncompressed_##cname##_store(struct config_item *item, \ if (ret) \ goto end; \ \ - if (num > 255) { \ - ret = -EINVAL; \ - goto end; \ - } \ u->desc.aname = num; \ ret = len; \ end: \ @@ -1767,10 +1763,6 @@ uvcg_mjpeg_##cname##_store(struct config_item *item, \ if (ret) \ goto end; \ \ - if (num > 255) { \ - ret = -EINVAL; \ - goto end; \ - } \ u->desc.aname = num; \ ret = len; \ end: \ diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h index 8549c0b27b9d..341391dbc81f 100644 --- a/drivers/usb/gadget/function/uvc_configfs.h +++ b/drivers/usb/gadget/function/uvc_configfs.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef UVC_CONFIGFS_H #define UVC_CONFIGFS_H diff --git a/drivers/usb/gadget/function/uvc_v4l2.h b/drivers/usb/gadget/function/uvc_v4l2.h index a75e9c397446..452d71059b3f 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.h +++ b/drivers/usb/gadget/function/uvc_v4l2.h @@ -7,7 +7,7 @@ * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __UVC_V4L2_H__ diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h index 278dc52c7604..dff12103f696 100644 --- a/drivers/usb/gadget/function/uvc_video.h +++ b/drivers/usb/gadget/function/uvc_video.h @@ -7,7 +7,7 @@ * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __UVC_VIDEO_H__ #define __UVC_VIDEO_H__ diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index 784bf86dad4f..d7c9e4fca895 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Gadget support on a system involves # (a) a peripheral controller, and diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 37ca0e669bd8..249277d0e53f 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -1218,27 +1218,27 @@ ep0_poll (struct file *fd, poll_table *wait) if (dev->state <= STATE_DEV_OPENED) return DEFAULT_POLLMASK; - poll_wait(fd, &dev->wait, wait); - - spin_lock_irq (&dev->lock); - - /* report fd mode change before acting on it */ - if (dev->setup_abort) { - dev->setup_abort = 0; - mask = EPOLLHUP; - goto out; - } - - if (dev->state == STATE_DEV_SETUP) { - if (dev->setup_in || dev->setup_can_stall) - mask = EPOLLOUT; - } else { - if (dev->ev_next != 0) - mask = EPOLLIN; - } + poll_wait(fd, &dev->wait, wait); + + spin_lock_irq(&dev->lock); + + /* report fd mode change before acting on it */ + if (dev->setup_abort) { + dev->setup_abort = 0; + mask = EPOLLHUP; + goto out; + } + + if (dev->state == STATE_DEV_SETUP) { + if (dev->setup_in || dev->setup_can_stall) + mask = EPOLLOUT; + } else { + if (dev->ev_next != 0) + mask = EPOLLIN; + } out: - spin_unlock_irq(&dev->lock); - return mask; + spin_unlock_irq(&dev->lock); + return mask; } static long dev_ioctl (struct file *fd, unsigned code, unsigned long value) diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index dbaa46eee853..6aea1ecb3999 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -5,7 +5,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #include "u_f.h" diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 09f90447fed5..eaa13fd3dc7f 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -7,7 +7,7 @@ * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __U_F_H__ diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h index 8acd21779ac8..5d7d35c8cc31 100644 --- a/drivers/usb/gadget/u_os_desc.h +++ b/drivers/usb/gadget/u_os_desc.h @@ -7,7 +7,7 @@ * Copyright (c) 2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ #ifndef __U_OS_DESC_H__ diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 0a16cbd4e528..ef0259a950ba 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Gadget support on a system involves # (a) a peripheral controller, and diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 4a28e3fbeb0b..83340f4fdc6e 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -120,7 +120,7 @@ static void ast_vhub_epn_handle_ack(struct ast_vhub_ep *ep) /* No current DMA ongoing */ req->active = false; - /* Grab lenght out of HW */ + /* Grab length out of HW */ len = VHUB_EP_DMA_TX_SIZE(stat); /* If not using DMA, copy data out if needed */ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index 35ba0e55a2e9..7c040f56100e 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -295,7 +295,7 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, dsize = AST_VHUB_HUB_DESC_SIZE; memcpy(ep->buf, &ast_vhub_hub_desc, dsize); BUILD_BUG_ON(dsize > sizeof(ast_vhub_hub_desc)); - BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); + BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); break; default: return std_req_stall; diff --git a/drivers/usb/gadget/udc/bdc/Kconfig b/drivers/usb/gadget/udc/bdc/Kconfig index c74ac25dddcd..3e88c7670b2e 100644 --- a/drivers/usb/gadget/udc/bdc/Kconfig +++ b/drivers/usb/gadget/udc/bdc/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_BDC_UDC tristate "Broadcom USB3.0 device controller IP driver(BDC)" depends on USB_GADGET && HAS_DMA diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.c b/drivers/usb/gadget/udc/bdc/bdc_cmd.c index 6305bf2c8b59..44c2a5eef785 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_cmd.c +++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.c @@ -311,8 +311,8 @@ int bdc_ep_clear_stall(struct bdc *bdc, int epnum) /* if the endpoint it not stallled */ if (!(ep->flags & BDC_EP_STALL)) { ret = bdc_ep_set_stall(bdc, epnum); - if (ret) - return ret; + if (ret) + return ret; } } /* Preserve the seq number for ep0 only */ diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 87d6b12779f2..7cf34beb50df 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -281,10 +281,10 @@ EXPORT_SYMBOL_GPL(usb_ep_queue); * @ep:the endpoint associated with the request * @req:the request being canceled * - * If the request is still active on the endpoint, it is dequeued and its - * completion routine is called (with status -ECONNRESET); else a negative - * error code is returned. This is guaranteed to happen before the call to - * usb_ep_dequeue() returns. + * If the request is still active on the endpoint, it is dequeued and + * eventually its completion routine is called (with status -ECONNRESET); + * else a negative error code is returned. This routine is asynchronous, + * that is, it may return before the completion routine runs. * * Note that some hardware can't clear out write fifos (to unlink the request * at the head of the queue) except as part of disconnecting from usb. Such diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index bc6abaea907d..cec49294bac6 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -326,6 +326,7 @@ dma_reset: static void fotg210_start_dma(struct fotg210_ep *ep, struct fotg210_request *req) { + struct device *dev = &ep->fotg210->gadget.dev; dma_addr_t d; u8 *buffer; u32 length; @@ -348,18 +349,14 @@ static void fotg210_start_dma(struct fotg210_ep *ep, length = req->req.length; } - d = dma_map_single(NULL, buffer, length, + d = dma_map_single(dev, buffer, length, ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (dma_mapping_error(NULL, d)) { + if (dma_mapping_error(dev, d)) { pr_err("dma_mapping_error\n"); return; } - dma_sync_single_for_device(NULL, d, length, - ep->dir_in ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - fotg210_enable_dma(ep, d, length); /* check if dma is done */ @@ -370,7 +367,7 @@ static void fotg210_start_dma(struct fotg210_ep *ep, /* update actual transfer length */ req->req.actual += length; - dma_unmap_single(NULL, d, length, DMA_TO_DEVICE); + dma_unmap_single(dev, d, length, DMA_TO_DEVICE); } static void fotg210_ep0_queue(struct fotg210_ep *ep, diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index e7dae5379e04..f63f82450bf4 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -516,8 +516,8 @@ static int net2280_disable(struct usb_ep *_ep) unsigned long flags; ep = container_of(_ep, struct net2280_ep, ep); - if (!_ep || !ep->desc || _ep->name == ep0name) { - pr_err("%s: Invalid ep=%p or ep->desc\n", __func__, _ep); + if (!_ep || _ep->name == ep0name) { + pr_err("%s: Invalid ep=%p\n", __func__, _ep); return -EINVAL; } spin_lock_irqsave(&ep->dev->lock, flags); @@ -2279,7 +2279,7 @@ static void usb_reinit_338x(struct net2280 *dev) * - It is safe to set for all connection speeds; all chip revisions. * - R-M-W to leave other bits undisturbed. * - Reference PLX TT-7372 - */ + */ val = readl(&dev->ll_chicken_reg->ll_tsn_chicken_bit); val |= BIT(RECOVERY_IDLE_TO_RECOVER_FMW); writel(val, &dev->ll_chicken_reg->ll_tsn_chicken_bit); diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 6e34f9594159..7dc248546fd4 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2630,6 +2630,10 @@ MODULE_DEVICE_TABLE(of, usb3_of_match); static const struct soc_device_attribute renesas_usb3_quirks_match[] = { { + .soc_id = "r8a774c0", + .data = &renesas_usb3_priv_r8a77990, + }, + { .soc_id = "r8a7795", .revision = "ES1.*", .data = &renesas_usb3_priv_r8a7795_es1, }, diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index d4da47f4f6f4..3fcded31405a 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -947,15 +947,14 @@ static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp) UDC_DMA_STP_STS_BS_HOST_READY, UDC_DMA_STP_STS_BS); - - /* clear NAK by writing CNAK */ - if (ep->naking) { - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &ep->regs->ctl); - ep->naking = 0; - UDC_QUEUE_CNAK(ep, ep->num); - } + /* clear NAK by writing CNAK */ + if (ep->naking) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 16758b12a5e9..d809671c5fea 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Host Controller Drivers # @@ -69,13 +70,13 @@ config USB_XHCI_MTK If unsure, say N. config USB_XHCI_MVEBU - tristate "xHCI support for Marvell Armada 375/38x" + tristate "xHCI support for Marvell Armada 375/38x/37xx" select USB_XHCI_PLATFORM depends on HAS_IOMEM depends on ARCH_MVEBU || COMPILE_TEST ---help--- Say 'Y' to enable the support for the xHCI host controller - found in Marvell Armada 375/38x ARM SOCs. + found in Marvell Armada 375/38x/37xx ARM SOCs. config USB_XHCI_RCAR tristate "xHCI support for Renesas R-Car SoCs" @@ -179,8 +180,7 @@ config XPS_USB_HCD_XILINX devices only. config USB_EHCI_FSL - tristate "Support for Freescale PPC on-chip EHCI USB controller" - depends on FSL_SOC + tristate "Support for Freescale on-chip EHCI USB controller" select USB_EHCI_ROOT_HUB_TT ---help--- Variation of ARC USB block used in some Freescale chips. diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 0a9fd2022acf..e3d0c1c25160 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -23,6 +23,7 @@ #include <linux/platform_device.h> #include <linux/fsl_devices.h> #include <linux/of_platform.h> +#include <linux/io.h> #include "ehci.h" #include "ehci-fsl.h" @@ -50,6 +51,7 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) struct resource *res; int irq; int retval; + u32 tmp; pr_debug("initializing FSL-SOC USB Controller\n"); @@ -114,17 +116,22 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) } /* Enable USB controller, 83xx or 8536 */ - if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) - clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, 0x4); - + if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) { + tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= 0x4; + iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL); + } /* * Enable UTMI phy and program PTS field in UTMI mode before asserting * controller reset for USB Controller version 2.5 */ if (pdata->has_fsl_erratum_a007792) { - clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, CTRL_UTMI_PHY_EN); + tmp = ioread32be(hcd->regs + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= CTRL_UTMI_PHY_EN; + iowrite32be(tmp, hcd->regs + FSL_SOC_USB_CTRL); + writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1); } @@ -174,7 +181,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) { - u32 portsc; + u32 portsc, tmp; struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; struct device *dev = hcd->self.controller; @@ -192,11 +199,16 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_ULPI: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrbits32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, - ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); + /* turn off UTMI PHY first */ + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~(CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + + /* then turn on ULPI and enable USB controller */ + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); } portsc |= PORT_PTS_ULPI; break; @@ -210,16 +222,21 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_UTMI_DUAL: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, UTMI_PHY_EN); + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= UTMI_PHY_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to become stable - 10ms*/ } /* enable UTMI PHY */ - if (pdata->have_sysif_regs) - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, - CTRL_UTMI_PHY_EN); + if (pdata->have_sysif_regs) { + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= CTRL_UTMI_PHY_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + } portsc |= PORT_PTS_UTMI; break; case FSL_USB2_PHY_NONE: @@ -241,9 +258,12 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); - if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - CONTROL_REGISTER_W1C_MASK, USB_CTRL_USB_EN); + if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) { + tmp = ioread32be(non_ehci + FSL_SOC_USB_CTRL); + tmp &= ~CONTROL_REGISTER_W1C_MASK; + tmp |= USB_CTRL_USB_EN; + iowrite32be(tmp, non_ehci + FSL_SOC_USB_CTRL); + } return 0; } @@ -284,14 +304,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) return -EINVAL; if (pdata->operating_mode == FSL_USB2_MPH_HOST) { - unsigned int chip, rev, svr; - - svr = mfspr(SPRN_SVR); - chip = svr >> 16; - rev = (svr >> 4) & 0xf; /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */ - if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055)) + if (pdata->has_fsl_erratum_14 == 1) ehci->has_fsl_port_bug = 1; if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 1ad72647a069..790acf3633e8 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -182,6 +182,23 @@ static int ehci_orion_drv_reset(struct usb_hcd *hcd) return ret; } +static int __maybe_unused ehci_orion_drv_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return ehci_suspend(hcd, device_may_wakeup(dev)); +} + +static int __maybe_unused ehci_orion_drv_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return ehci_resume(hcd, false); +} + +static SIMPLE_DEV_PM_OPS(ehci_orion_pm_ops, ehci_orion_drv_suspend, + ehci_orion_drv_resume); + static const struct ehci_driver_overrides orion_overrides __initconst = { .extra_priv_size = sizeof(struct orion_ehci_hcd), .reset = ehci_orion_drv_reset, @@ -257,15 +274,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) if (IS_ERR(priv->phy)) { err = PTR_ERR(priv->phy); if (err != -ENOSYS) - goto err_phy_get; - } else { - err = phy_init(priv->phy); - if (err) - goto err_phy_init; - - err = phy_power_on(priv->phy); - if (err) - goto err_phy_power_on; + goto err_dis_clk; } /* @@ -297,19 +306,12 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) - goto err_add_hcd; + goto err_dis_clk; device_wakeup_enable(hcd->self.controller); return 0; -err_add_hcd: - if (!IS_ERR(priv->phy)) - phy_power_off(priv->phy); -err_phy_power_on: - if (!IS_ERR(priv->phy)) - phy_exit(priv->phy); -err_phy_init: -err_phy_get: +err_dis_clk: if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); usb_put_hcd(hcd); @@ -327,11 +329,6 @@ static int ehci_orion_drv_remove(struct platform_device *pdev) usb_remove_hcd(hcd); - if (!IS_ERR(priv->phy)) { - phy_power_off(priv->phy); - phy_exit(priv->phy); - } - if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); @@ -354,6 +351,7 @@ static struct platform_driver ehci_orion_driver = { .driver = { .name = "orion-ehci", .of_match_table = ehci_orion_dt_ids, + .pm = &ehci_orion_pm_ops, }, }; diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 677f9d592109..4f8b8a08c914 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -225,6 +225,12 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->has_fsl_erratum_a005697 = of_property_read_bool(np, "fsl,usb_erratum-a005697"); + if (of_get_property(np, "fsl,usb_erratum_14", NULL)) + pdata->has_fsl_erratum_14 = 1; + else + pdata->has_fsl_erratum_14 = 0; + + /* * Determine whether phy_clk_valid needs to be checked * by reading property in device tree diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index ec6739ef3129..fc35a7993b7b 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -141,8 +141,11 @@ static struct regmap *at91_dt_syscon_sfr(void) struct regmap *regmap; regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); - if (IS_ERR(regmap)) - regmap = NULL; + if (IS_ERR(regmap)) { + regmap = syscon_regmap_lookup_by_compatible("microchip,sam9x60-sfr"); + if (IS_ERR(regmap)) + regmap = NULL; + } return regmap; } diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index c5e6e8d0b5ef..47c5515a9ce4 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -1323,7 +1323,7 @@ static struct list_head *qh_urb_transaction(struct oxu_hcd *oxu, } /* by default, enable interrupt on urb completion */ - qtd->hw_token |= cpu_to_le32(QTD_IOC); + qtd->hw_token |= cpu_to_le32(QTD_IOC); return head; cleanup: @@ -2253,16 +2253,12 @@ static void scan_periodic(struct oxu_hcd *oxu) for (;;) { union ehci_shadow q, *q_p; __le32 type, *hw_p; - unsigned uframes; /* don't scan past the live uframe */ frame = now_uframe >> 3; - if (frame == (clock >> 3)) - uframes = now_uframe & 0x07; - else { + if (frame != (clock >> 3)) { /* safe to scan the whole frame at once */ now_uframe |= 0x07; - uframes = 8; } restart: @@ -2832,7 +2828,6 @@ static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, { struct oxu_hcd *oxu = hcd_to_oxu(hcd); int num, rem; - int transfer_buffer_length; void *transfer_buffer; struct urb *murb; int i, ret; @@ -2843,7 +2838,6 @@ static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, /* Otherwise we should verify the USB transfer buffer size! */ transfer_buffer = urb->transfer_buffer; - transfer_buffer_length = urb->transfer_buffer_length; num = urb->transfer_buffer_length / 4096; rem = urb->transfer_buffer_length % 4096; diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 5b8a3d9530c4..934584f0a20a 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2477,7 +2477,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } urb->error_count = 0; + } + urb->error_count = 0; usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { @@ -2982,7 +2983,8 @@ static int u132_remove(struct platform_device *pdev) while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; u132_ring_cancel_work(u132, ring); - } while (endps-- > 0) { + } + while (endps-- > 0) { struct u132_endp *endp = u132->endp[endps]; if (endp) u132_endp_cancel_work(u132, endp); diff --git a/drivers/usb/host/whci/Kbuild b/drivers/usb/host/whci/Makefile index 26df0138079e..859d20079df6 100644 --- a/drivers/usb/host/whci/Kbuild +++ b/drivers/usb/host/whci/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o whci-hcd-y := \ diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 86cff5c28eff..c78be578abb0 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -181,7 +181,7 @@ static void xhci_dbc_flush_endpoint_requests(struct dbc_ep *dep) xhci_dbc_flush_single_request(req); } -static void xhci_dbc_flush_reqests(struct xhci_dbc *dbc) +static void xhci_dbc_flush_requests(struct xhci_dbc *dbc) { xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_OUT]); xhci_dbc_flush_endpoint_requests(&dbc->eps[BULK_IN]); @@ -687,7 +687,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) !(portsc & DBC_PORTSC_CONN_STATUS)) { xhci_info(xhci, "DbC cable unplugged\n"); dbc->state = DS_ENABLED; - xhci_dbc_flush_reqests(dbc); + xhci_dbc_flush_requests(dbc); return EVT_DISC; } @@ -697,7 +697,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) xhci_info(xhci, "DbC port reset\n"); writel(portsc, &dbc->regs->portsc); dbc->state = DS_ENABLED; - xhci_dbc_flush_reqests(dbc); + xhci_dbc_flush_requests(dbc); return EVT_DISC; } diff --git a/drivers/usb/host/xhci-debugfs.h b/drivers/usb/host/xhci-debugfs.h index ac5bc40f5c3a..f7a4e2492b00 100644 --- a/drivers/usb/host/xhci-debugfs.h +++ b/drivers/usb/host/xhci-debugfs.h @@ -80,7 +80,6 @@ struct xhci_regset { char name[DEBUGFS_NAMELEN]; struct debugfs_regset32 regset; size_t nregs; - struct dentry *parent; struct list_head list; }; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8067f178fa84..cf5e17962179 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -933,7 +933,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) * that tt_info, then free the child first. Recursive. * We can't rely on udev at this point to find child-parent relationships. */ -void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) +static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) { struct xhci_virt_device *vdev; struct list_head *tt_list_head; diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index 32e158568788..60651a50770f 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -13,6 +13,7 @@ #include <linux/usb/hcd.h> #include "xhci-mvebu.h" +#include "xhci.h" #define USB3_MAX_WINDOWS 4 #define USB3_WIN_CTRL(w) (0x0 + ((w) * 8)) @@ -72,3 +73,13 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) return 0; } + +int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + /* Without reset on resume, the HC won't work at all */ + xhci->quirks |= XHCI_RESET_ON_RESUME; + + return 0; +} diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h index 09791df2cec0..ca0a3a5721dd 100644 --- a/drivers/usb/host/xhci-mvebu.h +++ b/drivers/usb/host/xhci-mvebu.h @@ -12,10 +12,16 @@ struct usb_hcd; #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd); +int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd); #else static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) { return 0; } + +static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) +{ + return 0; +} #endif #endif /* __LINUX_XHCI_MVEBU_H */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index a9ec7051f286..c2fe218e051f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -194,6 +194,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_SSIC_PORT_UNUSED; if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) xhci->quirks |= XHCI_INTEL_USB_ROLE_SW; if (pdev->vendor == PCI_VENDOR_ID_INTEL && diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index ef09cb06212f..0ac4ec975547 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -98,6 +98,10 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = { .init_quirk = xhci_mvebu_mbus_init_quirk, }; +static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { + .init_quirk = xhci_mvebu_a3700_init_quirk, +}; + static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = { .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1, .init_quirk = xhci_rcar_init_quirk, @@ -124,6 +128,9 @@ static const struct of_device_id usb_xhci_of_match[] = { .compatible = "marvell,armada-380-xhci", .data = &xhci_plat_marvell_armada, }, { + .compatible = "marvell,armada3700-xhci", + .data = &xhci_plat_marvell_armada3700, + }, { .compatible = "renesas,xhci-r8a7790", .data = &xhci_plat_renesas_rcar_gen2, }, { diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 938ff06c0349..efb0cad8710e 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -941,9 +941,9 @@ static void tegra_xusb_powerdomain_remove(struct device *dev, device_link_del(tegra->genpd_dl_ss); if (tegra->genpd_dl_host) device_link_del(tegra->genpd_dl_host); - if (tegra->genpd_dev_ss) + if (!IS_ERR_OR_NULL(tegra->genpd_dev_ss)) dev_pm_domain_detach(tegra->genpd_dev_ss, true); - if (tegra->genpd_dev_host) + if (!IS_ERR_OR_NULL(tegra->genpd_dev_host)) dev_pm_domain_detach(tegra->genpd_dev_host, true); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 005e65922608..7fa58c99f126 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1455,8 +1455,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag else num_tds = 1; - urb_priv = kzalloc(sizeof(struct urb_priv) + - num_tds * sizeof(struct xhci_td), mem_flags); + urb_priv = kzalloc(struct_size(urb_priv, td, num_tds), mem_flags); if (!urb_priv) return -ENOMEM; diff --git a/drivers/usb/image/Kconfig b/drivers/usb/image/Kconfig index 320d368c8dac..26c75f309da9 100644 --- a/drivers/usb/image/Kconfig +++ b/drivers/usb/image/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Imaging devices configuration # diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig index c94b7d953399..b1022cc490a2 100644 --- a/drivers/usb/isp1760/Kconfig +++ b/drivers/usb/isp1760/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_ISP1760 tristate "NXP ISP 1760/1761 support" depends on USB || USB_GADGET diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 68d2f2cd17dd..be04c117fe80 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Miscellaneous driver configuration # diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 76c718ac8c78..257efacf3551 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -915,7 +915,6 @@ static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) int bytes_read = 0; int retry_on_empty = 1; int retry_on_timeout = 3; - int empty_packets = 0; read:{ int packet_bytes = 0; int retval = usb_bulk_msg(ftdi->udev, @@ -960,31 +959,6 @@ read:{ dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", retval, packet_bytes, bytes_read, diag); return retval; - } else if (packet_bytes == 2) { - unsigned char s0 = ftdi->bulk_in_buffer[0]; - unsigned char s1 = ftdi->bulk_in_buffer[1]; - empty_packets += 1; - if (s0 == 0x31 && s1 == 0x60) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else if (s0 == 0x31 && s1 == 0x00) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } else if (packet_bytes == 1) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; } else { if (retry_on_empty-- > 0) { goto more; diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig index 36bc28c884ad..9b632ab24f03 100644 --- a/drivers/usb/misc/sisusbvga/Kconfig +++ b/drivers/usb/misc/sisusbvga/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 config USB_SISUSBVGA tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)" diff --git a/drivers/usb/misc/sisusbvga/Makefile b/drivers/usb/misc/sisusbvga/Makefile index 6ed3a638261a..6551bce68ac5 100644 --- a/drivers/usb/misc/sisusbvga/Makefile +++ b/drivers/usb/misc/sisusbvga/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o -sisusbvga-y := sisusb.o sisusb_init.o sisusb_con.o +sisusbvga-y := sisusb.o +sisusbvga-$(CONFIG_USB_SISUSBVGA_CON) += sisusb_con.o sisusb_init.o diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 3198d0477cf8..9560fde621ee 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -53,7 +53,7 @@ #include "sisusb.h" #include "sisusb_init.h" -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON #include <linux/font.h> #endif @@ -61,7 +61,7 @@ /* Forward declarations / clean-up routines */ -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON static int sisusb_first_vc; static int sisusb_last_vc; module_param_named(first, sisusb_first_vc, int, 0); @@ -1198,7 +1198,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, /* High level: Gfx (indexed) register access */ -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data) { return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data); @@ -1272,7 +1272,7 @@ int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, /* Write/read video ram */ -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data) { return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data); @@ -2255,7 +2255,7 @@ static int sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen) } -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON /* Set up default text mode: * - Set text mode (0x03) @@ -2448,7 +2448,7 @@ void sisusb_delete(struct kref *kref) sisusb->sisusb_dev = NULL; sisusb_free_buffers(sisusb); sisusb_free_urbs(sisusb); -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON kfree(sisusb->SiS_Pr); #endif kfree(sisusb); @@ -2844,7 +2844,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, case SUCMD_HANDLETEXTMODE: retval = 0; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON /* Gfx core must be initialized, SiS_Pr must exist */ if (!sisusb->gfxinit || !sisusb->SiS_Pr) return -ENODEV; @@ -2860,7 +2860,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, #endif break; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON case SUCMD_SETMODE: /* Gfx core must be initialized, SiS_Pr must exist */ if (!sisusb->gfxinit || !sisusb->SiS_Pr) @@ -2944,7 +2944,7 @@ static long sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) x.sisusb_vramsize = sisusb->vramsize; x.sisusb_minor = sisusb->minor; x.sisusb_fbdevactive = 0; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON x.sisusb_conactive = sisusb->haveconsole ? 1 : 0; #else x.sisusb_conactive = 0; @@ -2975,7 +2975,7 @@ err_out: return retval; } -#ifdef SISUSB_NEW_CONFIG_COMPAT +#ifdef CONFIG_COMPAT static long sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { @@ -2998,7 +2998,7 @@ static const struct file_operations usb_sisusb_fops = { .read = sisusb_read, .write = sisusb_write, .llseek = sisusb_lseek, -#ifdef SISUSB_NEW_CONFIG_COMPAT +#ifdef CONFIG_COMPAT .compat_ioctl = sisusb_compat_ioctl, #endif .unlocked_ioctl = sisusb_ioctl @@ -3091,7 +3091,7 @@ static int sisusb_probe(struct usb_interface *intf, dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs); -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON /* Allocate our SiS_Pr */ sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL); if (!sisusb->SiS_Pr) { @@ -3112,7 +3112,7 @@ static int sisusb_probe(struct usb_interface *intf, if (dev->speed == USB_SPEED_HIGH || dev->speed >= USB_SPEED_SUPER) { int initscreen = 1; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON if (sisusb_first_vc > 0 && sisusb_last_vc > 0 && sisusb_first_vc <= sisusb_last_vc && sisusb_last_vc <= MAX_NR_CONSOLES) @@ -3134,7 +3134,7 @@ static int sisusb_probe(struct usb_interface *intf, dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n"); #endif -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc); #endif @@ -3160,7 +3160,7 @@ static void sisusb_disconnect(struct usb_interface *intf) if (!sisusb) return; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON sisusb_console_exit(sisusb); #endif @@ -3210,7 +3210,7 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON sisusb_init_concode(); #endif diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 20f03ad0ea16..8a5e6bb07d05 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -38,17 +38,8 @@ #ifndef _SISUSB_H_ #define _SISUSB_H_ -#ifdef CONFIG_COMPAT -#define SISUSB_NEW_CONFIG_COMPAT -#endif - #include <linux/mutex.h> -/* For older kernels, support for text consoles is by default - * off. To enable text console support, change the following: - */ -/* #define CONFIG_USB_SISUSBVGA_CON */ - /* Version Information */ #define SISUSB_VERSION 0 @@ -57,10 +48,6 @@ /* Include console and mode switching code? */ -#ifdef CONFIG_USB_SISUSBVGA_CON -#define INCL_SISUSB_CON 1 -#endif - #include <linux/console.h> #include <linux/vt_kern.h> #include "sisusb_struct.h" @@ -139,7 +126,7 @@ struct sisusb_usb_data { unsigned char gfxinit; /* graphics core initialized? */ unsigned short chipid, chipvendor; unsigned short chiprevision; -#ifdef INCL_SISUSB_CON +#ifdef CONFIG_USB_SISUSBVGA_CON struct SiS_Private *SiS_Pr; unsigned long scrbuf; unsigned int scrbuf_size; diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index c4f017e1d17a..cd0155310fea 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -70,13 +70,6 @@ #include "sisusb.h" #include "sisusb_init.h" -#ifdef INCL_SISUSB_CON - -#define sisusbcon_writew(val, addr) (*(addr) = (val)) -#define sisusbcon_readw(addr) (*(addr)) -#define sisusbcon_memmovew(d, s, c) memmove(d, s, c) -#define sisusbcon_memcpyw(d, s, c) memcpy(d, s, c) - /* vc_data -> sisusb conversion table */ static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES]; @@ -86,9 +79,7 @@ static const struct consw sisusb_con; static inline void sisusbcon_memsetw(u16 *s, u16 c, unsigned int count) { - count /= 2; - while (count--) - sisusbcon_writew(c, s++); + memset16(s, c, count / 2); } static inline void @@ -346,25 +337,30 @@ sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count) */ while (count--) { - u16 a = sisusbcon_readw(p); - - a = ((a) & 0x88ff) | - (((a) & 0x7000) >> 4) | - (((a) & 0x0700) << 4); + u16 a = *p; - sisusbcon_writew(a, p++); + *p++ = ((a) & 0x88ff) | + (((a) & 0x7000) >> 4) | + (((a) & 0x0700) << 4); } } -#define SISUSB_VADDR(x,y) \ - ((u16 *)c->vc_origin + \ - (y) * sisusb->sisusb_num_columns + \ - (x)) +static inline void *sisusb_vaddr(const struct sisusb_usb_data *sisusb, + const struct vc_data *c, unsigned int x, unsigned int y) +{ + return (u16 *)c->vc_origin + y * sisusb->sisusb_num_columns + x; +} + +static inline unsigned long sisusb_haddr(const struct sisusb_usb_data *sisusb, + const struct vc_data *c, unsigned int x, unsigned int y) +{ + unsigned long offset = c->vc_origin - sisusb->scrbuf; -#define SISUSB_HADDR(x,y) \ - ((u16 *)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)) + \ - (y) * sisusb->sisusb_num_columns + \ - (x)) + /* 2 bytes per each character */ + offset += 2 * (y * sisusb->sisusb_num_columns + x); + + return sisusb->vrambase + offset; +} /* Interface routine */ static void @@ -382,9 +378,8 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) return; } - - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), 2); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y), + sisusb_haddr(sisusb, c, x, y), 2); mutex_unlock(&sisusb->lock); } @@ -395,8 +390,6 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, int count, int y, int x) { struct sisusb_usb_data *sisusb; - u16 *dest; - int i; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) @@ -408,18 +401,15 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, * because the vt does this AFTER calling us. */ - dest = SISUSB_VADDR(x, y); - - for (i = count; i > 0; i--) - sisusbcon_writew(sisusbcon_readw(s++), dest++); + memcpy(sisusb_vaddr(sisusb, c, x, y), s, count * 2); if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; } - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), count * 2); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y), + sisusb_haddr(sisusb, c, x, y), count * 2); mutex_unlock(&sisusb->lock); } @@ -446,7 +436,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) * this AFTER calling us. */ - dest = SISUSB_VADDR(x, y); + dest = sisusb_vaddr(sisusb, c, x, y); cols = sisusb->sisusb_num_columns; @@ -472,8 +462,8 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) length = ((height * cols) - x - (cols - width - x)) * 2; - sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), length); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, x, y), + sisusb_haddr(sisusb, c, x, y), length); mutex_unlock(&sisusb->lock); } @@ -517,12 +507,10 @@ sisusbcon_switch(struct vc_data *c) (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); /* Restore the screen contents */ - sisusbcon_memcpyw((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, - length); + memcpy((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, length); - sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, - (long)SISUSB_HADDR(0, 0), - length); + sisusb_copy_memory(sisusb, (char *)c->vc_origin, + sisusb_haddr(sisusb, c, 0, 0), length); mutex_unlock(&sisusb->lock); @@ -556,8 +544,7 @@ sisusbcon_save_screen(struct vc_data *c) (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); /* Save the screen contents to vc's private buffer */ - sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, - length); + memcpy((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, length); mutex_unlock(&sisusb->lock); } @@ -628,10 +615,8 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) sisusbcon_memsetw((u16 *)c->vc_origin, c->vc_video_erase_char, c->vc_screenbuf_size); - sisusb_copy_memory(sisusb, - (unsigned char *)c->vc_origin, - (u32)(sisusb->vrambase + - (c->vc_origin - sisusb->scrbuf)), + sisusb_copy_memory(sisusb, (char *)c->vc_origin, + sisusb_haddr(sisusb, c, 0, 0), c->vc_screenbuf_size); sisusb->con_blanked = 1; ret = 1; @@ -796,24 +781,24 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, switch (dir) { case SM_UP: - sisusbcon_memmovew(SISUSB_VADDR(0, t), - SISUSB_VADDR(0, t + lines), + memmove(sisusb_vaddr(sisusb, c, 0, t), + sisusb_vaddr(sisusb, c, 0, t + lines), (b - t - lines) * cols * 2); - sisusbcon_memsetw(SISUSB_VADDR(0, b - lines), eattr, - lines * cols * 2); + sisusbcon_memsetw(sisusb_vaddr(sisusb, c, 0, b - lines), + eattr, lines * cols * 2); break; case SM_DOWN: - sisusbcon_memmovew(SISUSB_VADDR(0, t + lines), - SISUSB_VADDR(0, t), + memmove(sisusb_vaddr(sisusb, c, 0, t + lines), + sisusb_vaddr(sisusb, c, 0, t), (b - t - lines) * cols * 2); - sisusbcon_memsetw(SISUSB_VADDR(0, t), eattr, + sisusbcon_memsetw(sisusb_vaddr(sisusb, c, 0, t), eattr, lines * cols * 2); break; } - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), - (long)SISUSB_HADDR(0, t), length); + sisusb_copy_memory(sisusb, sisusb_vaddr(sisusb, c, 0, t), + sisusb_haddr(sisusb, c, 0, t), length); mutex_unlock(&sisusb->lock); @@ -830,7 +815,6 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, int copyall = 0; unsigned long oldorigin; unsigned int delta = lines * c->vc_size_row; - u32 originoffset; /* Returning != 0 means we have done the scrolling successfully. * Returning 0 makes vt do the scrolling on its own. @@ -874,7 +858,7 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, if (c->vc_scr_end + delta >= sisusb->scrbuf + sisusb->scrbuf_size) { - sisusbcon_memcpyw((u16 *)sisusb->scrbuf, + memcpy((u16 *)sisusb->scrbuf, (u16 *)(oldorigin + delta), c->vc_screenbuf_size - delta); c->vc_origin = sisusb->scrbuf; @@ -892,12 +876,10 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, case SM_DOWN: if (oldorigin - delta < sisusb->scrbuf) { - sisusbcon_memmovew((u16 *)(sisusb->scrbuf + - sisusb->scrbuf_size - - c->vc_screenbuf_size + - delta), - (u16 *)oldorigin, - c->vc_screenbuf_size - delta); + memmove((void *)sisusb->scrbuf + sisusb->scrbuf_size - + c->vc_screenbuf_size + delta, + (u16 *)oldorigin, + c->vc_screenbuf_size - delta); c->vc_origin = sisusb->scrbuf + sisusb->scrbuf_size - c->vc_screenbuf_size; @@ -913,23 +895,21 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, break; } - originoffset = (u32)(c->vc_origin - sisusb->scrbuf); - if (copyall) sisusb_copy_memory(sisusb, (char *)c->vc_origin, - (u32)(sisusb->vrambase + originoffset), + sisusb_haddr(sisusb, c, 0, 0), c->vc_screenbuf_size); else if (dir == SM_UP) sisusb_copy_memory(sisusb, (char *)c->vc_origin + c->vc_screenbuf_size - delta, - (u32)sisusb->vrambase + originoffset + + sisusb_haddr(sisusb, c, 0, 0) + c->vc_screenbuf_size - delta, delta); else sisusb_copy_memory(sisusb, (char *)c->vc_origin, - (u32)(sisusb->vrambase + originoffset), + sisusb_haddr(sisusb, c, 0, 0), delta); c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; @@ -1534,8 +1514,3 @@ void __init sisusb_init_concode(void) for (i = 0; i < MAX_NR_CONSOLES; i++) mysisusbs[i] = NULL; } - -#endif /* INCL_CON */ - - - diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 6a30e8bd9221..66f6ab5acd97 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -44,9 +44,6 @@ #include <linux/spinlock.h> #include "sisusb.h" - -#ifdef INCL_SISUSB_CON - #include "sisusb_init.h" /*********************************************/ @@ -955,5 +952,3 @@ int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) return SiSUSBSetMode(SiS_Pr, ModeNo); } - -#endif /* INCL_SISUSB_CON */ diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index a6efb9a72939..4d72b7d1d383 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -337,10 +337,12 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, struct device *dev = hub->dev; struct device_node *np = dev->of_node; int len, err, i; - u32 property_u32 = 0; + u32 port, property_u32 = 0; const u32 *cproperty_u32; const char *cproperty_char; char str[USB251XB_STRING_BUFSIZE / 2]; + struct property *prop; + const __be32 *p; if (!np) { dev_err(dev, "failed to get ofdata\n"); @@ -539,6 +541,16 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, (wchar_t *)hub->serial, USB251XB_STRING_BUFSIZE); + /* + * The datasheet documents the register as 'Port Swap' but in real the + * register controls the USB DP/DM signal swapping for each port. + */ + hub->port_swap = USB251XB_DEF_PORT_SWAP; + of_property_for_each_u32(np, "swap-dx-lanes", prop, p, port) { + if ((port >= 0) && (port <= data->port_cnt)) + hub->port_swap |= BIT(port); + } + /* The following parameters are currently not exposed to devicetree, but * may be as soon as needed. */ @@ -546,7 +558,6 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->boost_up = USB251XB_DEF_BOOST_UP; hub->boost_57 = USB251XB_DEF_BOOST_57; hub->boost_14 = USB251XB_DEF_BOOST_14; - hub->port_swap = USB251XB_DEF_PORT_SWAP; hub->port_map12 = USB251XB_DEF_PORT_MAP_12; hub->port_map34 = USB251XB_DEF_PORT_MAP_34; hub->port_map56 = USB251XB_DEF_PORT_MAP_56; diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index f723f7b8c9ac..d5141aa79dd4 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -355,11 +355,8 @@ static int usb3503_platform_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int usb3503_i2c_suspend(struct device *dev) +static int usb3503_suspend(struct usb3503 *hub) { - struct i2c_client *client = to_i2c_client(dev); - struct usb3503 *hub = i2c_get_clientdata(client); - usb3503_switch_mode(hub, USB3503_MODE_STANDBY); if (hub->clk) @@ -368,11 +365,8 @@ static int usb3503_i2c_suspend(struct device *dev) return 0; } -static int usb3503_i2c_resume(struct device *dev) +static int usb3503_resume(struct usb3503 *hub) { - struct i2c_client *client = to_i2c_client(dev); - struct usb3503 *hub = i2c_get_clientdata(client); - if (hub->clk) clk_prepare_enable(hub->clk); @@ -380,11 +374,38 @@ static int usb3503_i2c_resume(struct device *dev) return 0; } + +static int usb3503_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + return usb3503_suspend(i2c_get_clientdata(client)); +} + +static int usb3503_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + return usb3503_resume(i2c_get_clientdata(client)); +} + +static int usb3503_platform_suspend(struct device *dev) +{ + return usb3503_suspend(dev_get_drvdata(dev)); +} + +static int usb3503_platform_resume(struct device *dev) +{ + return usb3503_resume(dev_get_drvdata(dev)); +} #endif static SIMPLE_DEV_PM_OPS(usb3503_i2c_pm_ops, usb3503_i2c_suspend, usb3503_i2c_resume); +static SIMPLE_DEV_PM_OPS(usb3503_platform_pm_ops, usb3503_platform_suspend, + usb3503_platform_resume); + static const struct i2c_device_id usb3503_id[] = { { USB3503_I2C_NAME, 0 }, { } @@ -415,6 +436,7 @@ static struct platform_driver usb3503_platform_driver = { .driver = { .name = USB3503_I2C_NAME, .of_match_table = of_match_ptr(usb3503_of_match), + .pm = &usb3503_platform_pm_ops, }, .probe = usb3503_platform_probe, .remove = usb3503_platform_remove, diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index c7f82310e73e..98ada1a3425c 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -347,6 +347,14 @@ static unsigned get_maxpacket(struct usb_device *udev, int pipe) return le16_to_cpup(&ep->desc.wMaxPacketSize); } +static int ss_isoc_get_packet_num(struct usb_device *udev, int pipe) +{ + struct usb_host_endpoint *ep = usb_pipe_endpoint(udev, pipe); + + return USB_SS_MULT(ep->ss_ep_comp.bmAttributes) + * (1 + ep->ss_ep_comp.bMaxBurst); +} + static void simple_fill_buf(struct urb *urb) { unsigned i; @@ -1976,8 +1984,13 @@ static struct urb *iso_alloc_urb( if (bytes < 0 || !desc) return NULL; + maxp = usb_endpoint_maxp(desc); - maxp *= usb_endpoint_maxp_mult(desc); + if (udev->speed >= USB_SPEED_SUPER) + maxp *= ss_isoc_get_packet_num(udev, pipe); + else + maxp *= usb_endpoint_maxp_mult(desc); + packets = DIV_ROUND_UP(bytes, maxp); urb = usb_alloc_urb(packets, GFP_KERNEL); @@ -2065,17 +2078,24 @@ test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param, packets *= param->iterations; if (context.is_iso) { + int transaction_num; + + if (udev->speed >= USB_SPEED_SUPER) + transaction_num = ss_isoc_get_packet_num(udev, pipe); + else + transaction_num = usb_endpoint_maxp_mult(desc); + dev_info(&dev->intf->dev, "iso period %d %sframes, wMaxPacket %d, transactions: %d\n", 1 << (desc->bInterval - 1), - (udev->speed == USB_SPEED_HIGH) ? "micro" : "", + (udev->speed >= USB_SPEED_HIGH) ? "micro" : "", usb_endpoint_maxp(desc), - usb_endpoint_maxp_mult(desc)); + transaction_num); dev_info(&dev->intf->dev, "total %lu msec (%lu packets)\n", (packets * (1 << (desc->bInterval - 1))) - / ((udev->speed == USB_SPEED_HIGH) ? 8 : 1), + / ((udev->speed >= USB_SPEED_HIGH) ? 8 : 1), packets); } diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig index 5c6ffa2a612e..48f1b2dadb24 100644 --- a/drivers/usb/mon/Kconfig +++ b/drivers/usb/mon/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Monitor configuration # diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig index 40bbf1f53337..bcc23486c4ed 100644 --- a/drivers/usb/mtu3/Kconfig +++ b/drivers/usb/mtu3/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +# # For MTK USB3.0 IP config USB_MTU3 diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index ad08895e78f9..f742fddc5e2c 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Dual Role (OTG-ready) Controller Drivers # for silicon based on Mentor Graphics INVENTRA designs @@ -111,9 +112,9 @@ config USB_MUSB_UX500 config USB_MUSB_JZ4740 tristate "JZ4740" depends on NOP_USB_XCEIV - depends on MACH_JZ4740 || COMPILE_TEST + depends on MIPS || COMPILE_TEST depends on USB_MUSB_GADGET - depends on USB_OTG_BLACKLIST_HUB + depends on USB=n || USB_OTG_BLACKLIST_HUB config USB_MUSB_AM335X_CHILD tristate diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index 04d8b2bc205a..a60627bf7be3 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -10,6 +10,7 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/usb/usb_phy_generic.h> @@ -188,11 +189,20 @@ static int jz4740_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id jz4740_musb_of_match[] = { + { .compatible = "ingenic,jz4740-musb" }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4740_musb_of_match); +#endif + static struct platform_driver jz4740_driver = { .probe = jz4740_probe, .remove = jz4740_remove, .driver = { .name = "musb-jz4740", + .of_match_table = of_match_ptr(jz4740_musb_of_match), }, }; diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index b59ce9ad14ce..eb308ec35c66 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -378,7 +378,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, qh = first_qh(head); break; } - /* else: fall through */ + /* fall through */ case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: @@ -1283,7 +1283,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); } - return; + return; } done: diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 91ea3083e7ad..8c509b060c09 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Physical Layer USB driver configuration # diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 183550b63faa..dade34d70419 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -400,7 +400,7 @@ static int twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); - cancel_delayed_work(&twl->get_status_work); + cancel_delayed_work_sync(&twl->get_status_work); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 4e59c649db81..ddd3be48f948 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -340,7 +340,7 @@ static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, pipe = usbhsh_uep_to_pipe(uep); if (unlikely(!pipe)) { - dev_err(dev, "uep doens't have pipe\n"); + dev_err(dev, "uep doesn't have pipe\n"); } else if (1 == uep->counter--) { /* last user */ struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep); struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index aa3820448286..5e730e9b40ef 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -59,7 +59,7 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, if (enable) { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); /* The controller on R-Car Gen3 needs to wait up to 45 usec */ - udelay(45); + usleep_range(45, 90); } else { usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0); } diff --git a/drivers/usb/renesas_usbhs/rza.c b/drivers/usb/renesas_usbhs/rza.c index 5b287257ec11..8c739bd24acd 100644 --- a/drivers/usb/renesas_usbhs/rza.c +++ b/drivers/usb/renesas_usbhs/rza.c @@ -35,7 +35,7 @@ static int usbhs_rza1_hardware_init(struct platform_device *pdev) /* Enable USB PLL (NOTE: ch0 controls both ch0 and ch1) */ usbhs_bset(priv, SYSCFG, UPLLE, UPLLE); - udelay(1000); + usleep_range(1000, 2000); usbhs_bset(priv, SUSPMODE, SUSPM, SUSPM); return 0; diff --git a/drivers/usb/roles/Kconfig b/drivers/usb/roles/Kconfig index e4194ac94510..f8b31aa67526 100644 --- a/drivers/usb/roles/Kconfig +++ b/drivers/usb/roles/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USB_ROLE_SWITCH tristate "USB Role Switch Support" help diff --git a/drivers/usb/roles/Makefile b/drivers/usb/roles/Makefile index c02873206fc1..757a7d2797eb 100644 --- a/drivers/usb/roles/Makefile +++ b/drivers/usb/roles/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_USB_ROLE_SWITCH) += roles.o roles-y := class.o obj-$(CONFIG_USB_ROLES_INTEL_XHCI) += intel-xhci-usb-role-switch.o diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 99116af07f1d..f45d8df5cfb8 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -8,6 +8,7 @@ */ #include <linux/usb/role.h> +#include <linux/property.h> #include <linux/device.h> #include <linux/module.h> #include <linux/mutex.h> @@ -84,7 +85,12 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw) } EXPORT_SYMBOL_GPL(usb_role_switch_get_role); -static int __switch_match(struct device *dev, const void *name) +static int switch_fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} + +static int switch_name_match(struct device *dev, const void *name) { return !strcmp((const char *)name, dev_name(dev)); } @@ -94,8 +100,16 @@ static void *usb_role_switch_match(struct device_connection *con, int ep, { struct device *dev; - dev = class_find_device(role_class, NULL, con->endpoint[ep], - __switch_match); + if (con->fwnode) { + if (!fwnode_property_present(con->fwnode, con->id)) + return NULL; + + dev = class_find_device(role_class, NULL, con->fwnode, + switch_fwnode_match); + } else { + dev = class_find_device(role_class, NULL, con->endpoint[ep], + switch_name_match); + } return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER); } @@ -266,6 +280,7 @@ usb_role_switch_register(struct device *parent, sw->get = desc->get; sw->dev.parent = parent; + sw->dev.fwnode = desc->fwnode; sw->dev.class = role_class; sw->dev.type = &usb_role_dev_type; dev_set_name(&sw->dev, "%s-role-switch", dev_name(parent)); diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 533f127c30ad..7d031911d04e 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Serial device configuration # diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index c0777a374a88..fffe23ab0189 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -61,6 +61,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */ + { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */ { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ @@ -245,6 +246,7 @@ struct cp210x_serial_private { u8 gpio_input; #endif u8 partnum; + speed_t min_speed; speed_t max_speed; bool use_actual_rate; }; @@ -443,10 +445,10 @@ struct cp210x_pin_mode { #define CP210X_PIN_MODE_GPIO BIT(0) /* - * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes. - * Structure needs padding due to unused/unspecified bytes. + * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes + * on a CP2105 chip. Structure needs padding due to unused/unspecified bytes. */ -struct cp210x_config { +struct cp210x_dual_port_config { __le16 gpio_mode; u8 __pad0[2]; __le16 reset_state; @@ -457,6 +459,19 @@ struct cp210x_config { u8 device_cfg; } __packed; +/* + * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xd bytes + * on a CP2104 chip. Structure needs padding due to unused/unspecified bytes. + */ +struct cp210x_single_port_config { + __le16 gpio_mode; + u8 __pad0[2]; + __le16 reset_state; + u8 __pad1[4]; + __le16 suspend_state; + u8 device_cfg; +} __packed; + /* GPIO modes */ #define CP210X_SCI_GPIO_MODE_OFFSET 9 #define CP210X_SCI_GPIO_MODE_MASK GENMASK(11, 9) @@ -464,11 +479,19 @@ struct cp210x_config { #define CP210X_ECI_GPIO_MODE_OFFSET 2 #define CP210X_ECI_GPIO_MODE_MASK GENMASK(3, 2) +#define CP210X_GPIO_MODE_OFFSET 8 +#define CP210X_GPIO_MODE_MASK GENMASK(11, 8) + /* CP2105 port configuration values */ #define CP2105_GPIO0_TXLED_MODE BIT(0) #define CP2105_GPIO1_RXLED_MODE BIT(1) #define CP2105_GPIO1_RS485_MODE BIT(2) +/* CP2104 port configuration values */ +#define CP2104_GPIO0_TXLED_MODE BIT(0) +#define CP2104_GPIO1_RXLED_MODE BIT(1) +#define CP2104_GPIO2_RS485_MODE BIT(2) + /* CP2102N configuration array indices */ #define CP210X_2NCONFIG_CONFIG_VERSION_IDX 2 #define CP210X_2NCONFIG_GPIO_MODE_IDX 581 @@ -1051,14 +1074,11 @@ static speed_t cp210x_get_an205_rate(speed_t baud) return cp210x_an205_table1[i].rate; } -static speed_t cp210x_get_actual_rate(struct usb_serial *serial, speed_t baud) +static speed_t cp210x_get_actual_rate(speed_t baud) { - struct cp210x_serial_private *priv = usb_get_serial_data(serial); unsigned int prescale = 1; unsigned int div; - baud = clamp(baud, 300u, priv->max_speed); - if (baud <= 365) prescale = 4; @@ -1101,20 +1121,18 @@ static void cp210x_change_speed(struct tty_struct *tty, struct cp210x_serial_private *priv = usb_get_serial_data(serial); u32 baud; - baud = tty->termios.c_ospeed; - /* * This maps the requested rate to the actual rate, a valid rate on * cp2102 or cp2103, or to an arbitrary rate in [1M, max_speed]. * * NOTE: B0 is not implemented. */ + baud = clamp(tty->termios.c_ospeed, priv->min_speed, priv->max_speed); + if (priv->use_actual_rate) - baud = cp210x_get_actual_rate(serial, baud); + baud = cp210x_get_actual_rate(baud); else if (baud < 1000000) baud = cp210x_get_an205_rate(baud); - else if (baud > priv->max_speed) - baud = priv->max_speed; dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud); if (cp210x_write_u32_reg(port, CP210X_SET_BAUDRATE, baud)) { @@ -1353,8 +1371,13 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio) if (priv->partnum == CP210X_PARTNUM_CP2105) req_type = REQTYPE_INTERFACE_TO_HOST; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + result = cp210x_read_vendor_block(serial, req_type, CP210X_READ_LATCH, &buf, sizeof(buf)); + usb_autopm_put_interface(serial->interface); if (result < 0) return result; @@ -1375,6 +1398,10 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) buf.mask = BIT(gpio); + result = usb_autopm_get_interface(serial->interface); + if (result) + goto out; + if (priv->partnum == CP210X_PARTNUM_CP2105) { result = cp210x_write_vendor_block(serial, REQTYPE_HOST_TO_INTERFACE, @@ -1392,6 +1419,8 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) NULL, 0, USB_CTRL_SET_TIMEOUT); } + usb_autopm_put_interface(serial->interface); +out: if (result < 0) { dev_err(&serial->interface->dev, "failed to set GPIO value: %d\n", result); @@ -1470,7 +1499,7 @@ static int cp2105_gpioconf_init(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); struct cp210x_pin_mode mode; - struct cp210x_config config; + struct cp210x_dual_port_config config; u8 intf_num = cp210x_interface_num(serial); u8 iface_config; int result; @@ -1529,6 +1558,56 @@ static int cp2105_gpioconf_init(struct usb_serial *serial) return 0; } +static int cp2104_gpioconf_init(struct usb_serial *serial) +{ + struct cp210x_serial_private *priv = usb_get_serial_data(serial); + struct cp210x_single_port_config config; + u8 iface_config; + u8 gpio_latch; + int result; + u8 i; + + result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST, + CP210X_GET_PORTCONFIG, &config, + sizeof(config)); + if (result < 0) + return result; + + priv->gc.ngpio = 4; + + iface_config = config.device_cfg; + priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) & + CP210X_GPIO_MODE_MASK) >> + CP210X_GPIO_MODE_OFFSET); + gpio_latch = (u8)((le16_to_cpu(config.reset_state) & + CP210X_GPIO_MODE_MASK) >> + CP210X_GPIO_MODE_OFFSET); + + /* mark all pins which are not in GPIO mode */ + if (iface_config & CP2104_GPIO0_TXLED_MODE) /* GPIO 0 */ + priv->gpio_altfunc |= BIT(0); + if (iface_config & CP2104_GPIO1_RXLED_MODE) /* GPIO 1 */ + priv->gpio_altfunc |= BIT(1); + if (iface_config & CP2104_GPIO2_RS485_MODE) /* GPIO 2 */ + priv->gpio_altfunc |= BIT(2); + + /* + * Like CP2102N, CP2104 has also no strict input and output pin + * modes. + * Do the same input mode emulation as CP2102N. + */ + for (i = 0; i < priv->gc.ngpio; ++i) { + /* + * Set direction to "input" iff pin is open-drain and reset + * value is 1. + */ + if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i))) + priv->gpio_input |= BIT(i); + } + + return 0; +} + static int cp2102n_gpioconf_init(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); @@ -1574,12 +1653,6 @@ static int cp2102n_gpioconf_init(struct usb_serial *serial) if (config_version != 0x01) return -ENOTSUPP; - /* - * We only support 4 GPIOs even on the QFN28 package, because - * config locations of GPIOs 4-6 determined using reverse - * engineering revealed conflicting offsets with other - * documented functions. So we'll just play it safe for now. - */ priv->gc.ngpio = 4; /* @@ -1594,6 +1667,19 @@ static int cp2102n_gpioconf_init(struct usb_serial *serial) /* 0 indicates GPIO mode, 1 is alternate function */ priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f; + if (priv->partnum == CP210X_PARTNUM_CP2102N_QFN28) { + /* + * For the QFN28 package, GPIO4-6 are controlled by + * the low three bits of the mode/latch fields. + * Contrary to the document linked above, the bits for + * the SUSPEND pins are elsewhere. No alternate + * function is available for these pins. + */ + priv->gc.ngpio = 7; + gpio_latch |= (gpio_rst_latch & 7) << 4; + priv->gpio_pushpull |= (gpio_pushpull & 7) << 4; + } + /* * The CP2102N does not strictly has input and output pin modes, * it only knows open-drain and push-pull modes which is set at @@ -1620,6 +1706,9 @@ static int cp210x_gpio_init(struct usb_serial *serial) int result; switch (priv->partnum) { + case CP210X_PARTNUM_CP2104: + result = cp2104_gpioconf_init(serial); + break; case CP210X_PARTNUM_CP2105: result = cp2105_gpioconf_init(serial); break; @@ -1716,6 +1805,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) { struct cp210x_serial_private *priv = usb_get_serial_data(serial); bool use_actual_rate = false; + speed_t min = 300; speed_t max; switch (priv->partnum) { @@ -1738,6 +1828,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) use_actual_rate = true; max = 2000000; /* ECI */ } else { + min = 2400; max = 921600; /* SCI */ } break; @@ -1752,6 +1843,7 @@ static void cp210x_init_max_speed(struct usb_serial *serial) break; } + priv->min_speed = min; priv->max_speed = max; priv->use_actual_rate = use_actual_rate; } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 77ef4c481f3c..8f5b17471759 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1025,6 +1025,8 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) }, { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) }, { USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) }, + /* EZPrototypes devices */ + { USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 975d02666c5a..b863bedb55a1 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1309,6 +1309,12 @@ #define IONICS_PLUGCOMPUTER_PID 0x0102 /* + * EZPrototypes (PID reseller) + */ +#define EZPROTOTYPES_VID 0x1c40 +#define HJELMSLUND_USB485_ISO_PID 0x0477 + +/* * Dresden Elektronik Sensor Terminal Board */ #define DE_VID 0x1cf1 /* Vendor ID */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index aef15497ff31..11b21d9410f3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1148,6 +1148,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), .driver_info = NCTRL(0) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */ + .driver_info = NCTRL(0) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 6fd427284b12..59aad38b490a 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # USB Storage driver configuration # diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c index edcf2be0e0eb..395cf8fb5870 100644 --- a/drivers/usb/storage/karma.c +++ b/drivers/usb/storage/karma.c @@ -167,6 +167,7 @@ static int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us) static void rio_karma_destructor(void *extra) { struct karma_data *data = (struct karma_data *) extra; + kfree(data->recv); } @@ -174,6 +175,7 @@ static int rio_karma_init(struct us_data *us) { int ret = 0; struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO); + if (!data) goto out; diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig index 30a847c2089d..89d9193bd1cf 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 menuconfig TYPEC tristate "USB Type-C Support" diff --git a/drivers/usb/typec/altmodes/Kconfig b/drivers/usb/typec/altmodes/Kconfig index efef2a64bc51..ef2226eb7a33 100644 --- a/drivers/usb/typec/altmodes/Kconfig +++ b/drivers/usb/typec/altmodes/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 menu "USB Type-C Alternate Mode drivers" diff --git a/drivers/usb/typec/altmodes/Makefile b/drivers/usb/typec/altmodes/Makefile index 5caf094ef71a..eda8456f1c92 100644 --- a/drivers/usb/typec/altmodes/Makefile +++ b/drivers/usb/typec/altmodes/Makefile @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_TYPEC_DP_ALTMODE) += typec_displayport.o typec_displayport-y := displayport.o diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 3f06e94771a7..610d790bc9be 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -24,10 +24,6 @@ enum { DP_CONF_DUAL_D, }; -/* Helper for setting/getting the pin assignement value to the configuration */ -#define DP_CONF_SET_PIN_ASSIGN(_a_) ((_a_) << 8) -#define DP_CONF_GET_PIN_ASSIGN(_conf_) (((_conf_) & GENMASK(15, 8)) >> 8) - /* Pin assignments that use USB3.1 Gen2 signaling to carry DP protocol */ #define DP_PIN_ASSIGN_GEN2_BR_MASK (BIT(DP_PIN_ASSIGN_A) | \ BIT(DP_PIN_ASSIGN_B)) diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 5db0593ca0bd..2eb623841847 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -9,6 +9,7 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/property.h> #include <linux/slab.h> #include "bus.h" @@ -204,15 +205,32 @@ static void typec_altmode_put_partner(struct altmode *altmode) put_device(&adev->dev); } -static int __typec_port_match(struct device *dev, const void *name) +static int typec_port_fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} + +static int typec_port_name_match(struct device *dev, const void *name) { return !strcmp((const char *)name, dev_name(dev)); } static void *typec_port_match(struct device_connection *con, int ep, void *data) { - return class_find_device(typec_class, NULL, con->endpoint[ep], - __typec_port_match); + struct device *dev; + + /* + * FIXME: Check does the fwnode supports the requested SVID. If it does + * we need to return ERR_PTR(-PROBE_DEFER) when there is no device. + */ + if (con->fwnode) + return class_find_device(typec_class, NULL, con->fwnode, + typec_port_fwnode_match); + + dev = class_find_device(typec_class, NULL, con->endpoint[ep], + typec_port_name_match); + + return dev ? dev : ERR_PTR(-EPROBE_DEFER); } struct typec_altmode * @@ -277,7 +295,7 @@ void typec_altmode_update_active(struct typec_altmode *adev, bool active) if (adev->active == active) return; - if (!is_typec_port(adev->dev.parent)) { + if (!is_typec_port(adev->dev.parent) && adev->dev.driver) { if (!active) module_put(adev->dev.driver->owner); else @@ -1496,11 +1514,8 @@ typec_port_register_altmode(struct typec_port *port, { struct typec_altmode *adev; struct typec_mux *mux; - char id[10]; - - sprintf(id, "id%04xm%02x", desc->svid, desc->mode); - mux = typec_mux_get(&port->dev, id); + mux = typec_mux_get(&port->dev, desc); if (IS_ERR(mux)) return ERR_CAST(mux); @@ -1593,7 +1608,7 @@ struct typec_port *typec_register_port(struct device *parent, return ERR_CAST(port->sw); } - port->mux = typec_mux_get(&port->dev, "typec-mux"); + port->mux = typec_mux_get(&port->dev, NULL); if (IS_ERR(port->mux)) { put_device(&port->dev); return ERR_CAST(port->mux); diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index d990aa510fab..2ce54f3fc79c 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -11,6 +11,8 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/property.h> +#include <linux/slab.h> #include <linux/usb/typec_mux.h> static DEFINE_MUTEX(switch_lock); @@ -23,15 +25,25 @@ static void *typec_switch_match(struct device_connection *con, int ep, { struct typec_switch *sw; - list_for_each_entry(sw, &switch_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(sw->dev))) - return sw; + if (!con->fwnode) { + list_for_each_entry(sw, &switch_list, entry) + if (!strcmp(con->endpoint[ep], dev_name(sw->dev))) + return sw; + return ERR_PTR(-EPROBE_DEFER); + } /* - * We only get called if a connection was found, tell the caller to - * wait for the switch to show up. + * With OF graph the mux node must have a boolean device property named + * "orientation-switch". */ - return ERR_PTR(-EPROBE_DEFER); + if (con->id && !fwnode_property_present(con->fwnode, con->id)) + return NULL; + + list_for_each_entry(sw, &switch_list, entry) + if (dev_fwnode(sw->dev) == con->fwnode) + return sw; + + return con->id ? ERR_PTR(-EPROBE_DEFER) : NULL; } /** @@ -48,7 +60,7 @@ struct typec_switch *typec_switch_get(struct device *dev) struct typec_switch *sw; mutex_lock(&switch_lock); - sw = device_connection_find_match(dev, "typec-switch", NULL, + sw = device_connection_find_match(dev, "orientation-switch", NULL, typec_switch_match); if (!IS_ERR_OR_NULL(sw)) { WARN_ON(!try_module_get(sw->dev->driver->owner)); @@ -112,35 +124,87 @@ EXPORT_SYMBOL_GPL(typec_switch_unregister); static void *typec_mux_match(struct device_connection *con, int ep, void *data) { + const struct typec_altmode_desc *desc = data; struct typec_mux *mux; + int nval; + bool match; + u16 *val; + int i; - list_for_each_entry(mux, &mux_list, entry) - if (!strcmp(con->endpoint[ep], dev_name(mux->dev))) - return mux; + if (!con->fwnode) { + list_for_each_entry(mux, &mux_list, entry) + if (!strcmp(con->endpoint[ep], dev_name(mux->dev))) + return mux; + return ERR_PTR(-EPROBE_DEFER); + } /* - * We only get called if a connection was found, tell the caller to - * wait for the switch to show up. + * Check has the identifier already been "consumed". If it + * has, no need to do any extra connection identification. */ + match = !con->id; + if (match) + goto find_mux; + + /* Accessory Mode muxes */ + if (!desc) { + match = fwnode_property_present(con->fwnode, "accessory"); + if (match) + goto find_mux; + return NULL; + } + + /* Alternate Mode muxes */ + nval = fwnode_property_read_u16_array(con->fwnode, "svid", NULL, 0); + if (nval <= 0) + return NULL; + + val = kcalloc(nval, sizeof(*val), GFP_KERNEL); + if (!val) + return ERR_PTR(-ENOMEM); + + nval = fwnode_property_read_u16_array(con->fwnode, "svid", val, nval); + if (nval < 0) { + kfree(val); + return ERR_PTR(nval); + } + + for (i = 0; i < nval; i++) { + match = val[i] == desc->svid; + if (match) { + kfree(val); + goto find_mux; + } + } + kfree(val); + return NULL; + +find_mux: + list_for_each_entry(mux, &mux_list, entry) + if (dev_fwnode(mux->dev) == con->fwnode) + return mux; + return ERR_PTR(-EPROBE_DEFER); } /** * typec_mux_get - Find USB Type-C Multiplexer * @dev: The caller device - * @name: Mux identifier + * @desc: Alt Mode description * * Finds a mux linked to the caller. This function is primarily meant for the * Type-C drivers. Returns a reference to the mux on success, NULL if no * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection * was found but the mux has not been enumerated yet. */ -struct typec_mux *typec_mux_get(struct device *dev, const char *name) +struct typec_mux *typec_mux_get(struct device *dev, + const struct typec_altmode_desc *desc) { struct typec_mux *mux; mutex_lock(&mux_lock); - mux = device_connection_find_match(dev, name, NULL, typec_mux_match); + mux = device_connection_find_match(dev, "mode-switch", (void *)desc, + typec_mux_match); if (!IS_ERR_OR_NULL(mux)) { WARN_ON(!try_module_get(mux->dev->driver->owner)); get_device(mux->dev); diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 9a954d2b8d8f..01ed0d5e10e8 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + menu "USB Type-C Multiplexer/DeMultiplexer Switch support" config TYPEC_MUX_PI3USB30532 diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index f03ea8a61768..72481bbb2af3 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config TYPEC_TCPM tristate "USB Type-C Port Controller Manager" depends on USB diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index f1c39a3c7534..0f62db091d8d 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -4435,66 +4435,6 @@ sink: return 0; } -int tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo, - unsigned int nr_pdo) -{ - if (tcpm_validate_caps(port, pdo, nr_pdo)) - return -EINVAL; - - mutex_lock(&port->lock); - port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, pdo, nr_pdo); - switch (port->state) { - case SRC_UNATTACHED: - case SRC_ATTACH_WAIT: - case SRC_TRYWAIT: - tcpm_set_cc(port, tcpm_rp_cc(port)); - break; - case SRC_SEND_CAPABILITIES: - case SRC_NEGOTIATE_CAPABILITIES: - case SRC_READY: - case SRC_WAIT_NEW_CAPABILITIES: - tcpm_set_cc(port, tcpm_rp_cc(port)); - tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); - break; - default: - break; - } - mutex_unlock(&port->lock); - return 0; -} -EXPORT_SYMBOL_GPL(tcpm_update_source_capabilities); - -int tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo, - unsigned int nr_pdo, - unsigned int operating_snk_mw) -{ - if (tcpm_validate_caps(port, pdo, nr_pdo)) - return -EINVAL; - - mutex_lock(&port->lock); - port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, pdo, nr_pdo); - port->operating_snk_mw = operating_snk_mw; - port->update_sink_caps = true; - - switch (port->state) { - case SNK_NEGOTIATE_CAPABILITIES: - case SNK_NEGOTIATE_PPS_CAPABILITIES: - case SNK_READY: - case SNK_TRANSITION_SINK: - case SNK_TRANSITION_SINK_VBUS: - if (port->pps_data.active) - tcpm_set_state(port, SNK_NEGOTIATE_PPS_CAPABILITIES, 0); - else - tcpm_set_state(port, SNK_NEGOTIATE_CAPABILITIES, 0); - break; - default: - break; - } - mutex_unlock(&port->lock); - return 0; -} -EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities); - /* Power Supply access to expose source power information */ enum tcpm_psy_online_states { TCPM_PSY_OFFLINE = 0, @@ -4811,12 +4751,12 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) err = devm_tcpm_psy_register(port); if (err) - goto out_destroy_wq; + goto out_role_sw_put; port->typec_port = typec_register_port(port->dev, &port->typec_caps); if (IS_ERR(port->typec_port)) { err = PTR_ERR(port->typec_port); - goto out_destroy_wq; + goto out_role_sw_put; } if (tcpc->config && tcpc->config->alt_modes) { @@ -4849,8 +4789,10 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) tcpm_log(port, "%s: registered", dev_name(dev)); return port; -out_destroy_wq: +out_role_sw_put: usb_role_switch_put(port->role_sw); +out_destroy_wq: + tcpm_debugfs_exit(port); destroy_workqueue(port->wq); return ERR_PTR(err); } diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c index 1c0033ad8738..c674abe3cf99 100644 --- a/drivers/usb/typec/tps6598x.c +++ b/drivers/usb/typec/tps6598x.c @@ -14,6 +14,8 @@ #include <linux/usb/typec.h> /* Register offsets */ +#define TPS_REG_VID 0x00 +#define TPS_REG_MODE 0x03 #define TPS_REG_CMD1 0x08 #define TPS_REG_DATA1 0x09 #define TPS_REG_INT_EVENT1 0x14 @@ -66,6 +68,20 @@ struct tps6598x_rx_identity_reg { #define TPS_TASK_TIMEOUT 1 #define TPS_TASK_REJECTED 3 +enum { + TPS_MODE_APP, + TPS_MODE_BOOT, + TPS_MODE_BIST, + TPS_MODE_DISC, +}; + +static const char *const modes[] = { + [TPS_MODE_APP] = "APP ", + [TPS_MODE_BOOT] = "BOOT", + [TPS_MODE_BIST] = "BIST", + [TPS_MODE_DISC] = "DISC", +}; + /* Unrecognized commands will be replaced with "!CMD" */ #define INVALID_CMD(_cmd_) (_cmd_ == 0x444d4321) @@ -110,6 +126,20 @@ tps6598x_block_read(struct tps6598x *tps, u8 reg, void *val, size_t len) return 0; } +static int tps6598x_block_write(struct tps6598x *tps, u8 reg, + void *val, size_t len) +{ + u8 data[TPS_MAX_LEN + 1]; + + if (!tps->i2c_protocol) + return regmap_raw_write(tps->regmap, reg, val, len); + + data[0] = len; + memcpy(&data[1], val, len); + + return regmap_raw_write(tps->regmap, reg, data, sizeof(data)); +} + static inline int tps6598x_read16(struct tps6598x *tps, u8 reg, u16 *val) { return tps6598x_block_read(tps, reg, val, sizeof(u16)); @@ -127,23 +157,23 @@ static inline int tps6598x_read64(struct tps6598x *tps, u8 reg, u64 *val) static inline int tps6598x_write16(struct tps6598x *tps, u8 reg, u16 val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u16)); + return tps6598x_block_write(tps, reg, &val, sizeof(u16)); } static inline int tps6598x_write32(struct tps6598x *tps, u8 reg, u32 val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u32)); + return tps6598x_block_write(tps, reg, &val, sizeof(u32)); } static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u64)); + return tps6598x_block_write(tps, reg, &val, sizeof(u64)); } static inline int tps6598x_write_4cc(struct tps6598x *tps, u8 reg, const char *val) { - return regmap_raw_write(tps->regmap, reg, &val, sizeof(u32)); + return tps6598x_block_write(tps, reg, &val, sizeof(u32)); } static int tps6598x_read_partner_identity(struct tps6598x *tps) @@ -229,8 +259,8 @@ static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, return -EBUSY; if (in_len) { - ret = regmap_raw_write(tps->regmap, TPS_REG_DATA1, - in_data, in_len); + ret = tps6598x_block_write(tps, TPS_REG_DATA1, + in_data, in_len); if (ret) return ret; } @@ -384,6 +414,32 @@ err_unlock: return IRQ_HANDLED; } +static int tps6598x_check_mode(struct tps6598x *tps) +{ + char mode[5] = { }; + int ret; + + ret = tps6598x_read32(tps, TPS_REG_MODE, (void *)mode); + if (ret) + return ret; + + switch (match_string(modes, ARRAY_SIZE(modes), mode)) { + case TPS_MODE_APP: + return 0; + case TPS_MODE_BOOT: + dev_warn(tps->dev, "dead-battery condition\n"); + return 0; + case TPS_MODE_BIST: + case TPS_MODE_DISC: + default: + dev_err(tps->dev, "controller in unsupported mode \"%s\"\n", + mode); + break; + } + + return -ENODEV; +} + static const struct regmap_config tps6598x_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -409,10 +465,8 @@ static int tps6598x_probe(struct i2c_client *client) if (IS_ERR(tps->regmap)) return PTR_ERR(tps->regmap); - ret = tps6598x_read32(tps, 0, &vid); - if (ret < 0) - return ret; - if (!vid) + ret = tps6598x_read32(tps, TPS_REG_VID, &vid); + if (ret < 0 || !vid) return -ENODEV; /* @@ -425,6 +479,11 @@ static int tps6598x_probe(struct i2c_client *client) if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) tps->i2c_protocol = true; + /* Make sure the controller has application firmware running */ + ret = tps6598x_check_mode(tps); + if (ret) + return ret; + ret = tps6598x_read32(tps, TPS_REG_STATUS, &status); if (ret < 0) return ret; diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 78118883f96c..15c2ac7db02d 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config TYPEC_UCSI tristate "USB Type-C Connector System Software Interface driver" depends on !CPU_BIG_ENDIAN diff --git a/drivers/usb/typec/ucsi/debug.h b/drivers/usb/typec/ucsi/debug.h deleted file mode 100644 index fdeff39df120..000000000000 --- a/drivers/usb/typec/ucsi/debug.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __UCSI_DEBUG_H -#define __UCSI_DEBUG_H - -#include "ucsi.h" - -static const char * const ucsi_cmd_strs[] = { - [0] = "Unknown command", - [UCSI_PPM_RESET] = "PPM_RESET", - [UCSI_CANCEL] = "CANCEL", - [UCSI_CONNECTOR_RESET] = "CONNECTOR_RESET", - [UCSI_ACK_CC_CI] = "ACK_CC_CI", - [UCSI_SET_NOTIFICATION_ENABLE] = "SET_NOTIFICATION_ENABLE", - [UCSI_GET_CAPABILITY] = "GET_CAPABILITY", - [UCSI_GET_CONNECTOR_CAPABILITY] = "GET_CONNECTOR_CAPABILITY", - [UCSI_SET_UOM] = "SET_UOM", - [UCSI_SET_UOR] = "SET_UOR", - [UCSI_SET_PDM] = "SET_PDM", - [UCSI_SET_PDR] = "SET_PDR", - [UCSI_GET_ALTERNATE_MODES] = "GET_ALTERNATE_MODES", - [UCSI_GET_CAM_SUPPORTED] = "GET_CAM_SUPPORTED", - [UCSI_GET_CURRENT_CAM] = "GET_CURRENT_CAM", - [UCSI_SET_NEW_CAM] = "SET_NEW_CAM", - [UCSI_GET_PDOS] = "GET_PDOS", - [UCSI_GET_CABLE_PROPERTY] = "GET_CABLE_PROPERTY", - [UCSI_GET_CONNECTOR_STATUS] = "GET_CONNECTOR_STATUS", - [UCSI_GET_ERROR_STATUS] = "GET_ERROR_STATUS", -}; - -static inline const char *ucsi_cmd_str(u64 raw_cmd) -{ - u8 cmd = raw_cmd & GENMASK(7, 0); - - return ucsi_cmd_strs[(cmd >= ARRAY_SIZE(ucsi_cmd_strs)) ? 0 : cmd]; -} - -static const char * const ucsi_ack_strs[] = { - [0] = "", - [UCSI_ACK_EVENT] = "event", - [UCSI_ACK_CMD] = "command", -}; - -static inline const char *ucsi_ack_str(u8 ack) -{ - return ucsi_ack_strs[(ack >= ARRAY_SIZE(ucsi_ack_strs)) ? 0 : ack]; -} - -static inline const char *ucsi_cci_str(u32 cci) -{ - if (cci & GENMASK(7, 0)) { - if (cci & BIT(29)) - return "Event pending (ACK completed)"; - if (cci & BIT(31)) - return "Event pending (command completed)"; - return "Connector Change"; - } - if (cci & BIT(29)) - return "ACK completed"; - if (cci & BIT(31)) - return "Command completed"; - - return ""; -} - -#endif /* __UCSI_DEBUG_H */ diff --git a/drivers/usb/typec/ucsi/trace.c b/drivers/usb/typec/ucsi/trace.c index d9a6ff6e673c..ffa3b4c3f338 100644 --- a/drivers/usb/typec/ucsi/trace.c +++ b/drivers/usb/typec/ucsi/trace.c @@ -1,3 +1,62 @@ // SPDX-License-Identifier: GPL-2.0 #define CREATE_TRACE_POINTS +#include "ucsi.h" #include "trace.h" + +static const char * const ucsi_cmd_strs[] = { + [0] = "Unknown command", + [UCSI_PPM_RESET] = "PPM_RESET", + [UCSI_CANCEL] = "CANCEL", + [UCSI_CONNECTOR_RESET] = "CONNECTOR_RESET", + [UCSI_ACK_CC_CI] = "ACK_CC_CI", + [UCSI_SET_NOTIFICATION_ENABLE] = "SET_NOTIFICATION_ENABLE", + [UCSI_GET_CAPABILITY] = "GET_CAPABILITY", + [UCSI_GET_CONNECTOR_CAPABILITY] = "GET_CONNECTOR_CAPABILITY", + [UCSI_SET_UOM] = "SET_UOM", + [UCSI_SET_UOR] = "SET_UOR", + [UCSI_SET_PDM] = "SET_PDM", + [UCSI_SET_PDR] = "SET_PDR", + [UCSI_GET_ALTERNATE_MODES] = "GET_ALTERNATE_MODES", + [UCSI_GET_CAM_SUPPORTED] = "GET_CAM_SUPPORTED", + [UCSI_GET_CURRENT_CAM] = "GET_CURRENT_CAM", + [UCSI_SET_NEW_CAM] = "SET_NEW_CAM", + [UCSI_GET_PDOS] = "GET_PDOS", + [UCSI_GET_CABLE_PROPERTY] = "GET_CABLE_PROPERTY", + [UCSI_GET_CONNECTOR_STATUS] = "GET_CONNECTOR_STATUS", + [UCSI_GET_ERROR_STATUS] = "GET_ERROR_STATUS", +}; + +const char *ucsi_cmd_str(u64 raw_cmd) +{ + u8 cmd = raw_cmd & GENMASK(7, 0); + + return ucsi_cmd_strs[(cmd >= ARRAY_SIZE(ucsi_cmd_strs)) ? 0 : cmd]; +} + +static const char * const ucsi_ack_strs[] = { + [0] = "", + [UCSI_ACK_EVENT] = "event", + [UCSI_ACK_CMD] = "command", +}; + +const char *ucsi_ack_str(u8 ack) +{ + return ucsi_ack_strs[(ack >= ARRAY_SIZE(ucsi_ack_strs)) ? 0 : ack]; +} + +const char *ucsi_cci_str(u32 cci) +{ + if (cci & GENMASK(7, 0)) { + if (cci & BIT(29)) + return "Event pending (ACK completed)"; + if (cci & BIT(31)) + return "Event pending (command completed)"; + return "Connector Change"; + } + if (cci & BIT(29)) + return "ACK completed"; + if (cci & BIT(31)) + return "Command completed"; + + return ""; +} diff --git a/drivers/usb/typec/ucsi/trace.h b/drivers/usb/typec/ucsi/trace.h index d5092446ecc6..5e2906df2db7 100644 --- a/drivers/usb/typec/ucsi/trace.h +++ b/drivers/usb/typec/ucsi/trace.h @@ -7,8 +7,11 @@ #define __UCSI_TRACE_H #include <linux/tracepoint.h> -#include "ucsi.h" -#include "debug.h" + +const char *ucsi_cmd_str(u64 raw_cmd); +const char *ucsi_ack_str(u8 ack); +const char *ucsi_cci_str(u32 cci); +const char *ucsi_recipient_str(u8 recipient); DECLARE_EVENT_CLASS(ucsi_log_ack, TP_PROTO(u8 ack), diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index a20b65cb6678..2f86b28fa3da 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config USBIP_CORE tristate "USB/IP support" depends on NET diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 1e592ec94ba4..f46ee1fefe02 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -702,8 +702,10 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag } vdev = &vhci_hcd->vdev[portnum-1]; - /* patch to usb_sg_init() is in 2.5.60 */ - BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); + if (!urb->transfer_buffer && urb->transfer_buffer_length) { + dev_dbg(dev, "Null URB transfer buffer\n"); + return -EINVAL; + } spin_lock_irqsave(&vhci->lock, flags); diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c index 1634d8698e15..a72c17ff1c6a 100644 --- a/drivers/usb/usbip/vudc_dev.c +++ b/drivers/usb/usbip/vudc_dev.c @@ -297,7 +297,8 @@ static void vep_free_request(struct usb_ep *_ep, struct usb_request *_req) { struct vrequest *req; - if (WARN_ON(!_ep || !_req)) + /* ep is always valid here - see usb_ep_free_request() */ + if (!_req) return; req = to_vrequest(_req); diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig index 348de1d6726e..12e89189ca7d 100644 --- a/drivers/usb/wusbcore/Kconfig +++ b/drivers/usb/wusbcore/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Wireless USB Core configuration # diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c index 222228c5c1e1..af77064c7456 100644 --- a/drivers/usb/wusbcore/cbaf.c +++ b/drivers/usb/wusbcore/cbaf.c @@ -302,10 +302,8 @@ static ssize_t cbaf_wusb_chid_show(struct device *dev, { struct usb_interface *iface = to_usb_interface(dev); struct cbaf *cbaf = usb_get_intfdata(iface); - char pr_chid[WUSB_CKHDID_STRSIZE]; - ckhdid_printf(pr_chid, sizeof(pr_chid), &cbaf->chid); - return scnprintf(buf, PAGE_SIZE, "%s\n", pr_chid); + return sprintf(buf, "%16ph\n", cbaf->chid.data); } static ssize_t cbaf_wusb_chid_store(struct device *dev, @@ -415,10 +413,8 @@ static ssize_t cbaf_wusb_cdid_show(struct device *dev, { struct usb_interface *iface = to_usb_interface(dev); struct cbaf *cbaf = usb_get_intfdata(iface); - char pr_cdid[WUSB_CKHDID_STRSIZE]; - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &cbaf->cdid); - return scnprintf(buf, PAGE_SIZE, "%s\n", pr_cdid); + return sprintf(buf, "%16ph\n", cbaf->cdid.data); } static ssize_t cbaf_wusb_cdid_store(struct device *dev, @@ -503,7 +499,6 @@ static int cbaf_cc_upload(struct cbaf *cbaf) int result; struct device *dev = &cbaf->usb_iface->dev; struct wusb_cbaf_cc_data *ccd; - char pr_cdid[WUSB_CKHDID_STRSIZE]; ccd = cbaf->buffer; *ccd = cbaf_cc_data_defaults; @@ -513,10 +508,8 @@ static int cbaf_cc_upload(struct cbaf *cbaf) ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups); dev_dbg(dev, "Trying to upload CC:\n"); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CHID); - dev_dbg(dev, " CHID %s\n", pr_cdid); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CDID); - dev_dbg(dev, " CDID %s\n", pr_cdid); + dev_dbg(dev, " CHID %16ph\n", ccd->CHID.data); + dev_dbg(dev, " CDID %16ph\n", ccd->CDID.data); dev_dbg(dev, " Bandgroups 0x%04x\n", cbaf->host_band_groups); result = usb_control_msg( diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c index 85a1acf3a729..67b0a4c412b2 100644 --- a/drivers/usb/wusbcore/dev-sysfs.c +++ b/drivers/usb/wusbcore/dev-sysfs.c @@ -50,10 +50,9 @@ static ssize_t wusb_cdid_show(struct device *dev, wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev)); if (wusb_dev == NULL) return -ENODEV; - result = ckhdid_printf(buf, PAGE_SIZE, &wusb_dev->cdid); - strcat(buf, "\n"); + result = sprintf(buf, "%16ph\n", wusb_dev->cdid.data); wusb_dev_put(wusb_dev); - return result + 1; + return result; } static DEVICE_ATTR_RO(wusb_cdid); diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index fcb06aef2675..a93837d57d53 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -532,7 +532,7 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc, } dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &dnc->CDID); + sprintf(pr_cdid, "%16ph", dnc->CDID.data); dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n", pr_cdid, wusb_dn_connect_prev_dev_addr(dnc), diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 01f2f21830c0..abf88cea37bb 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -662,9 +662,9 @@ static void __wa_setup_isoc_packet_descr( /* populate isoc packet descriptor. */ packet_desc->bPacketType = WA_XFER_ISO_PACKET_INFO; - packet_desc->wLength = cpu_to_le16(sizeof(*packet_desc) + - (sizeof(packet_desc->PacketLength[0]) * - seg->isoc_frame_count)); + packet_desc->wLength = cpu_to_le16(struct_size(packet_desc, + PacketLength, + seg->isoc_frame_count)); for (frame_index = 0; frame_index < seg->isoc_frame_count; ++frame_index) { int offset_index = frame_index + seg->isoc_frame_offset; @@ -2438,7 +2438,7 @@ static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb) struct wa_rpipe *rpipe; unsigned done = 0, dti_busy = 0, data_frame_count = 0, seg_index; unsigned first_frame_index = 0, rpipe_ready = 0; - int expected_size; + size_t expected_size; /* We have a xfer result buffer; check it */ dev_dbg(dev, "DTI: isoc packet status %d bytes at %p\n", @@ -2460,11 +2460,10 @@ static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb) goto error_bad_seg; seg = xfer->seg[wa->dti_isoc_xfer_seg]; rpipe = xfer->ep->hcpriv; - expected_size = sizeof(*packet_status) + - (sizeof(packet_status->PacketStatus[0]) * - seg->isoc_frame_count); + expected_size = struct_size(packet_status, PacketStatus, + seg->isoc_frame_count); if (urb->actual_length != expected_size) { - dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %d needed)\n", + dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %zu needed)\n", urb->actual_length, expected_size); goto error_bad_seg; } diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c index e5ba6140c1ba..d0b404d258e8 100644 --- a/drivers/usb/wusbcore/wusbhc.c +++ b/drivers/usb/wusbcore/wusbhc.c @@ -80,17 +80,13 @@ static ssize_t wusb_chid_show(struct device *dev, { struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); const struct wusb_ckhdid *chid; - ssize_t result = 0; if (wusbhc->wuie_host_info != NULL) chid = &wusbhc->wuie_host_info->CHID; else chid = &wusb_ckhdid_zero; - result += ckhdid_printf(buf, PAGE_SIZE, chid); - result += sprintf(buf + result, "\n"); - - return result; + return sprintf(buf, "%16ph\n", chid->data); } /* diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c index 1d2a939cfcf8..ed993e363472 100644 --- a/drivers/uwb/drp-ie.c +++ b/drivers/uwb/drp-ie.c @@ -125,9 +125,8 @@ static struct uwb_ie_drp *uwb_drp_ie_alloc(void) { struct uwb_ie_drp *drp_ie; - drp_ie = kzalloc(sizeof(struct uwb_ie_drp) + - UWB_NUM_ZONES * sizeof(struct uwb_drp_alloc), - GFP_KERNEL); + drp_ie = kzalloc(struct_size(drp_ie, allocs, UWB_NUM_ZONES), + GFP_KERNEL); if (drp_ie) drp_ie->hdr.element_id = UWB_IE_DRP; return drp_ie; |