diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-22 11:15:59 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-22 11:15:59 -0800 |
commit | 8ff546b801e5cca0337c0f0a7234795d0a6309a1 (patch) | |
tree | fbda2c8e8e5aa9b82d389091f7945e28cdb67418 /drivers | |
parent | ca78d3173cff3503bcd15723b049757f75762d15 (diff) | |
parent | 0df8a3dbacb585bb9c8b2e55de43c6aac9d86488 (diff) |
Merge tag 'usb-4.11-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 and PHY driver updates for 4.11-rc1.
Nothing major, just the normal amount of churn in the usb gadget and
dwc and xhci controllers, new device ids, new phy drivers, a new
usb-serial driver, and a few other minor changes in different USB
drivers.
All have been in linux-next for a long time with no reported issues"
* tag 'usb-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (265 commits)
usb: cdc-wdm: remove logically dead code
USB: serial: keyspan: drop header file
USB: serial: io_edgeport: drop io-tables header file
usb: musb: add code comment for clarification
usb: misc: add USB251xB/xBi Hi-Speed Hub Controller Driver
usb: misc: usbtest: remove redundant check on retval < 0
USB: serial: upd78f0730: sort device ids
USB: serial: upd78f0730: add ID for EVAL-ADXL362Z
ohci-hub: fix typo in dbg_port macro
usb: musb: dsps: Manage CPPI 4.1 DMA interrupt in DSPS
usb: musb: tusb6010: Clean up tusb_omap_dma structure
usb: musb: cppi_dma: Clean up cppi41_dma_controller structure
usb: musb: cppi_dma: Clean up cppi structure
usb: musb: cppi41: Detect aborted transfers in cppi41_dma_callback()
usb: musb: dma: Add a DMA completion platform callback
drivers: usb: usbip: Add missing break statement to switch
usb: mtu3: remove redundant dev_err call in get_ssusb_rscs()
USB: serial: mos7840: fix another NULL-deref at open
USB: serial: console: clean up sanity checks
USB: serial: console: fix uninitialised spinlock
...
Diffstat (limited to 'drivers')
170 files changed, 7224 insertions, 4433 deletions
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c index 200828c60db9..d74cee077842 100644 --- a/drivers/dma/cppi41.c +++ b/drivers/dma/cppi41.c @@ -79,14 +79,6 @@ #define QMGR_QUEUE_C(n) (0x2008 + (n) * 0x10) #define QMGR_QUEUE_D(n) (0x200c + (n) * 0x10) -/* Glue layer specific */ -/* USBSS / USB AM335x */ -#define USBSS_IRQ_STATUS 0x28 -#define USBSS_IRQ_ENABLER 0x2c -#define USBSS_IRQ_CLEARR 0x30 - -#define USBSS_IRQ_PD_COMP (1 << 2) - /* Packet Descriptor */ #define PD2_ZERO_LENGTH (1 << 19) @@ -294,14 +286,8 @@ static irqreturn_t cppi41_irq(int irq, void *data) { struct cppi41_dd *cdd = data; struct cppi41_channel *c; - u32 status; int i; - status = cppi_readl(cdd->usbss_mem + USBSS_IRQ_STATUS); - if (!(status & USBSS_IRQ_PD_COMP)) - return IRQ_NONE; - cppi_writel(status, cdd->usbss_mem + USBSS_IRQ_STATUS); - for (i = QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE); i < QMGR_NUM_PEND; i++) { u32 val; @@ -618,6 +604,7 @@ static void cppi41_compute_td_desc(struct cppi41_desc *d) static int cppi41_tear_down_chan(struct cppi41_channel *c) { + struct dmaengine_result abort_result; struct cppi41_dd *cdd = c->cdd; struct cppi41_desc *td; u32 reg; @@ -701,6 +688,12 @@ static int cppi41_tear_down_chan(struct cppi41_channel *c) c->td_seen = 0; c->td_desc_seen = 0; cppi_writel(0, c->gcr_reg); + + /* Invoke the callback to do the necessary clean-up */ + abort_result.result = DMA_TRANS_ABORTED; + dma_cookie_complete(&c->txd); + dmaengine_desc_get_callback_invoke(&c->txd, &abort_result); + return 0; } @@ -1066,8 +1059,6 @@ static int cppi41_dma_probe(struct platform_device *pdev) goto err_irq; } - cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER); - ret = devm_request_irq(&pdev->dev, irq, glue_info->isr, IRQF_SHARED, dev_name(dev), cdd); if (ret) @@ -1091,7 +1082,6 @@ err_of: dma_async_device_unregister(&cdd->ddev); err_dma_reg: err_irq: - cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); cleanup_chans(cdd); err_chans: deinit_cppi41(dev, cdd); @@ -1119,7 +1109,6 @@ static int cppi41_dma_remove(struct platform_device *pdev) of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&cdd->ddev); - cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); devm_free_irq(&pdev->dev, cdd->irq, cdd); cleanup_chans(cdd); deinit_cppi41(&pdev->dev, cdd); @@ -1138,7 +1127,6 @@ static int __maybe_unused cppi41_suspend(struct device *dev) struct cppi41_dd *cdd = dev_get_drvdata(dev); cdd->dma_tdfdq = cppi_readl(cdd->ctrl_mem + DMA_TDFDQ); - cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); disable_sched(cdd); return 0; @@ -1164,8 +1152,6 @@ static int __maybe_unused cppi41_resume(struct device *dev) cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE); cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE); - cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER); - return 0; } diff --git a/drivers/of/device.c b/drivers/of/device.c index fd5cfad7c403..b1e6bebda3f3 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -225,6 +225,30 @@ ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) return tsize; } +EXPORT_SYMBOL_GPL(of_device_get_modalias); + +int of_device_request_module(struct device *dev) +{ + char *str; + ssize_t size; + int ret; + + size = of_device_get_modalias(dev, NULL, 0); + if (size < 0) + return size; + + str = kmalloc(size + 1, GFP_KERNEL); + if (!str) + return -ENOMEM; + + of_device_get_modalias(dev, str, size); + str[size] = '\0'; + ret = request_module(str); + kfree(str); + + return ret; +} +EXPORT_SYMBOL_GPL(of_device_request_module); /** * of_device_uevent - Display OF related uevent information @@ -287,3 +311,4 @@ int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) return 0; } +EXPORT_SYMBOL_GPL(of_device_uevent_modalias); diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e8eb7f225a88..bb5cf6f49b06 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -363,6 +363,7 @@ config PHY_ROCKCHIP_INNO_USB2 tristate "Rockchip INNO USB2PHY Driver" depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF depends on COMMON_CLK + depends on EXTCON depends on USB_SUPPORT select GENERIC_PHY select USB_COMMON @@ -437,6 +438,21 @@ config PHY_QCOM_UFS help Support for UFS PHY on QCOM chipsets. +config PHY_QCOM_USB_HS + tristate "Qualcomm USB HS PHY module" + depends on USB_ULPI_BUS + select GENERIC_PHY + help + Support for the USB high-speed ULPI compliant phy on Qualcomm + chipsets. + +config PHY_QCOM_USB_HSIC + tristate "Qualcomm USB HSIC ULPI PHY module" + depends on USB_ULPI_BUS + select GENERIC_PHY + help + Support for the USB HSIC ULPI compliant PHY on QCOM chipsets. + config PHY_TUSB1210 tristate "TI TUSB1210 ULPI PHY module" depends on USB_ULPI_BUS @@ -486,4 +502,12 @@ config PHY_MESON8B_USB2 and GXBB SoCs. If unsure, say N. +config PHY_NSP_USB3 + tristate "Broadcom NorthStar plus USB3 PHY driver" + depends on OF && (ARCH_BCM_NSP || COMPILE_TEST) + select GENERIC_PHY + default ARCH_BCM_NSP + help + Enable this to support the Broadcom Northstar plus USB3 PHY. + If unsure, say N. endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 65eb2f436a41..9f008004f75d 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -52,6 +52,8 @@ obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o +obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o +obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o @@ -59,3 +61,4 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o +obj-$(CONFIG_PHY_NSP_USB3) += phy-bcm-nsp-usb3.o diff --git a/drivers/phy/phy-bcm-cygnus-pcie.c b/drivers/phy/phy-bcm-cygnus-pcie.c index 082c03f6438f..0f4ac5d63cff 100644 --- a/drivers/phy/phy-bcm-cygnus-pcie.c +++ b/drivers/phy/phy-bcm-cygnus-pcie.c @@ -114,7 +114,7 @@ static int cygnus_pcie_phy_power_off(struct phy *p) return cygnus_pcie_power_config(phy, false); } -static struct phy_ops cygnus_pcie_phy_ops = { +static const struct phy_ops cygnus_pcie_phy_ops = { .power_on = cygnus_pcie_phy_power_on, .power_off = cygnus_pcie_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-bcm-nsp-usb3.c b/drivers/phy/phy-bcm-nsp-usb3.c new file mode 100644 index 000000000000..49024eaa5545 --- /dev/null +++ b/drivers/phy/phy-bcm-nsp-usb3.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016 Broadcom + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/mdio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/phy/phy.h> +#include <linux/regmap.h> + +#define NSP_USB3_RST_CTRL_OFFSET 0x3f8 + +/* mdio reg access */ +#define NSP_USB3_PHY_BASE_ADDR_REG 0x1f + +#define NSP_USB3_PHY_PLL30_BLOCK 0x8000 +#define NSP_USB3_PLL_CONTROL 0x01 +#define NSP_USB3_PLLA_CONTROL0 0x0a +#define NSP_USB3_PLLA_CONTROL1 0x0b + +#define NSP_USB3_PHY_TX_PMD_BLOCK 0x8040 +#define NSP_USB3_TX_PMD_CONTROL1 0x01 + +#define NSP_USB3_PHY_PIPE_BLOCK 0x8060 +#define NSP_USB3_LFPS_CMP 0x02 +#define NSP_USB3_LFPS_DEGLITCH 0x03 + +struct nsp_usb3_phy { + struct regmap *usb3_ctrl; + struct phy *phy; + struct mdio_device *mdiodev; +}; + +static int nsp_usb3_phy_init(struct phy *phy) +{ + struct nsp_usb3_phy *iphy = phy_get_drvdata(phy); + struct mii_bus *bus = iphy->mdiodev->bus; + int addr = iphy->mdiodev->addr; + u32 data; + int rc; + + rc = regmap_read(iphy->usb3_ctrl, 0, &data); + if (rc) + return rc; + data |= 1; + rc = regmap_write(iphy->usb3_ctrl, 0, data); + if (rc) + return rc; + + rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 1); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG, + NSP_USB3_PHY_PLL30_BLOCK); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x1000); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL0, 0x6400); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0xc000); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0x8000); + if (rc) + return rc; + + rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 0); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x9000); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG, + NSP_USB3_PHY_PIPE_BLOCK); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_CMP, 0xf30d); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_DEGLITCH, 0x6302); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG, + NSP_USB3_PHY_TX_PMD_BLOCK); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_TX_PMD_CONTROL1, 0x1003); + + return rc; +} + +static struct phy_ops nsp_usb3_phy_ops = { + .init = nsp_usb3_phy_init, + .owner = THIS_MODULE, +}; + +static int nsp_usb3_phy_probe(struct mdio_device *mdiodev) +{ + struct device *dev = &mdiodev->dev; + struct phy_provider *provider; + struct nsp_usb3_phy *iphy; + + iphy = devm_kzalloc(dev, sizeof(*iphy), GFP_KERNEL); + if (!iphy) + return -ENOMEM; + iphy->mdiodev = mdiodev; + + iphy->usb3_ctrl = syscon_regmap_lookup_by_phandle(dev->of_node, + "usb3-ctrl-syscon"); + if (IS_ERR(iphy->usb3_ctrl)) + return PTR_ERR(iphy->usb3_ctrl); + + iphy->phy = devm_phy_create(dev, dev->of_node, &nsp_usb3_phy_ops); + if (IS_ERR(iphy->phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(iphy->phy); + } + + phy_set_drvdata(iphy->phy, iphy); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) { + dev_err(dev, "could not register PHY provider\n"); + return PTR_ERR(provider); + } + + return 0; +} + +static const struct of_device_id nsp_usb3_phy_of_match[] = { + {.compatible = "brcm,nsp-usb3-phy",}, + { /* sentinel */ } +}; + +static struct mdio_driver nsp_usb3_phy_driver = { + .mdiodrv = { + .driver = { + .name = "nsp-usb3-phy", + .of_match_table = nsp_usb3_phy_of_match, + }, + }, + .probe = nsp_usb3_phy_probe, +}; + +mdio_module_driver(nsp_usb3_phy_driver); + +MODULE_DESCRIPTION("Broadcom NSP USB3 PHY driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com"); diff --git a/drivers/phy/phy-hi6220-usb.c b/drivers/phy/phy-hi6220-usb.c index b2141cbd4cf6..398c1021deec 100644 --- a/drivers/phy/phy-hi6220-usb.c +++ b/drivers/phy/phy-hi6220-usb.c @@ -112,7 +112,7 @@ static int hi6220_phy_exit(struct phy *phy) return hi6220_phy_setup(priv, false); } -static struct phy_ops hi6220_phy_ops = { +static const struct phy_ops hi6220_phy_ops = { .init = hi6220_phy_start, .exit = hi6220_phy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c index 4d85e730ccab..d9720675b9db 100644 --- a/drivers/phy/phy-mt65xx-usb3.c +++ b/drivers/phy/phy-mt65xx-usb3.c @@ -506,7 +506,7 @@ static struct phy *mt65xx_phy_xlate(struct device *dev, return instance->phy; } -static struct phy_ops mt65xx_u3phy_ops = { +static const struct phy_ops mt65xx_u3phy_ops = { .init = mt65xx_phy_init, .exit = mt65xx_phy_exit, .power_on = mt65xx_phy_power_on, diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h index d505d98cf5f8..13b02b7de30b 100644 --- a/drivers/phy/phy-qcom-ufs-i.h +++ b/drivers/phy/phy-qcom-ufs-i.h @@ -77,7 +77,6 @@ struct ufs_qcom_phy_vreg { int min_uV; int max_uV; bool enabled; - bool is_always_on; }; struct ufs_qcom_phy { diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c index c71c84734916..12a1b498dc4b 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c @@ -132,27 +132,18 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev) &ufs_qcom_phy_qmp_14nm_phy_ops, &phy_14nm_ops); if (!generic_phy) { - dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n", - __func__); err = -EIO; goto out; } err = ufs_qcom_phy_init_clks(phy_common); - if (err) { - dev_err(phy_common->dev, - "%s: ufs_qcom_phy_init_clks() failed %d\n", - __func__, err); + if (err) goto out; - } err = ufs_qcom_phy_init_vregulators(phy_common); - if (err) { - dev_err(phy_common->dev, - "%s: ufs_qcom_phy_init_vregulators() failed %d\n", - __func__, err); + if (err) goto out; - } + phy_common->vdda_phy.max_uV = UFS_PHY_VDDA_PHY_UV; phy_common->vdda_phy.min_uV = UFS_PHY_VDDA_PHY_UV; diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c index 1a26a64e06d3..4f68acb58b73 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -190,25 +190,17 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev) &ufs_qcom_phy_qmp_20nm_phy_ops, &phy_20nm_ops); if (!generic_phy) { - dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n", - __func__); err = -EIO; goto out; } err = ufs_qcom_phy_init_clks(phy_common); - if (err) { - dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n", - __func__, err); + if (err) goto out; - } err = ufs_qcom_phy_init_vregulators(phy_common); - if (err) { - dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n", - __func__, err); + if (err) goto out; - } ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common); diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c index c69568b8543d..43865ef340e2 100644 --- a/drivers/phy/phy-qcom-ufs.c +++ b/drivers/phy/phy-qcom-ufs.c @@ -189,12 +189,12 @@ int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common) if (err) goto out; +skip_txrx_clk: err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk_src", &phy_common->ref_clk_src); if (err) goto out; -skip_txrx_clk: /* * "ref_clk_parent" is optional hence don't abort init if it's not * found. @@ -210,25 +210,19 @@ out: } EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_clks); -static int __ufs_qcom_phy_init_vreg(struct device *dev, - struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional) +static int ufs_qcom_phy_init_vreg(struct device *dev, + struct ufs_qcom_phy_vreg *vreg, + const char *name) { int err = 0; char prop_name[MAX_PROP_NAME]; - vreg->name = devm_kstrdup(dev, name, GFP_KERNEL); - if (!vreg->name) { - err = -ENOMEM; - goto out; - } - + vreg->name = name; vreg->reg = devm_regulator_get(dev, name); if (IS_ERR(vreg->reg)) { err = PTR_ERR(vreg->reg); - vreg->reg = NULL; - if (!optional) - dev_err(dev, "failed to get %s, %d\n", name, err); + dev_err(dev, "failed to get %s, %d\n", name, err); goto out; } @@ -248,9 +242,6 @@ static int __ufs_qcom_phy_init_vreg(struct device *dev, } err = 0; } - snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name); - vreg->is_always_on = of_property_read_bool(dev->of_node, - prop_name); } if (!strcmp(name, "vdda-pll")) { @@ -265,17 +256,9 @@ static int __ufs_qcom_phy_init_vreg(struct device *dev, } out: - if (err) - kfree(vreg->name); return err; } -static int ufs_qcom_phy_init_vreg(struct device *dev, - struct ufs_qcom_phy_vreg *vreg, const char *name) -{ - return __ufs_qcom_phy_init_vreg(dev, vreg, name, false); -} - int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common) { int err; @@ -291,9 +274,9 @@ int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common) if (err) goto out; - /* vddp-ref-clk-* properties are optional */ - __ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk, - "vddp-ref-clk", true); + err = ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk, + "vddp-ref-clk"); + out: return err; } @@ -416,7 +399,7 @@ static int ufs_qcom_phy_disable_vreg(struct device *dev, { int ret = 0; - if (!vreg || !vreg->enabled || vreg->is_always_on) + if (!vreg || !vreg->enabled) goto out; ret = regulator_disable(vreg->reg); diff --git a/drivers/phy/phy-qcom-usb-hs.c b/drivers/phy/phy-qcom-usb-hs.c new file mode 100644 index 000000000000..94dfbfd739c3 --- /dev/null +++ b/drivers/phy/phy-qcom-usb-hs.c @@ -0,0 +1,296 @@ +/** + * Copyright (C) 2016 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/ulpi/driver.h> +#include <linux/ulpi/regs.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h> +#include <linux/of_device.h> +#include <linux/reset.h> +#include <linux/extcon.h> +#include <linux/notifier.h> + +#include "ulpi_phy.h" + +#define ULPI_PWR_CLK_MNG_REG 0x88 +# define ULPI_PWR_OTG_COMP_DISABLE BIT(0) + +#define ULPI_MISC_A 0x96 +# define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1) +# define ULPI_MISC_A_VBUSVLDEXT BIT(0) + + +struct ulpi_seq { + u8 addr; + u8 val; +}; + +struct qcom_usb_hs_phy { + struct ulpi *ulpi; + struct phy *phy; + struct clk *ref_clk; + struct clk *sleep_clk; + struct regulator *v1p8; + struct regulator *v3p3; + struct reset_control *reset; + struct ulpi_seq *init_seq; + struct extcon_dev *vbus_edev; + struct notifier_block vbus_notify; +}; + +static int qcom_usb_hs_phy_set_mode(struct phy *phy, enum phy_mode mode) +{ + struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); + u8 addr; + int ret; + + if (!uphy->vbus_edev) { + u8 val = 0; + + switch (mode) { + case PHY_MODE_USB_OTG: + case PHY_MODE_USB_HOST: + val |= ULPI_INT_IDGRD; + case PHY_MODE_USB_DEVICE: + val |= ULPI_INT_SESS_VALID; + default: + break; + } + + ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_RISE, val); + if (ret) + return ret; + ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_FALL, val); + } else { + switch (mode) { + case PHY_MODE_USB_OTG: + case PHY_MODE_USB_DEVICE: + addr = ULPI_SET(ULPI_MISC_A); + break; + case PHY_MODE_USB_HOST: + addr = ULPI_CLR(ULPI_MISC_A); + break; + default: + return -EINVAL; + } + + ret = ulpi_write(uphy->ulpi, ULPI_SET(ULPI_PWR_CLK_MNG_REG), + ULPI_PWR_OTG_COMP_DISABLE); + if (ret) + return ret; + ret = ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXTSEL); + } + + return ret; +} + +static int +qcom_usb_hs_phy_vbus_notifier(struct notifier_block *nb, unsigned long event, + void *ptr) +{ + struct qcom_usb_hs_phy *uphy; + u8 addr; + + uphy = container_of(nb, struct qcom_usb_hs_phy, vbus_notify); + + if (event) + addr = ULPI_SET(ULPI_MISC_A); + else + addr = ULPI_CLR(ULPI_MISC_A); + + return ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXT); +} + +static int qcom_usb_hs_phy_power_on(struct phy *phy) +{ + struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); + struct ulpi *ulpi = uphy->ulpi; + const struct ulpi_seq *seq; + int ret, state; + + ret = clk_prepare_enable(uphy->ref_clk); + if (ret) + return ret; + + ret = clk_prepare_enable(uphy->sleep_clk); + if (ret) + goto err_sleep; + + ret = regulator_set_load(uphy->v1p8, 50000); + if (ret < 0) + goto err_1p8; + + ret = regulator_enable(uphy->v1p8); + if (ret) + goto err_1p8; + + ret = regulator_set_voltage_triplet(uphy->v3p3, 3050000, 3300000, + 3300000); + if (ret) + goto err_3p3; + + ret = regulator_set_load(uphy->v3p3, 50000); + if (ret < 0) + goto err_3p3; + + ret = regulator_enable(uphy->v3p3); + if (ret) + goto err_3p3; + + for (seq = uphy->init_seq; seq->addr; seq++) { + ret = ulpi_write(ulpi, ULPI_EXT_VENDOR_SPECIFIC + seq->addr, + seq->val); + if (ret) + goto err_ulpi; + } + + if (uphy->reset) { + ret = reset_control_reset(uphy->reset); + if (ret) + goto err_ulpi; + } + + if (uphy->vbus_edev) { + state = extcon_get_cable_state_(uphy->vbus_edev, EXTCON_USB); + /* setup initial state */ + qcom_usb_hs_phy_vbus_notifier(&uphy->vbus_notify, state, + uphy->vbus_edev); + ret = extcon_register_notifier(uphy->vbus_edev, EXTCON_USB, + &uphy->vbus_notify); + if (ret) + goto err_ulpi; + } + + return 0; +err_ulpi: + regulator_disable(uphy->v3p3); +err_3p3: + regulator_disable(uphy->v1p8); +err_1p8: + clk_disable_unprepare(uphy->sleep_clk); +err_sleep: + clk_disable_unprepare(uphy->ref_clk); + return ret; +} + +static int qcom_usb_hs_phy_power_off(struct phy *phy) +{ + int ret; + struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); + + if (uphy->vbus_edev) { + ret = extcon_unregister_notifier(uphy->vbus_edev, EXTCON_USB, + &uphy->vbus_notify); + if (ret) + return ret; + } + + regulator_disable(uphy->v3p3); + regulator_disable(uphy->v1p8); + clk_disable_unprepare(uphy->sleep_clk); + clk_disable_unprepare(uphy->ref_clk); + + return 0; +} + +static const struct phy_ops qcom_usb_hs_phy_ops = { + .power_on = qcom_usb_hs_phy_power_on, + .power_off = qcom_usb_hs_phy_power_off, + .set_mode = qcom_usb_hs_phy_set_mode, + .owner = THIS_MODULE, +}; + +static int qcom_usb_hs_phy_probe(struct ulpi *ulpi) +{ + struct qcom_usb_hs_phy *uphy; + struct phy_provider *p; + struct clk *clk; + struct regulator *reg; + struct reset_control *reset; + int size; + int ret; + + uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL); + if (!uphy) + return -ENOMEM; + ulpi_set_drvdata(ulpi, uphy); + uphy->ulpi = ulpi; + + size = of_property_count_u8_elems(ulpi->dev.of_node, "qcom,init-seq"); + if (size < 0) + size = 0; + uphy->init_seq = devm_kmalloc_array(&ulpi->dev, (size / 2) + 1, + sizeof(*uphy->init_seq), GFP_KERNEL); + if (!uphy->init_seq) + return -ENOMEM; + ret = of_property_read_u8_array(ulpi->dev.of_node, "qcom,init-seq", + (u8 *)uphy->init_seq, size); + if (ret && size) + return ret; + /* NUL terminate */ + uphy->init_seq[size / 2].addr = uphy->init_seq[size / 2].val = 0; + + uphy->ref_clk = clk = devm_clk_get(&ulpi->dev, "ref"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->sleep_clk = clk = devm_clk_get(&ulpi->dev, "sleep"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->v1p8 = reg = devm_regulator_get(&ulpi->dev, "v1p8"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + uphy->v3p3 = reg = devm_regulator_get(&ulpi->dev, "v3p3"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + uphy->reset = reset = devm_reset_control_get(&ulpi->dev, "por"); + if (IS_ERR(reset)) { + if (PTR_ERR(reset) == -EPROBE_DEFER) + return PTR_ERR(reset); + uphy->reset = NULL; + } + + uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node, + &qcom_usb_hs_phy_ops); + if (IS_ERR(uphy->phy)) + return PTR_ERR(uphy->phy); + + uphy->vbus_edev = extcon_get_edev_by_phandle(&ulpi->dev, 0); + if (IS_ERR(uphy->vbus_edev)) { + if (PTR_ERR(uphy->vbus_edev) != -ENODEV) + return PTR_ERR(uphy->vbus_edev); + uphy->vbus_edev = NULL; + } + + uphy->vbus_notify.notifier_call = qcom_usb_hs_phy_vbus_notifier; + phy_set_drvdata(uphy->phy, uphy); + + p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(p); +} + +static const struct of_device_id qcom_usb_hs_phy_match[] = { + { .compatible = "qcom,usb-hs-phy", }, + { } +}; +MODULE_DEVICE_TABLE(of, qcom_usb_hs_phy_match); + +static struct ulpi_driver qcom_usb_hs_phy_driver = { + .probe = qcom_usb_hs_phy_probe, + .driver = { + .name = "qcom_usb_hs_phy", + .of_match_table = qcom_usb_hs_phy_match, + }, +}; +module_ulpi_driver(qcom_usb_hs_phy_driver); + +MODULE_DESCRIPTION("Qualcomm USB HS phy"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-qcom-usb-hsic.c b/drivers/phy/phy-qcom-usb-hsic.c new file mode 100644 index 000000000000..47690f9945b9 --- /dev/null +++ b/drivers/phy/phy-qcom-usb-hsic.c @@ -0,0 +1,160 @@ +/** + * Copyright (C) 2016 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/ulpi/driver.h> +#include <linux/ulpi/regs.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/pinctrl-state.h> +#include <linux/delay.h> +#include <linux/clk.h> + +#include "ulpi_phy.h" + +#define ULPI_HSIC_CFG 0x30 +#define ULPI_HSIC_IO_CAL 0x33 + +struct qcom_usb_hsic_phy { + struct ulpi *ulpi; + struct phy *phy; + struct pinctrl *pctl; + struct clk *phy_clk; + struct clk *cal_clk; + struct clk *cal_sleep_clk; +}; + +static int qcom_usb_hsic_phy_power_on(struct phy *phy) +{ + struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy); + struct ulpi *ulpi = uphy->ulpi; + struct pinctrl_state *pins_default; + int ret; + + ret = clk_prepare_enable(uphy->phy_clk); + if (ret) + return ret; + + ret = clk_prepare_enable(uphy->cal_clk); + if (ret) + goto err_cal; + + ret = clk_prepare_enable(uphy->cal_sleep_clk); + if (ret) + goto err_sleep; + + /* Set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */ + ret = ulpi_write(ulpi, ULPI_HSIC_IO_CAL, 0xff); + if (ret) + goto err_ulpi; + + /* Enable periodic IO calibration in HSIC_CFG register */ + ret = ulpi_write(ulpi, ULPI_HSIC_CFG, 0xa8); + if (ret) + goto err_ulpi; + + /* Configure pins for HSIC functionality */ + pins_default = pinctrl_lookup_state(uphy->pctl, PINCTRL_STATE_DEFAULT); + if (IS_ERR(pins_default)) + return PTR_ERR(pins_default); + + ret = pinctrl_select_state(uphy->pctl, pins_default); + if (ret) + goto err_ulpi; + + /* Enable HSIC mode in HSIC_CFG register */ + ret = ulpi_write(ulpi, ULPI_SET(ULPI_HSIC_CFG), 0x01); + if (ret) + goto err_ulpi; + + /* Disable auto-resume */ + ret = ulpi_write(ulpi, ULPI_CLR(ULPI_IFC_CTRL), + ULPI_IFC_CTRL_AUTORESUME); + if (ret) + goto err_ulpi; + + return ret; +err_ulpi: + clk_disable_unprepare(uphy->cal_sleep_clk); +err_sleep: + clk_disable_unprepare(uphy->cal_clk); +err_cal: + clk_disable_unprepare(uphy->phy_clk); + return ret; +} + +static int qcom_usb_hsic_phy_power_off(struct phy *phy) +{ + struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy); + + clk_disable_unprepare(uphy->cal_sleep_clk); + clk_disable_unprepare(uphy->cal_clk); + clk_disable_unprepare(uphy->phy_clk); + + return 0; +} + +static const struct phy_ops qcom_usb_hsic_phy_ops = { + .power_on = qcom_usb_hsic_phy_power_on, + .power_off = qcom_usb_hsic_phy_power_off, + .owner = THIS_MODULE, +}; + +static int qcom_usb_hsic_phy_probe(struct ulpi *ulpi) +{ + struct qcom_usb_hsic_phy *uphy; + struct phy_provider *p; + struct clk *clk; + + uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL); + if (!uphy) + return -ENOMEM; + ulpi_set_drvdata(ulpi, uphy); + + uphy->ulpi = ulpi; + uphy->pctl = devm_pinctrl_get(&ulpi->dev); + if (IS_ERR(uphy->pctl)) + return PTR_ERR(uphy->pctl); + + uphy->phy_clk = clk = devm_clk_get(&ulpi->dev, "phy"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->cal_clk = clk = devm_clk_get(&ulpi->dev, "cal"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->cal_sleep_clk = clk = devm_clk_get(&ulpi->dev, "cal_sleep"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node, + &qcom_usb_hsic_phy_ops); + if (IS_ERR(uphy->phy)) + return PTR_ERR(uphy->phy); + phy_set_drvdata(uphy->phy, uphy); + + p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(p); +} + +static const struct of_device_id qcom_usb_hsic_phy_match[] = { + { .compatible = "qcom,usb-hsic-phy", }, + { } +}; +MODULE_DEVICE_TABLE(of, qcom_usb_hsic_phy_match); + +static struct ulpi_driver qcom_usb_hsic_phy_driver = { + .probe = qcom_usb_hsic_phy_probe, + .driver = { + .name = "qcom_usb_hsic_phy", + .of_match_table = qcom_usb_hsic_phy_match, + }, +}; +module_ulpi_driver(qcom_usb_hsic_phy_driver); + +MODULE_DESCRIPTION("Qualcomm USB HSIC phy"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index c63da1b955c1..afb4d048d3e9 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -94,11 +94,11 @@ static void rcar_gen3_phy_usb2_work(struct work_struct *work) work); if (ch->extcon_host) { - extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true); - extcon_set_cable_state_(ch->extcon, EXTCON_USB, false); + extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true); + extcon_set_state_sync(ch->extcon, EXTCON_USB, false); } else { - extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false); - extcon_set_cable_state_(ch->extcon, EXTCON_USB, true); + extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, false); + extcon_set_state_sync(ch->extcon, EXTCON_USB, true); } } @@ -350,7 +350,7 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p) return ret; } -static struct phy_ops rcar_gen3_phy_usb2_ops = { +static const struct phy_ops rcar_gen3_phy_usb2_ops = { .init = rcar_gen3_phy_usb2_init, .exit = rcar_gen3_phy_usb2_exit, .power_on = rcar_gen3_phy_usb2_power_on, diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c index 2f99ec95079c..4ea95c28a66f 100644 --- a/drivers/phy/phy-rockchip-inno-usb2.c +++ b/drivers/phy/phy-rockchip-inno-usb2.c @@ -595,9 +595,14 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) if (rport->vbus_attached != vbus_attach) { rport->vbus_attached = vbus_attach; - if (notify_charger && rphy->edev) + if (notify_charger && rphy->edev) { extcon_set_cable_state_(rphy->edev, cable, vbus_attach); + if (cable == EXTCON_CHG_USB_SDP) + extcon_set_state_sync(rphy->edev, + EXTCON_USB, + vbus_attach); + } } break; case OTG_STATE_B_PERIPHERAL: diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index bf28a0fdd569..a21b5f24a340 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -99,6 +99,7 @@ enum sun4i_usb_phy_type { sun6i_a31_phy, sun8i_a33_phy, sun8i_h3_phy, + sun8i_v3s_phy, sun50i_a64_phy, }; @@ -188,7 +189,8 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, spin_lock_irqsave(&phy_data->reg_lock, flags); if (phy_data->cfg->type == sun8i_a33_phy || - phy_data->cfg->type == sun50i_a64_phy) { + phy_data->cfg->type == sun50i_a64_phy || + phy_data->cfg->type == sun8i_v3s_phy) { /* A33 or A64 needs us to set phyctl to 0 explicitly */ writel(0, phyctl); } @@ -534,7 +536,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) mutex_unlock(&phy0->mutex); if (id_notify) { - extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST, + extcon_set_state_sync(data->extcon, EXTCON_USB_HOST, !id_det); /* When leaving host mode force end the session here */ if (force_session_end && id_det == 1) { @@ -547,7 +549,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) } if (vbus_notify) - extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det); + extcon_set_state_sync(data->extcon, EXTCON_USB, vbus_det); if (sun4i_usb_phy0_poll(data)) queue_delayed_work(system_wq, &data->detect, POLL_TIME); @@ -825,6 +827,15 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { .enable_pmu_unk1 = true, }; +static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = { + .num_phys = 1, + .type = sun8i_v3s_phy, + .disc_thresh = 3, + .phyctl_offset = REG_PHYCTL_A33, + .dedicated_clocks = true, + .enable_pmu_unk1 = true, +}; + static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { .num_phys = 2, .type = sun50i_a64_phy, @@ -842,6 +853,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg }, { .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg }, { .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg }, + { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg }, { .compatible = "allwinner,sun50i-a64-usb-phy", .data = &sun50i_a64_cfg}, { }, diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 5e5b9eb7ebf6..fc96f5cdcb5c 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -2,6 +2,7 @@ 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 select EXTCON + select RESET_CONTROLLER help Say Y here if your system has a dual role high speed USB controller based on ChipIdea silicon IP. It supports: @@ -38,4 +39,11 @@ config USB_CHIPIDEA_HOST Say Y here to enable host controller functionality of the ChipIdea driver. +config USB_CHIPIDEA_ULPI + bool "ChipIdea ULPI PHY support" + depends on USB_ULPI_BUS=y || USB_ULPI_BUS=USB_CHIPIDEA + help + Say Y here if you have a ULPI PHY attached to your ChipIdea + controller. + endif diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 518e445476c3..39fca5715ed3 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -4,6 +4,7 @@ ci_hdrc-y := core.o otg.o debug.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o +ci_hdrc-$(CONFIG_USB_CHIPIDEA_ULPI) += ulpi.o # Glue/Bridge layers go here diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index cd414559040f..59e22389c10b 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -18,6 +18,8 @@ #include <linux/usb.h> #include <linux/usb/gadget.h> #include <linux/usb/otg-fsm.h> +#include <linux/usb/otg.h> +#include <linux/ulpi/interface.h> /****************************************************************************** * DEFINE @@ -52,6 +54,7 @@ enum ci_hw_regs { OP_ENDPTLISTADDR, OP_TTCTRL, OP_BURSTSIZE, + OP_ULPI_VIEWPORT, OP_PORTSC, OP_DEVLC, OP_OTGSC, @@ -187,6 +190,8 @@ struct hw_bank { * @test_mode: the selected test mode * @platdata: platform specific information supplied by parent device * @vbus_active: is VBUS active + * @ulpi: pointer to ULPI device, if any + * @ulpi_ops: ULPI read/write ops for this device * @phy: pointer to PHY, if any * @usb_phy: pointer to USB PHY, if any and if using the USB PHY framework * @hcd: pointer to usb_hcd for ehci host driver @@ -236,6 +241,10 @@ struct ci_hdrc { struct ci_hdrc_platform_data *platdata; int vbus_active; +#ifdef CONFIG_USB_CHIPIDEA_ULPI + struct ulpi *ulpi; + struct ulpi_ops ulpi_ops; +#endif struct phy *phy; /* old usb_phy interface */ struct usb_phy *usb_phy; @@ -418,6 +427,16 @@ static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci) #endif } +#if IS_ENABLED(CONFIG_USB_CHIPIDEA_ULPI) +int ci_ulpi_init(struct ci_hdrc *ci); +void ci_ulpi_exit(struct ci_hdrc *ci); +int ci_ulpi_resume(struct ci_hdrc *ci); +#else +static inline int ci_ulpi_init(struct ci_hdrc *ci) { return 0; } +static inline void ci_ulpi_exit(struct ci_hdrc *ci) { } +static inline int ci_ulpi_resume(struct ci_hdrc *ci) { return 0; } +#endif + u32 hw_read_intr_enable(struct ci_hdrc *ci); u32 hw_read_intr_status(struct ci_hdrc *ci); @@ -428,8 +447,7 @@ int hw_port_test_set(struct ci_hdrc *ci, u8 mode); u8 hw_port_test_get(struct ci_hdrc *ci); -int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, - u32 value, unsigned int timeout_ms); +void hw_phymode_configure(struct ci_hdrc *ci); void ci_platform_configure(struct ci_hdrc *ci); diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 3889809fd0c4..0bdfcdcbf7a5 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -8,90 +8,292 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/usb/msm_hsusb_hw.h> -#include <linux/usb/ulpi.h> -#include <linux/usb/gadget.h> #include <linux/usb/chipidea.h> +#include <linux/clk.h> +#include <linux/reset.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/io.h> +#include <linux/reset-controller.h> +#include <linux/extcon.h> +#include <linux/of.h> #include "ci.h" -#define MSM_USB_BASE (ci->hw_bank.abs) +#define HS_PHY_AHB_MODE 0x0098 -static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) +#define HS_PHY_GENCONFIG 0x009c +#define HS_PHY_TXFIFO_IDLE_FORCE_DIS BIT(4) + +#define HS_PHY_GENCONFIG_2 0x00a0 +#define HS_PHY_SESS_VLD_CTRL_EN BIT(7) +#define HS_PHY_ULPI_TX_PKT_EN_CLR_FIX BIT(19) + +#define HSPHY_SESS_VLD_CTRL BIT(25) + +/* Vendor base starts at 0x200 beyond CI base */ +#define HS_PHY_CTRL 0x0040 +#define HS_PHY_SEC_CTRL 0x0078 +#define HS_PHY_DIG_CLAMP_N BIT(16) +#define HS_PHY_POR_ASSERT BIT(0) + +struct ci_hdrc_msm { + struct platform_device *ci; + struct clk *core_clk; + struct clk *iface_clk; + struct clk *fs_clk; + struct ci_hdrc_platform_data pdata; + struct reset_controller_dev rcdev; + bool secondary_phy; + bool hsic; + void __iomem *base; +}; + +static int +ci_hdrc_msm_por_reset(struct reset_controller_dev *r, unsigned long id) { - struct device *dev = ci->gadget.dev.parent; + struct ci_hdrc_msm *ci_msm = container_of(r, struct ci_hdrc_msm, rcdev); + void __iomem *addr = ci_msm->base; + u32 val; + + if (id) + addr += HS_PHY_SEC_CTRL; + else + addr += HS_PHY_CTRL; + + val = readl_relaxed(addr); + val |= HS_PHY_POR_ASSERT; + writel(val, addr); + /* + * wait for minimum 10 microseconds as suggested by manual. + * Use a slightly larger value since the exact value didn't + * work 100% of the time. + */ + udelay(12); + val &= ~HS_PHY_POR_ASSERT; + writel(val, addr); + + return 0; +} + +static const struct reset_control_ops ci_hdrc_msm_reset_ops = { + .reset = ci_hdrc_msm_por_reset, +}; + +static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) +{ + struct device *dev = ci->dev->parent; + struct ci_hdrc_msm *msm_ci = dev_get_drvdata(dev); + int ret; switch (event) { case CI_HDRC_CONTROLLER_RESET_EVENT: dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n"); - writel(0, USB_AHBBURST); + + hw_phymode_configure(ci); + if (msm_ci->secondary_phy) { + u32 val = readl_relaxed(msm_ci->base + HS_PHY_SEC_CTRL); + val |= HS_PHY_DIG_CLAMP_N; + writel_relaxed(val, msm_ci->base + HS_PHY_SEC_CTRL); + } + + ret = phy_init(ci->phy); + if (ret) + return ret; + + ret = phy_power_on(ci->phy); + if (ret) { + phy_exit(ci->phy); + return ret; + } + /* use AHB transactor, allow posted data writes */ - writel(0x8, USB_AHBMODE); - usb_phy_init(ci->usb_phy); + hw_write_id_reg(ci, HS_PHY_AHB_MODE, 0xffffffff, 0x8); + + /* workaround for rx buffer collision issue */ + hw_write_id_reg(ci, HS_PHY_GENCONFIG, + HS_PHY_TXFIFO_IDLE_FORCE_DIS, 0); + + if (!msm_ci->hsic) + hw_write_id_reg(ci, HS_PHY_GENCONFIG_2, + HS_PHY_ULPI_TX_PKT_EN_CLR_FIX, 0); + + if (!IS_ERR(ci->platdata->vbus_extcon.edev)) { + hw_write_id_reg(ci, HS_PHY_GENCONFIG_2, + HS_PHY_SESS_VLD_CTRL_EN, + HS_PHY_SESS_VLD_CTRL_EN); + hw_write(ci, OP_USBCMD, HSPHY_SESS_VLD_CTRL, + HSPHY_SESS_VLD_CTRL); + + } break; case CI_HDRC_CONTROLLER_STOPPED_EVENT: dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n"); - /* - * Put the phy in non-driving mode. Otherwise host - * may not detect soft-disconnection. - */ - usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN); + phy_power_off(ci->phy); + phy_exit(ci->phy); break; default: dev_dbg(dev, "unknown ci_hdrc event\n"); break; } + + return 0; } -static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { - .name = "ci_hdrc_msm", - .capoffset = DEF_CAPOFFSET, - .flags = CI_HDRC_REGS_SHARED | - CI_HDRC_DISABLE_STREAMING, +static int ci_hdrc_msm_mux_phy(struct ci_hdrc_msm *ci, + struct platform_device *pdev) +{ + struct regmap *regmap; + struct device *dev = &pdev->dev; + struct of_phandle_args args; + u32 val; + int ret; - .notify_event = ci_hdrc_msm_notify_event, -}; + ret = of_parse_phandle_with_fixed_args(dev->of_node, "phy-select", 2, 0, + &args); + if (ret) + return 0; + + regmap = syscon_node_to_regmap(args.np); + of_node_put(args.np); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = regmap_write(regmap, args.args[0], args.args[1]); + if (ret) + return ret; + + ci->secondary_phy = !!args.args[1]; + if (ci->secondary_phy) { + val = readl_relaxed(ci->base + HS_PHY_SEC_CTRL); + val |= HS_PHY_DIG_CLAMP_N; + writel_relaxed(val, ci->base + HS_PHY_SEC_CTRL); + } + + return 0; +} static int ci_hdrc_msm_probe(struct platform_device *pdev) { + struct ci_hdrc_msm *ci; struct platform_device *plat_ci; - struct usb_phy *phy; + struct clk *clk; + struct reset_control *reset; + struct resource *res; + int ret; + struct device_node *ulpi_node, *phy_node; dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n"); - /* - * OTG(PHY) driver takes care of PHY initialization, clock management, - * powering up VBUS, mapping of registers address space and power - * management. - */ - phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); - if (IS_ERR(phy)) - return PTR_ERR(phy); + ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL); + if (!ci) + return -ENOMEM; + platform_set_drvdata(pdev, ci); + + ci->pdata.name = "ci_hdrc_msm"; + ci->pdata.capoffset = DEF_CAPOFFSET; + ci->pdata.flags = CI_HDRC_REGS_SHARED | CI_HDRC_DISABLE_STREAMING | + CI_HDRC_OVERRIDE_AHB_BURST | + CI_HDRC_OVERRIDE_PHY_CONTROL; + ci->pdata.notify_event = ci_hdrc_msm_notify_event; + + reset = devm_reset_control_get(&pdev->dev, "core"); + if (IS_ERR(reset)) + return PTR_ERR(reset); + + ci->core_clk = clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(clk)) + return PTR_ERR(clk); - ci_hdrc_msm_platdata.usb_phy = phy; + ci->iface_clk = clk = devm_clk_get(&pdev->dev, "iface"); + if (IS_ERR(clk)) + return PTR_ERR(clk); - plat_ci = ci_hdrc_add_device(&pdev->dev, - pdev->resource, pdev->num_resources, - &ci_hdrc_msm_platdata); + ci->fs_clk = clk = devm_clk_get(&pdev->dev, "fs"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + ci->fs_clk = NULL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ci->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ci->base)) + return PTR_ERR(ci->base); + + ci->rcdev.owner = THIS_MODULE; + ci->rcdev.ops = &ci_hdrc_msm_reset_ops; + ci->rcdev.of_node = pdev->dev.of_node; + ci->rcdev.nr_resets = 2; + ret = reset_controller_register(&ci->rcdev); + if (ret) + return ret; + + ret = clk_prepare_enable(ci->fs_clk); + if (ret) + goto err_fs; + + reset_control_assert(reset); + usleep_range(10000, 12000); + reset_control_deassert(reset); + + clk_disable_unprepare(ci->fs_clk); + + ret = clk_prepare_enable(ci->core_clk); + if (ret) + goto err_fs; + + ret = clk_prepare_enable(ci->iface_clk); + if (ret) + goto err_iface; + + ret = ci_hdrc_msm_mux_phy(ci, pdev); + if (ret) + goto err_mux; + + ulpi_node = of_find_node_by_name(pdev->dev.of_node, "ulpi"); + if (ulpi_node) { + phy_node = of_get_next_available_child(ulpi_node, NULL); + ci->hsic = of_device_is_compatible(phy_node, "qcom,usb-hsic-phy"); + of_node_put(phy_node); + } + of_node_put(ulpi_node); + + plat_ci = ci_hdrc_add_device(&pdev->dev, pdev->resource, + pdev->num_resources, &ci->pdata); if (IS_ERR(plat_ci)) { - dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n"); - return PTR_ERR(plat_ci); + ret = PTR_ERR(plat_ci); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n"); + goto err_mux; } - platform_set_drvdata(pdev, plat_ci); + ci->ci = plat_ci; + pm_runtime_set_active(&pdev->dev); pm_runtime_no_callbacks(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0; + +err_mux: + clk_disable_unprepare(ci->iface_clk); +err_iface: + clk_disable_unprepare(ci->core_clk); +err_fs: + reset_controller_unregister(&ci->rcdev); + return ret; } static int ci_hdrc_msm_remove(struct platform_device *pdev) { - struct platform_device *plat_ci = platform_get_drvdata(pdev); + struct ci_hdrc_msm *ci = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); - ci_hdrc_remove_device(plat_ci); + ci_hdrc_remove_device(ci->ci); + clk_disable_unprepare(ci->iface_clk); + clk_disable_unprepare(ci->core_clk); + reset_controller_unregister(&ci->rcdev); return 0; } diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index 4456d2cf80ff..d162cc0bb8ce 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -74,10 +74,6 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev) } } - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); - if (ret) - goto clk_err; - ci_pdata->name = dev_name(dev); priv->ci_pdev = ci_hdrc_add_device(dev, pdev->resource, diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 3dbb4a21ab44..79ad8e91632e 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -62,7 +62,6 @@ #include <linux/usb/chipidea.h> #include <linux/usb/of.h> #include <linux/of.h> -#include <linux/phy.h> #include <linux/regulator/consumer.h> #include <linux/usb/ehci_def.h> @@ -86,6 +85,7 @@ static const u8 ci_regs_nolpm[] = { [OP_ENDPTLISTADDR] = 0x18U, [OP_TTCTRL] = 0x1CU, [OP_BURSTSIZE] = 0x20U, + [OP_ULPI_VIEWPORT] = 0x30U, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0x64U, @@ -110,6 +110,7 @@ static const u8 ci_regs_lpm[] = { [OP_ENDPTLISTADDR] = 0x18U, [OP_TTCTRL] = 0x1CU, [OP_BURSTSIZE] = 0x20U, + [OP_ULPI_VIEWPORT] = 0x30U, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0xC4U, @@ -285,7 +286,7 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) return 0; } -static void hw_phymode_configure(struct ci_hdrc *ci) +void hw_phymode_configure(struct ci_hdrc *ci) { u32 portsc, lpm, sts = 0; @@ -325,6 +326,7 @@ static void hw_phymode_configure(struct ci_hdrc *ci) hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS); } } +EXPORT_SYMBOL_GPL(hw_phymode_configure); /** * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy @@ -361,6 +363,9 @@ static int _ci_usb_phy_init(struct ci_hdrc *ci) */ static void ci_usb_phy_exit(struct ci_hdrc *ci) { + if (ci->platdata->flags & CI_HDRC_OVERRIDE_PHY_CONTROL) + return; + if (ci->phy) { phy_power_off(ci->phy); phy_exit(ci->phy); @@ -379,6 +384,9 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) { int ret; + if (ci->platdata->flags & CI_HDRC_OVERRIDE_PHY_CONTROL) + return 0; + switch (ci->platdata->phy_mode) { case USBPHY_INTERFACE_MODE_UTMI: case USBPHY_INTERFACE_MODE_UTMIW: @@ -419,13 +427,21 @@ void ci_platform_configure(struct ci_hdrc *ci) is_device_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_DC; is_host_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_HC; - if (is_device_mode && - (ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING)) - hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + if (is_device_mode) { + phy_set_mode(ci->phy, PHY_MODE_USB_DEVICE); + + if (ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, + USBMODE_CI_SDIS); + } + + if (is_host_mode) { + phy_set_mode(ci->phy, PHY_MODE_USB_HOST); - if (is_host_mode && - (ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING)) - hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + if (ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, + USBMODE_CI_SDIS); + } if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { if (ci->hw_bank.lpm) @@ -495,9 +511,12 @@ int hw_device_reset(struct ci_hdrc *ci) return ret; } - if (ci->platdata->notify_event) - ci->platdata->notify_event(ci, + if (ci->platdata->notify_event) { + ret = ci->platdata->notify_event(ci, CI_HDRC_CONTROLLER_RESET_EVENT); + if (ret) + return ret; + } /* USBMODE should be configured step by step */ hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); @@ -516,38 +535,6 @@ int hw_device_reset(struct ci_hdrc *ci) return 0; } -/** - * hw_wait_reg: wait the register value - * - * Sometimes, it needs to wait register value before going on. - * Eg, when switch to device mode, the vbus value should be lower - * than OTGSC_BSV before connects to host. - * - * @ci: the controller - * @reg: register index - * @mask: mast bit - * @value: the bit value to wait - * @timeout_ms: timeout in millisecond - * - * This function returns an error code if timeout - */ -int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, - u32 value, unsigned int timeout_ms) -{ - unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); - - while (hw_read(ci, reg, mask) != value) { - if (time_after(jiffies, elapse)) { - dev_err(ci->dev, "timeout waiting for %08x in %d\n", - mask, reg); - return -ETIMEDOUT; - } - msleep(20); - } - - return 0; -} - static irqreturn_t ci_irq(int irq, void *data) { struct ci_hdrc *ci = data; @@ -601,35 +588,14 @@ static irqreturn_t ci_irq(int irq, void *data) return ret; } -static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event, - void *ptr) -{ - struct ci_hdrc_cable *vbus = container_of(nb, struct ci_hdrc_cable, nb); - struct ci_hdrc *ci = vbus->ci; - - if (event) - vbus->state = true; - else - vbus->state = false; - - vbus->changed = true; - - ci_irq(ci->irq, ci); - return NOTIFY_DONE; -} - -static int ci_id_notifier(struct notifier_block *nb, unsigned long event, - void *ptr) +static int ci_cable_notifier(struct notifier_block *nb, unsigned long event, + void *ptr) { - struct ci_hdrc_cable *id = container_of(nb, struct ci_hdrc_cable, nb); - struct ci_hdrc *ci = id->ci; + struct ci_hdrc_cable *cbl = container_of(nb, struct ci_hdrc_cable, nb); + struct ci_hdrc *ci = cbl->ci; - if (event) - id->state = false; - else - id->state = true; - - id->changed = true; + cbl->connected = event; + cbl->changed = true; ci_irq(ci->irq, ci); return NOTIFY_DONE; @@ -738,27 +704,27 @@ static int ci_get_platdata(struct device *dev, } cable = &platdata->vbus_extcon; - cable->nb.notifier_call = ci_vbus_notifier; + cable->nb.notifier_call = ci_cable_notifier; cable->edev = ext_vbus; if (!IS_ERR(ext_vbus)) { - ret = extcon_get_cable_state_(cable->edev, EXTCON_USB); + ret = extcon_get_state(cable->edev, EXTCON_USB); if (ret) - cable->state = true; + cable->connected = true; else - cable->state = false; + cable->connected = false; } cable = &platdata->id_extcon; - cable->nb.notifier_call = ci_id_notifier; + cable->nb.notifier_call = ci_cable_notifier; cable->edev = ext_id; if (!IS_ERR(ext_id)) { - ret = extcon_get_cable_state_(cable->edev, EXTCON_USB_HOST); + ret = extcon_get_state(cable->edev, EXTCON_USB_HOST); if (ret) - cable->state = false; + cable->connected = true; else - cable->state = true; + cable->connected = false; } return 0; } @@ -771,8 +737,8 @@ static int ci_extcon_register(struct ci_hdrc *ci) id = &ci->platdata->id_extcon; id->ci = ci; if (!IS_ERR(id->edev)) { - ret = extcon_register_notifier(id->edev, EXTCON_USB_HOST, - &id->nb); + ret = devm_extcon_register_notifier(ci->dev, id->edev, + EXTCON_USB_HOST, &id->nb); if (ret < 0) { dev_err(ci->dev, "register ID failed\n"); return ret; @@ -782,11 +748,9 @@ static int ci_extcon_register(struct ci_hdrc *ci) vbus = &ci->platdata->vbus_extcon; vbus->ci = ci; if (!IS_ERR(vbus->edev)) { - ret = extcon_register_notifier(vbus->edev, EXTCON_USB, - &vbus->nb); + ret = devm_extcon_register_notifier(ci->dev, vbus->edev, + EXTCON_USB, &vbus->nb); if (ret < 0) { - extcon_unregister_notifier(id->edev, EXTCON_USB_HOST, - &id->nb); dev_err(ci->dev, "register VBUS failed\n"); return ret; } @@ -795,20 +759,6 @@ static int ci_extcon_register(struct ci_hdrc *ci) return 0; } -static void ci_extcon_unregister(struct ci_hdrc *ci) -{ - struct ci_hdrc_cable *cable; - - cable = &ci->platdata->id_extcon; - if (!IS_ERR(cable->edev)) - extcon_unregister_notifier(cable->edev, EXTCON_USB_HOST, - &cable->nb); - - cable = &ci->platdata->vbus_extcon; - if (!IS_ERR(cable->edev)) - extcon_unregister_notifier(cable->edev, EXTCON_USB, &cable->nb); -} - static DEFINE_IDA(ci_ida); struct platform_device *ci_hdrc_add_device(struct device *dev, @@ -921,6 +871,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) CI_HDRC_IMX28_WRITE_FIX); ci->supports_runtime_pm = !!(ci->platdata->flags & CI_HDRC_SUPPORTS_RUNTIME_PM); + platform_set_drvdata(pdev, ci); ret = hw_device_init(ci, base); if (ret < 0) { @@ -928,6 +879,10 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } + ret = ci_ulpi_init(ci); + if (ret) + return ret; + if (ci->platdata->phy) { ci->phy = ci->platdata->phy; } else if (ci->platdata->usb_phy) { @@ -938,11 +893,15 @@ static int ci_hdrc_probe(struct platform_device *pdev) /* if both generic PHY and USB PHY layers aren't enabled */ if (PTR_ERR(ci->phy) == -ENOSYS && - PTR_ERR(ci->usb_phy) == -ENXIO) - return -ENXIO; + PTR_ERR(ci->usb_phy) == -ENXIO) { + ret = -ENXIO; + goto ulpi_exit; + } - if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) - return -EPROBE_DEFER; + if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) { + ret = -EPROBE_DEFER; + goto ulpi_exit; + } if (IS_ERR(ci->phy)) ci->phy = NULL; @@ -1027,7 +986,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) } } - platform_set_drvdata(pdev, ci); ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name, ci); if (ret) @@ -1054,11 +1012,12 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (!ret) return 0; - ci_extcon_unregister(ci); stop: ci_role_destroy(ci); deinit_phy: ci_usb_phy_exit(ci); +ulpi_exit: + ci_ulpi_exit(ci); return ret; } @@ -1074,10 +1033,10 @@ static int ci_hdrc_remove(struct platform_device *pdev) } dbg_remove_files(ci); - ci_extcon_unregister(ci); ci_role_destroy(ci); ci_hdrc_enter_lpm(ci, true); ci_usb_phy_exit(ci); + ci_ulpi_exit(ci); return 0; } @@ -1125,6 +1084,7 @@ static void ci_controller_suspend(struct ci_hdrc *ci) static int ci_controller_resume(struct device *dev) { struct ci_hdrc *ci = dev_get_drvdata(dev); + int ret; dev_dbg(dev, "at %s\n", __func__); @@ -1134,6 +1094,11 @@ static int ci_controller_resume(struct device *dev) } ci_hdrc_enter_lpm(ci, false); + + ret = ci_ulpi_resume(ci); + if (ret) + return ret; + if (ci->usb_phy) { usb_phy_set_suspend(ci->usb_phy, 0); usb_phy_set_wakeup(ci->usb_phy, false); diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 111b0e0b8698..915f3e91586e 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -90,6 +90,13 @@ static int ehci_ci_reset(struct usb_hcd *hcd) ehci->need_io_watchdog = 0; + if (ci->platdata->notify_event) { + ret = ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_RESET_EVENT); + if (ret) + return ret; + } + ci_platform_configure(ci); return ret; @@ -187,6 +194,9 @@ static void host_stop(struct ci_hdrc *ci) struct usb_hcd *hcd = ci->hcd; if (hcd) { + if (ci->platdata->notify_event) + ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_STOPPED_EVENT); usb_remove_hcd(hcd); ci->role = CI_ROLE_END; synchronize_irq(ci->irq); diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 03b6743461d1..10236fe71522 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -44,12 +44,15 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) else val &= ~OTGSC_BSVIS; - cable->changed = false; - - if (cable->state) + if (cable->connected) val |= OTGSC_BSV; else val &= ~OTGSC_BSV; + + if (cable->enabled) + val |= OTGSC_BSVIE; + else + val &= ~OTGSC_BSVIE; } cable = &ci->platdata->id_extcon; @@ -59,15 +62,18 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) else val &= ~OTGSC_IDIS; - cable->changed = false; + if (cable->connected) + val &= ~OTGSC_ID; /* host */ + else + val |= OTGSC_ID; /* device */ - if (cable->state) - val |= OTGSC_ID; + if (cable->enabled) + val |= OTGSC_IDIE; else - val &= ~OTGSC_ID; + val &= ~OTGSC_IDIE; } - return val; + return val & mask; } /** @@ -77,6 +83,36 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) */ void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data) { + struct ci_hdrc_cable *cable; + + cable = &ci->platdata->vbus_extcon; + if (!IS_ERR(cable->edev)) { + if (data & mask & OTGSC_BSVIS) + cable->changed = false; + + /* Don't enable vbus interrupt if using external notifier */ + if (data & mask & OTGSC_BSVIE) { + cable->enabled = true; + data &= ~OTGSC_BSVIE; + } else if (mask & OTGSC_BSVIE) { + cable->enabled = false; + } + } + + cable = &ci->platdata->id_extcon; + if (!IS_ERR(cable->edev)) { + if (data & mask & OTGSC_IDIS) + cable->changed = false; + + /* Don't enable id interrupt if using external notifier */ + if (data & mask & OTGSC_IDIE) { + cable->enabled = true; + data &= ~OTGSC_IDIE; + } else if (mask & OTGSC_IDIE) { + cable->enabled = false; + } + } + hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data); } @@ -98,13 +134,37 @@ void ci_handle_vbus_change(struct ci_hdrc *ci) if (!ci->is_otg) return; - if (hw_read_otgsc(ci, OTGSC_BSV)) + if (hw_read_otgsc(ci, OTGSC_BSV) && !ci->vbus_active) usb_gadget_vbus_connect(&ci->gadget); - else + else if (!hw_read_otgsc(ci, OTGSC_BSV) && ci->vbus_active) usb_gadget_vbus_disconnect(&ci->gadget); } -#define CI_VBUS_STABLE_TIMEOUT_MS 5000 +/** + * When we switch to device mode, the vbus value should be lower + * than OTGSC_BSV before connecting to host. + * + * @ci: the controller + * + * This function returns an error code if timeout + */ +static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci) +{ + unsigned long elapse = jiffies + msecs_to_jiffies(5000); + u32 mask = OTGSC_BSV; + + while (hw_read_otgsc(ci, mask)) { + if (time_after(jiffies, elapse)) { + dev_err(ci->dev, "timeout waiting for %08x in OTGSC\n", + mask); + return -ETIMEDOUT; + } + msleep(20); + } + + return 0; +} + static void ci_handle_id_switch(struct ci_hdrc *ci) { enum ci_role role = ci_otg_role(ci); @@ -115,12 +175,21 @@ static void ci_handle_id_switch(struct ci_hdrc *ci) ci_role_stop(ci); - if (role == CI_ROLE_GADGET) - /* wait vbus lower than OTGSC_BSV */ - hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0, - CI_VBUS_STABLE_TIMEOUT_MS); + if (role == CI_ROLE_GADGET && + IS_ERR(ci->platdata->vbus_extcon.edev)) + /* + * Wait vbus lower than OTGSC_BSV before connecting + * to host. If connecting status is from an external + * connector instead of register, we don't need to + * care vbus on the board, since it will not affect + * external connector status. + */ + hw_wait_vbus_lower_bsv(ci); ci_role_start(ci, role); + /* vbus change may have already occurred */ + if (role == CI_ROLE_GADGET) + ci_handle_vbus_change(ci); } } /** diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index cf132f057137..f88e9157fad0 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1725,7 +1725,6 @@ static int ci_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget); - unsigned long flags; int retval = -ENOMEM; if (driver->disconnect == NULL) @@ -1752,7 +1751,6 @@ static int ci_udc_start(struct usb_gadget *gadget, pm_runtime_get_sync(&ci->gadget.dev); if (ci->vbus_active) { - spin_lock_irqsave(&ci->lock, flags); hw_device_reset(ci); } else { usb_udc_vbus_handler(&ci->gadget, false); @@ -1761,7 +1759,6 @@ static int ci_udc_start(struct usb_gadget *gadget, } retval = hw_device_state(ci, ci->ep0out->qh.dma); - spin_unlock_irqrestore(&ci->lock, flags); if (retval) pm_runtime_put_sync(&ci->gadget.dev); @@ -1796,10 +1793,10 @@ static int ci_udc_stop(struct usb_gadget *gadget) if (ci->vbus_active) { hw_device_state(ci, 0); + spin_unlock_irqrestore(&ci->lock, flags); if (ci->platdata->notify_event) ci->platdata->notify_event(ci, CI_HDRC_CONTROLLER_STOPPED_EVENT); - spin_unlock_irqrestore(&ci->lock, flags); _gadget_stop_activity(&ci->gadget); spin_lock_irqsave(&ci->lock, flags); pm_runtime_put(&ci->gadget.dev); diff --git a/drivers/usb/chipidea/ulpi.c b/drivers/usb/chipidea/ulpi.c new file mode 100644 index 000000000000..1219583dc1b2 --- /dev/null +++ b/drivers/usb/chipidea/ulpi.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016 Linaro Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/device.h> +#include <linux/usb/chipidea.h> +#include <linux/ulpi/interface.h> + +#include "ci.h" + +#define ULPI_WAKEUP BIT(31) +#define ULPI_RUN BIT(30) +#define ULPI_WRITE BIT(29) +#define ULPI_SYNC_STATE BIT(27) +#define ULPI_ADDR(n) ((n) << 16) +#define ULPI_DATA(n) (n) + +static int ci_ulpi_wait(struct ci_hdrc *ci, u32 mask) +{ + unsigned long usec = 10000; + + while (usec--) { + if (!hw_read(ci, OP_ULPI_VIEWPORT, mask)) + return 0; + + udelay(1); + } + + return -ETIMEDOUT; +} + +static int ci_ulpi_read(struct device *dev, u8 addr) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + int ret; + + hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP); + ret = ci_ulpi_wait(ci, ULPI_WAKEUP); + if (ret) + return ret; + + hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_RUN | ULPI_ADDR(addr)); + ret = ci_ulpi_wait(ci, ULPI_RUN); + if (ret) + return ret; + + return hw_read(ci, OP_ULPI_VIEWPORT, GENMASK(15, 8)) >> 8; +} + +static int ci_ulpi_write(struct device *dev, u8 addr, u8 val) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + int ret; + + hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP); + ret = ci_ulpi_wait(ci, ULPI_WAKEUP); + if (ret) + return ret; + + hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, + ULPI_RUN | ULPI_WRITE | ULPI_ADDR(addr) | val); + return ci_ulpi_wait(ci, ULPI_RUN); +} + +int ci_ulpi_init(struct ci_hdrc *ci) +{ + if (ci->platdata->phy_mode != USBPHY_INTERFACE_MODE_ULPI) + return 0; + + /* + * Set PORTSC correctly so we can read/write ULPI registers for + * identification purposes + */ + hw_phymode_configure(ci); + + ci->ulpi_ops.read = ci_ulpi_read; + ci->ulpi_ops.write = ci_ulpi_write; + ci->ulpi = ulpi_register_interface(ci->dev, &ci->ulpi_ops); + if (IS_ERR(ci->ulpi)) + dev_err(ci->dev, "failed to register ULPI interface"); + + return PTR_ERR_OR_ZERO(ci->ulpi); +} + +void ci_ulpi_exit(struct ci_hdrc *ci) +{ + if (ci->ulpi) { + ulpi_unregister_interface(ci->ulpi); + ci->ulpi = NULL; + } +} + +int ci_ulpi_resume(struct ci_hdrc *ci) +{ + int cnt = 100000; + + while (cnt-- > 0) { + if (hw_read(ci, OP_ULPI_VIEWPORT, ULPI_SYNC_STATE)) + return 0; + udelay(1); + } + + return -ETIMEDOUT; +} diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e35b1508d3eb..235e305f8473 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -913,7 +913,6 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) struct serial_struct tmp; memset(&tmp, 0, sizeof(tmp)); - tmp.flags = ASYNC_LOW_LATENCY; tmp.xmit_fifo_size = acm->writesize; tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); tmp.close_delay = acm->port.close_delay / 10; diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 0a6369510f2d..8fda45a45bd3 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -531,7 +531,7 @@ retry: i++; if (file->f_flags & O_NONBLOCK) { if (!test_bit(WDM_READ, &desc->flags)) { - rv = cntr ? cntr : -EAGAIN; + rv = -EAGAIN; goto err; } rv = 0; diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 8b317702d761..c9480d77810c 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -16,6 +16,9 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/acpi.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/clk/clk-conf.h> /* -------------------------------------------------------------------------- */ @@ -39,6 +42,10 @@ static int ulpi_match(struct device *dev, struct device_driver *driver) struct ulpi *ulpi = to_ulpi_dev(dev); const struct ulpi_device_id *id; + /* Some ULPI devices don't have a vendor id so rely on OF match */ + if (ulpi->id.vendor == 0) + return of_driver_match_device(dev, driver); + for (id = drv->id_table; id->vendor; id++) if (id->vendor == ulpi->id.vendor && id->product == ulpi->id.product) @@ -50,6 +57,11 @@ static int ulpi_match(struct device *dev, struct device_driver *driver) static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ulpi *ulpi = to_ulpi_dev(dev); + int ret; + + ret = of_device_uevent_modalias(dev, env); + if (ret != -ENODEV) + return ret; if (add_uevent_var(env, "MODALIAS=ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product)) @@ -60,6 +72,11 @@ static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env) static int ulpi_probe(struct device *dev) { struct ulpi_driver *drv = to_ulpi_driver(dev->driver); + int ret; + + ret = of_clk_set_defaults(dev->of_node, false); + if (ret < 0) + return ret; return drv->probe(to_ulpi_dev(dev)); } @@ -87,8 +104,13 @@ static struct bus_type ulpi_bus = { static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { + int len; struct ulpi *ulpi = to_ulpi_dev(dev); + len = of_device_get_modalias(dev, buf, PAGE_SIZE - 1); + if (len != -ENODEV) + return len; + return sprintf(buf, "ulpi:v%04xp%04x\n", ulpi->id.vendor, ulpi->id.product); } @@ -153,23 +175,45 @@ EXPORT_SYMBOL_GPL(ulpi_unregister_driver); /* -------------------------------------------------------------------------- */ -static int ulpi_register(struct device *dev, struct ulpi *ulpi) +static int ulpi_of_register(struct ulpi *ulpi) { - int ret; + struct device_node *np = NULL, *child; + struct device *parent; + + /* Find a ulpi bus underneath the parent or the grandparent */ + parent = ulpi->dev.parent; + if (parent->of_node) + np = of_find_node_by_name(parent->of_node, "ulpi"); + else if (parent->parent && parent->parent->of_node) + np = of_find_node_by_name(parent->parent->of_node, "ulpi"); + if (!np) + return 0; + + child = of_get_next_available_child(np, NULL); + of_node_put(np); + if (!child) + return -EINVAL; - ulpi->dev.parent = dev; /* needed early for ops */ + ulpi->dev.of_node = child; + + return 0; +} + +static int ulpi_read_id(struct ulpi *ulpi) +{ + int ret; /* Test the interface */ ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa); if (ret < 0) - return ret; + goto err; ret = ulpi_read(ulpi, ULPI_SCRATCH); if (ret < 0) return ret; if (ret != 0xaa) - return -ENODEV; + goto err; ulpi->id.vendor = ulpi_read(ulpi, ULPI_VENDOR_ID_LOW); ulpi->id.vendor |= ulpi_read(ulpi, ULPI_VENDOR_ID_HIGH) << 8; @@ -177,13 +221,35 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi) ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW); ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8; + /* Some ULPI devices don't have a vendor id so rely on OF match */ + if (ulpi->id.vendor == 0) + goto err; + + request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product); + return 0; +err: + of_device_request_module(&ulpi->dev); + return 0; +} + +static int ulpi_register(struct device *dev, struct ulpi *ulpi) +{ + int ret; + + ulpi->dev.parent = dev; /* needed early for ops */ ulpi->dev.bus = &ulpi_bus; ulpi->dev.type = &ulpi_dev_type; dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev)); ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev)); - request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product); + ret = ulpi_of_register(ulpi); + if (ret) + return ret; + + ret = ulpi_read_id(ulpi); + if (ret) + return ret; ret = device_register(&ulpi->dev); if (ret) @@ -234,6 +300,7 @@ EXPORT_SYMBOL_GPL(ulpi_register_interface); */ void ulpi_unregister_interface(struct ulpi *ulpi) { + of_node_put(ulpi->dev.of_node); device_unregister(&ulpi->dev); } EXPORT_SYMBOL_GPL(ulpi_unregister_interface); diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 4016dae7433b..52747b6ac89a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -134,42 +134,35 @@ enum snoop_when { #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) /* Limit on the total amount of memory we can allocate for transfers */ -static unsigned usbfs_memory_mb = 16; +static u32 usbfs_memory_mb = 16; module_param(usbfs_memory_mb, uint, 0644); MODULE_PARM_DESC(usbfs_memory_mb, "maximum MB allowed for usbfs buffers (0 = no limit)"); -/* Hard limit, necessary to avoid arithmetic overflow */ -#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) - -static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ +static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */ /* Check whether it's okay to allocate more memory for a transfer */ -static int usbfs_increase_memory_usage(unsigned amount) +static int usbfs_increase_memory_usage(u64 amount) { - unsigned lim; + u64 lim; - /* - * Convert usbfs_memory_mb to bytes, avoiding overflows. - * 0 means use the hard limit (effectively unlimited). - */ lim = ACCESS_ONCE(usbfs_memory_mb); - if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) - lim = USBFS_XFER_MAX; - else - lim <<= 20; + lim <<= 20; - atomic_add(amount, &usbfs_memory_usage); - if (atomic_read(&usbfs_memory_usage) <= lim) - return 0; - atomic_sub(amount, &usbfs_memory_usage); - return -ENOMEM; + atomic64_add(amount, &usbfs_memory_usage); + + if (lim > 0 && atomic64_read(&usbfs_memory_usage) > lim) { + atomic64_sub(amount, &usbfs_memory_usage); + return -ENOMEM; + } + + return 0; } /* Memory for a transfer is being deallocated */ -static void usbfs_decrease_memory_usage(unsigned amount) +static void usbfs_decrease_memory_usage(u64 amount) { - atomic_sub(amount, &usbfs_memory_usage); + atomic64_sub(amount, &usbfs_memory_usage); } static int connected(struct usb_dev_state *ps) @@ -1191,7 +1184,7 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; - if (len1 >= USBFS_XFER_MAX) + if (len1 >= (INT_MAX - sizeof(struct urb))) return -EINVAL; ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); if (ret) @@ -1584,10 +1577,6 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb return -EINVAL; } - if (uurb->buffer_length >= USBFS_XFER_MAX) { - ret = -EINVAL; - goto error; - } if (uurb->buffer_length > 0 && !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 479e223f9cff..612fab6e54fb 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -3017,6 +3017,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) } usb_put_invalidate_rhdev(hcd); + hcd->flags = 0; } EXPORT_SYMBOL_GPL(usb_remove_hcd); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index dea55914d641..2184ef40a82a 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -122,12 +122,11 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, * This function sends a simple control message to a specified endpoint and * waits for the message to complete, or timeout. * - * Don't use this function from within an interrupt context, like a bottom half - * handler. If you need an asynchronous message, or need to send a message - * from within interrupt context, use usb_submit_urb(). - * If a thread in your driver uses this call, make sure your disconnect() - * method can wait for it to complete. Since you don't have a handle on the - * URB used, you can't cancel the request. + * Don't use this function from within an interrupt context. If you need + * an asynchronous message, or need to send a message from within interrupt + * context, use usb_submit_urb(). If a thread in your driver uses this call, + * make sure your disconnect() method can wait for it to complete. Since you + * don't have a handle on the URB used, you can't cancel the request. * * Return: If successful, the number of bytes transferred. Otherwise, a negative * error number. @@ -173,12 +172,11 @@ EXPORT_SYMBOL_GPL(usb_control_msg); * This function sends a simple interrupt message to a specified endpoint and * waits for the message to complete, or timeout. * - * Don't use this function from within an interrupt context, like a bottom half - * handler. If you need an asynchronous message, or need to send a message - * from within interrupt context, use usb_submit_urb() If a thread in your - * driver uses this call, make sure your disconnect() method can wait for it to - * complete. Since you don't have a handle on the URB used, you can't cancel - * the request. + * Don't use this function from within an interrupt context. If you need + * an asynchronous message, or need to send a message from within interrupt + * context, use usb_submit_urb() If a thread in your driver uses this call, + * make sure your disconnect() method can wait for it to complete. Since you + * don't have a handle on the URB used, you can't cancel the request. * * Return: * If successful, 0. Otherwise a negative error number. The number of actual @@ -207,12 +205,11 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg); * This function sends a simple bulk message to a specified endpoint * and waits for the message to complete, or timeout. * - * Don't use this function from within an interrupt context, like a bottom half - * handler. If you need an asynchronous message, or need to send a message - * from within interrupt context, use usb_submit_urb() If a thread in your - * driver uses this call, make sure your disconnect() method can wait for it to - * complete. Since you don't have a handle on the URB used, you can't cancel - * the request. + * Don't use this function from within an interrupt context. If you need + * an asynchronous message, or need to send a message from within interrupt + * context, use usb_submit_urb() If a thread in your driver uses this call, + * make sure your disconnect() method can wait for it to complete. Since you + * don't have a handle on the URB used, you can't cancel the request. * * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl, * users are forced to abuse this routine by using it to submit URBs for diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 11d8ae9aead1..1b6612c2cdda 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -104,7 +104,7 @@ static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) gr = &hsotg->gr_backup; if (!gr->valid) { dev_err(hsotg->dev, "%s: no global registers to restore\n", - __func__); + __func__); return -EINVAL; } gr->valid = false; @@ -155,21 +155,21 @@ int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore) ret = dwc2_restore_global_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to restore registers\n", - __func__); + __func__); return ret; } if (dwc2_is_host_mode(hsotg)) { ret = dwc2_restore_host_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to restore host registers\n", - __func__); + __func__); return ret; } } else { ret = dwc2_restore_device_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to restore device registers\n", - __func__); + __func__); return ret; } } @@ -195,7 +195,7 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg) ret = dwc2_backup_global_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to backup global registers\n", - __func__); + __func__); return ret; } @@ -203,14 +203,14 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg) ret = dwc2_backup_host_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to backup host registers\n", - __func__); + __func__); return ret; } } else { ret = dwc2_backup_device_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to backup device registers\n", - __func__); + __func__); return ret; } } @@ -313,7 +313,7 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) * Do core a soft reset of the core. Be careful with this because it * resets all the internal state machines of the core. */ -int dwc2_core_reset(struct dwc2_hsotg *hsotg) +int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) { u32 greset; int count = 0; @@ -369,7 +369,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg) } } while (!(greset & GRSTCTL_AHBIDLE)); - if (wait_for_host_mode) + if (wait_for_host_mode && !skip_wait) dwc2_wait_for_mode(hsotg, true); return 0; @@ -455,7 +455,7 @@ void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); if (dwc2_iddig_filter_enabled(hsotg)) - usleep_range(100000, 110000); + msleep(100); } /* @@ -500,7 +500,7 @@ int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg) { int retval; - retval = dwc2_core_reset(hsotg); + retval = dwc2_core_reset(hsotg, false); if (retval) return retval; @@ -541,7 +541,7 @@ void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg) addr = hsotg->regs + HAINTMSK; dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr, dwc2_readl(addr)); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { addr = hsotg->regs + HFLBADDR; dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n", (unsigned long)addr, dwc2_readl(addr)); @@ -571,7 +571,7 @@ void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg) addr = hsotg->regs + HCDMA(i); dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n", (unsigned long)addr, dwc2_readl(addr)); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { addr = hsotg->regs + HCDMAB(i); dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n", (unsigned long)addr, dwc2_readl(addr)); @@ -751,11 +751,6 @@ bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host) return dwc2_force_mode(hsotg, host); } -u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg) -{ - return hsotg->params.otg_ver == 1 ? 0x0200 : 0x0103; -} - bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg) { if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff) @@ -793,7 +788,7 @@ void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg) } /* Returns the controller's GHWCFG2.OTG_MODE. */ -unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg) +unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg) { u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2); @@ -804,7 +799,7 @@ unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg) /* Returns true if the controller is capable of DRD. */ bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg) { - unsigned op_mode = dwc2_op_mode(hsotg); + unsigned int op_mode = dwc2_op_mode(hsotg); return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) || (op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) || @@ -814,7 +809,7 @@ bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg) /* Returns true if the controller is host-only. */ bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg) { - unsigned op_mode = dwc2_op_mode(hsotg); + unsigned int op_mode = dwc2_op_mode(hsotg); return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) || (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST); @@ -823,7 +818,7 @@ bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg) /* Returns true if the controller is device-only. */ bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg) { - unsigned op_mode = dwc2_op_mode(hsotg); + unsigned int op_mode = dwc2_op_mode(hsotg); return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE); diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 302b8f5f7d27..1a7e83005082 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -127,6 +127,8 @@ static const char * const dwc2_hsotg_supply_names[] = { "vusb_a", /* analog USB supply, 1.1V */ }; +#define DWC2_NUM_SUPPLIES ARRAY_SIZE(dwc2_hsotg_supply_names) + /* * EP0_MPS_LIMIT * @@ -246,7 +248,8 @@ struct dwc2_hsotg_req { void *saved_req_buf; }; -#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ + IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) #define call_gadget(_hs, _entry) \ do { \ if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ @@ -271,13 +274,6 @@ enum dwc2_lx_state { DWC2_L3, /* Off state */ }; -/* - * Gadget periodic tx fifo sizes as used by legacy driver - * EP0 is not included - */ -#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \ - 768, 0, 0, 0, 0, 0, 0, 0} - /* Gadget ep0 states */ enum dwc2_ep0_state { DWC2_EP0_SETUP, @@ -295,9 +291,6 @@ enum dwc2_ep0_state { * 1 - SRP Only capable * 2 - No HNP/SRP capable (always available) * Defaults to best available option (0, 1, then 2) - * @otg_ver: OTG version supported - * 0 - 1.3 (default) - * 1 - 2.0 * @host_dma: Specifies whether to use slave or DMA mode for accessing * the data FIFOs. The driver will automatically detect the * value for this parameter if none is specified. @@ -444,6 +437,11 @@ enum dwc2_ep0_state { * in DWORDS with possible values from from * 16-32768 (default: 256, 256, 256, 256, 768, * 768, 768, 768, 0, 0, 0, 0, 0, 0, 0). + * @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL + * while full&low speed device connect. And change speed + * back to DWC2_SPEED_PARAM_HIGH while device is gone. + * 0 - No (default) + * 1 - Yes * * The following parameters may be specified when starting the module. These * parameters define how the DWC_otg controller should be configured. A @@ -452,63 +450,48 @@ enum dwc2_ep0_state { * default described above. */ struct dwc2_core_params { - /* - * Don't add any non-int members here, this will break - * dwc2_set_all_params! - */ - int otg_cap; + u8 otg_cap; #define DWC2_CAP_PARAM_HNP_SRP_CAPABLE 0 #define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE 1 #define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 - int otg_ver; - int dma_desc_enable; - int dma_desc_fs_enable; - int speed; -#define DWC2_SPEED_PARAM_HIGH 0 -#define DWC2_SPEED_PARAM_FULL 1 -#define DWC2_SPEED_PARAM_LOW 2 - - int enable_dynamic_fifo; - int en_multiple_tx_fifo; - int host_rx_fifo_size; - int host_nperio_tx_fifo_size; - int host_perio_tx_fifo_size; - int max_transfer_size; - int max_packet_count; - int host_channels; - int phy_type; + u8 phy_type; #define DWC2_PHY_TYPE_PARAM_FS 0 #define DWC2_PHY_TYPE_PARAM_UTMI 1 #define DWC2_PHY_TYPE_PARAM_ULPI 2 - int phy_utmi_width; - int phy_ulpi_ddr; - int phy_ulpi_ext_vbus; -#define DWC2_PHY_ULPI_INTERNAL_VBUS 0 -#define DWC2_PHY_ULPI_EXTERNAL_VBUS 1 - - int i2c_enable; - int ulpi_fs_ls; - int host_support_fs_ls_low_power; - int host_ls_low_power_phy_clk; -#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0 -#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1 - - int ts_dline; - int reload_ctl; - int ahbcfg; - int uframe_sched; - int external_id_pin_ctl; - int hibernation; + u8 speed; +#define DWC2_SPEED_PARAM_HIGH 0 +#define DWC2_SPEED_PARAM_FULL 1 +#define DWC2_SPEED_PARAM_LOW 2 - /* - * The following parameters are *only* set via device - * properties and cannot be set directly in this structure. - */ + u8 phy_utmi_width; + bool phy_ulpi_ddr; + bool phy_ulpi_ext_vbus; + bool enable_dynamic_fifo; + bool en_multiple_tx_fifo; + bool i2c_enable; + bool ulpi_fs_ls; + bool ts_dline; + bool reload_ctl; + bool uframe_sched; + bool external_id_pin_ctl; + bool hibernation; + u16 max_packet_count; + u32 max_transfer_size; + u32 ahbcfg; /* Host parameters */ bool host_dma; + bool dma_desc_enable; + bool dma_desc_fs_enable; + bool host_support_fs_ls_low_power; + bool host_ls_low_power_phy_clk; + + u8 host_channels; + u16 host_rx_fifo_size; + u16 host_nperio_tx_fifo_size; + u16 host_perio_tx_fifo_size; /* Gadget parameters */ bool g_dma; @@ -516,6 +499,8 @@ struct dwc2_core_params { u32 g_rx_fifo_size; u32 g_np_tx_fifo_size; u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; + + bool change_speed_quirk; }; /** @@ -603,8 +588,8 @@ struct dwc2_hw_params { #define DWC2_CTRL_BUFF_SIZE 8 /** - * struct dwc2_gregs_backup - Holds global registers state before entering partial - * power down + * struct dwc2_gregs_backup - Holds global registers state before + * entering partial power down * @gotgctl: Backup of GOTGCTL register * @gintmsk: Backup of GINTMSK register * @gahbcfg: Backup of GAHBCFG register @@ -634,8 +619,8 @@ struct dwc2_gregs_backup { }; /** - * struct dwc2_dregs_backup - Holds device registers state before entering partial - * power down + * struct dwc2_dregs_backup - Holds device registers state before + * entering partial power down * @dcfg: Backup of DCFG register * @dctl: Backup of DCTL register * @daintmsk: Backup of DAINTMSK register @@ -664,8 +649,8 @@ struct dwc2_dregs_backup { }; /** - * struct dwc2_hregs_backup - Holds host registers state before entering partial - * power down + * struct dwc2_hregs_backup - Holds host registers state before + * entering partial power down * @hcfg: Backup of HCFG register * @haintmsk: Backup of HAINTMSK register * @hcintmsk: Backup of HCINTMSK register @@ -782,9 +767,10 @@ struct dwc2_hregs_backup { * @gadget_enabled Peripheral mode sub-driver initialization indicator. * @ll_hw_enabled Status of low-level hardware resources. * @phy: The otg phy transceiver structure for phy control. - * @uphy: The otg phy transceiver structure for old USB phy control. - * @plat: The platform specific configuration data. This can be removed once - * all SoCs support usb transceiver. + * @uphy: The otg phy transceiver structure for old USB phy + * control. + * @plat: The platform specific configuration data. This can be + * removed once all SoCs support usb transceiver. * @supplies: Definition of USB power supplies * @phyif: PHY interface width * @lock: Spinlock that protects all the driver data structures @@ -921,7 +907,7 @@ struct dwc2_hsotg { struct phy *phy; struct usb_phy *uphy; struct dwc2_hsotg_plat *plat; - struct regulator_bulk_data supplies[ARRAY_SIZE(dwc2_hsotg_supply_names)]; + struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; u32 phyif; spinlock_t lock; @@ -947,6 +933,7 @@ struct dwc2_hsotg { /* DWC OTG HW Release versions */ #define DWC2_CORE_REV_2_71a 0x4f54271a #define DWC2_CORE_REV_2_90a 0x4f54290a +#define DWC2_CORE_REV_2_91a 0x4f54291a #define DWC2_CORE_REV_2_92a 0x4f54292a #define DWC2_CORE_REV_2_94a 0x4f54294a #define DWC2_CORE_REV_3_00a 0x4f54300a @@ -1033,7 +1020,8 @@ struct dwc2_hsotg { #endif #endif /* CONFIG_USB_DWC2_HOST || CONFIG_USB_DWC2_DUAL_ROLE */ -#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ + IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) /* Gadget structures */ struct usb_gadget_driver *driver; int fifo_mem; @@ -1101,37 +1089,37 @@ static inline bool dwc2_is_hs_iot(struct dwc2_hsotg *hsotg) * The following functions support initialization of the core driver component * and the DWC_otg controller */ -extern int dwc2_core_reset(struct dwc2_hsotg *hsotg); -extern int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg); -extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg); -extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore); +int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait); +int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg); +int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg); +int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore); bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host); void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg); void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg); -extern bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg); +bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg); /* * Common core Functions. * The following functions support managing the DWC_otg controller in either * device or host mode. */ -extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes); -extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num); -extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg); +void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes); +void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num); +void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg); -extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd); -extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); +void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd); +void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); /* This function should be called on every hardware interrupt. */ -extern irqreturn_t dwc2_handle_common_intr(int irq, void *dev); +irqreturn_t dwc2_handle_common_intr(int irq, void *dev); /* The device ID match table */ extern const struct of_device_id dwc2_of_match_table[]; -extern int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg); -extern int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg); +int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg); +int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg); /* Parameters */ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg); @@ -1145,7 +1133,7 @@ int dwc2_init_params(struct dwc2_hsotg *hsotg); * are read in and cached so they always read directly from the * GHWCFG2 register. */ -unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg); +unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg); bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg); bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg); bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg); @@ -1157,6 +1145,7 @@ static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg) { return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0; } + static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) { return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0; @@ -1165,29 +1154,28 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) /* * Dump core registers and SPRAM */ -extern void dwc2_dump_dev_registers(struct dwc2_hsotg *hsotg); -extern void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg); -extern void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg); - -/* - * Return OTG version - either 1.3 or 2.0 - */ -extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg); +void dwc2_dump_dev_registers(struct dwc2_hsotg *hsotg); +void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg); +void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg); /* Gadget defines */ -#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) -extern int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg); -extern int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2); -extern int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2); -extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq); -extern void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, - bool reset); -extern void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg); -extern void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2); -extern int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode); +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ + IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg); +int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2); +int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2); +int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq); +void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, + bool reset); +void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg); +void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2); +int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode); #define dwc2_is_device_connected(hsotg) (hsotg->connected) int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg); int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg); +int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg); +int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg); +int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg); #else static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2) { return 0; } @@ -1198,25 +1186,31 @@ static inline int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2) static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) { return 0; } static inline void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, - bool reset) {} + bool reset) {} static inline void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) {} static inline void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2) {} static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, - int testmode) + int testmode) { return 0; } #define dwc2_is_device_connected(hsotg) (0) static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) { return 0; } static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg) { return 0; } +static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) +{ return 0; } +static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) +{ return 0; } +static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) +{ return 0; } #endif #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) -extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg); -extern int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us); -extern void dwc2_hcd_connect(struct dwc2_hsotg *hsotg); -extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force); -extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg); +int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg); +int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us); +void dwc2_hcd_connect(struct dwc2_hsotg *hsotg); +void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force); +void dwc2_hcd_start(struct dwc2_hsotg *hsotg); int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg); int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg); #else @@ -1229,7 +1223,7 @@ static inline void dwc2_hcd_connect(struct dwc2_hsotg *hsotg) {} static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force) {} static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {} static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {} -static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) +static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg) { return 0; } static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg) { return 0; } diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index 5b228ba6045f..b8bcb007c92a 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -159,9 +159,8 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) " ++OTG Interrupt: Session Request Success Status Change++\n"); gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); if (gotgctl & GOTGCTL_SESREQSCS) { - if (hsotg->params.phy_type == - DWC2_PHY_TYPE_PARAM_FS - && hsotg->params.i2c_enable > 0) { + if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS && + hsotg->params.i2c_enable) { hsotg->srp_success = 1; } else { /* Clear Session Request */ @@ -317,7 +316,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) dwc2_writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n", - hsotg->lx_state); + hsotg->lx_state); if (dwc2_is_device_mode(hsotg)) { if (hsotg->lx_state == DWC2_L2) { @@ -437,7 +436,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) /* Ignore suspend request before enumeration */ if (!dwc2_is_device_connected(hsotg)) { dev_dbg(hsotg->dev, - "ignore suspend request before enumeration\n"); + "ignore suspend request before enumeration\n"); return; } @@ -445,7 +444,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) if (ret) { if (ret != -ENOTSUPP) dev_err(hsotg->dev, - "enter hibernation failed\n"); + "enter hibernation failed\n"); goto skip_power_saving; } diff --git a/drivers/usb/dwc2/debug.h b/drivers/usb/dwc2/debug.h index 12dbd1daec87..8222783e6822 100644 --- a/drivers/usb/dwc2/debug.h +++ b/drivers/usb/dwc2/debug.h @@ -17,8 +17,8 @@ #include "core.h" #ifdef CONFIG_DEBUG_FS -extern int dwc2_debugfs_init(struct dwc2_hsotg *); -extern void dwc2_debugfs_exit(struct dwc2_hsotg *); +int dwc2_debugfs_init(struct dwc2_hsotg *hsotg); +void dwc2_debugfs_exit(struct dwc2_hsotg *hsotg); #else static inline int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) { return 0; } diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index 0a130916a91c..794b959a7c8c 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -137,7 +137,7 @@ static int state_show(struct seq_file *seq, void *v) int idx; seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", - dwc2_readl(regs + DCFG), + dwc2_readl(regs + DCFG), dwc2_readl(regs + DCTL), dwc2_readl(regs + DSTS)); @@ -338,23 +338,23 @@ static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) { struct dentry *root; struct dentry *file; - unsigned epidx; + unsigned int epidx; root = hsotg->debug_root; /* create general state file */ - file = debugfs_create_file("state", S_IRUGO, root, hsotg, &state_fops); + file = debugfs_create_file("state", 0444, root, hsotg, &state_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "%s: failed to create state\n", __func__); - file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, hsotg, - &testmode_fops); + file = debugfs_create_file("testmode", 0644, root, hsotg, + &testmode_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "%s: failed to create testmode\n", - __func__); + __func__); - file = debugfs_create_file("fifo", S_IRUGO, root, hsotg, &fifo_fops); + file = debugfs_create_file("fifo", 0444, root, hsotg, &fifo_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__); @@ -364,8 +364,8 @@ static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) ep = hsotg->eps_out[epidx]; if (ep) { - file = debugfs_create_file(ep->name, S_IRUGO, - root, ep, &ep_fops); + file = debugfs_create_file(ep->name, 0444, + root, ep, &ep_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "failed to create %s debug file\n", ep->name); @@ -377,8 +377,8 @@ static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) ep = hsotg->eps_in[epidx]; if (ep) { - file = debugfs_create_file(ep->name, S_IRUGO, - root, ep, &ep_fops); + file = debugfs_create_file(ep->name, 0444, + root, ep, &ep_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "failed to create %s debug file\n", ep->name); @@ -725,6 +725,143 @@ static const struct debugfs_reg32 dwc2_regs[] = { dump_register(HCDMAB(15)), }; +#define print_param(_seq, _ptr, _param) \ +seq_printf((_seq), "%-30s: %d\n", #_param, (_ptr)->_param) + +#define print_param_hex(_seq, _ptr, _param) \ +seq_printf((_seq), "%-30s: 0x%x\n", #_param, (_ptr)->_param) + +static int params_show(struct seq_file *seq, void *v) +{ + struct dwc2_hsotg *hsotg = seq->private; + struct dwc2_core_params *p = &hsotg->params; + int i; + + print_param(seq, p, otg_cap); + print_param(seq, p, dma_desc_enable); + print_param(seq, p, dma_desc_fs_enable); + print_param(seq, p, speed); + print_param(seq, p, enable_dynamic_fifo); + print_param(seq, p, en_multiple_tx_fifo); + print_param(seq, p, host_rx_fifo_size); + print_param(seq, p, host_nperio_tx_fifo_size); + print_param(seq, p, host_perio_tx_fifo_size); + print_param(seq, p, max_transfer_size); + print_param(seq, p, max_packet_count); + print_param(seq, p, host_channels); + print_param(seq, p, phy_type); + print_param(seq, p, phy_utmi_width); + print_param(seq, p, phy_ulpi_ddr); + print_param(seq, p, phy_ulpi_ext_vbus); + print_param(seq, p, i2c_enable); + print_param(seq, p, ulpi_fs_ls); + print_param(seq, p, host_support_fs_ls_low_power); + print_param(seq, p, host_ls_low_power_phy_clk); + print_param(seq, p, ts_dline); + print_param(seq, p, reload_ctl); + print_param_hex(seq, p, ahbcfg); + print_param(seq, p, uframe_sched); + print_param(seq, p, external_id_pin_ctl); + print_param(seq, p, hibernation); + print_param(seq, p, host_dma); + print_param(seq, p, g_dma); + print_param(seq, p, g_dma_desc); + print_param(seq, p, g_rx_fifo_size); + print_param(seq, p, g_np_tx_fifo_size); + + for (i = 0; i < MAX_EPS_CHANNELS; i++) { + char str[32]; + + snprintf(str, 32, "g_tx_fifo_size[%d]", i); + seq_printf(seq, "%-30s: %d\n", str, p->g_tx_fifo_size[i]); + } + + return 0; +} + +static int params_open(struct inode *inode, struct file *file) +{ + return single_open(file, params_show, inode->i_private); +} + +static const struct file_operations params_fops = { + .owner = THIS_MODULE, + .open = params_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int hw_params_show(struct seq_file *seq, void *v) +{ + struct dwc2_hsotg *hsotg = seq->private; + struct dwc2_hw_params *hw = &hsotg->hw_params; + + print_param(seq, hw, op_mode); + print_param(seq, hw, arch); + print_param(seq, hw, dma_desc_enable); + print_param(seq, hw, enable_dynamic_fifo); + print_param(seq, hw, en_multiple_tx_fifo); + print_param(seq, hw, rx_fifo_size); + print_param(seq, hw, host_nperio_tx_fifo_size); + print_param(seq, hw, dev_nperio_tx_fifo_size); + print_param(seq, hw, host_perio_tx_fifo_size); + print_param(seq, hw, nperio_tx_q_depth); + print_param(seq, hw, host_perio_tx_q_depth); + print_param(seq, hw, dev_token_q_depth); + print_param(seq, hw, max_transfer_size); + print_param(seq, hw, max_packet_count); + print_param(seq, hw, host_channels); + print_param(seq, hw, hs_phy_type); + print_param(seq, hw, fs_phy_type); + print_param(seq, hw, i2c_enable); + print_param(seq, hw, num_dev_ep); + print_param(seq, hw, num_dev_perio_in_ep); + print_param(seq, hw, total_fifo_size); + print_param(seq, hw, power_optimized); + print_param(seq, hw, utmi_phy_data_width); + print_param_hex(seq, hw, snpsid); + print_param_hex(seq, hw, dev_ep_dirs); + + return 0; +} + +static int hw_params_open(struct inode *inode, struct file *file) +{ + return single_open(file, hw_params_show, inode->i_private); +} + +static const struct file_operations hw_params_fops = { + .owner = THIS_MODULE, + .open = hw_params_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int dr_mode_show(struct seq_file *seq, void *v) +{ + struct dwc2_hsotg *hsotg = seq->private; + const char *dr_mode = ""; + + device_property_read_string(hsotg->dev, "dr_mode", &dr_mode); + seq_printf(seq, "%s\n", dr_mode); + return 0; +} + +static int dr_mode_open(struct inode *inode, struct file *file) +{ + return single_open(file, dr_mode_show, inode->i_private); +} + +static const struct file_operations dr_mode_fops = { + .owner = THIS_MODULE, + .open = dr_mode_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) { int ret; @@ -736,6 +873,25 @@ int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) goto err0; } + file = debugfs_create_file("params", 0444, + hsotg->debug_root, + hsotg, ¶ms_fops); + if (IS_ERR(file)) + dev_err(hsotg->dev, "%s: failed to create params\n", __func__); + + file = debugfs_create_file("hw_params", 0444, + hsotg->debug_root, + hsotg, &hw_params_fops); + if (IS_ERR(file)) + dev_err(hsotg->dev, "%s: failed to create hw_params\n", + __func__); + + file = debugfs_create_file("dr_mode", 0444, + hsotg->debug_root, + hsotg, &dr_mode_fops); + if (IS_ERR(file)) + dev_err(hsotg->dev, "%s: failed to create dr_mode\n", __func__); + /* Add gadget debugfs nodes */ dwc2_hsotg_create_debug(hsotg); @@ -750,8 +906,8 @@ int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) hsotg->regset->nregs = ARRAY_SIZE(dwc2_regs); hsotg->regset->base = hsotg->regs; - file = debugfs_create_regset32("regdump", S_IRUGO, hsotg->debug_root, - hsotg->regset); + file = debugfs_create_regset32("regdump", 0444, hsotg->debug_root, + hsotg->regset); if (!file) { ret = -ENOMEM; goto err1; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 77c5fcf3a5bf..bc3b3fda5000 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -171,7 +171,7 @@ static void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) * request. */ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, - unsigned int ep, unsigned int dir_in, + unsigned int ep, unsigned int dir_in, unsigned int en) { unsigned long flags; @@ -192,6 +192,99 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, } /** + * dwc2_hsotg_tx_fifo_count - return count of TX FIFOs in device mode + */ +int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) +{ + if (hsotg->hw_params.en_multiple_tx_fifo) + /* In dedicated FIFO mode we need count of IN EPs */ + return (dwc2_readl(hsotg->regs + GHWCFG4) & + GHWCFG4_NUM_IN_EPS_MASK) >> GHWCFG4_NUM_IN_EPS_SHIFT; + else + /* In shared FIFO mode we need count of Periodic IN EPs */ + return hsotg->hw_params.num_dev_perio_in_ep; +} + +/** + * dwc2_hsotg_ep_info_size - return Endpoint Info Control block size in DWORDs + */ +static int dwc2_hsotg_ep_info_size(struct dwc2_hsotg *hsotg) +{ + int val = 0; + int i; + u32 ep_dirs; + + /* + * Don't need additional space for ep info control registers in + * slave mode. + */ + if (!using_dma(hsotg)) { + dev_dbg(hsotg->dev, "Buffer DMA ep info size 0\n"); + return 0; + } + + /* + * Buffer DMA mode - 1 location per endpoit + * Descriptor DMA mode - 4 locations per endpoint + */ + ep_dirs = hsotg->hw_params.dev_ep_dirs; + + for (i = 0; i <= hsotg->hw_params.num_dev_ep; i++) { + val += ep_dirs & 3 ? 1 : 2; + ep_dirs >>= 2; + } + + if (using_desc_dma(hsotg)) + val = val * 4; + + return val; +} + +/** + * dwc2_hsotg_tx_fifo_total_depth - return total FIFO depth available for + * device mode TX FIFOs + */ +int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) +{ + int ep_info_size; + int addr; + int tx_addr_max; + u32 np_tx_fifo_size; + + np_tx_fifo_size = min_t(u32, hsotg->hw_params.dev_nperio_tx_fifo_size, + hsotg->params.g_np_tx_fifo_size); + + /* Get Endpoint Info Control block size in DWORDs. */ + ep_info_size = dwc2_hsotg_ep_info_size(hsotg); + tx_addr_max = hsotg->hw_params.total_fifo_size - ep_info_size; + + addr = hsotg->params.g_rx_fifo_size + np_tx_fifo_size; + if (tx_addr_max <= addr) + return 0; + + return tx_addr_max - addr; +} + +/** + * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode + * TX FIFOs + */ +int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) +{ + int tx_fifo_count; + int tx_fifo_depth; + + tx_fifo_depth = dwc2_hsotg_tx_fifo_total_depth(hsotg); + + tx_fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); + + if (!tx_fifo_count) + return tx_fifo_depth; + else + return tx_fifo_depth / tx_fifo_count; +} + +/** * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs * @hsotg: The device instance. */ @@ -241,6 +334,9 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) val = dwc2_readl(hsotg->regs + DPTXFSIZN(ep)); } + dwc2_writel(hsotg->hw_params.total_fifo_size | + addr << GDFIFOCFG_EPINFOBASE_SHIFT, + hsotg->regs + GDFIFOCFG); /* * according to p428 of the design guide, we need to ensure that * all fifos are flushed before continuing @@ -277,11 +373,11 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) * Allocate a new USB request structure appropriate for the specified endpoint */ static struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep, - gfp_t flags) + gfp_t flags) { struct dwc2_hsotg_req *req; - req = kzalloc(sizeof(struct dwc2_hsotg_req), flags); + req = kzalloc(sizeof(*req), flags); if (!req) return NULL; @@ -312,10 +408,11 @@ static inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep) * of a request to ensure the buffer is ready for access by the caller. */ static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) { struct usb_request *req = &hs_req->req; + usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); } @@ -384,7 +481,7 @@ fail: * This routine is only needed for PIO */ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) { bool periodic = is_ep_periodic(hs_ep); @@ -466,7 +563,7 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", - __func__, gnptxsts, can_write, to_write, max_transfer); + __func__, gnptxsts, can_write, to_write, max_transfer); /* * limit to 512 bytes of data, it seems at least on the non-periodic @@ -487,7 +584,7 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, /* it's needed only when we do not use dedicated fifos */ if (!hsotg->dedicated_fifos) dwc2_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTXFEMP : + periodic ? GINTSTS_PTXFEMP : GINTSTS_NPTXFEMP); } @@ -516,12 +613,12 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, /* it's needed only when we do not use dedicated fifos */ if (!hsotg->dedicated_fifos) dwc2_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTXFEMP : + periodic ? GINTSTS_PTXFEMP : GINTSTS_NPTXFEMP); } dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", - to_write, hs_req->req.length, can_write, buf_pos); + to_write, hs_req->req.length, can_write, buf_pos); if (to_write <= 0) return -ENOSPC; @@ -547,17 +644,17 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, * Return the maximum data that can be queued in one go on a given endpoint * so that transfers that are too long can be split. */ -static unsigned get_ep_limit(struct dwc2_hsotg_ep *hs_ep) +static unsigned int get_ep_limit(struct dwc2_hsotg_ep *hs_ep) { int index = hs_ep->index; - unsigned maxsize; - unsigned maxpkt; + unsigned int maxsize; + unsigned int maxpkt; if (index != 0) { maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; } else { - maxsize = 64+64; + maxsize = 64 + 64; if (hs_ep->dir_in) maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; else @@ -580,11 +677,11 @@ static unsigned get_ep_limit(struct dwc2_hsotg_ep *hs_ep) } /** -* dwc2_hsotg_read_frameno - read current frame number -* @hsotg: The device instance -* -* Return the current frame number -*/ + * dwc2_hsotg_read_frameno - read current frame number + * @hsotg: The device instance + * + * Return the current frame number + */ static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) { u32 dsts; @@ -874,7 +971,7 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) * appropriately, and writing any data to the FIFOs. */ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req, bool continuing) { @@ -885,9 +982,9 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, u32 epsize_reg; u32 epsize; u32 ctrl; - unsigned length; - unsigned packets; - unsigned maxreq; + unsigned int length; + unsigned int packets; + unsigned int maxreq; unsigned int dma_reg; if (index != 0) { @@ -966,7 +1063,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, if (dir_in && ureq->zero && !continuing) { /* Test if zlp is actually required. */ if ((ureq->length >= hs_ep->ep.maxpacket) && - !(ureq->length % hs_ep->ep.maxpacket)) + !(ureq->length % hs_ep->ep.maxpacket)) hs_ep->send_zlp = 1; } @@ -1070,7 +1167,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, /* check ep is enabled */ if (!(dwc2_readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) dev_dbg(hsotg->dev, - "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", + "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", index, dwc2_readl(hsotg->regs + epctrl_reg)); dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", @@ -1093,7 +1190,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, * cleanup on completion. */ static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct usb_request *req) { int ret; @@ -1112,7 +1209,8 @@ dma_error: } static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) + struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_req *hs_req) { void *req_buf = hs_req->req.buf; @@ -1123,7 +1221,7 @@ static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, WARN_ON(hs_req->saved_req_buf); dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__, - hs_ep->ep.name, req_buf, hs_req->req.length); + hs_ep->ep.name, req_buf, hs_req->req.length); hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC); if (!hs_req->req.buf) { @@ -1142,8 +1240,10 @@ static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, return 0; } -static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) +static void +dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, + struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_req *hs_req) { /* If dma is not being used or buffer was aligned */ if (!using_dma(hsotg) || !hs_req->saved_req_buf) @@ -1155,7 +1255,7 @@ static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, /* Copy data from bounce buffer on successful out transfer */ if (!hs_ep->dir_in && !hs_req->req.status) memcpy(hs_req->saved_req_buf, hs_req->req.buf, - hs_req->req.actual); + hs_req->req.actual); /* Free bounce buffer */ kfree(hs_req->req.buf); @@ -1224,7 +1324,7 @@ static int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg, } static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags) + gfp_t gfp_flags) { struct dwc2_hsotg_req *hs_req = our_req(req); struct dwc2_hsotg_ep *hs_ep = our_ep(ep); @@ -1239,7 +1339,7 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, /* Prevent new request submission when controller is suspended */ if (hs->lx_state == DWC2_L2) { dev_dbg(hs->dev, "%s: don't submit request while suspended\n", - __func__); + __func__); return -EAGAIN; } @@ -1300,7 +1400,7 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, } static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags) + gfp_t gfp_flags) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hs = hs_ep->parent; @@ -1315,7 +1415,7 @@ static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, } static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, - struct usb_request *req) + struct usb_request *req) { struct dwc2_hsotg_req *hs_req = our_req(req); @@ -1331,7 +1431,7 @@ static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, * submitted that need cleaning up. */ static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, - struct usb_request *req) + struct usb_request *req) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hsotg = hs_ep->parent; @@ -1350,7 +1450,7 @@ static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, * structure, or return NULL if it is not a valid endpoint. */ static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, - u32 windex) + u32 windex) { struct dwc2_hsotg_ep *ep; int dir = (windex & USB_DIR_IN) ? 1 : 0; @@ -1407,7 +1507,7 @@ int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) * an internal method of sending replies to certain control requests, etc. */ static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *ep, + struct dwc2_hsotg_ep *ep, void *buff, int length) { @@ -1450,7 +1550,7 @@ static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, * @ctrl: USB control request */ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, - struct usb_ctrlrequest *ctrl) + struct usb_ctrlrequest *ctrl) { struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; struct dwc2_hsotg_ep *ep; @@ -1466,8 +1566,11 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - reply = cpu_to_le16(0); /* bit 0 => self powered, - * bit 1 => remote wakeup */ + /* + * bit 0 => self powered + * bit 1 => remote wakeup + */ + reply = cpu_to_le16(0); break; case USB_RECIP_INTERFACE: @@ -1555,7 +1658,7 @@ static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) * @ctrl: USB control request */ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, - struct usb_ctrlrequest *ctrl) + struct usb_ctrlrequest *ctrl) { struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; struct dwc2_hsotg_req *hs_req; @@ -1640,9 +1743,8 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, } /* If we have pending request, then start it */ - if (!ep->req) { + if (!ep->req) dwc2_gadget_start_next_request(ep); - } } break; @@ -1705,7 +1807,7 @@ static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) * gadget driver). */ static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, - struct usb_ctrlrequest *ctrl) + struct usb_ctrlrequest *ctrl) { struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; int ret = 0; @@ -1781,7 +1883,7 @@ static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, * EP0 setup packets */ static void dwc2_hsotg_complete_setup(struct usb_ep *ep, - struct usb_request *req) + struct usb_request *req) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hsotg = hs_ep->parent; @@ -1839,7 +1941,7 @@ static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) } static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep) + struct dwc2_hsotg_ep *hs_ep) { u32 ctrl; u8 index = hs_ep->index; @@ -1885,11 +1987,10 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, * Note, expects the ep to already be locked as appropriate. */ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req, int result) { - if (!hs_req) { dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); return; @@ -1935,9 +2036,8 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, * so be careful when doing this. */ - if (!hs_ep->req && result >= 0) { + if (!hs_ep->req && result >= 0) dwc2_gadget_start_next_request(hs_ep); - } } /* @@ -2068,13 +2168,12 @@ static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) int max_req; int read_ptr; - if (!hs_req) { u32 epctl = dwc2_readl(hsotg->regs + DOEPCTL(ep_idx)); int ptr; dev_dbg(hsotg->dev, - "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", + "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", __func__, size, ep_idx, epctl); /* dump the data from the FIFO, we've nothing we can do */ @@ -2134,7 +2233,7 @@ static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) } static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg, - u32 epctl_reg) + u32 epctl_reg) { u32 ctrl; @@ -2191,7 +2290,7 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; struct dwc2_hsotg_req *hs_req = hs_ep->req; struct usb_request *req = &hs_req->req; - unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize); + unsigned int size_left = DXEPTSIZ_XFERSIZE_GET(epsize); int result = 0; if (!hs_req) { @@ -2210,7 +2309,7 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); if (using_dma(hsotg)) { - unsigned size_done; + unsigned int size_done; /* * Calculate the size of the transfer by checking how much @@ -2295,7 +2394,7 @@ static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) size >>= GRXSTS_BYTECNT_SHIFT; dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", - __func__, grxstsr, size, epnum); + __func__, grxstsr, size, epnum); switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { case GRXSTS_PKTSTS_GLOBALOUTNAK: @@ -2470,7 +2569,7 @@ static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) * make an attempt to write data into the FIFO. */ static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep) + struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg_req *hs_req = hs_ep->req; @@ -2481,7 +2580,7 @@ static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, */ if (hs_ep->index != 0) dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, - hs_ep->dir_in, 0); + hs_ep->dir_in, 0); return 0; } @@ -2503,7 +2602,7 @@ static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, * call the relevant completion routines. */ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep) + struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg_req *hs_req = hs_ep->req; u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); @@ -2531,7 +2630,7 @@ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode); if (ret < 0) { dev_dbg(hsotg->dev, "Invalid Test #%d\n", - hsotg->test_mode); + hsotg->test_mode); dwc2_hsotg_stall_ep0(hsotg); return; } @@ -2751,19 +2850,19 @@ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) } /** -* dwc2_gadget_handle_nak - handle NAK interrupt -* @hs_ep: The endpoint on which interrupt is asserted. -* -* This is starting point for ISOC-IN transfer, synchronization done with -* first IN token received from host while corresponding EP is disabled. -* -* Device does not know when first one token will arrive from host. On first -* token arrival HW generates 2 interrupts: 'in token received while FIFO empty' -* and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was -* sent in response to that as there was no data in FIFO. SW is basing on this -* interrupt to obtain frame in which token has come and then based on the -* interval calculates next frame for transfer. -*/ + * dwc2_gadget_handle_nak - handle NAK interrupt + * @hs_ep: The endpoint on which interrupt is asserted. + * + * This is starting point for ISOC-IN transfer, synchronization done with + * first IN token received from host while corresponding EP is disabled. + * + * Device does not know when first one token will arrive from host. On first + * token arrival HW generates 2 interrupts: 'in token received while FIFO empty' + * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was + * sent in response to that as there was no data in FIFO. SW is basing on this + * interrupt to obtain frame in which token has come and then based on the + * interval calculates next frame for transfer. + */ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg *hsotg = hs_ep->parent; @@ -2807,7 +2906,7 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) * Process and clear any interrupt pending for an individual endpoint */ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, - int dir_in) + int dir_in) { struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); @@ -2824,7 +2923,7 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, if (!hs_ep) { dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", - __func__, idx, dir_in ? "in" : "out"); + __func__, idx, dir_in ? "in" : "out"); return; } @@ -3059,13 +3158,13 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, int result) { struct dwc2_hsotg_req *req, *treq; - unsigned size; + unsigned int size; ep->req = NULL; list_for_each_entry_safe(req, treq, &ep->queue, queue) dwc2_hsotg_complete_request(hsotg, ep, req, - result); + result); if (!hsotg->dedicated_fifos) return; @@ -3084,7 +3183,7 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, */ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) { - unsigned ep; + unsigned int ep; if (!hsotg->connected) return; @@ -3095,10 +3194,10 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) for (ep = 0; ep < hsotg->num_of_eps; ep++) { if (hsotg->eps_in[ep]) kill_all_requests(hsotg, hsotg->eps_in[ep], - -ESHUTDOWN); + -ESHUTDOWN); if (hsotg->eps_out[ep]) kill_all_requests(hsotg, hsotg->eps_out[ep], - -ESHUTDOWN); + -ESHUTDOWN); } call_gadget(hsotg, disconnect); @@ -3147,7 +3246,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) * Issue a soft reset to the core, and await the core finishing it. */ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, - bool is_usb_reset) + bool is_usb_reset) { u32 intmsk; u32 val; @@ -3158,7 +3257,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); if (!is_usb_reset) - if (dwc2_core_reset(hsotg)) + if (dwc2_core_reset(hsotg, true)) return; /* @@ -3221,7 +3320,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, if (!using_desc_dma(hsotg)) intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; - if (hsotg->params.external_id_pin_ctl <= 0) + if (!hsotg->params.external_id_pin_ctl) intmsk |= GINTSTS_CONIDSTSCHNG; dwc2_writel(intmsk, hsotg->regs + GINTMSK); @@ -3462,7 +3561,6 @@ irq_retry: } if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { - u32 usb_status = dwc2_readl(hsotg->regs + GOTGCTL); u32 connected = hsotg->connected; @@ -3601,7 +3699,7 @@ irq_retry: */ if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) - goto irq_retry; + goto irq_retry; spin_unlock(&hsotg->lock); @@ -3705,7 +3803,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, * This is called from the USB gadget code's usb_ep_enable(). */ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) + const struct usb_endpoint_descriptor *desc) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hsotg = hs_ep->parent; @@ -3827,12 +3925,13 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, if (dir_in && hsotg->dedicated_fifos) { u32 fifo_index = 0; u32 fifo_size = UINT_MAX; - size = hs_ep->ep.maxpacket*hs_ep->mc; + + size = hs_ep->ep.maxpacket * hs_ep->mc; for (i = 1; i < hsotg->num_of_eps; ++i) { - if (hsotg->fifo_map & (1<<i)) + if (hsotg->fifo_map & (1 << i)) continue; val = dwc2_readl(hsotg->regs + DPTXFSIZN(i)); - val = (val >> FIFOSIZE_DEPTH_SHIFT)*4; + val = (val >> FIFOSIZE_DEPTH_SHIFT) * 4; if (val < size) continue; /* Search for smallest acceptable fifo */ @@ -4033,23 +4132,22 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) epctl &= ~DXEPCTL_STALL; xfertype = epctl & DXEPCTL_EPTYPE_MASK; if (xfertype == DXEPCTL_EPTYPE_BULK || - xfertype == DXEPCTL_EPTYPE_INTERRUPT) - epctl |= DXEPCTL_SETD0PID; + xfertype == DXEPCTL_EPTYPE_INTERRUPT) + epctl |= DXEPCTL_SETD0PID; } dwc2_writel(epctl, hs->regs + epreg); } else { - epreg = DOEPCTL(index); epctl = dwc2_readl(hs->regs + epreg); - if (value) + if (value) { epctl |= DXEPCTL_STALL; - else { + } else { epctl &= ~DXEPCTL_STALL; xfertype = epctl & DXEPCTL_EPTYPE_MASK; if (xfertype == DXEPCTL_EPTYPE_BULK || - xfertype == DXEPCTL_EPTYPE_INTERRUPT) - epctl |= DXEPCTL_SETD0PID; + xfertype == DXEPCTL_EPTYPE_INTERRUPT) + epctl |= DXEPCTL_SETD0PID; } dwc2_writel(epctl, hs->regs + epreg); } @@ -4090,7 +4188,7 @@ static struct usb_ep_ops dwc2_hsotg_ep_ops = { }; /** - * dwc2_hsotg_init - initalize the usb core + * dwc2_hsotg_init - initialize the usb core * @hsotg: The driver state */ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) @@ -4144,7 +4242,7 @@ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) * to work. */ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) + struct usb_gadget_driver *driver) { struct dwc2_hsotg *hsotg = to_hsotg(gadget); unsigned long flags; @@ -4267,7 +4365,7 @@ static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) unsigned long flags = 0; dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, - hsotg->op_state); + hsotg->op_state); /* Don't modify pullup state while in host mode */ if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { @@ -4329,7 +4427,7 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) * * Report how much power the device may consume to the phy. */ -static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned mA) +static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) { struct dwc2_hsotg *hsotg = to_hsotg(gadget); @@ -4358,7 +4456,7 @@ static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { * direction information and other state that may be required. */ static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, int epnum, bool dir_in) { @@ -4415,6 +4513,7 @@ static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, if (using_dma(hsotg)) { u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); + if (dir_in) dwc2_writel(next, hsotg->regs + DIEPCTL(epnum)); else @@ -4441,8 +4540,9 @@ static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) /* Add ep0 */ hsotg->num_of_eps++; - hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, sizeof(struct dwc2_hsotg_ep), - GFP_KERNEL); + hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, + sizeof(struct dwc2_hsotg_ep), + GFP_KERNEL); if (!hsotg->eps_in[0]) return -ENOMEM; /* Same dwc2_hsotg_ep is used in both directions for ep0 */ @@ -4521,7 +4621,6 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) idx, dwc2_readl(regs + DOEPCTL(idx)), dwc2_readl(regs + DOEPTSIZ(idx)), dwc2_readl(regs + DOEPDMA(idx))); - } dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", @@ -4576,7 +4675,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) } ret = devm_request_irq(hsotg->dev, irq, dwc2_hsotg_irq, IRQF_SHARED, - dev_name(hsotg->dev), hsotg); + dev_name(hsotg->dev), hsotg); if (ret < 0) { dev_err(dev, "cannot claim IRQ for gadget\n"); return ret; @@ -4607,10 +4706,10 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { if (hsotg->eps_in[epnum]) dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum], - epnum, 1); + epnum, 1); if (hsotg->eps_out[epnum]) dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum], - epnum, 0); + epnum, 0); } ret = usb_add_gadget_udc(dev, &hsotg->gadget); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 46d0ad5105e4..a73722e27d07 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -42,6 +42,7 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/interrupt.h> +#include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/io.h> @@ -54,6 +55,8 @@ #include "core.h" #include "hcd.h" +static void dwc2_port_resume(struct dwc2_hsotg *hsotg); + /* * ========================================================================= * Host Core Layer Functions @@ -79,9 +82,9 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg) /* Enable the interrupts in the GINTMSK */ intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT; - if (hsotg->params.host_dma <= 0) + if (!hsotg->params.host_dma) intmsk |= GINTSTS_RXFLVL; - if (hsotg->params.external_id_pin_ctl <= 0) + if (!hsotg->params.external_id_pin_ctl) intmsk |= GINTSTS_CONIDSTSCHNG; intmsk |= GINTSTS_WKUPINT | GINTSTS_USBSUSP | @@ -100,7 +103,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && - hsotg->params.ulpi_fs_ls > 0) || + hsotg->params.ulpi_fs_ls) || hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { /* Full speed PHY */ val = HCFG_FSLSPCLKSEL_48_MHZ; @@ -152,7 +155,7 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) if (dwc2_is_host_mode(hsotg)) dwc2_init_fs_ls_pclk_sel(hsotg); - if (hsotg->params.i2c_enable > 0) { + if (hsotg->params.i2c_enable) { dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); /* Program GUSBCFG.OtgUtmiFsSel to I2C */ @@ -195,7 +198,7 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); usbcfg |= GUSBCFG_ULPI_UTMI_SEL; usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); - if (hsotg->params.phy_ulpi_ddr > 0) + if (hsotg->params.phy_ulpi_ddr) usbcfg |= GUSBCFG_DDRSEL; break; case DWC2_PHY_TYPE_PARAM_UTMI: @@ -246,7 +249,7 @@ static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && - hsotg->params.ulpi_fs_ls > 0) { + hsotg->params.ulpi_fs_ls) { dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); usbcfg |= GUSBCFG_ULPI_FS_LS; @@ -290,17 +293,17 @@ static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg) hsotg->params.host_dma, hsotg->params.dma_desc_enable); - if (hsotg->params.host_dma > 0) { - if (hsotg->params.dma_desc_enable > 0) + if (hsotg->params.host_dma) { + if (hsotg->params.dma_desc_enable) dev_dbg(hsotg->dev, "Using Descriptor DMA mode\n"); else dev_dbg(hsotg->dev, "Using Buffer DMA mode\n"); } else { dev_dbg(hsotg->dev, "Using Slave mode\n"); - hsotg->params.dma_desc_enable = 0; + hsotg->params.dma_desc_enable = false; } - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) ahbcfg |= GAHBCFG_DMA_EN; dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG); @@ -491,9 +494,10 @@ static void dwc2_config_fifos(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n", dwc2_readl(hsotg->regs + HPTXFSIZ)); - if (hsotg->params.en_multiple_tx_fifo > 0 && - hsotg->hw_params.snpsid <= DWC2_CORE_REV_2_94a) { + if (hsotg->params.en_multiple_tx_fifo && + hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_91a) { /* + * This feature was implemented in 2.91a version * Global DFIFOCFG calculation for Host mode - * include RxFIFO, NPTXFIFO and HPTXFIFO */ @@ -771,7 +775,7 @@ static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg, * For Descriptor DMA mode core halts the channel on AHB error. * Interrupt is not required. */ - if (hsotg->params.dma_desc_enable <= 0) { + if (!hsotg->params.dma_desc_enable) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "desc DMA disabled\n"); hcintmsk |= HCINTMSK_AHBERR; @@ -804,7 +808,7 @@ static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg, { u32 intmsk; - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "DMA enabled\n"); dwc2_hc_enable_dma_ints(hsotg, chan); @@ -1024,7 +1028,7 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan, /* No need to set the bit in DDMA for disabling the channel */ /* TODO check it everywhere channel is disabled */ - if (hsotg->params.dma_desc_enable <= 0) { + if (!hsotg->params.dma_desc_enable) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "desc DMA disabled\n"); hcchar |= HCCHAR_CHENA; @@ -1034,7 +1038,7 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan, } hcchar |= HCCHAR_CHDIS; - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "DMA not enabled\n"); hcchar |= HCCHAR_CHENA; @@ -1380,7 +1384,7 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, dev_vdbg(hsotg->dev, "%s()\n", __func__); if (chan->do_ping) { - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "ping, no DMA\n"); dwc2_hc_do_ping(hsotg, chan); @@ -1508,7 +1512,7 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, TSIZ_SC_MC_PID_SHIFT); } - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { dwc2_writel((u32)chan->xfer_dma, hsotg->regs + HCDMA(chan->hc_num)); if (dbg_hc(chan)) @@ -1551,7 +1555,7 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, chan->xfer_started = 1; chan->requests++; - if (hsotg->params.host_dma <= 0 && + if (!hsotg->params.host_dma && !chan->ep_is_in && chan->xfer_len > 0) /* Load OUT packet into the appropriate Tx FIFO */ dwc2_hc_write_packet(hsotg, chan); @@ -1834,7 +1838,7 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) u32 hcchar; int i; - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { /* Flush out any channel requests in slave mode */ for (i = 0; i < num_channels; i++) { channel = hsotg->hc_ptr_array[i]; @@ -1870,7 +1874,7 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) channel->qh = NULL; } /* All channels have been freed, mark them available */ - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { hsotg->available_host_channels = hsotg->params.host_channels; } else { @@ -2107,7 +2111,7 @@ static int dwc2_hcd_urb_dequeue(struct dwc2_hsotg *hsotg, * Free the QTD and clean up the associated QH. Leave the QH in the * schedule if it has any remaining QTDs. */ - if (hsotg->params.dma_desc_enable <= 0) { + if (!hsotg->params.dma_desc_enable) { u8 in_process = urb_qtd->in_process; dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh); @@ -2150,7 +2154,7 @@ static int dwc2_hcd_endpoint_disable(struct dwc2_hsotg *hsotg, } spin_unlock_irqrestore(&hsotg->lock, flags); - usleep_range(20000, 40000); + msleep(20); spin_lock_irqsave(&hsotg->lock, flags); qh = ep->hcpriv; if (!qh) { @@ -2215,13 +2219,12 @@ static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup) /* Set ULPI External VBUS bit if needed */ usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV; - if (hsotg->params.phy_ulpi_ext_vbus == - DWC2_PHY_ULPI_EXTERNAL_VBUS) + if (hsotg->params.phy_ulpi_ext_vbus) usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV; /* Set external TS Dline pulsing bit if needed */ usbcfg &= ~GUSBCFG_TERMSELDLPULSE; - if (hsotg->params.ts_dline > 0) + if (hsotg->params.ts_dline) usbcfg |= GUSBCFG_TERMSELDLPULSE; dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); @@ -2260,10 +2263,7 @@ static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup) /* Program the GOTGCTL register */ otgctl = dwc2_readl(hsotg->regs + GOTGCTL); otgctl &= ~GOTGCTL_OTGVER; - if (hsotg->params.otg_ver > 0) - otgctl |= GOTGCTL_OTGVER; dwc2_writel(otgctl, hsotg->regs + GOTGCTL); - dev_dbg(hsotg->dev, "OTG VER PARAM: %d\n", hsotg->params.otg_ver); /* Clear the SRP success bit for FS-I2c */ hsotg->srp_success = 0; @@ -2319,13 +2319,13 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) * runtime. This bit needs to be programmed during initial configuration * and its value must not be changed during runtime. */ - if (hsotg->params.reload_ctl > 0) { + if (hsotg->params.reload_ctl) { hfir = dwc2_readl(hsotg->regs + HFIR); hfir |= HFIR_RLDCTRL; dwc2_writel(hfir, hsotg->regs + HFIR); } - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { u32 op_mode = hsotg->hw_params.op_mode; if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a || @@ -2337,7 +2337,7 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) "Hardware does not support descriptor DMA mode -\n"); dev_err(hsotg->dev, "falling back to buffer DMA mode.\n"); - hsotg->params.dma_desc_enable = 0; + hsotg->params.dma_desc_enable = false; } else { hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg |= HCFG_DESCDMA; @@ -2363,7 +2363,7 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) otgctl &= ~GOTGCTL_HSTSETHNPEN; dwc2_writel(otgctl, hsotg->regs + GOTGCTL); - if (hsotg->params.dma_desc_enable <= 0) { + if (!hsotg->params.dma_desc_enable) { int num_channels, i; u32 hcchar; @@ -2430,7 +2430,7 @@ static void dwc2_hcd_reinit(struct dwc2_hsotg *hsotg) hsotg->flags.d32 = 0; hsotg->non_periodic_qh_ptr = &hsotg->non_periodic_sched_active; - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { hsotg->available_host_channels = hsotg->params.host_channels; } else { @@ -2488,7 +2488,7 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, chan->do_ping = 0; chan->ep_is_in = 0; chan->data_pid_start = DWC2_HC_PID_SETUP; - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) chan->xfer_dma = urb->setup_dma; else chan->xfer_buf = urb->setup_packet; @@ -2515,7 +2515,7 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, chan->do_ping = 0; chan->data_pid_start = DWC2_HC_PID_DATA1; chan->xfer_len = 0; - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) chan->xfer_dma = hsotg->status_buf_dma; else chan->xfer_buf = hsotg->status_buf; @@ -2533,13 +2533,13 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, case USB_ENDPOINT_XFER_ISOC: chan->ep_type = USB_ENDPOINT_XFER_ISOC; - if (hsotg->params.dma_desc_enable > 0) + if (hsotg->params.dma_desc_enable) break; frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; frame_desc->status = 0; - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { chan->xfer_dma = urb->dma; chan->xfer_dma += frame_desc->offset + qtd->isoc_split_offset; @@ -2577,7 +2577,7 @@ static void dwc2_free_dma_aligned_buffer(struct urb *urb) return; temp = container_of(urb->transfer_buffer, - struct dma_aligned_buffer, data); + struct dma_aligned_buffer, data); if (usb_urb_dir_in(urb)) memcpy(temp->old_xfer_buffer, temp->data, @@ -2621,7 +2621,7 @@ static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) } static int dwc2_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) + gfp_t mem_flags) { int ret; @@ -2718,10 +2718,10 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) chan->multi_count = 1; if (urb->actual_length > urb->length && - !dwc2_hcd_is_pipe_in(&urb->pipe_info)) + !dwc2_hcd_is_pipe_in(&urb->pipe_info)) urb->actual_length = urb->length; - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) chan->xfer_dma = urb->dma + urb->actual_length; else chan->xfer_buf = (u8 *)urb->buf + urb->actual_length; @@ -2746,7 +2746,7 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) */ chan->multi_count = dwc2_hb_mult(qh->maxp); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { chan->desc_list_addr = qh->desc_list_dma; chan->desc_list_sz = qh->desc_list_sz; } @@ -2783,7 +2783,7 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( while (qh_ptr != &hsotg->periodic_sched_ready) { if (list_empty(&hsotg->free_hc_list)) break; - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { if (hsotg->available_host_channels <= 1) break; hsotg->available_host_channels--; @@ -2810,14 +2810,14 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( num_channels = hsotg->params.host_channels; qh_ptr = hsotg->non_periodic_sched_inactive.next; while (qh_ptr != &hsotg->non_periodic_sched_inactive) { - if (hsotg->params.uframe_sched <= 0 && + if (!hsotg->params.uframe_sched && hsotg->non_periodic_channels >= num_channels - hsotg->periodic_channels) break; if (list_empty(&hsotg->free_hc_list)) break; qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { if (hsotg->available_host_channels < 1) break; hsotg->available_host_channels--; @@ -2839,7 +2839,7 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( else ret_val = DWC2_TRANSACTION_ALL; - if (hsotg->params.uframe_sched <= 0) + if (!hsotg->params.uframe_sched) hsotg->non_periodic_channels++; } @@ -2878,8 +2878,8 @@ static int dwc2_queue_transaction(struct dwc2_hsotg *hsotg, list_move_tail(&chan->split_order_list_entry, &hsotg->split_order); - if (hsotg->params.host_dma > 0) { - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.host_dma) { + if (hsotg->params.dma_desc_enable) { if (!chan->xfer_started || chan->ep_type == USB_ENDPOINT_XFER_ISOC) { dwc2_hcd_start_xfer_ddma(hsotg, chan->qh); @@ -2967,7 +2967,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg) qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT; if (qspcavail == 0) { - no_queue_space = 1; + no_queue_space = true; break; } @@ -2988,15 +2988,15 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg) * The flag prevents any halts to get into the request queue in * the middle of multiple high-bandwidth packets getting queued. */ - if (hsotg->params.host_dma <= 0 && - qh->channel->multi_count > 1) + if (!hsotg->params.host_dma && + qh->channel->multi_count > 1) hsotg->queuing_high_bandwidth = 1; fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT; status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail); if (status < 0) { - no_fifo_space = 1; + no_fifo_space = true; break; } @@ -3007,7 +3007,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg) * controller automatically handles multiple packets for * high-bandwidth transfers. */ - if (hsotg->params.host_dma > 0 || status == 0 || + if (hsotg->params.host_dma || status == 0 || qh->channel->requests == qh->channel->multi_count) { qh_ptr = qh_ptr->next; /* @@ -3024,7 +3024,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg) exit: if (no_queue_space || no_fifo_space || - (hsotg->params.host_dma <= 0 && + (!hsotg->params.host_dma && !list_empty(&hsotg->periodic_sched_assigned))) { /* * May need to queue more transactions as the request @@ -3045,7 +3045,7 @@ exit: * now. This function is called from interrupt * handlers to queue more transactions as transfer * states change. - */ + */ gintmsk = dwc2_readl(hsotg->regs + GINTMSK); if (gintmsk & GINTSTS_PTXFEMP) { gintmsk &= ~GINTSTS_PTXFEMP; @@ -3104,7 +3104,7 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg) tx_status = dwc2_readl(hsotg->regs + GNPTXSTS); qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT; - if (hsotg->params.host_dma <= 0 && qspcavail == 0) { + if (!hsotg->params.host_dma && qspcavail == 0) { no_queue_space = 1; break; } @@ -3137,7 +3137,7 @@ next: hsotg->non_periodic_qh_ptr->next; } while (hsotg->non_periodic_qh_ptr != orig_qh_ptr); - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { tx_status = dwc2_readl(hsotg->regs + GNPTXSTS); qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT; @@ -3235,12 +3235,25 @@ static void dwc2_conn_id_status_change(struct work_struct *work) if (gotgctl & GOTGCTL_CONID_B) { /* Wait for switch to device mode */ dev_dbg(hsotg->dev, "connId B\n"); + if (hsotg->bus_suspended) { + dev_info(hsotg->dev, + "Do port resume before switching to device mode\n"); + dwc2_port_resume(hsotg); + } while (!dwc2_is_device_mode(hsotg)) { dev_info(hsotg->dev, "Waiting for Peripheral Mode, Mode=%s\n", dwc2_is_host_mode(hsotg) ? "Host" : "Peripheral"); - usleep_range(20000, 40000); + msleep(20); + /* + * Sometimes the initial GOTGCTRL read is wrong, so + * check it again and jump to host mode if that was + * the case. + */ + gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); + if (!(gotgctl & GOTGCTL_CONID_B)) + goto host; if (++count > 250) break; } @@ -3255,13 +3268,14 @@ static void dwc2_conn_id_status_change(struct work_struct *work) spin_unlock_irqrestore(&hsotg->lock, flags); dwc2_hsotg_core_connect(hsotg); } else { +host: /* A-Device connector (Host Mode) */ dev_dbg(hsotg->dev, "connId A\n"); while (!dwc2_is_host_mode(hsotg)) { dev_info(hsotg->dev, "Waiting for Host Mode, Mode=%s\n", dwc2_is_host_mode(hsotg) ? "Host" : "Peripheral"); - usleep_range(20000, 40000); + msleep(20); if (++count > 250) break; } @@ -3296,7 +3310,7 @@ static void dwc2_wakeup_detected(unsigned long data) dwc2_readl(hsotg->regs + HPRT0)); dwc2_hcd_rem_wakeup(hsotg); - hsotg->bus_suspended = 0; + hsotg->bus_suspended = false; /* Change to L0 state */ hsotg->lx_state = DWC2_L0; @@ -3332,7 +3346,7 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) hprt0 |= HPRT0_SUSP; dwc2_writel(hprt0, hsotg->regs + HPRT0); - hsotg->bus_suspended = 1; + hsotg->bus_suspended = true; /* * If hibernation is supported, Phy clock will be suspended @@ -3354,7 +3368,7 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) spin_unlock_irqrestore(&hsotg->lock, flags); - usleep_range(200000, 250000); + msleep(200); } else { spin_unlock_irqrestore(&hsotg->lock, flags); } @@ -3378,7 +3392,7 @@ static void dwc2_port_resume(struct dwc2_hsotg *hsotg) pcgctl &= ~PCGCTL_STOPPCLK; dwc2_writel(pcgctl, hsotg->regs + PCGCTL); spin_unlock_irqrestore(&hsotg->lock, flags); - usleep_range(20000, 40000); + msleep(20); spin_lock_irqsave(&hsotg->lock, flags); } @@ -3394,7 +3408,7 @@ static void dwc2_port_resume(struct dwc2_hsotg *hsotg) hprt0 = dwc2_read_hprt0(hsotg); hprt0 &= ~(HPRT0_RES | HPRT0_SUSP); dwc2_writel(hprt0, hsotg->regs + HPRT0); - hsotg->bus_suspended = 0; + hsotg->bus_suspended = false; spin_unlock_irqrestore(&hsotg->lock, flags); } @@ -3614,7 +3628,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, u32 hcfg; dev_info(hsotg->dev, "Enabling descriptor DMA mode\n"); - hsotg->params.dma_desc_enable = 1; + hsotg->params.dma_desc_enable = true; hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg |= HCFG_DESCDMA; dwc2_writel(hcfg, hsotg->regs + HCFG); @@ -3691,7 +3705,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, } /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ - usleep_range(50000, 70000); + msleep(50); hprt0 &= ~HPRT0_RST; dwc2_writel(hprt0, hsotg->regs + HPRT0); hsotg->lx_state = DWC2_L0; /* Now back to On state */ @@ -4047,7 +4061,7 @@ static struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd) { struct wrapper_priv_data *p; - p = (struct wrapper_priv_data *) &hcd->hcd_priv; + p = (struct wrapper_priv_data *)&hcd->hcd_priv; return p->hsotg; } @@ -4082,7 +4096,7 @@ struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, void *context, *ttport = urb->dev->ttport; dwc_tt = urb->dev->tt->hcpriv; - if (dwc_tt == NULL) { + if (!dwc_tt) { size_t bitmap_size; /* @@ -4096,7 +4110,7 @@ struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, void *context, dwc_tt = kzalloc(sizeof(*dwc_tt) + bitmap_size, mem_flags); - if (dwc_tt == NULL) + if (!dwc_tt) return NULL; dwc_tt->usb_tt = urb->dev->tt; @@ -4123,7 +4137,7 @@ struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, void *context, void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg, struct dwc2_tt *dwc_tt) { /* Model kfree and make put of NULL a no-op */ - if (dwc_tt == NULL) + if (!dwc_tt) return; WARN_ON(dwc_tt->refcount < 1); @@ -4206,7 +4220,6 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, usb_pipein(urb->pipe) ? "IN" : "OUT", status, urb->actual_length); - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb); for (i = 0; i < urb->number_of_packets; ++i) { @@ -4587,7 +4600,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, dwc2_dump_urb_info(hcd, urb, "urb_enqueue"); } - if (ep == NULL) + if (!ep) return -EINVAL; if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS || @@ -4657,7 +4670,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, urb->iso_frame_desc[i].length); urb->hcpriv = dwc2_urb; - qh = (struct dwc2_qh *) ep->hcpriv; + qh = (struct dwc2_qh *)ep->hcpriv; /* Create QH for the endpoint if it doesn't exist */ if (!qh) { qh = dwc2_hcd_qh_create(hsotg, dwc2_urb, mem_flags); @@ -4712,7 +4725,7 @@ fail1: dwc2_hcd_qh_unlink(hsotg, qh); /* Free each QTD in the QH's QTD list */ list_for_each_entry_safe(qtd2, qtd2_tmp, &qh->qtd_list, - qtd_list_entry) + qtd_list_entry) dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh); dwc2_hcd_qh_free(hsotg, qh); } @@ -4860,6 +4873,61 @@ static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, spin_unlock_irqrestore(&hsotg->lock, flags); } +/* + * HPRT0_SPD_HIGH_SPEED: high speed + * HPRT0_SPD_FULL_SPEED: full speed + */ +static void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + + if (hsotg->params.speed == speed) + return; + + hsotg->params.speed = speed; + queue_work(hsotg->wq_otg, &hsotg->wf_otg); +} + +static void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + + if (!hsotg->params.change_speed_quirk) + return; + + /* + * On removal, set speed to default high-speed. + */ + if (udev->parent && udev->parent->speed > USB_SPEED_UNKNOWN && + udev->parent->speed < USB_SPEED_HIGH) { + dev_info(hsotg->dev, "Set speed to default high-speed\n"); + dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED); + } +} + +static int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + + if (!hsotg->params.change_speed_quirk) + return 0; + + if (udev->speed == USB_SPEED_HIGH) { + dev_info(hsotg->dev, "Set speed to high-speed\n"); + dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED); + } else if ((udev->speed == USB_SPEED_FULL || + udev->speed == USB_SPEED_LOW)) { + /* + * Change speed setting to full-speed if there's + * a full-speed or low-speed device plugged in. + */ + dev_info(hsotg->dev, "Set speed to full-speed\n"); + dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED); + } + + return 0; +} + static struct hc_driver dwc2_hc_driver = { .description = "dwc2_hsotg", .product_desc = "DWC OTG Controller", @@ -4911,7 +4979,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg) for (i = 0; i < MAX_EPS_CHANNELS; i++) { struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i]; - if (chan != NULL) { + if (chan) { dev_dbg(hsotg->dev, "HCD Free channel #%i, chan=%p\n", i, chan); hsotg->hc_ptr_array[i] = NULL; @@ -4919,7 +4987,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg) } } - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { if (hsotg->status_buf) { dma_free_coherent(hsotg->dev, DWC2_HCD_STATUS_BUF_SIZE, hsotg->status_buf, @@ -4967,8 +5035,10 @@ static void dwc2_hcd_release(struct dwc2_hsotg *hsotg) * USB bus with the core and calls the hc_driver->start() function. It returns * a negative error on failure. */ -int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) +int dwc2_hcd_init(struct dwc2_hsotg *hsotg) { + struct platform_device *pdev = to_platform_device(hsotg->dev); + struct resource *res; struct usb_hcd *hcd; struct dwc2_host_chan *channel; u32 hcfg; @@ -4999,32 +5069,41 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) hsotg->last_frame_num = HFNUM_MAX_FRNUM; /* Check if the bus driver or platform code has setup a dma_mask */ - if (hsotg->params.host_dma > 0 && - hsotg->dev->dma_mask == NULL) { + if (hsotg->params.host_dma && + !hsotg->dev->dma_mask) { dev_warn(hsotg->dev, "dma_mask not set, disabling DMA\n"); - hsotg->params.host_dma = 0; - hsotg->params.dma_desc_enable = 0; + hsotg->params.host_dma = false; + hsotg->params.dma_desc_enable = false; } /* Set device flags indicating whether the HCD supports DMA */ - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0) dev_warn(hsotg->dev, "can't set DMA mask\n"); if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0) dev_warn(hsotg->dev, "can't set coherent DMA mask\n"); } + if (hsotg->params.change_speed_quirk) { + dwc2_hc_driver.free_dev = dwc2_free_dev; + dwc2_hc_driver.reset_device = dwc2_reset_device; + } + hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev)); if (!hcd) goto error1; - if (hsotg->params.host_dma <= 0) + if (!hsotg->params.host_dma) hcd->self.uses_dma = 0; hcd->has_tt = 1; - ((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + ((struct wrapper_priv_data *)&hcd->hcd_priv)->hsotg = hsotg; hsotg->priv = hcd; /* @@ -5072,7 +5151,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) for (i = 0; i < num_channels; i++) { channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (channel == NULL) + if (!channel) goto error3; channel->hc_num = i; INIT_LIST_HEAD(&channel->split_order_list_entry); @@ -5091,7 +5170,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) * done after usb_add_hcd since that function allocates the DMA buffer * pool. */ - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) hsotg->status_buf = dma_alloc_coherent(hsotg->dev, DWC2_HCD_STATUS_BUF_SIZE, &hsotg->status_buf_dma, GFP_KERNEL); @@ -5121,8 +5200,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) * Disable descriptor dma mode since it will not be * usable. */ - hsotg->params.dma_desc_enable = 0; - hsotg->params.dma_desc_fs_enable = 0; + hsotg->params.dma_desc_enable = false; + hsotg->params.dma_desc_fs_enable = false; } hsotg->desc_hsisoc_cache = kmem_cache_create("dwc2-hsisoc-desc", @@ -5138,8 +5217,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) * Disable descriptor dma mode since it will not be * usable. */ - hsotg->params.dma_desc_enable = 0; - hsotg->params.dma_desc_fs_enable = 0; + hsotg->params.dma_desc_enable = false; + hsotg->params.dma_desc_fs_enable = false; } } @@ -5164,7 +5243,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) * allocates the DMA buffer pool, registers the USB bus, requests the * IRQ line, and calls hcd_start method. */ - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + retval = usb_add_hcd(hcd, hsotg->irq, IRQF_SHARED); if (retval < 0) goto error4; diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 1ed5fa2beff4..11c3c145b793 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -521,29 +521,29 @@ static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe) return !dwc2_hcd_is_pipe_in(pipe); } -extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq); -extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg); +int dwc2_hcd_init(struct dwc2_hsotg *hsotg); +void dwc2_hcd_remove(struct dwc2_hsotg *hsotg); /* Transaction Execution Functions */ -extern enum dwc2_transaction_type dwc2_hcd_select_transactions( +enum dwc2_transaction_type dwc2_hcd_select_transactions( struct dwc2_hsotg *hsotg); -extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, - enum dwc2_transaction_type tr_type); +void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, + enum dwc2_transaction_type tr_type); /* Schedule Queue Functions */ /* Implemented in hcd_queue.c */ -extern struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, - struct dwc2_hcd_urb *urb, +struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, + struct dwc2_hcd_urb *urb, gfp_t mem_flags); -extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); -extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); -extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); -extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, - int sched_csplit); +void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, + int sched_csplit); -extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb); -extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, - struct dwc2_qh *qh); +void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb); +int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, + struct dwc2_qh *qh); /* Unlinks and frees a QTD */ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, @@ -556,15 +556,15 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, } /* Descriptor DMA support functions */ -extern void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, - struct dwc2_qh *qh); -extern void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg, - struct dwc2_host_chan *chan, int chnum, +void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, + struct dwc2_qh *qh); +void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg, + struct dwc2_host_chan *chan, int chnum, enum dwc2_halt_status halt_status); -extern int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, - gfp_t mem_flags); -extern void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, + gfp_t mem_flags); +void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); /* Check if QH is non-periodic */ #define dwc2_qh_is_non_per(_qh_ptr_) \ @@ -732,8 +732,8 @@ static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg, return qh->host_us; } -extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, - struct dwc2_host_chan *chan, int chnum, +void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, + struct dwc2_host_chan *chan, int chnum, struct dwc2_qtd *qtd); /* HCD Core API */ @@ -746,14 +746,14 @@ extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, * Returns IRQ_HANDLED if interrupt is handled * Return IRQ_NONE if interrupt is not handled */ -extern irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg); +irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg); /** * dwc2_hcd_stop() - Halts the DWC_otg host mode operation * * @hsotg: The DWC2 HCD */ -extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg); +void dwc2_hcd_stop(struct dwc2_hsotg *hsotg); /** * dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host, @@ -761,7 +761,7 @@ extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg); * * @hsotg: The DWC2 HCD */ -extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg); +int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg); /** * dwc2_hcd_dump_state() - Dumps hsotg state @@ -771,7 +771,7 @@ extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg); * NOTE: This function will be removed once the peripheral controller code * is integrated and the driver is stable */ -extern void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg); +void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg); /** * dwc2_hcd_dump_frrem() - Dumps the average frame remaining at SOF @@ -784,7 +784,7 @@ extern void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg); * NOTE: This function will be removed once the peripheral controller code * is integrated and the driver is stable */ -extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg); +void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg); /* URB interface */ @@ -793,15 +793,15 @@ extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg); #define URB_SEND_ZERO_PACKET 0x2 /* Host driver callbacks */ -extern struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, - void *context, gfp_t mem_flags, - int *ttport); - -extern void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg, - struct dwc2_tt *dwc_tt); -extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context); -extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, - int status); +struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, + void *context, gfp_t mem_flags, + int *ttport); + +void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg, + struct dwc2_tt *dwc_tt); +int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context); +void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, + int status); #ifdef DEBUG /* diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c index cf0367768cb3..b8bdf545c3a7 100644 --- a/drivers/usb/dwc2/hcd_ddma.c +++ b/drivers/usb/dwc2/hcd_ddma.c @@ -89,8 +89,8 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, { struct kmem_cache *desc_cache; - if (qh->ep_type == USB_ENDPOINT_XFER_ISOC - && qh->dev_speed == USB_SPEED_HIGH) + if (qh->ep_type == USB_ENDPOINT_XFER_ISOC && + qh->dev_speed == USB_SPEED_HIGH) desc_cache = hsotg->desc_hsisoc_cache; else desc_cache = hsotg->desc_gen_cache; @@ -106,7 +106,7 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, qh->desc_list_sz, DMA_TO_DEVICE); - qh->n_bytes = kzalloc(sizeof(u32) * dwc2_max_desc_num(qh), flags); + qh->n_bytes = kcalloc(dwc2_max_desc_num(qh), sizeof(u32), flags); if (!qh->n_bytes) { dma_unmap_single(hsotg->dev, qh->desc_list_dma, qh->desc_list_sz, @@ -123,8 +123,8 @@ static void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) { struct kmem_cache *desc_cache; - if (qh->ep_type == USB_ENDPOINT_XFER_ISOC - && qh->dev_speed == USB_SPEED_HIGH) + if (qh->ep_type == USB_ENDPOINT_XFER_ISOC && + qh->dev_speed == USB_SPEED_HIGH) desc_cache = hsotg->desc_hsisoc_cache; else desc_cache = hsotg->desc_gen_cache; @@ -175,7 +175,6 @@ static void dwc2_frame_list_free(struct dwc2_hsotg *hsotg) hsotg->frame_list = NULL; spin_unlock_irqrestore(&hsotg->lock, flags); - } static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en) @@ -297,7 +296,7 @@ static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan = qh->channel; if (dwc2_qh_is_non_per(qh)) { - if (hsotg->params.uframe_sched > 0) + if (hsotg->params.uframe_sched) hsotg->available_host_channels++; else hsotg->non_periodic_channels--; @@ -404,7 +403,7 @@ void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC || qh->ep_type == USB_ENDPOINT_XFER_INT) && - (hsotg->params.uframe_sched > 0 || + (hsotg->params.uframe_sched || !hsotg->periodic_channels) && hsotg->frame_list) { dwc2_per_sched_disable(hsotg); dwc2_frame_list_free(hsotg); @@ -570,7 +569,7 @@ static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, #endif dma_sync_single_for_device(hsotg->dev, - qh->desc_list_dma + + qh->desc_list_dma + (idx * sizeof(struct dwc2_dma_desc)), sizeof(struct dwc2_dma_desc), DMA_TO_DEVICE); @@ -776,7 +775,7 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg, n_desc - 1, &qh->desc_list[n_desc - 1]); dma_sync_single_for_device(hsotg->dev, - qh->desc_list_dma + + qh->desc_list_dma + ((n_desc - 1) * sizeof(struct dwc2_dma_desc)), sizeof(struct dwc2_dma_desc), @@ -816,7 +815,7 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg, dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n", &qh->desc_list[0]); dma_sync_single_for_device(hsotg->dev, - qh->desc_list_dma, + qh->desc_list_dma, sizeof(struct dwc2_dma_desc), DMA_TO_DEVICE); } @@ -1064,7 +1063,7 @@ stop_scan: } static int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg, - struct dwc2_host_chan *chan, + struct dwc2_host_chan *chan, struct dwc2_qtd *qtd, struct dwc2_dma_desc *dma_desc, enum dwc2_halt_status halt_status, diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index b8f4b6aaf1d0..28a8210710b1 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -60,7 +60,7 @@ static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg) if (expected != curr_frame_number) dwc2_sch_vdbg(hsotg, "MISSED SOF %04x != %04x\n", - expected, curr_frame_number); + expected, curr_frame_number); #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) { @@ -163,7 +163,7 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg) * (micro)frame */ list_move_tail(&qh->qh_list_entry, - &hsotg->periodic_sched_ready); + &hsotg->periodic_sched_ready); } } tr_type = dwc2_hcd_select_transactions(hsotg); @@ -297,8 +297,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0, HCFG_FSLSPCLKSEL_SHIFT; if (prtspd == HPRT0_SPD_LOW_SPEED && - params->host_ls_low_power_phy_clk == - DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ) { + params->host_ls_low_power_phy_clk) { /* 6 MHZ */ dev_vdbg(hsotg->dev, "FS_PHY programming HCFG to 6 MHz\n"); @@ -398,7 +397,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg) if (hsotg->params.dma_desc_fs_enable) { u32 hcfg; - hsotg->params.dma_desc_enable = 0; + hsotg->params.dma_desc_enable = false; hsotg->new_connection = false; hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg &= ~HCFG_DESCDMA; @@ -442,7 +441,7 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg, count = (hctsiz & TSIZ_XFERSIZE_MASK) >> TSIZ_XFERSIZE_SHIFT; length = chan->xfer_len - count; - if (short_read != NULL) + if (short_read) *short_read = (count != 0); } else if (chan->qh->do_split) { length = qtd->ssplit_out_xfer_count; @@ -604,7 +603,7 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state( /* Skip whole frame */ if (chan->qh->do_split && chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in && - hsotg->params.host_dma > 0) { + hsotg->params.host_dma) { qtd->complete_split = 0; qtd->isoc_split_offset = 0; } @@ -743,7 +742,7 @@ cleanup: dwc2_hc_cleanup(hsotg, chan); list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list); - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { hsotg->available_host_channels++; } else { switch (chan->ep_type) { @@ -789,7 +788,7 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg, if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "%s()\n", __func__); - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "DMA enabled\n"); dwc2_release_channel(hsotg, chan, qtd, halt_status); @@ -823,7 +822,7 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg, * processed. */ list_move_tail(&chan->qh->qh_list_entry, - &hsotg->periodic_sched_assigned); + &hsotg->periodic_sched_assigned); /* * Make sure the Periodic Tx FIFO Empty interrupt is @@ -979,7 +978,7 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg, pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, halt_status); if (pipe_type == USB_ENDPOINT_XFER_ISOC) /* Do not disable the interrupt, just clear it */ @@ -990,7 +989,7 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg, /* Handle xfer complete on CSPLIT */ if (chan->qh->do_split) { if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in && - hsotg->params.host_dma > 0) { + hsotg->params.host_dma) { if (qtd->complete_split && dwc2_xfercomp_isoc_split_in(hsotg, chan, chnum, qtd)) @@ -1078,7 +1077,8 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg, dev_vdbg(hsotg->dev, " Isochronous transfer complete\n"); if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_ALL) halt_status = dwc2_update_isoc_urb_state(hsotg, chan, - chnum, qtd, DWC2_HC_XFER_COMPLETE); + chnum, qtd, + DWC2_HC_XFER_COMPLETE); dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd, halt_status); break; @@ -1102,7 +1102,7 @@ static void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg, dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: STALL Received--\n", chnum); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, DWC2_HC_XFER_STALL); goto handle_stall_done; @@ -1212,7 +1212,7 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg, switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_BULK: - if (hsotg->params.host_dma > 0 && chan->ep_is_in) { + if (hsotg->params.host_dma && chan->ep_is_in) { /* * NAK interrupts are enabled on bulk/control IN * transfers in DMA mode for the sole purpose of @@ -1358,7 +1358,7 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg, */ if (chan->do_split && chan->complete_split) { if (chan->ep_is_in && chan->ep_type == USB_ENDPOINT_XFER_ISOC && - hsotg->params.host_dma > 0) { + hsotg->params.host_dma) { qtd->complete_split = 0; qtd->isoc_split_offset = 0; qtd->isoc_frame_index++; @@ -1379,7 +1379,7 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh = chan->qh; bool past_end; - if (hsotg->params.uframe_sched <= 0) { + if (!hsotg->params.uframe_sched) { int frnum = dwc2_hcd_get_frame_number(hsotg); /* Don't have num_hs_transfers; simple logic */ @@ -1389,22 +1389,27 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg, int end_frnum; /* - * Figure out the end frame based on schedule. - * - * We don't want to go on trying again and again - * forever. Let's stop when we've done all the - * transfers that were scheduled. - * - * We're going to be comparing start_active_frame - * and next_active_frame, both of which are 1 - * before the time the packet goes on the wire, - * so that cancels out. Basically if had 1 - * transfer and we saw 1 NYET then we're done. - * We're getting a NYET here so if next >= - * (start + num_transfers) we're done. The - * complexity is that for all but ISOC_OUT we - * skip one slot. - */ + * Figure out the end frame based on + * schedule. + * + * We don't want to go on trying again + * and again forever. Let's stop when + * we've done all the transfers that + * were scheduled. + * + * We're going to be comparing + * start_active_frame and + * next_active_frame, both of which + * are 1 before the time the packet + * goes on the wire, so that cancels + * out. Basically if had 1 transfer + * and we saw 1 NYET then we're done. + * We're getting a NYET here so if + * next >= (start + num_transfers) + * we're done. The complexity is that + * for all but ISOC_OUT we skip one + * slot. + */ end_frnum = dwc2_frame_num_inc( qh->start_active_frame, qh->num_hs_transfers); @@ -1472,7 +1477,7 @@ static void dwc2_hc_babble_intr(struct dwc2_hsotg *hsotg, dwc2_hc_handle_tt_clear(hsotg, chan, qtd); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, DWC2_HC_XFER_BABBLE_ERR); goto disable_int; @@ -1577,7 +1582,7 @@ static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg, dev_err(hsotg->dev, " Interval: %d\n", urb->interval); /* Core halts the channel for Descriptor DMA mode */ - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, DWC2_HC_XFER_AHB_ERR); goto handle_ahberr_done; @@ -1609,7 +1614,7 @@ static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg, dwc2_hc_handle_tt_clear(hsotg, chan, qtd); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, DWC2_HC_XFER_XACT_ERR); goto handle_xacterr_done; @@ -1620,7 +1625,6 @@ static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg, case USB_ENDPOINT_XFER_BULK: qtd->error_count++; if (!chan->qh->ping_state) { - dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, qtd, DWC2_HC_XFER_XACT_ERR); dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); @@ -1645,7 +1649,7 @@ static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg, enum dwc2_halt_status halt_status; halt_status = dwc2_update_isoc_urb_state(hsotg, chan, - chnum, qtd, DWC2_HC_XFER_XACT_ERR); + chnum, qtd, DWC2_HC_XFER_XACT_ERR); dwc2_halt_channel(hsotg, chan, qtd, halt_status); } break; @@ -1803,8 +1807,8 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg, if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE || (chan->halt_status == DWC2_HC_XFER_AHB_ERR && - hsotg->params.dma_desc_enable <= 0)) { - if (hsotg->params.dma_desc_enable > 0) + !hsotg->params.dma_desc_enable)) { + if (hsotg->params.dma_desc_enable) dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, chan->halt_status); else @@ -1835,7 +1839,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg, } else if (chan->hcint & HCINTMSK_STALL) { dwc2_hc_stall_intr(hsotg, chan, chnum, qtd); } else if ((chan->hcint & HCINTMSK_XACTERR) && - hsotg->params.dma_desc_enable <= 0) { + !hsotg->params.dma_desc_enable) { if (out_nak_enh) { if (chan->hcint & (HCINTMSK_NYET | HCINTMSK_NAK | HCINTMSK_ACK)) { @@ -1855,10 +1859,10 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg, */ dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); } else if ((chan->hcint & HCINTMSK_XCS_XACT) && - hsotg->params.dma_desc_enable > 0) { + hsotg->params.dma_desc_enable) { dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); } else if ((chan->hcint & HCINTMSK_AHBERR) && - hsotg->params.dma_desc_enable > 0) { + hsotg->params.dma_desc_enable) { dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd); } else if (chan->hcint & HCINTMSK_BBLERR) { dwc2_hc_babble_intr(hsotg, chan, chnum, qtd); @@ -1951,7 +1955,7 @@ static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg, dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: Channel Halted--\n", chnum); - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { dwc2_hc_chhltd_intr_dma(hsotg, chan, chnum, qtd); } else { if (!dwc2_halt_status_ok(hsotg, chan, chnum, qtd)) @@ -1970,7 +1974,7 @@ static bool dwc2_check_qtd_still_ok(struct dwc2_qtd *qtd, struct dwc2_qh *qh) { struct dwc2_qtd *cur_head; - if (qh == NULL) + if (!qh) return false; cur_head = list_first_entry(&qh->qtd_list, struct dwc2_qtd, @@ -2028,7 +2032,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) * interrupt unmasked */ WARN_ON(hcint != HCINTMSK_CHHLTD); - if (hsotg->params.dma_desc_enable > 0) + if (hsotg->params.dma_desc_enable) dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, chan->halt_status); else @@ -2056,7 +2060,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) qtd = list_first_entry(&chan->qh->qtd_list, struct dwc2_qtd, qtd_list_entry); - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { if ((hcint & HCINTMSK_CHHLTD) && hcint != HCINTMSK_CHHLTD) hcint &= ~HCINTMSK_CHHLTD; } diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 5713f03a4e56..3ae8b1bbaa55 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -76,14 +76,13 @@ static int dwc2_periodic_channel_available(struct dwc2_hsotg *hsotg) int num_channels; num_channels = hsotg->params.host_channels; - if (hsotg->periodic_channels + hsotg->non_periodic_channels < - num_channels - && hsotg->periodic_channels < num_channels - 1) { + if ((hsotg->periodic_channels + hsotg->non_periodic_channels < + num_channels) && (hsotg->periodic_channels < num_channels - 1)) { status = 0; } else { dev_dbg(hsotg->dev, - "%s: Total channels: %d, Periodic: %d, " - "Non-periodic: %d\n", __func__, num_channels, + "%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n", + __func__, num_channels, hsotg->periodic_channels, hsotg->non_periodic_channels); status = -ENOSPC; } @@ -485,7 +484,6 @@ static void pmap_print(unsigned long *map, int bits_per_period, } } - struct dwc2_qh_print_data { struct dwc2_hsotg *hsotg; struct dwc2_qh *qh; @@ -558,7 +556,6 @@ static void dwc2_qh_schedule_print(struct dwc2_hsotg *hsotg, DWC2_HS_SCHEDULE_UFRAMES, "uFrame", "us", dwc2_qh_print, &print_data); } - return; } #else static inline void dwc2_qh_schedule_print(struct dwc2_hsotg *hsotg, @@ -587,7 +584,7 @@ static int dwc2_ls_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, unsigned long *map = dwc2_get_ls_map(hsotg, qh); int slice; - if (map == NULL) + if (!map) return -EINVAL; /* @@ -626,7 +623,7 @@ static void dwc2_ls_pmap_unschedule(struct dwc2_hsotg *hsotg, unsigned long *map = dwc2_get_ls_map(hsotg, qh); /* Schedule should have failed, so no worries about no error code */ - if (map == NULL) + if (!map) return; pmap_unschedule(map, DWC2_LS_PERIODIC_SLICES_PER_FRAME, @@ -1107,7 +1104,7 @@ static void dwc2_pick_first_frame(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) next_active_frame = earliest_frame; /* Get the "no microframe schduler" out of the way... */ - if (hsotg->params.uframe_sched <= 0) { + if (!hsotg->params.uframe_sched) { if (qh->do_split) /* Splits are active at microframe 0 minus 1 */ next_active_frame |= 0x7; @@ -1182,7 +1179,7 @@ exit: qh->start_active_frame = next_active_frame; dwc2_sch_vdbg(hsotg, "QH=%p First fn=%04x nxt=%04x\n", - qh, frame_number, qh->next_active_frame); + qh, frame_number, qh->next_active_frame); } /** @@ -1200,7 +1197,7 @@ static int dwc2_do_reserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) { int status; - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { status = dwc2_uframe_schedule(hsotg, qh); } else { status = dwc2_periodic_channel_available(hsotg); @@ -1221,7 +1218,7 @@ static int dwc2_do_reserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) return status; } - if (hsotg->params.uframe_sched <= 0) + if (!hsotg->params.uframe_sched) /* Reserve periodic channel */ hsotg->periodic_channels++; @@ -1257,7 +1254,7 @@ static void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) /* Update claimed usecs per (micro)frame */ hsotg->periodic_usecs -= qh->host_us; - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { dwc2_uframe_unschedule(hsotg, qh); } else { /* Release periodic channel reservation */ @@ -1394,7 +1391,7 @@ static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) qh->unreserve_pending = 0; - if (hsotg->params.dma_desc_enable > 0) + if (hsotg->params.dma_desc_enable) /* Don't rely on SOF and start in ready schedule */ list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_ready); else @@ -1501,7 +1498,6 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, device_ns += dwc_tt->usb_tt->think_time; qh->device_us = NS_TO_US(device_ns); - qh->device_interval = urb->interval; qh->host_interval = urb->interval * (do_split ? 8 : 1); @@ -1587,7 +1583,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, * Return: Pointer to the newly allocated QH, or NULL on error */ struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, - struct dwc2_hcd_urb *urb, + struct dwc2_hcd_urb *urb, gfp_t mem_flags) { struct dwc2_qh *qh; @@ -1602,7 +1598,7 @@ struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, dwc2_qh_init(hsotg, qh, urb, mem_flags); - if (hsotg->params.dma_desc_enable > 0 && + if (hsotg->params.dma_desc_enable && dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) { dwc2_hcd_qh_free(hsotg, qh); return NULL; @@ -1714,7 +1710,7 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) dwc2_deschedule_periodic(hsotg, qh); hsotg->periodic_qh_count--; if (!hsotg->periodic_qh_count && - hsotg->params.dma_desc_enable <= 0) { + !hsotg->params.dma_desc_enable) { intr_mask = dwc2_readl(hsotg->regs + GINTMSK); intr_mask &= ~GINTSTS_SOF; dwc2_writel(intr_mask, hsotg->regs + GINTMSK); @@ -1741,7 +1737,7 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) * Return: number missed by (or 0 if we didn't miss). */ static int dwc2_next_for_periodic_split(struct dwc2_hsotg *hsotg, - struct dwc2_qh *qh, u16 frame_number) + struct dwc2_qh *qh, u16 frame_number) { u16 old_frame = qh->next_active_frame; u16 prev_frame_number = dwc2_frame_num_dec(frame_number, 1); @@ -1804,7 +1800,7 @@ static int dwc2_next_for_periodic_split(struct dwc2_hsotg *hsotg, * Return: number missed by (or 0 if we didn't miss). */ static int dwc2_next_periodic_start(struct dwc2_hsotg *hsotg, - struct dwc2_qh *qh, u16 frame_number) + struct dwc2_qh *qh, u16 frame_number) { int missed = 0; u16 interval = qh->host_interval; @@ -1926,7 +1922,7 @@ void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, missed = dwc2_next_periodic_start(hsotg, qh, frame_number); dwc2_sch_vdbg(hsotg, - "QH=%p next(%d) fn=%04x, sch=%04x=>%04x (%+d) miss=%d %s\n", + "QH=%p next(%d) fn=%04x, sch=%04x=>%04x (%+d) miss=%d %s\n", qh, sched_next_periodic_split, frame_number, old_frame, qh->next_active_frame, dwc2_frame_num_dec(qh->next_active_frame, old_frame), diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 5be056b39e5c..bde72489ae66 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -40,37 +40,37 @@ #define HSOTG_REG(x) (x) #define GOTGCTL HSOTG_REG(0x000) -#define GOTGCTL_CHIRPEN (1 << 27) +#define GOTGCTL_CHIRPEN BIT(27) #define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22) #define GOTGCTL_MULT_VALID_BC_SHIFT 22 -#define GOTGCTL_OTGVER (1 << 20) -#define GOTGCTL_BSESVLD (1 << 19) -#define GOTGCTL_ASESVLD (1 << 18) -#define GOTGCTL_DBNC_SHORT (1 << 17) -#define GOTGCTL_CONID_B (1 << 16) -#define GOTGCTL_DBNCE_FLTR_BYPASS (1 << 15) -#define GOTGCTL_DEVHNPEN (1 << 11) -#define GOTGCTL_HSTSETHNPEN (1 << 10) -#define GOTGCTL_HNPREQ (1 << 9) -#define GOTGCTL_HSTNEGSCS (1 << 8) -#define GOTGCTL_SESREQ (1 << 1) -#define GOTGCTL_SESREQSCS (1 << 0) +#define GOTGCTL_OTGVER BIT(20) +#define GOTGCTL_BSESVLD BIT(19) +#define GOTGCTL_ASESVLD BIT(18) +#define GOTGCTL_DBNC_SHORT BIT(17) +#define GOTGCTL_CONID_B BIT(16) +#define GOTGCTL_DBNCE_FLTR_BYPASS BIT(15) +#define GOTGCTL_DEVHNPEN BIT(11) +#define GOTGCTL_HSTSETHNPEN BIT(10) +#define GOTGCTL_HNPREQ BIT(9) +#define GOTGCTL_HSTNEGSCS BIT(8) +#define GOTGCTL_SESREQ BIT(1) +#define GOTGCTL_SESREQSCS BIT(0) #define GOTGINT HSOTG_REG(0x004) -#define GOTGINT_DBNCE_DONE (1 << 19) -#define GOTGINT_A_DEV_TOUT_CHG (1 << 18) -#define GOTGINT_HST_NEG_DET (1 << 17) -#define GOTGINT_HST_NEG_SUC_STS_CHNG (1 << 9) -#define GOTGINT_SES_REQ_SUC_STS_CHNG (1 << 8) -#define GOTGINT_SES_END_DET (1 << 2) +#define GOTGINT_DBNCE_DONE BIT(19) +#define GOTGINT_A_DEV_TOUT_CHG BIT(18) +#define GOTGINT_HST_NEG_DET BIT(17) +#define GOTGINT_HST_NEG_SUC_STS_CHNG BIT(9) +#define GOTGINT_SES_REQ_SUC_STS_CHNG BIT(8) +#define GOTGINT_SES_END_DET BIT(2) #define GAHBCFG HSOTG_REG(0x008) -#define GAHBCFG_AHB_SINGLE (1 << 23) -#define GAHBCFG_NOTI_ALL_DMA_WRIT (1 << 22) -#define GAHBCFG_REM_MEM_SUPP (1 << 21) -#define GAHBCFG_P_TXF_EMP_LVL (1 << 8) -#define GAHBCFG_NP_TXF_EMP_LVL (1 << 7) -#define GAHBCFG_DMA_EN (1 << 5) +#define GAHBCFG_AHB_SINGLE BIT(23) +#define GAHBCFG_NOTI_ALL_DMA_WRIT BIT(22) +#define GAHBCFG_REM_MEM_SUPP BIT(21) +#define GAHBCFG_P_TXF_EMP_LVL BIT(8) +#define GAHBCFG_NP_TXF_EMP_LVL BIT(7) +#define GAHBCFG_DMA_EN BIT(5) #define GAHBCFG_HBSTLEN_MASK (0xf << 1) #define GAHBCFG_HBSTLEN_SHIFT 1 #define GAHBCFG_HBSTLEN_SINGLE 0 @@ -78,38 +78,38 @@ #define GAHBCFG_HBSTLEN_INCR4 3 #define GAHBCFG_HBSTLEN_INCR8 5 #define GAHBCFG_HBSTLEN_INCR16 7 -#define GAHBCFG_GLBL_INTR_EN (1 << 0) +#define GAHBCFG_GLBL_INTR_EN BIT(0) #define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \ GAHBCFG_NP_TXF_EMP_LVL | \ GAHBCFG_DMA_EN | \ GAHBCFG_GLBL_INTR_EN) #define GUSBCFG HSOTG_REG(0x00C) -#define GUSBCFG_FORCEDEVMODE (1 << 30) -#define GUSBCFG_FORCEHOSTMODE (1 << 29) -#define GUSBCFG_TXENDDELAY (1 << 28) -#define GUSBCFG_ICTRAFFICPULLREMOVE (1 << 27) -#define GUSBCFG_ICUSBCAP (1 << 26) -#define GUSBCFG_ULPI_INT_PROT_DIS (1 << 25) -#define GUSBCFG_INDICATORPASSTHROUGH (1 << 24) -#define GUSBCFG_INDICATORCOMPLEMENT (1 << 23) -#define GUSBCFG_TERMSELDLPULSE (1 << 22) -#define GUSBCFG_ULPI_INT_VBUS_IND (1 << 21) -#define GUSBCFG_ULPI_EXT_VBUS_DRV (1 << 20) -#define GUSBCFG_ULPI_CLK_SUSP_M (1 << 19) -#define GUSBCFG_ULPI_AUTO_RES (1 << 18) -#define GUSBCFG_ULPI_FS_LS (1 << 17) -#define GUSBCFG_OTG_UTMI_FS_SEL (1 << 16) -#define GUSBCFG_PHY_LP_CLK_SEL (1 << 15) +#define GUSBCFG_FORCEDEVMODE BIT(30) +#define GUSBCFG_FORCEHOSTMODE BIT(29) +#define GUSBCFG_TXENDDELAY BIT(28) +#define GUSBCFG_ICTRAFFICPULLREMOVE BIT(27) +#define GUSBCFG_ICUSBCAP BIT(26) +#define GUSBCFG_ULPI_INT_PROT_DIS BIT(25) +#define GUSBCFG_INDICATORPASSTHROUGH BIT(24) +#define GUSBCFG_INDICATORCOMPLEMENT BIT(23) +#define GUSBCFG_TERMSELDLPULSE BIT(22) +#define GUSBCFG_ULPI_INT_VBUS_IND BIT(21) +#define GUSBCFG_ULPI_EXT_VBUS_DRV BIT(20) +#define GUSBCFG_ULPI_CLK_SUSP_M BIT(19) +#define GUSBCFG_ULPI_AUTO_RES BIT(18) +#define GUSBCFG_ULPI_FS_LS BIT(17) +#define GUSBCFG_OTG_UTMI_FS_SEL BIT(16) +#define GUSBCFG_PHY_LP_CLK_SEL BIT(15) #define GUSBCFG_USBTRDTIM_MASK (0xf << 10) #define GUSBCFG_USBTRDTIM_SHIFT 10 -#define GUSBCFG_HNPCAP (1 << 9) -#define GUSBCFG_SRPCAP (1 << 8) -#define GUSBCFG_DDRSEL (1 << 7) -#define GUSBCFG_PHYSEL (1 << 6) -#define GUSBCFG_FSINTF (1 << 5) -#define GUSBCFG_ULPI_UTMI_SEL (1 << 4) -#define GUSBCFG_PHYIF16 (1 << 3) +#define GUSBCFG_HNPCAP BIT(9) +#define GUSBCFG_SRPCAP BIT(8) +#define GUSBCFG_DDRSEL BIT(7) +#define GUSBCFG_PHYSEL BIT(6) +#define GUSBCFG_FSINTF BIT(5) +#define GUSBCFG_ULPI_UTMI_SEL BIT(4) +#define GUSBCFG_PHYIF16 BIT(3) #define GUSBCFG_PHYIF8 (0 << 3) #define GUSBCFG_TOUTCAL_MASK (0x7 << 0) #define GUSBCFG_TOUTCAL_SHIFT 0 @@ -117,54 +117,54 @@ #define GUSBCFG_TOUTCAL(_x) ((_x) << 0) #define GRSTCTL HSOTG_REG(0x010) -#define GRSTCTL_AHBIDLE (1 << 31) -#define GRSTCTL_DMAREQ (1 << 30) +#define GRSTCTL_AHBIDLE BIT(31) +#define GRSTCTL_DMAREQ BIT(30) #define GRSTCTL_TXFNUM_MASK (0x1f << 6) #define GRSTCTL_TXFNUM_SHIFT 6 #define GRSTCTL_TXFNUM_LIMIT 0x1f #define GRSTCTL_TXFNUM(_x) ((_x) << 6) -#define GRSTCTL_TXFFLSH (1 << 5) -#define GRSTCTL_RXFFLSH (1 << 4) -#define GRSTCTL_IN_TKNQ_FLSH (1 << 3) -#define GRSTCTL_FRMCNTRRST (1 << 2) -#define GRSTCTL_HSFTRST (1 << 1) -#define GRSTCTL_CSFTRST (1 << 0) +#define GRSTCTL_TXFFLSH BIT(5) +#define GRSTCTL_RXFFLSH BIT(4) +#define GRSTCTL_IN_TKNQ_FLSH BIT(3) +#define GRSTCTL_FRMCNTRRST BIT(2) +#define GRSTCTL_HSFTRST BIT(1) +#define GRSTCTL_CSFTRST BIT(0) #define GINTSTS HSOTG_REG(0x014) #define GINTMSK HSOTG_REG(0x018) -#define GINTSTS_WKUPINT (1 << 31) -#define GINTSTS_SESSREQINT (1 << 30) -#define GINTSTS_DISCONNINT (1 << 29) -#define GINTSTS_CONIDSTSCHNG (1 << 28) -#define GINTSTS_LPMTRANRCVD (1 << 27) -#define GINTSTS_PTXFEMP (1 << 26) -#define GINTSTS_HCHINT (1 << 25) -#define GINTSTS_PRTINT (1 << 24) -#define GINTSTS_RESETDET (1 << 23) -#define GINTSTS_FET_SUSP (1 << 22) -#define GINTSTS_INCOMPL_IP (1 << 21) -#define GINTSTS_INCOMPL_SOOUT (1 << 21) -#define GINTSTS_INCOMPL_SOIN (1 << 20) -#define GINTSTS_OEPINT (1 << 19) -#define GINTSTS_IEPINT (1 << 18) -#define GINTSTS_EPMIS (1 << 17) -#define GINTSTS_RESTOREDONE (1 << 16) -#define GINTSTS_EOPF (1 << 15) -#define GINTSTS_ISOUTDROP (1 << 14) -#define GINTSTS_ENUMDONE (1 << 13) -#define GINTSTS_USBRST (1 << 12) -#define GINTSTS_USBSUSP (1 << 11) -#define GINTSTS_ERLYSUSP (1 << 10) -#define GINTSTS_I2CINT (1 << 9) -#define GINTSTS_ULPI_CK_INT (1 << 8) -#define GINTSTS_GOUTNAKEFF (1 << 7) -#define GINTSTS_GINNAKEFF (1 << 6) -#define GINTSTS_NPTXFEMP (1 << 5) -#define GINTSTS_RXFLVL (1 << 4) -#define GINTSTS_SOF (1 << 3) -#define GINTSTS_OTGINT (1 << 2) -#define GINTSTS_MODEMIS (1 << 1) -#define GINTSTS_CURMODE_HOST (1 << 0) +#define GINTSTS_WKUPINT BIT(31) +#define GINTSTS_SESSREQINT BIT(30) +#define GINTSTS_DISCONNINT BIT(29) +#define GINTSTS_CONIDSTSCHNG BIT(28) +#define GINTSTS_LPMTRANRCVD BIT(27) +#define GINTSTS_PTXFEMP BIT(26) +#define GINTSTS_HCHINT BIT(25) +#define GINTSTS_PRTINT BIT(24) +#define GINTSTS_RESETDET BIT(23) +#define GINTSTS_FET_SUSP BIT(22) +#define GINTSTS_INCOMPL_IP BIT(21) +#define GINTSTS_INCOMPL_SOOUT BIT(21) +#define GINTSTS_INCOMPL_SOIN BIT(20) +#define GINTSTS_OEPINT BIT(19) +#define GINTSTS_IEPINT BIT(18) +#define GINTSTS_EPMIS BIT(17) +#define GINTSTS_RESTOREDONE BIT(16) +#define GINTSTS_EOPF BIT(15) +#define GINTSTS_ISOUTDROP BIT(14) +#define GINTSTS_ENUMDONE BIT(13) +#define GINTSTS_USBRST BIT(12) +#define GINTSTS_USBSUSP BIT(11) +#define GINTSTS_ERLYSUSP BIT(10) +#define GINTSTS_I2CINT BIT(9) +#define GINTSTS_ULPI_CK_INT BIT(8) +#define GINTSTS_GOUTNAKEFF BIT(7) +#define GINTSTS_GINNAKEFF BIT(6) +#define GINTSTS_NPTXFEMP BIT(5) +#define GINTSTS_RXFLVL BIT(4) +#define GINTSTS_SOF BIT(3) +#define GINTSTS_OTGINT BIT(2) +#define GINTSTS_MODEMIS BIT(1) +#define GINTSTS_CURMODE_HOST BIT(0) #define GRXSTSR HSOTG_REG(0x01C) #define GRXSTSP HSOTG_REG(0x020) @@ -208,14 +208,14 @@ #define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v) (((_v) >> 0) & 0xffff) #define GI2CCTL HSOTG_REG(0x0030) -#define GI2CCTL_BSYDNE (1 << 31) -#define GI2CCTL_RW (1 << 30) -#define GI2CCTL_I2CDATSE0 (1 << 28) +#define GI2CCTL_BSYDNE BIT(31) +#define GI2CCTL_RW BIT(30) +#define GI2CCTL_I2CDATSE0 BIT(28) #define GI2CCTL_I2CDEVADDR_MASK (0x3 << 26) #define GI2CCTL_I2CDEVADDR_SHIFT 26 -#define GI2CCTL_I2CSUSPCTL (1 << 25) -#define GI2CCTL_ACK (1 << 24) -#define GI2CCTL_I2CEN (1 << 23) +#define GI2CCTL_I2CSUSPCTL BIT(25) +#define GI2CCTL_ACK BIT(24) +#define GI2CCTL_I2CEN BIT(23) #define GI2CCTL_ADDR_MASK (0x7f << 16) #define GI2CCTL_ADDR_SHIFT 16 #define GI2CCTL_REGADDR_MASK (0xff << 8) @@ -230,16 +230,16 @@ #define GHWCFG1 HSOTG_REG(0x0044) #define GHWCFG2 HSOTG_REG(0x0048) -#define GHWCFG2_OTG_ENABLE_IC_USB (1 << 31) +#define GHWCFG2_OTG_ENABLE_IC_USB BIT(31) #define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1f << 26) #define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT 26 #define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24) #define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT 24 #define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22) #define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT 22 -#define GHWCFG2_MULTI_PROC_INT (1 << 20) -#define GHWCFG2_DYNAMIC_FIFO (1 << 19) -#define GHWCFG2_PERIO_EP_SUPPORTED (1 << 18) +#define GHWCFG2_MULTI_PROC_INT BIT(20) +#define GHWCFG2_DYNAMIC_FIFO BIT(19) +#define GHWCFG2_PERIO_EP_SUPPORTED BIT(18) #define GHWCFG2_NUM_HOST_CHAN_MASK (0xf << 14) #define GHWCFG2_NUM_HOST_CHAN_SHIFT 14 #define GHWCFG2_NUM_DEV_EP_MASK (0xf << 10) @@ -256,7 +256,7 @@ #define GHWCFG2_HS_PHY_TYPE_UTMI 1 #define GHWCFG2_HS_PHY_TYPE_ULPI 2 #define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 -#define GHWCFG2_POINT2POINT (1 << 5) +#define GHWCFG2_POINT2POINT BIT(5) #define GHWCFG2_ARCHITECTURE_MASK (0x3 << 3) #define GHWCFG2_ARCHITECTURE_SHIFT 3 #define GHWCFG2_SLAVE_ONLY_ARCH 0 @@ -276,32 +276,32 @@ #define GHWCFG3 HSOTG_REG(0x004c) #define GHWCFG3_DFIFO_DEPTH_MASK (0xffff << 16) #define GHWCFG3_DFIFO_DEPTH_SHIFT 16 -#define GHWCFG3_OTG_LPM_EN (1 << 15) -#define GHWCFG3_BC_SUPPORT (1 << 14) -#define GHWCFG3_OTG_ENABLE_HSIC (1 << 13) -#define GHWCFG3_ADP_SUPP (1 << 12) -#define GHWCFG3_SYNCH_RESET_TYPE (1 << 11) -#define GHWCFG3_OPTIONAL_FEATURES (1 << 10) -#define GHWCFG3_VENDOR_CTRL_IF (1 << 9) -#define GHWCFG3_I2C (1 << 8) -#define GHWCFG3_OTG_FUNC (1 << 7) +#define GHWCFG3_OTG_LPM_EN BIT(15) +#define GHWCFG3_BC_SUPPORT BIT(14) +#define GHWCFG3_OTG_ENABLE_HSIC BIT(13) +#define GHWCFG3_ADP_SUPP BIT(12) +#define GHWCFG3_SYNCH_RESET_TYPE BIT(11) +#define GHWCFG3_OPTIONAL_FEATURES BIT(10) +#define GHWCFG3_VENDOR_CTRL_IF BIT(9) +#define GHWCFG3_I2C BIT(8) +#define GHWCFG3_OTG_FUNC BIT(7) #define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4) #define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT 4 #define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xf << 0) #define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT 0 #define GHWCFG4 HSOTG_REG(0x0050) -#define GHWCFG4_DESC_DMA_DYN (1 << 31) -#define GHWCFG4_DESC_DMA (1 << 30) +#define GHWCFG4_DESC_DMA_DYN BIT(31) +#define GHWCFG4_DESC_DMA BIT(30) #define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) #define GHWCFG4_NUM_IN_EPS_SHIFT 26 -#define GHWCFG4_DED_FIFO_EN (1 << 25) +#define GHWCFG4_DED_FIFO_EN BIT(25) #define GHWCFG4_DED_FIFO_SHIFT 25 -#define GHWCFG4_SESSION_END_FILT_EN (1 << 24) -#define GHWCFG4_B_VALID_FILT_EN (1 << 23) -#define GHWCFG4_A_VALID_FILT_EN (1 << 22) -#define GHWCFG4_VBUS_VALID_FILT_EN (1 << 21) -#define GHWCFG4_IDDIG_FILT_EN (1 << 20) +#define GHWCFG4_SESSION_END_FILT_EN BIT(24) +#define GHWCFG4_B_VALID_FILT_EN BIT(23) +#define GHWCFG4_A_VALID_FILT_EN BIT(22) +#define GHWCFG4_VBUS_VALID_FILT_EN BIT(21) +#define GHWCFG4_IDDIG_FILT_EN BIT(20) #define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xf << 16) #define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) @@ -309,64 +309,64 @@ #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 -#define GHWCFG4_XHIBER (1 << 7) -#define GHWCFG4_HIBER (1 << 6) -#define GHWCFG4_MIN_AHB_FREQ (1 << 5) -#define GHWCFG4_POWER_OPTIMIZ (1 << 4) +#define GHWCFG4_XHIBER BIT(7) +#define GHWCFG4_HIBER BIT(6) +#define GHWCFG4_MIN_AHB_FREQ BIT(5) +#define GHWCFG4_POWER_OPTIMIZ BIT(4) #define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xf << 0) #define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT 0 #define GLPMCFG HSOTG_REG(0x0054) -#define GLPMCFG_INV_SEL_HSIC (1 << 31) -#define GLPMCFG_HSIC_CONNECT (1 << 30) +#define GLPMCFG_INV_SEL_HSIC BIT(31) +#define GLPMCFG_HSIC_CONNECT BIT(30) #define GLPMCFG_RETRY_COUNT_STS_MASK (0x7 << 25) #define GLPMCFG_RETRY_COUNT_STS_SHIFT 25 -#define GLPMCFG_SEND_LPM (1 << 24) +#define GLPMCFG_SEND_LPM BIT(24) #define GLPMCFG_RETRY_COUNT_MASK (0x7 << 21) #define GLPMCFG_RETRY_COUNT_SHIFT 21 #define GLPMCFG_LPM_CHAN_INDEX_MASK (0xf << 17) #define GLPMCFG_LPM_CHAN_INDEX_SHIFT 17 -#define GLPMCFG_SLEEP_STATE_RESUMEOK (1 << 16) -#define GLPMCFG_PRT_SLEEP_STS (1 << 15) +#define GLPMCFG_SLEEP_STATE_RESUMEOK BIT(16) +#define GLPMCFG_PRT_SLEEP_STS BIT(15) #define GLPMCFG_LPM_RESP_MASK (0x3 << 13) #define GLPMCFG_LPM_RESP_SHIFT 13 #define GLPMCFG_HIRD_THRES_MASK (0x1f << 8) #define GLPMCFG_HIRD_THRES_SHIFT 8 #define GLPMCFG_HIRD_THRES_EN (0x10 << 8) -#define GLPMCFG_EN_UTMI_SLEEP (1 << 7) -#define GLPMCFG_REM_WKUP_EN (1 << 6) +#define GLPMCFG_EN_UTMI_SLEEP BIT(7) +#define GLPMCFG_REM_WKUP_EN BIT(6) #define GLPMCFG_HIRD_MASK (0xf << 2) #define GLPMCFG_HIRD_SHIFT 2 -#define GLPMCFG_APPL_RESP (1 << 1) -#define GLPMCFG_LPM_CAP_EN (1 << 0) +#define GLPMCFG_APPL_RESP BIT(1) +#define GLPMCFG_LPM_CAP_EN BIT(0) #define GPWRDN HSOTG_REG(0x0058) #define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24) #define GPWRDN_MULT_VAL_ID_BC_SHIFT 24 -#define GPWRDN_ADP_INT (1 << 23) -#define GPWRDN_BSESSVLD (1 << 22) -#define GPWRDN_IDSTS (1 << 21) +#define GPWRDN_ADP_INT BIT(23) +#define GPWRDN_BSESSVLD BIT(22) +#define GPWRDN_IDSTS BIT(21) #define GPWRDN_LINESTATE_MASK (0x3 << 19) #define GPWRDN_LINESTATE_SHIFT 19 -#define GPWRDN_STS_CHGINT_MSK (1 << 18) -#define GPWRDN_STS_CHGINT (1 << 17) -#define GPWRDN_SRP_DET_MSK (1 << 16) -#define GPWRDN_SRP_DET (1 << 15) -#define GPWRDN_CONNECT_DET_MSK (1 << 14) -#define GPWRDN_CONNECT_DET (1 << 13) -#define GPWRDN_DISCONN_DET_MSK (1 << 12) -#define GPWRDN_DISCONN_DET (1 << 11) -#define GPWRDN_RST_DET_MSK (1 << 10) -#define GPWRDN_RST_DET (1 << 9) -#define GPWRDN_LNSTSCHG_MSK (1 << 8) -#define GPWRDN_LNSTSCHG (1 << 7) -#define GPWRDN_DIS_VBUS (1 << 6) -#define GPWRDN_PWRDNSWTCH (1 << 5) -#define GPWRDN_PWRDNRSTN (1 << 4) -#define GPWRDN_PWRDNCLMP (1 << 3) -#define GPWRDN_RESTORE (1 << 2) -#define GPWRDN_PMUACTV (1 << 1) -#define GPWRDN_PMUINTSEL (1 << 0) +#define GPWRDN_STS_CHGINT_MSK BIT(18) +#define GPWRDN_STS_CHGINT BIT(17) +#define GPWRDN_SRP_DET_MSK BIT(16) +#define GPWRDN_SRP_DET BIT(15) +#define GPWRDN_CONNECT_DET_MSK BIT(14) +#define GPWRDN_CONNECT_DET BIT(13) +#define GPWRDN_DISCONN_DET_MSK BIT(12) +#define GPWRDN_DISCONN_DET BIT(11) +#define GPWRDN_RST_DET_MSK BIT(10) +#define GPWRDN_RST_DET BIT(9) +#define GPWRDN_LNSTSCHG_MSK BIT(8) +#define GPWRDN_LNSTSCHG BIT(7) +#define GPWRDN_DIS_VBUS BIT(6) +#define GPWRDN_PWRDNSWTCH BIT(5) +#define GPWRDN_PWRDNRSTN BIT(4) +#define GPWRDN_PWRDNCLMP BIT(3) +#define GPWRDN_RESTORE BIT(2) +#define GPWRDN_PMUACTV BIT(1) +#define GPWRDN_PMUINTSEL BIT(0) #define GDFIFOCFG HSOTG_REG(0x005c) #define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16) @@ -377,16 +377,16 @@ #define ADPCTL HSOTG_REG(0x0060) #define ADPCTL_AR_MASK (0x3 << 27) #define ADPCTL_AR_SHIFT 27 -#define ADPCTL_ADP_TMOUT_INT_MSK (1 << 26) -#define ADPCTL_ADP_SNS_INT_MSK (1 << 25) -#define ADPCTL_ADP_PRB_INT_MSK (1 << 24) -#define ADPCTL_ADP_TMOUT_INT (1 << 23) -#define ADPCTL_ADP_SNS_INT (1 << 22) -#define ADPCTL_ADP_PRB_INT (1 << 21) -#define ADPCTL_ADPENA (1 << 20) -#define ADPCTL_ADPRES (1 << 19) -#define ADPCTL_ENASNS (1 << 18) -#define ADPCTL_ENAPRB (1 << 17) +#define ADPCTL_ADP_TMOUT_INT_MSK BIT(26) +#define ADPCTL_ADP_SNS_INT_MSK BIT(25) +#define ADPCTL_ADP_PRB_INT_MSK BIT(24) +#define ADPCTL_ADP_TMOUT_INT BIT(23) +#define ADPCTL_ADP_SNS_INT BIT(22) +#define ADPCTL_ADP_PRB_INT BIT(21) +#define ADPCTL_ADPENA BIT(20) +#define ADPCTL_ADPRES BIT(19) +#define ADPCTL_ENASNS BIT(18) +#define ADPCTL_ENAPRB BIT(17) #define ADPCTL_RTIM_MASK (0x7ff << 6) #define ADPCTL_RTIM_SHIFT 6 #define ADPCTL_PRB_PER_MASK (0x3 << 4) @@ -412,7 +412,7 @@ /* Device mode registers */ #define DCFG HSOTG_REG(0x800) -#define DCFG_DESCDMA_EN (1 << 23) +#define DCFG_DESCDMA_EN BIT(23) #define DCFG_EPMISCNT_MASK (0x1f << 18) #define DCFG_EPMISCNT_SHIFT 18 #define DCFG_EPMISCNT_LIMIT 0x1f @@ -425,7 +425,7 @@ #define DCFG_DEVADDR_SHIFT 4 #define DCFG_DEVADDR_LIMIT 0x7f #define DCFG_DEVADDR(_x) ((_x) << 4) -#define DCFG_NZ_STS_OUT_HSHK (1 << 2) +#define DCFG_NZ_STS_OUT_HSHK BIT(2) #define DCFG_DEVSPD_MASK (0x3 << 0) #define DCFG_DEVSPD_SHIFT 0 #define DCFG_DEVSPD_HS 0 @@ -434,54 +434,54 @@ #define DCFG_DEVSPD_FS48 3 #define DCTL HSOTG_REG(0x804) -#define DCTL_PWRONPRGDONE (1 << 11) -#define DCTL_CGOUTNAK (1 << 10) -#define DCTL_SGOUTNAK (1 << 9) -#define DCTL_CGNPINNAK (1 << 8) -#define DCTL_SGNPINNAK (1 << 7) +#define DCTL_PWRONPRGDONE BIT(11) +#define DCTL_CGOUTNAK BIT(10) +#define DCTL_SGOUTNAK BIT(9) +#define DCTL_CGNPINNAK BIT(8) +#define DCTL_SGNPINNAK BIT(7) #define DCTL_TSTCTL_MASK (0x7 << 4) #define DCTL_TSTCTL_SHIFT 4 -#define DCTL_GOUTNAKSTS (1 << 3) -#define DCTL_GNPINNAKSTS (1 << 2) -#define DCTL_SFTDISCON (1 << 1) -#define DCTL_RMTWKUPSIG (1 << 0) +#define DCTL_GOUTNAKSTS BIT(3) +#define DCTL_GNPINNAKSTS BIT(2) +#define DCTL_SFTDISCON BIT(1) +#define DCTL_RMTWKUPSIG BIT(0) #define DSTS HSOTG_REG(0x808) #define DSTS_SOFFN_MASK (0x3fff << 8) #define DSTS_SOFFN_SHIFT 8 #define DSTS_SOFFN_LIMIT 0x3fff #define DSTS_SOFFN(_x) ((_x) << 8) -#define DSTS_ERRATICERR (1 << 3) +#define DSTS_ERRATICERR BIT(3) #define DSTS_ENUMSPD_MASK (0x3 << 1) #define DSTS_ENUMSPD_SHIFT 1 #define DSTS_ENUMSPD_HS 0 #define DSTS_ENUMSPD_FS 1 #define DSTS_ENUMSPD_LS 2 #define DSTS_ENUMSPD_FS48 3 -#define DSTS_SUSPSTS (1 << 0) +#define DSTS_SUSPSTS BIT(0) #define DIEPMSK HSOTG_REG(0x810) -#define DIEPMSK_NAKMSK (1 << 13) -#define DIEPMSK_BNAININTRMSK (1 << 9) -#define DIEPMSK_TXFIFOUNDRNMSK (1 << 8) -#define DIEPMSK_TXFIFOEMPTY (1 << 7) -#define DIEPMSK_INEPNAKEFFMSK (1 << 6) -#define DIEPMSK_INTKNEPMISMSK (1 << 5) -#define DIEPMSK_INTKNTXFEMPMSK (1 << 4) -#define DIEPMSK_TIMEOUTMSK (1 << 3) -#define DIEPMSK_AHBERRMSK (1 << 2) -#define DIEPMSK_EPDISBLDMSK (1 << 1) -#define DIEPMSK_XFERCOMPLMSK (1 << 0) +#define DIEPMSK_NAKMSK BIT(13) +#define DIEPMSK_BNAININTRMSK BIT(9) +#define DIEPMSK_TXFIFOUNDRNMSK BIT(8) +#define DIEPMSK_TXFIFOEMPTY BIT(7) +#define DIEPMSK_INEPNAKEFFMSK BIT(6) +#define DIEPMSK_INTKNEPMISMSK BIT(5) +#define DIEPMSK_INTKNTXFEMPMSK BIT(4) +#define DIEPMSK_TIMEOUTMSK BIT(3) +#define DIEPMSK_AHBERRMSK BIT(2) +#define DIEPMSK_EPDISBLDMSK BIT(1) +#define DIEPMSK_XFERCOMPLMSK BIT(0) #define DOEPMSK HSOTG_REG(0x814) -#define DOEPMSK_BNAMSK (1 << 9) -#define DOEPMSK_BACK2BACKSETUP (1 << 6) -#define DOEPMSK_STSPHSERCVDMSK (1 << 5) -#define DOEPMSK_OUTTKNEPDISMSK (1 << 4) -#define DOEPMSK_SETUPMSK (1 << 3) -#define DOEPMSK_AHBERRMSK (1 << 2) -#define DOEPMSK_EPDISBLDMSK (1 << 1) -#define DOEPMSK_XFERCOMPLMSK (1 << 0) +#define DOEPMSK_BNAMSK BIT(9) +#define DOEPMSK_BACK2BACKSETUP BIT(6) +#define DOEPMSK_STSPHSERCVDMSK BIT(5) +#define DOEPMSK_OUTTKNEPDISMSK BIT(4) +#define DOEPMSK_SETUPMSK BIT(3) +#define DOEPMSK_AHBERRMSK BIT(2) +#define DOEPMSK_EPDISBLDMSK BIT(1) +#define DOEPMSK_XFERCOMPLMSK BIT(0) #define DAINT HSOTG_REG(0x818) #define DAINTMSK HSOTG_REG(0x81C) @@ -516,30 +516,30 @@ #define D0EPCTL_MPS_16 2 #define D0EPCTL_MPS_8 3 -#define DXEPCTL_EPENA (1 << 31) -#define DXEPCTL_EPDIS (1 << 30) -#define DXEPCTL_SETD1PID (1 << 29) -#define DXEPCTL_SETODDFR (1 << 29) -#define DXEPCTL_SETD0PID (1 << 28) -#define DXEPCTL_SETEVENFR (1 << 28) -#define DXEPCTL_SNAK (1 << 27) -#define DXEPCTL_CNAK (1 << 26) +#define DXEPCTL_EPENA BIT(31) +#define DXEPCTL_EPDIS BIT(30) +#define DXEPCTL_SETD1PID BIT(29) +#define DXEPCTL_SETODDFR BIT(29) +#define DXEPCTL_SETD0PID BIT(28) +#define DXEPCTL_SETEVENFR BIT(28) +#define DXEPCTL_SNAK BIT(27) +#define DXEPCTL_CNAK BIT(26) #define DXEPCTL_TXFNUM_MASK (0xf << 22) #define DXEPCTL_TXFNUM_SHIFT 22 #define DXEPCTL_TXFNUM_LIMIT 0xf #define DXEPCTL_TXFNUM(_x) ((_x) << 22) -#define DXEPCTL_STALL (1 << 21) -#define DXEPCTL_SNP (1 << 20) +#define DXEPCTL_STALL BIT(21) +#define DXEPCTL_SNP BIT(20) #define DXEPCTL_EPTYPE_MASK (0x3 << 18) #define DXEPCTL_EPTYPE_CONTROL (0x0 << 18) #define DXEPCTL_EPTYPE_ISO (0x1 << 18) #define DXEPCTL_EPTYPE_BULK (0x2 << 18) #define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18) -#define DXEPCTL_NAKSTS (1 << 17) -#define DXEPCTL_DPID (1 << 16) -#define DXEPCTL_EOFRNUM (1 << 16) -#define DXEPCTL_USBACTEP (1 << 15) +#define DXEPCTL_NAKSTS BIT(17) +#define DXEPCTL_DPID BIT(16) +#define DXEPCTL_EOFRNUM BIT(16) +#define DXEPCTL_USBACTEP BIT(15) #define DXEPCTL_NEXTEP_MASK (0xf << 11) #define DXEPCTL_NEXTEP_SHIFT 11 #define DXEPCTL_NEXTEP_LIMIT 0xf @@ -551,26 +551,26 @@ #define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) #define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) -#define DXEPINT_SETUP_RCVD (1 << 15) -#define DXEPINT_NYETINTRPT (1 << 14) -#define DXEPINT_NAKINTRPT (1 << 13) -#define DXEPINT_BBLEERRINTRPT (1 << 12) -#define DXEPINT_PKTDRPSTS (1 << 11) -#define DXEPINT_BNAINTR (1 << 9) -#define DXEPINT_TXFIFOUNDRN (1 << 8) -#define DXEPINT_OUTPKTERR (1 << 8) -#define DXEPINT_TXFEMP (1 << 7) -#define DXEPINT_INEPNAKEFF (1 << 6) -#define DXEPINT_BACK2BACKSETUP (1 << 6) -#define DXEPINT_INTKNEPMIS (1 << 5) -#define DXEPINT_STSPHSERCVD (1 << 5) -#define DXEPINT_INTKNTXFEMP (1 << 4) -#define DXEPINT_OUTTKNEPDIS (1 << 4) -#define DXEPINT_TIMEOUT (1 << 3) -#define DXEPINT_SETUP (1 << 3) -#define DXEPINT_AHBERR (1 << 2) -#define DXEPINT_EPDISBLD (1 << 1) -#define DXEPINT_XFERCOMPL (1 << 0) +#define DXEPINT_SETUP_RCVD BIT(15) +#define DXEPINT_NYETINTRPT BIT(14) +#define DXEPINT_NAKINTRPT BIT(13) +#define DXEPINT_BBLEERRINTRPT BIT(12) +#define DXEPINT_PKTDRPSTS BIT(11) +#define DXEPINT_BNAINTR BIT(9) +#define DXEPINT_TXFIFOUNDRN BIT(8) +#define DXEPINT_OUTPKTERR BIT(8) +#define DXEPINT_TXFEMP BIT(7) +#define DXEPINT_INEPNAKEFF BIT(6) +#define DXEPINT_BACK2BACKSETUP BIT(6) +#define DXEPINT_INTKNEPMIS BIT(5) +#define DXEPINT_STSPHSERCVD BIT(5) +#define DXEPINT_INTKNTXFEMP BIT(4) +#define DXEPINT_OUTTKNEPDIS BIT(4) +#define DXEPINT_TIMEOUT BIT(3) +#define DXEPINT_SETUP BIT(3) +#define DXEPINT_AHBERR BIT(2) +#define DXEPINT_EPDISBLD BIT(1) +#define DXEPINT_XFERCOMPL BIT(0) #define DIEPTSIZ0 HSOTG_REG(0x910) #define DIEPTSIZ0_PKTCNT_MASK (0x3 << 19) @@ -587,7 +587,7 @@ #define DOEPTSIZ0_SUPCNT_SHIFT 29 #define DOEPTSIZ0_SUPCNT_LIMIT 0x3 #define DOEPTSIZ0_SUPCNT(_x) ((_x) << 29) -#define DOEPTSIZ0_PKTCNT (1 << 19) +#define DOEPTSIZ0_PKTCNT BIT(19) #define DOEPTSIZ0_XFERSIZE_MASK (0x7f << 0) #define DOEPTSIZ0_XFERSIZE_SHIFT 0 @@ -614,55 +614,55 @@ #define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) #define PCGCTL HSOTG_REG(0x0e00) -#define PCGCTL_IF_DEV_MODE (1 << 31) +#define PCGCTL_IF_DEV_MODE BIT(31) #define PCGCTL_P2HD_PRT_SPD_MASK (0x3 << 29) #define PCGCTL_P2HD_PRT_SPD_SHIFT 29 #define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3 << 27) #define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27 #define PCGCTL_MAC_DEV_ADDR_MASK (0x7f << 20) #define PCGCTL_MAC_DEV_ADDR_SHIFT 20 -#define PCGCTL_MAX_TERMSEL (1 << 19) +#define PCGCTL_MAX_TERMSEL BIT(19) #define PCGCTL_MAX_XCVRSELECT_MASK (0x3 << 17) #define PCGCTL_MAX_XCVRSELECT_SHIFT 17 -#define PCGCTL_PORT_POWER (1 << 16) +#define PCGCTL_PORT_POWER BIT(16) #define PCGCTL_PRT_CLK_SEL_MASK (0x3 << 14) #define PCGCTL_PRT_CLK_SEL_SHIFT 14 -#define PCGCTL_ESS_REG_RESTORED (1 << 13) -#define PCGCTL_EXTND_HIBER_SWITCH (1 << 12) -#define PCGCTL_EXTND_HIBER_PWRCLMP (1 << 11) -#define PCGCTL_ENBL_EXTND_HIBER (1 << 10) -#define PCGCTL_RESTOREMODE (1 << 9) -#define PCGCTL_RESETAFTSUSP (1 << 8) -#define PCGCTL_DEEP_SLEEP (1 << 7) -#define PCGCTL_PHY_IN_SLEEP (1 << 6) -#define PCGCTL_ENBL_SLEEP_GATING (1 << 5) -#define PCGCTL_RSTPDWNMODULE (1 << 3) -#define PCGCTL_PWRCLMP (1 << 2) -#define PCGCTL_GATEHCLK (1 << 1) -#define PCGCTL_STOPPCLK (1 << 0) +#define PCGCTL_ESS_REG_RESTORED BIT(13) +#define PCGCTL_EXTND_HIBER_SWITCH BIT(12) +#define PCGCTL_EXTND_HIBER_PWRCLMP BIT(11) +#define PCGCTL_ENBL_EXTND_HIBER BIT(10) +#define PCGCTL_RESTOREMODE BIT(9) +#define PCGCTL_RESETAFTSUSP BIT(8) +#define PCGCTL_DEEP_SLEEP BIT(7) +#define PCGCTL_PHY_IN_SLEEP BIT(6) +#define PCGCTL_ENBL_SLEEP_GATING BIT(5) +#define PCGCTL_RSTPDWNMODULE BIT(3) +#define PCGCTL_PWRCLMP BIT(2) +#define PCGCTL_GATEHCLK BIT(1) +#define PCGCTL_STOPPCLK BIT(0) #define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) /* Host Mode Registers */ #define HCFG HSOTG_REG(0x0400) -#define HCFG_MODECHTIMEN (1 << 31) -#define HCFG_PERSCHEDENA (1 << 26) +#define HCFG_MODECHTIMEN BIT(31) +#define HCFG_PERSCHEDENA BIT(26) #define HCFG_FRLISTEN_MASK (0x3 << 24) #define HCFG_FRLISTEN_SHIFT 24 #define HCFG_FRLISTEN_8 (0 << 24) #define FRLISTEN_8_SIZE 8 -#define HCFG_FRLISTEN_16 (1 << 24) +#define HCFG_FRLISTEN_16 BIT(24) #define FRLISTEN_16_SIZE 16 #define HCFG_FRLISTEN_32 (2 << 24) #define FRLISTEN_32_SIZE 32 #define HCFG_FRLISTEN_64 (3 << 24) #define FRLISTEN_64_SIZE 64 -#define HCFG_DESCDMA (1 << 23) +#define HCFG_DESCDMA BIT(23) #define HCFG_RESVALID_MASK (0xff << 8) #define HCFG_RESVALID_SHIFT 8 -#define HCFG_ENA32KHZ (1 << 7) -#define HCFG_FSLSSUPP (1 << 2) +#define HCFG_ENA32KHZ BIT(7) +#define HCFG_FSLSSUPP BIT(2) #define HCFG_FSLSPCLKSEL_MASK (0x3 << 0) #define HCFG_FSLSPCLKSEL_SHIFT 0 #define HCFG_FSLSPCLKSEL_30_60_MHZ 0 @@ -672,7 +672,7 @@ #define HFIR HSOTG_REG(0x0404) #define HFIR_FRINT_MASK (0xffff << 0) #define HFIR_FRINT_SHIFT 0 -#define HFIR_RLDCTRL (1 << 16) +#define HFIR_RLDCTRL BIT(16) #define HFNUM HSOTG_REG(0x0408) #define HFNUM_FRREM_MASK (0xffff << 16) @@ -682,12 +682,12 @@ #define HFNUM_MAX_FRNUM 0x3fff #define HPTXSTS HSOTG_REG(0x0410) -#define TXSTS_QTOP_ODD (1 << 31) +#define TXSTS_QTOP_ODD BIT(31) #define TXSTS_QTOP_CHNEP_MASK (0xf << 27) #define TXSTS_QTOP_CHNEP_SHIFT 27 #define TXSTS_QTOP_TOKEN_MASK (0x3 << 25) #define TXSTS_QTOP_TOKEN_SHIFT 25 -#define TXSTS_QTOP_TERMINATE (1 << 24) +#define TXSTS_QTOP_TERMINATE BIT(24) #define TXSTS_QSPCAVAIL_MASK (0xff << 16) #define TXSTS_QSPCAVAIL_SHIFT 16 #define TXSTS_FSPCAVAIL_MASK (0xffff << 0) @@ -705,39 +705,39 @@ #define HPRT0_SPD_LOW_SPEED 2 #define HPRT0_TSTCTL_MASK (0xf << 13) #define HPRT0_TSTCTL_SHIFT 13 -#define HPRT0_PWR (1 << 12) +#define HPRT0_PWR BIT(12) #define HPRT0_LNSTS_MASK (0x3 << 10) #define HPRT0_LNSTS_SHIFT 10 -#define HPRT0_RST (1 << 8) -#define HPRT0_SUSP (1 << 7) -#define HPRT0_RES (1 << 6) -#define HPRT0_OVRCURRCHG (1 << 5) -#define HPRT0_OVRCURRACT (1 << 4) -#define HPRT0_ENACHG (1 << 3) -#define HPRT0_ENA (1 << 2) -#define HPRT0_CONNDET (1 << 1) -#define HPRT0_CONNSTS (1 << 0) +#define HPRT0_RST BIT(8) +#define HPRT0_SUSP BIT(7) +#define HPRT0_RES BIT(6) +#define HPRT0_OVRCURRCHG BIT(5) +#define HPRT0_OVRCURRACT BIT(4) +#define HPRT0_ENACHG BIT(3) +#define HPRT0_ENA BIT(2) +#define HPRT0_CONNDET BIT(1) +#define HPRT0_CONNSTS BIT(0) #define HCCHAR(_ch) HSOTG_REG(0x0500 + 0x20 * (_ch)) -#define HCCHAR_CHENA (1 << 31) -#define HCCHAR_CHDIS (1 << 30) -#define HCCHAR_ODDFRM (1 << 29) +#define HCCHAR_CHENA BIT(31) +#define HCCHAR_CHDIS BIT(30) +#define HCCHAR_ODDFRM BIT(29) #define HCCHAR_DEVADDR_MASK (0x7f << 22) #define HCCHAR_DEVADDR_SHIFT 22 #define HCCHAR_MULTICNT_MASK (0x3 << 20) #define HCCHAR_MULTICNT_SHIFT 20 #define HCCHAR_EPTYPE_MASK (0x3 << 18) #define HCCHAR_EPTYPE_SHIFT 18 -#define HCCHAR_LSPDDEV (1 << 17) -#define HCCHAR_EPDIR (1 << 15) +#define HCCHAR_LSPDDEV BIT(17) +#define HCCHAR_EPDIR BIT(15) #define HCCHAR_EPNUM_MASK (0xf << 11) #define HCCHAR_EPNUM_SHIFT 11 #define HCCHAR_MPS_MASK (0x7ff << 0) #define HCCHAR_MPS_SHIFT 0 #define HCSPLT(_ch) HSOTG_REG(0x0504 + 0x20 * (_ch)) -#define HCSPLT_SPLTENA (1 << 31) -#define HCSPLT_COMPSPLT (1 << 16) +#define HCSPLT_SPLTENA BIT(31) +#define HCSPLT_COMPSPLT BIT(16) #define HCSPLT_XACTPOS_MASK (0x3 << 14) #define HCSPLT_XACTPOS_SHIFT 14 #define HCSPLT_XACTPOS_MID 0 @@ -752,23 +752,23 @@ #define HCINT(_ch) HSOTG_REG(0x0508 + 0x20 * (_ch)) #define HCINTMSK(_ch) HSOTG_REG(0x050c + 0x20 * (_ch)) #define HCINTMSK_RESERVED14_31 (0x3ffff << 14) -#define HCINTMSK_FRM_LIST_ROLL (1 << 13) -#define HCINTMSK_XCS_XACT (1 << 12) -#define HCINTMSK_BNA (1 << 11) -#define HCINTMSK_DATATGLERR (1 << 10) -#define HCINTMSK_FRMOVRUN (1 << 9) -#define HCINTMSK_BBLERR (1 << 8) -#define HCINTMSK_XACTERR (1 << 7) -#define HCINTMSK_NYET (1 << 6) -#define HCINTMSK_ACK (1 << 5) -#define HCINTMSK_NAK (1 << 4) -#define HCINTMSK_STALL (1 << 3) -#define HCINTMSK_AHBERR (1 << 2) -#define HCINTMSK_CHHLTD (1 << 1) -#define HCINTMSK_XFERCOMPL (1 << 0) +#define HCINTMSK_FRM_LIST_ROLL BIT(13) +#define HCINTMSK_XCS_XACT BIT(12) +#define HCINTMSK_BNA BIT(11) +#define HCINTMSK_DATATGLERR BIT(10) +#define HCINTMSK_FRMOVRUN BIT(9) +#define HCINTMSK_BBLERR BIT(8) +#define HCINTMSK_XACTERR BIT(7) +#define HCINTMSK_NYET BIT(6) +#define HCINTMSK_ACK BIT(5) +#define HCINTMSK_NAK BIT(4) +#define HCINTMSK_STALL BIT(3) +#define HCINTMSK_AHBERR BIT(2) +#define HCINTMSK_CHHLTD BIT(1) +#define HCINTMSK_XFERCOMPL BIT(0) #define HCTSIZ(_ch) HSOTG_REG(0x0510 + 0x20 * (_ch)) -#define TSIZ_DOPNG (1 << 31) +#define TSIZ_DOPNG BIT(31) #define TSIZ_SC_MC_PID_MASK (0x3 << 29) #define TSIZ_SC_MC_PID_SHIFT 29 #define TSIZ_SC_MC_PID_DATA0 0 @@ -808,14 +808,14 @@ struct dwc2_dma_desc { /* Host Mode DMA descriptor status quadlet */ -#define HOST_DMA_A (1 << 31) +#define HOST_DMA_A BIT(31) #define HOST_DMA_STS_MASK (0x3 << 28) #define HOST_DMA_STS_SHIFT 28 -#define HOST_DMA_STS_PKTERR (1 << 28) -#define HOST_DMA_EOL (1 << 26) -#define HOST_DMA_IOC (1 << 25) -#define HOST_DMA_SUP (1 << 24) -#define HOST_DMA_ALT_QTD (1 << 23) +#define HOST_DMA_STS_PKTERR BIT(28) +#define HOST_DMA_EOL BIT(26) +#define HOST_DMA_IOC BIT(25) +#define HOST_DMA_SUP BIT(24) +#define HOST_DMA_ALT_QTD BIT(23) #define HOST_DMA_QTD_OFFSET_MASK (0x3f << 17) #define HOST_DMA_QTD_OFFSET_SHIFT 17 #define HOST_DMA_ISOC_NBYTES_MASK (0xfff << 0) @@ -837,11 +837,11 @@ struct dwc2_dma_desc { #define DEV_DMA_STS_SUCC 0 #define DEV_DMA_STS_BUFF_FLUSH 1 #define DEV_DMA_STS_BUFF_ERR 3 -#define DEV_DMA_L (1 << 27) -#define DEV_DMA_SHORT (1 << 26) -#define DEV_DMA_IOC (1 << 25) -#define DEV_DMA_SR (1 << 24) -#define DEV_DMA_MTRF (1 << 23) +#define DEV_DMA_L BIT(27) +#define DEV_DMA_SHORT BIT(26) +#define DEV_DMA_IOC BIT(25) +#define DEV_DMA_SR BIT(24) +#define DEV_DMA_MTRF BIT(23) #define DEV_DMA_ISOC_PID_MASK (0x3 << 23) #define DEV_DMA_ISOC_PID_SHIFT 23 #define DEV_DMA_ISOC_PID_DATA0 0 diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index bcd1e19b4076..2990c347289f 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -38,1157 +38,499 @@ #include "core.h" -static const struct dwc2_core_params params_hi6220 = { - .otg_cap = 2, /* No HNP/SRP capable */ - .otg_ver = 0, /* 1.3 */ - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - .speed = 0, /* High Speed */ - .enable_dynamic_fifo = 1, - .en_multiple_tx_fifo = 1, - .host_rx_fifo_size = 512, - .host_nperio_tx_fifo_size = 512, - .host_perio_tx_fifo_size = 512, - .max_transfer_size = 65535, - .max_packet_count = 511, - .host_channels = 16, - .phy_type = 1, /* UTMI */ - .phy_utmi_width = 8, - .phy_ulpi_ddr = 0, /* Single */ - .phy_ulpi_ext_vbus = 0, - .i2c_enable = 0, - .ulpi_fs_ls = 0, - .host_support_fs_ls_low_power = 0, - .host_ls_low_power_phy_clk = 0, /* 48 MHz */ - .ts_dline = 0, - .reload_ctl = 0, - .ahbcfg = GAHBCFG_HBSTLEN_INCR16 << - GAHBCFG_HBSTLEN_SHIFT, - .uframe_sched = 0, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_bcm2835 = { - .otg_cap = 0, /* HNP/SRP capable */ - .otg_ver = 0, /* 1.3 */ - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - .speed = 0, /* High Speed */ - .enable_dynamic_fifo = 1, - .en_multiple_tx_fifo = 1, - .host_rx_fifo_size = 774, /* 774 DWORDs */ - .host_nperio_tx_fifo_size = 256, /* 256 DWORDs */ - .host_perio_tx_fifo_size = 512, /* 512 DWORDs */ - .max_transfer_size = 65535, - .max_packet_count = 511, - .host_channels = 8, - .phy_type = 1, /* UTMI */ - .phy_utmi_width = 8, /* 8 bits */ - .phy_ulpi_ddr = 0, /* Single */ - .phy_ulpi_ext_vbus = 0, - .i2c_enable = 0, - .ulpi_fs_ls = 0, - .host_support_fs_ls_low_power = 0, - .host_ls_low_power_phy_clk = 0, /* 48 MHz */ - .ts_dline = 0, - .reload_ctl = 0, - .ahbcfg = 0x10, - .uframe_sched = 0, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_rk3066 = { - .otg_cap = 2, /* non-HNP/non-SRP */ - .otg_ver = -1, - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - .speed = -1, - .enable_dynamic_fifo = 1, - .en_multiple_tx_fifo = -1, - .host_rx_fifo_size = 525, /* 525 DWORDs */ - .host_nperio_tx_fifo_size = 128, /* 128 DWORDs */ - .host_perio_tx_fifo_size = 256, /* 256 DWORDs */ - .max_transfer_size = -1, - .max_packet_count = -1, - .host_channels = -1, - .phy_type = -1, - .phy_utmi_width = -1, - .phy_ulpi_ddr = -1, - .phy_ulpi_ext_vbus = -1, - .i2c_enable = -1, - .ulpi_fs_ls = -1, - .host_support_fs_ls_low_power = -1, - .host_ls_low_power_phy_clk = -1, - .ts_dline = -1, - .reload_ctl = -1, - .ahbcfg = GAHBCFG_HBSTLEN_INCR16 << - GAHBCFG_HBSTLEN_SHIFT, - .uframe_sched = -1, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_ltq = { - .otg_cap = 2, /* non-HNP/non-SRP */ - .otg_ver = -1, - .dma_desc_enable = -1, - .dma_desc_fs_enable = -1, - .speed = -1, - .enable_dynamic_fifo = -1, - .en_multiple_tx_fifo = -1, - .host_rx_fifo_size = 288, /* 288 DWORDs */ - .host_nperio_tx_fifo_size = 128, /* 128 DWORDs */ - .host_perio_tx_fifo_size = 96, /* 96 DWORDs */ - .max_transfer_size = 65535, - .max_packet_count = 511, - .host_channels = -1, - .phy_type = -1, - .phy_utmi_width = -1, - .phy_ulpi_ddr = -1, - .phy_ulpi_ext_vbus = -1, - .i2c_enable = -1, - .ulpi_fs_ls = -1, - .host_support_fs_ls_low_power = -1, - .host_ls_low_power_phy_clk = -1, - .ts_dline = -1, - .reload_ctl = -1, - .ahbcfg = GAHBCFG_HBSTLEN_INCR16 << - GAHBCFG_HBSTLEN_SHIFT, - .uframe_sched = -1, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_amlogic = { - .otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE, - .otg_ver = -1, - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - .speed = DWC2_SPEED_PARAM_HIGH, - .enable_dynamic_fifo = 1, - .en_multiple_tx_fifo = -1, - .host_rx_fifo_size = 512, - .host_nperio_tx_fifo_size = 500, - .host_perio_tx_fifo_size = 500, - .max_transfer_size = -1, - .max_packet_count = -1, - .host_channels = 16, - .phy_type = DWC2_PHY_TYPE_PARAM_UTMI, - .phy_utmi_width = -1, - .phy_ulpi_ddr = -1, - .phy_ulpi_ext_vbus = -1, - .i2c_enable = -1, - .ulpi_fs_ls = -1, - .host_support_fs_ls_low_power = -1, - .host_ls_low_power_phy_clk = -1, - .ts_dline = -1, - .reload_ctl = 1, - .ahbcfg = GAHBCFG_HBSTLEN_INCR8 << - GAHBCFG_HBSTLEN_SHIFT, - .uframe_sched = 0, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_default = { - .otg_cap = -1, - .otg_ver = -1, - - /* - * Disable descriptor dma mode by default as the HW can support - * it, but does not support it for SPLIT transactions. - * Disable it for FS devices as well. - */ - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - - .speed = -1, - .enable_dynamic_fifo = -1, - .en_multiple_tx_fifo = -1, - .host_rx_fifo_size = -1, - .host_nperio_tx_fifo_size = -1, - .host_perio_tx_fifo_size = -1, - .max_transfer_size = -1, - .max_packet_count = -1, - .host_channels = -1, - .phy_type = -1, - .phy_utmi_width = -1, - .phy_ulpi_ddr = -1, - .phy_ulpi_ext_vbus = -1, - .i2c_enable = -1, - .ulpi_fs_ls = -1, - .host_support_fs_ls_low_power = -1, - .host_ls_low_power_phy_clk = -1, - .ts_dline = -1, - .reload_ctl = -1, - .ahbcfg = -1, - .uframe_sched = -1, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -const struct of_device_id dwc2_of_match_table[] = { - { .compatible = "brcm,bcm2835-usb", .data = ¶ms_bcm2835 }, - { .compatible = "hisilicon,hi6220-usb", .data = ¶ms_hi6220 }, - { .compatible = "rockchip,rk3066-usb", .data = ¶ms_rk3066 }, - { .compatible = "lantiq,arx100-usb", .data = ¶ms_ltq }, - { .compatible = "lantiq,xrx200-usb", .data = ¶ms_ltq }, - { .compatible = "snps,dwc2", .data = NULL }, - { .compatible = "samsung,s3c6400-hsotg", .data = NULL}, - { .compatible = "amlogic,meson8b-usb", .data = ¶ms_amlogic }, - { .compatible = "amlogic,meson-gxbb-usb", .data = ¶ms_amlogic }, - { .compatible = "amcc,dwc-otg", .data = NULL }, - {}, -}; -MODULE_DEVICE_TABLE(of, dwc2_of_match_table); - -static void dwc2_get_device_property(struct dwc2_hsotg *hsotg, - char *property, u8 size, u64 *value) +static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg) { - u32 val32; - - switch (size) { - case 0: - *value = device_property_read_bool(hsotg->dev, property); - break; - case 1: - case 2: - case 4: - if (device_property_read_u32(hsotg->dev, property, &val32)) - return; - - *value = val32; - break; - case 8: - if (device_property_read_u64(hsotg->dev, property, value)) - return; + struct dwc2_core_params *p = &hsotg->params; - break; - default: - /* - * The size is checked by the only function that calls - * this so this should never happen. - */ - WARN_ON(1); - return; - } + p->host_rx_fifo_size = 774; + p->max_transfer_size = 65535; + p->max_packet_count = 511; + p->ahbcfg = 0x10; + p->uframe_sched = false; } -static void dwc2_set_core_param(void *param, u8 size, u64 value) +static void dwc2_set_his_params(struct dwc2_hsotg *hsotg) { - switch (size) { - case 0: - *((bool *)param) = !!value; - break; - case 1: - *((u8 *)param) = (u8)value; - break; - case 2: - *((u16 *)param) = (u16)value; - break; - case 4: - *((u32 *)param) = (u32)value; - break; - case 8: - *((u64 *)param) = (u64)value; - break; - default: - /* - * The size is checked by the only function that calls - * this so this should never happen. - */ - WARN_ON(1); - return; - } -} + struct dwc2_core_params *p = &hsotg->params; -/** - * dwc2_set_param() - Set a core parameter - * - * @hsotg: Programming view of the DWC_otg controller - * @param: Pointer to the parameter to set - * @lookup: True if the property should be looked up - * @property: The device property to read - * @legacy: The param value to set if @property is not available. This - * will typically be the legacy value set in the static - * params structure. - * @def: The default value - * @min: The minimum value - * @max: The maximum value - * @size: The size of the core parameter in bytes, or 0 for bool. - * - * This function looks up @property and sets the @param to that value. - * If the property doesn't exist it uses the passed-in @value. It will - * verify that the value falls between @min and @max. If it doesn't, - * it will output an error and set the parameter to either @def or, - * failing that, to @min. - * - * The @size is used to write to @param and to query the device - * properties so that this same function can be used with different - * types of parameters. - */ -static void dwc2_set_param(struct dwc2_hsotg *hsotg, void *param, - bool lookup, char *property, u64 legacy, - u64 def, u64 min, u64 max, u8 size) + p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; + p->speed = DWC2_SPEED_PARAM_HIGH; + p->host_rx_fifo_size = 512; + p->host_nperio_tx_fifo_size = 512; + p->host_perio_tx_fifo_size = 512; + p->max_transfer_size = 65535; + p->max_packet_count = 511; + p->host_channels = 16; + p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; + p->phy_utmi_width = 8; + p->i2c_enable = false; + p->reload_ctl = false; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << + GAHBCFG_HBSTLEN_SHIFT; + p->uframe_sched = false; + p->change_speed_quirk = true; +} + +static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) { - u64 sizemax; - u64 value; - - if (WARN_ON(!hsotg || !param || !property)) - return; - - if (WARN((size > 8) || ((size & (size - 1)) != 0), - "Invalid size %d for %s\n", size, property)) - return; - - dev_vdbg(hsotg->dev, "%s: Setting %s: legacy=%llu, def=%llu, min=%llu, max=%llu, size=%d\n", - __func__, property, legacy, def, min, max, size); - - sizemax = (1ULL << (size * 8)) - 1; - value = legacy; - - /* Override legacy settings. */ - if (lookup) - dwc2_get_device_property(hsotg, property, size, &value); - - /* - * While the value is not valid, try setting it to the default - * value, and failing that, set it to the minimum. - */ - while ((value < min) || (value > max)) { - /* Print an error unless the value is set to auto. */ - if (value != sizemax) - dev_err(hsotg->dev, "Invalid value %llu for param %s\n", - value, property); + struct dwc2_core_params *p = &hsotg->params; - /* - * If we are already the default, just set it to the - * minimum. - */ - if (value == def) { - dev_vdbg(hsotg->dev, "%s: setting value to min=%llu\n", - __func__, min); - value = min; - break; - } + p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; + p->host_rx_fifo_size = 525; + p->host_nperio_tx_fifo_size = 128; + p->host_perio_tx_fifo_size = 256; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << + GAHBCFG_HBSTLEN_SHIFT; +} - /* Try the default value */ - dev_vdbg(hsotg->dev, "%s: setting value to default=%llu\n", - __func__, def); - value = def; - } +static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) +{ + struct dwc2_core_params *p = &hsotg->params; - dev_dbg(hsotg->dev, "Setting %s to %llu\n", property, value); - dwc2_set_core_param(param, size, value); + p->otg_cap = 2; + p->host_rx_fifo_size = 288; + p->host_nperio_tx_fifo_size = 128; + p->host_perio_tx_fifo_size = 96; + p->max_transfer_size = 65535; + p->max_packet_count = 511; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << + GAHBCFG_HBSTLEN_SHIFT; } -/** - * dwc2_set_param_u32() - Set a u32 parameter - * - * See dwc2_set_param(). - */ -static void dwc2_set_param_u32(struct dwc2_hsotg *hsotg, u32 *param, - bool lookup, char *property, u16 legacy, - u16 def, u16 min, u16 max) +static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg) { - dwc2_set_param(hsotg, param, lookup, property, - legacy, def, min, max, 4); + struct dwc2_core_params *p = &hsotg->params; + + p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; + p->speed = DWC2_SPEED_PARAM_HIGH; + p->host_rx_fifo_size = 512; + p->host_nperio_tx_fifo_size = 500; + p->host_perio_tx_fifo_size = 500; + p->host_channels = 16; + p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 << + GAHBCFG_HBSTLEN_SHIFT; + p->uframe_sched = false; } -/** - * dwc2_set_param_bool() - Set a bool parameter - * - * See dwc2_set_param(). - * - * Note: there is no 'legacy' argument here because there is no legacy - * source of bool params. - */ -static void dwc2_set_param_bool(struct dwc2_hsotg *hsotg, bool *param, - bool lookup, char *property, - bool def, bool min, bool max) +static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) { - dwc2_set_param(hsotg, param, lookup, property, - def, def, min, max, 0); + struct dwc2_core_params *p = &hsotg->params; + + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; } -#define DWC2_OUT_OF_BOUNDS(a, b, c) ((a) < (b) || (a) > (c)) +const struct of_device_id dwc2_of_match_table[] = { + { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params }, + { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params }, + { .compatible = "rockchip,rk3066-usb", .data = dwc2_set_rk_params }, + { .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params }, + { .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params }, + { .compatible = "snps,dwc2" }, + { .compatible = "samsung,s3c6400-hsotg" }, + { .compatible = "amlogic,meson8b-usb", + .data = dwc2_set_amlogic_params }, + { .compatible = "amlogic,meson-gxbb-usb", + .data = dwc2_set_amlogic_params }, + { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params }, + {}, +}; +MODULE_DEVICE_TABLE(of, dwc2_of_match_table); -/* Parameter access functions */ -static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val) +static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg) { - int valid = 1; + u8 val; - switch (val) { - case DWC2_CAP_PARAM_HNP_SRP_CAPABLE: - if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) - valid = 0; + switch (hsotg->hw_params.op_mode) { + case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: + val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE; break; - case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE: - switch (hsotg->hw_params.op_mode) { - case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: - case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: - break; - default: - valid = 0; - break; - } - break; - case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE: - /* always valid */ + case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: + val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE; break; default: - valid = 0; + val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; break; } - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for otg_cap parameter. Check HW configuration.\n", - val); - switch (hsotg->hw_params.op_mode) { - case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: - val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE; - break; - case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: - val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE; - break; - default: - val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; - break; - } - dev_dbg(hsotg->dev, "Setting otg_cap to %d\n", val); - } - hsotg->params.otg_cap = val; } -static void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val) +static void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg) { - int valid = 1; + int val; + u32 hs_phy_type = hsotg->hw_params.hs_phy_type; - if (val > 0 && (hsotg->params.host_dma <= 0 || - !hsotg->hw_params.dma_desc_enable)) - valid = 0; - if (val < 0) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for dma_desc_enable parameter. Check HW configuration.\n", - val); - val = (hsotg->params.host_dma > 0 && - hsotg->hw_params.dma_desc_enable); - dev_dbg(hsotg->dev, "Setting dma_desc_enable to %d\n", val); + val = DWC2_PHY_TYPE_PARAM_FS; + if (hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED) { + if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI || + hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI) + val = DWC2_PHY_TYPE_PARAM_UTMI; + else + val = DWC2_PHY_TYPE_PARAM_ULPI; } - hsotg->params.dma_desc_enable = val; -} - -static void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg, int val) -{ - int valid = 1; - - if (val > 0 && (hsotg->params.host_dma <= 0 || - !hsotg->hw_params.dma_desc_enable)) - valid = 0; - if (val < 0) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for dma_desc_fs_enable parameter. Check HW configuration.\n", - val); - val = (hsotg->params.host_dma > 0 && - hsotg->hw_params.dma_desc_enable); - } + if (dwc2_is_fs_iot(hsotg)) + hsotg->params.phy_type = DWC2_PHY_TYPE_PARAM_FS; - hsotg->params.dma_desc_fs_enable = val; - dev_dbg(hsotg->dev, "Setting dma_desc_fs_enable to %d\n", val); + hsotg->params.phy_type = val; } -static void -dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg, - int val) +static void dwc2_set_param_speed(struct dwc2_hsotg *hsotg) { - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "Wrong value for host_support_fs_low_power\n"); - dev_err(hsotg->dev, - "host_support_fs_low_power must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, - "Setting host_support_fs_low_power to %d\n", val); - } + int val; - hsotg->params.host_support_fs_ls_low_power = val; -} - -static void dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg, - int val) -{ - int valid = 1; + val = hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS ? + DWC2_SPEED_PARAM_FULL : DWC2_SPEED_PARAM_HIGH; - if (val > 0 && !hsotg->hw_params.enable_dynamic_fifo) - valid = 0; - if (val < 0) - valid = 0; + if (dwc2_is_fs_iot(hsotg)) + val = DWC2_SPEED_PARAM_FULL; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for enable_dynamic_fifo parameter. Check HW configuration.\n", - val); - val = hsotg->hw_params.enable_dynamic_fifo; - dev_dbg(hsotg->dev, "Setting enable_dynamic_fifo to %d\n", val); - } + if (dwc2_is_hs_iot(hsotg)) + val = DWC2_SPEED_PARAM_HIGH; - hsotg->params.enable_dynamic_fifo = val; + hsotg->params.speed = val; } -static void dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val) +static void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg) { - int valid = 1; + int val; - if (val < 16 || val > hsotg->hw_params.rx_fifo_size) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_rx_fifo_size. Check HW configuration.\n", - val); - val = hsotg->hw_params.rx_fifo_size; - dev_dbg(hsotg->dev, "Setting host_rx_fifo_size to %d\n", val); - } + val = (hsotg->hw_params.utmi_phy_data_width == + GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16; - hsotg->params.host_rx_fifo_size = val; + hsotg->params.phy_utmi_width = val; } -static void dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg, - int val) +static void dwc2_set_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg) { - int valid = 1; - - if (val < 16 || val > hsotg->hw_params.host_nperio_tx_fifo_size) - valid = 0; + struct dwc2_core_params *p = &hsotg->params; + int depth_average; + int fifo_count; + int i; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n", - val); - val = hsotg->hw_params.host_nperio_tx_fifo_size; - dev_dbg(hsotg->dev, "Setting host_nperio_tx_fifo_size to %d\n", - val); - } + fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); - hsotg->params.host_nperio_tx_fifo_size = val; + memset(p->g_tx_fifo_size, 0, sizeof(p->g_tx_fifo_size)); + depth_average = dwc2_hsotg_tx_fifo_average_depth(hsotg); + for (i = 1; i <= fifo_count; i++) + p->g_tx_fifo_size[i] = depth_average; } -static void dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg, - int val) +/** + * dwc2_set_default_params() - Set all core parameters to their + * auto-detected default values. + */ +static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) { - int valid = 1; + struct dwc2_hw_params *hw = &hsotg->hw_params; + struct dwc2_core_params *p = &hsotg->params; + bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH); - if (val < 16 || val > hsotg->hw_params.host_perio_tx_fifo_size) - valid = 0; + dwc2_set_param_otg_cap(hsotg); + dwc2_set_param_phy_type(hsotg); + dwc2_set_param_speed(hsotg); + dwc2_set_param_phy_utmi_width(hsotg); + p->phy_ulpi_ddr = false; + p->phy_ulpi_ext_vbus = false; + + p->enable_dynamic_fifo = hw->enable_dynamic_fifo; + p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo; + p->i2c_enable = hw->i2c_enable; + p->ulpi_fs_ls = false; + p->ts_dline = false; + p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a); + p->uframe_sched = true; + p->external_id_pin_ctl = false; + p->hibernation = false; + p->max_packet_count = hw->max_packet_count; + p->max_transfer_size = hw->max_transfer_size; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n", - val); - val = hsotg->hw_params.host_perio_tx_fifo_size; - dev_dbg(hsotg->dev, "Setting host_perio_tx_fifo_size to %d\n", - val); + if ((hsotg->dr_mode == USB_DR_MODE_HOST) || + (hsotg->dr_mode == USB_DR_MODE_OTG)) { + p->host_dma = dma_capable; + p->dma_desc_enable = false; + p->dma_desc_fs_enable = false; + p->host_support_fs_ls_low_power = false; + p->host_ls_low_power_phy_clk = false; + p->host_channels = hw->host_channels; + p->host_rx_fifo_size = hw->rx_fifo_size; + p->host_nperio_tx_fifo_size = hw->host_nperio_tx_fifo_size; + p->host_perio_tx_fifo_size = hw->host_perio_tx_fifo_size; } - hsotg->params.host_perio_tx_fifo_size = val; -} - -static void dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val) -{ - int valid = 1; - - if (val < 2047 || val > hsotg->hw_params.max_transfer_size) - valid = 0; + if ((hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) || + (hsotg->dr_mode == USB_DR_MODE_OTG)) { + p->g_dma = dma_capable; + p->g_dma_desc = hw->dma_desc_enable; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for max_transfer_size. Check HW configuration.\n", - val); - val = hsotg->hw_params.max_transfer_size; - dev_dbg(hsotg->dev, "Setting max_transfer_size to %d\n", val); + /* + * The values for g_rx_fifo_size (2048) and + * g_np_tx_fifo_size (1024) come from the legacy s3c + * gadget driver. These defaults have been hard-coded + * for some time so many platforms depend on these + * values. Leave them as defaults for now and only + * auto-detect if the hardware does not support the + * default. + */ + p->g_rx_fifo_size = 2048; + p->g_np_tx_fifo_size = 1024; + dwc2_set_param_tx_fifo_sizes(hsotg); } - - hsotg->params.max_transfer_size = val; } -static void dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val) +/** + * dwc2_get_device_properties() - Read in device properties. + * + * Read in the device properties and adjust core parameters if needed. + */ +static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) { - int valid = 1; - - if (val < 15 || val > hsotg->hw_params.max_packet_count) - valid = 0; + struct dwc2_core_params *p = &hsotg->params; + int num; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for max_packet_count. Check HW configuration.\n", - val); - val = hsotg->hw_params.max_packet_count; - dev_dbg(hsotg->dev, "Setting max_packet_count to %d\n", val); + if ((hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) || + (hsotg->dr_mode == USB_DR_MODE_OTG)) { + device_property_read_u32(hsotg->dev, "g-rx-fifo-size", + &p->g_rx_fifo_size); + + device_property_read_u32(hsotg->dev, "g-np-tx-fifo-size", + &p->g_np_tx_fifo_size); + + num = device_property_read_u32_array(hsotg->dev, + "g-tx-fifo-size", + NULL, 0); + + if (num > 0) { + num = min(num, 15); + memset(p->g_tx_fifo_size, 0, + sizeof(p->g_tx_fifo_size)); + device_property_read_u32_array(hsotg->dev, + "g-tx-fifo-size", + &p->g_tx_fifo_size[1], + num); + } } - - hsotg->params.max_packet_count = val; } -static void dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val) +static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) { int valid = 1; - if (val < 1 || val > hsotg->hw_params.host_channels) + switch (hsotg->params.otg_cap) { + case DWC2_CAP_PARAM_HNP_SRP_CAPABLE: + if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) + valid = 0; + break; + case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE: + switch (hsotg->hw_params.op_mode) { + case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: + case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: + break; + default: + valid = 0; + break; + } + break; + case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE: + /* always valid */ + break; + default: valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_channels. Check HW configuration.\n", - val); - val = hsotg->hw_params.host_channels; - dev_dbg(hsotg->dev, "Setting host_channels to %d\n", val); + break; } - hsotg->params.host_channels = val; + if (!valid) + dwc2_set_param_otg_cap(hsotg); } -static void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val) +static void dwc2_check_param_phy_type(struct dwc2_hsotg *hsotg) { int valid = 0; - u32 hs_phy_type, fs_phy_type; - - if (DWC2_OUT_OF_BOUNDS(val, DWC2_PHY_TYPE_PARAM_FS, - DWC2_PHY_TYPE_PARAM_ULPI)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for phy_type\n"); - dev_err(hsotg->dev, "phy_type must be 0, 1 or 2\n"); - } - - valid = 0; - } + u32 hs_phy_type; + u32 fs_phy_type; hs_phy_type = hsotg->hw_params.hs_phy_type; fs_phy_type = hsotg->hw_params.fs_phy_type; - if (val == DWC2_PHY_TYPE_PARAM_UTMI && - (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI || - hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) - valid = 1; - else if (val == DWC2_PHY_TYPE_PARAM_ULPI && - (hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI || - hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) - valid = 1; - else if (val == DWC2_PHY_TYPE_PARAM_FS && - fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) - valid = 1; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for phy_type. Check HW configuration.\n", - val); - val = DWC2_PHY_TYPE_PARAM_FS; - if (hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED) { - if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI || - hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI) - val = DWC2_PHY_TYPE_PARAM_UTMI; - else - val = DWC2_PHY_TYPE_PARAM_ULPI; - } - dev_dbg(hsotg->dev, "Setting phy_type to %d\n", val); - } - - hsotg->params.phy_type = val; -} - -static int dwc2_get_param_phy_type(struct dwc2_hsotg *hsotg) -{ - return hsotg->params.phy_type; -} - -static void dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val) -{ - int valid = 1; - - if (DWC2_OUT_OF_BOUNDS(val, 0, 2)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for speed parameter\n"); - dev_err(hsotg->dev, "max_speed parameter must be 0, 1, or 2\n"); - } - valid = 0; - } - - if (dwc2_is_hs_iot(hsotg) && - val == DWC2_SPEED_PARAM_LOW) - valid = 0; - - if (val == DWC2_SPEED_PARAM_HIGH && - dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS) - valid = 0; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for speed parameter. Check HW configuration.\n", - val); - val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS ? - DWC2_SPEED_PARAM_FULL : DWC2_SPEED_PARAM_HIGH; - dev_dbg(hsotg->dev, "Setting speed to %d\n", val); + switch (hsotg->params.phy_type) { + case DWC2_PHY_TYPE_PARAM_FS: + if (fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) + valid = 1; + break; + case DWC2_PHY_TYPE_PARAM_UTMI: + if ((hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI) || + (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) + valid = 1; + break; + case DWC2_PHY_TYPE_PARAM_ULPI: + if ((hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI) || + (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) + valid = 1; + break; + default: + break; } - hsotg->params.speed = val; + if (!valid) + dwc2_set_param_phy_type(hsotg); } -static void dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg, - int val) +static void dwc2_check_param_speed(struct dwc2_hsotg *hsotg) { int valid = 1; + int phy_type = hsotg->params.phy_type; + int speed = hsotg->params.speed; - if (DWC2_OUT_OF_BOUNDS(val, DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ, - DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) { - if (val >= 0) { - dev_err(hsotg->dev, - "Wrong value for host_ls_low_power_phy_clk parameter\n"); - dev_err(hsotg->dev, - "host_ls_low_power_phy_clk must be 0 or 1\n"); - } - valid = 0; - } - - if (val == DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ && - dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS) + switch (speed) { + case DWC2_SPEED_PARAM_HIGH: + if ((hsotg->params.speed == DWC2_SPEED_PARAM_HIGH) && + (phy_type == DWC2_PHY_TYPE_PARAM_FS)) + valid = 0; + break; + case DWC2_SPEED_PARAM_FULL: + case DWC2_SPEED_PARAM_LOW: + break; + default: valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n", - val); - val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS - ? DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ - : DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ; - dev_dbg(hsotg->dev, "Setting host_ls_low_power_phy_clk to %d\n", - val); - } - - hsotg->params.host_ls_low_power_phy_clk = val; -} - -static void dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for phy_ulpi_ddr\n"); - dev_err(hsotg->dev, "phy_upli_ddr must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting phy_upli_ddr to %d\n", val); - } - - hsotg->params.phy_ulpi_ddr = val; -} - -static void dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "Wrong value for phy_ulpi_ext_vbus\n"); - dev_err(hsotg->dev, - "phy_ulpi_ext_vbus must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting phy_ulpi_ext_vbus to %d\n", val); + break; } - hsotg->params.phy_ulpi_ext_vbus = val; + if (!valid) + dwc2_set_param_speed(hsotg); } -static void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val) +static void dwc2_check_param_phy_utmi_width(struct dwc2_hsotg *hsotg) { int valid = 0; + int param = hsotg->params.phy_utmi_width; + int width = hsotg->hw_params.utmi_phy_data_width; - switch (hsotg->hw_params.utmi_phy_data_width) { + switch (width) { case GHWCFG4_UTMI_PHY_DATA_WIDTH_8: - valid = (val == 8); + valid = (param == 8); break; case GHWCFG4_UTMI_PHY_DATA_WIDTH_16: - valid = (val == 16); + valid = (param == 16); break; case GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16: - valid = (val == 8 || val == 16); + valid = (param == 8 || param == 16); break; } - if (!valid) { - if (val >= 0) { - dev_err(hsotg->dev, - "%d invalid for phy_utmi_width. Check HW configuration.\n", - val); - } - val = (hsotg->hw_params.utmi_phy_data_width == - GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16; - dev_dbg(hsotg->dev, "Setting phy_utmi_width to %d\n", val); - } - - hsotg->params.phy_utmi_width = val; -} - -static void dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for ulpi_fs_ls\n"); - dev_err(hsotg->dev, "ulpi_fs_ls must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting ulpi_fs_ls to %d\n", val); - } - - hsotg->params.ulpi_fs_ls = val; -} - -static void dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for ts_dline\n"); - dev_err(hsotg->dev, "ts_dline must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting ts_dline to %d\n", val); - } - - hsotg->params.ts_dline = val; -} - -static void dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val) -{ - int valid = 1; - - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for i2c_enable\n"); - dev_err(hsotg->dev, "i2c_enable must be 0 or 1\n"); - } - - valid = 0; - } - - if (val == 1 && !(hsotg->hw_params.i2c_enable)) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for i2c_enable. Check HW configuration.\n", - val); - val = hsotg->hw_params.i2c_enable; - dev_dbg(hsotg->dev, "Setting i2c_enable to %d\n", val); - } - - hsotg->params.i2c_enable = val; -} - -static void dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg, - int val) -{ - int valid = 1; - - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "Wrong value for en_multiple_tx_fifo,\n"); - dev_err(hsotg->dev, - "en_multiple_tx_fifo must be 0 or 1\n"); - } - valid = 0; - } - - if (val == 1 && !hsotg->hw_params.en_multiple_tx_fifo) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n", - val); - val = hsotg->hw_params.en_multiple_tx_fifo; - dev_dbg(hsotg->dev, "Setting en_multiple_tx_fifo to %d\n", val); - } - - hsotg->params.en_multiple_tx_fifo = val; + if (!valid) + dwc2_set_param_phy_utmi_width(hsotg); } -static void dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val) +static void dwc2_check_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg) { - int valid = 1; - - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter reload_ctl\n", val); - dev_err(hsotg->dev, "reload_ctl must be 0 or 1\n"); - } - valid = 0; - } - - if (val == 1 && hsotg->hw_params.snpsid < DWC2_CORE_REV_2_92a) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for parameter reload_ctl. Check HW configuration.\n", - val); - val = hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_92a; - dev_dbg(hsotg->dev, "Setting reload_ctl to %d\n", val); - } + int fifo_count; + int fifo; + int min; + u32 total = 0; + u32 dptxfszn; - hsotg->params.reload_ctl = val; -} + fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); + min = hsotg->hw_params.en_multiple_tx_fifo ? 16 : 4; -static void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val) -{ - if (val != -1) - hsotg->params.ahbcfg = val; - else - hsotg->params.ahbcfg = GAHBCFG_HBSTLEN_INCR4 << - GAHBCFG_HBSTLEN_SHIFT; -} + for (fifo = 1; fifo <= fifo_count; fifo++) + total += hsotg->params.g_tx_fifo_size[fifo]; -static void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter otg_ver\n", val); - dev_err(hsotg->dev, - "otg_ver must be 0 (for OTG 1.3 support) or 1 (for OTG 2.0 support)\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting otg_ver to %d\n", val); + if (total > dwc2_hsotg_tx_fifo_total_depth(hsotg) || !total) { + dev_warn(hsotg->dev, "%s: Invalid parameter g-tx-fifo-size, setting to default average\n", + __func__); + dwc2_set_param_tx_fifo_sizes(hsotg); } - hsotg->params.otg_ver = val; -} + for (fifo = 1; fifo <= fifo_count; fifo++) { + dptxfszn = (dwc2_readl(hsotg->regs + DPTXFSIZN(fifo)) & + FIFOSIZE_DEPTH_MASK) >> FIFOSIZE_DEPTH_SHIFT; -static void dwc2_set_param_uframe_sched(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter uframe_sched\n", - val); - dev_err(hsotg->dev, "uframe_sched must be 0 or 1\n"); + if (hsotg->params.g_tx_fifo_size[fifo] < min || + hsotg->params.g_tx_fifo_size[fifo] > dptxfszn) { + dev_warn(hsotg->dev, "%s: Invalid parameter g_tx_fifo_size[%d]=%d\n", + __func__, fifo, + hsotg->params.g_tx_fifo_size[fifo]); + hsotg->params.g_tx_fifo_size[fifo] = dptxfszn; } - val = 1; - dev_dbg(hsotg->dev, "Setting uframe_sched to %d\n", val); } - - hsotg->params.uframe_sched = val; } -static void dwc2_set_param_external_id_pin_ctl(struct dwc2_hsotg *hsotg, - int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter external_id_pin_ctl\n", - val); - dev_err(hsotg->dev, "external_id_pin_ctl must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting external_id_pin_ctl to %d\n", val); - } +#define CHECK_RANGE(_param, _min, _max, _def) do { \ + if ((hsotg->params._param) < (_min) || \ + (hsotg->params._param) > (_max)) { \ + dev_warn(hsotg->dev, "%s: Invalid parameter %s=%d\n", \ + __func__, #_param, hsotg->params._param); \ + hsotg->params._param = (_def); \ + } \ + } while (0) - hsotg->params.external_id_pin_ctl = val; -} +#define CHECK_BOOL(_param, _check) do { \ + if (hsotg->params._param && !(_check)) { \ + dev_warn(hsotg->dev, "%s: Invalid parameter %s=%d\n", \ + __func__, #_param, hsotg->params._param); \ + hsotg->params._param = false; \ + } \ + } while (0) -static void dwc2_set_param_hibernation(struct dwc2_hsotg *hsotg, - int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter hibernation\n", - val); - dev_err(hsotg->dev, "hibernation must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting hibernation to %d\n", val); - } - - hsotg->params.hibernation = val; -} - -static void dwc2_set_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg) -{ - int i; - int num; - char *property = "g-tx-fifo-size"; - struct dwc2_core_params *p = &hsotg->params; - - memset(p->g_tx_fifo_size, 0, sizeof(p->g_tx_fifo_size)); - - /* Read tx fifo sizes */ - num = device_property_read_u32_array(hsotg->dev, property, NULL, 0); - - if (num > 0) { - device_property_read_u32_array(hsotg->dev, property, - &p->g_tx_fifo_size[1], - num); - } else { - u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE; - - memcpy(&p->g_tx_fifo_size[1], - p_tx_fifo, - sizeof(p_tx_fifo)); - - num = ARRAY_SIZE(p_tx_fifo); - } - - for (i = 0; i < num; i++) { - if ((i + 1) >= ARRAY_SIZE(p->g_tx_fifo_size)) - break; - - dev_dbg(hsotg->dev, "Setting %s[%d] to %d\n", - property, i + 1, p->g_tx_fifo_size[i + 1]); - } -} - -static void dwc2_set_gadget_dma(struct dwc2_hsotg *hsotg) +static void dwc2_check_params(struct dwc2_hsotg *hsotg) { struct dwc2_hw_params *hw = &hsotg->hw_params; struct dwc2_core_params *p = &hsotg->params; bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH); - /* Buffer DMA */ - dwc2_set_param_bool(hsotg, &p->g_dma, - false, "gadget-dma", - dma_capable, false, - dma_capable); - - /* DMA Descriptor */ - dwc2_set_param_bool(hsotg, &p->g_dma_desc, false, - "gadget-dma-desc", - !!hw->dma_desc_enable, false, - !!hw->dma_desc_enable); -} + dwc2_check_param_otg_cap(hsotg); + dwc2_check_param_phy_type(hsotg); + dwc2_check_param_speed(hsotg); + dwc2_check_param_phy_utmi_width(hsotg); + CHECK_BOOL(enable_dynamic_fifo, hw->enable_dynamic_fifo); + CHECK_BOOL(en_multiple_tx_fifo, hw->en_multiple_tx_fifo); + CHECK_BOOL(i2c_enable, hw->i2c_enable); + CHECK_BOOL(reload_ctl, (hsotg->hw_params.snpsid > DWC2_CORE_REV_2_92a)); + CHECK_RANGE(max_packet_count, + 15, hw->max_packet_count, + hw->max_packet_count); + CHECK_RANGE(max_transfer_size, + 2047, hw->max_transfer_size, + hw->max_transfer_size); -/** - * dwc2_set_parameters() - Set all core parameters. - * - * @hsotg: Programming view of the DWC_otg controller - * @params: The parameters to set - */ -static void dwc2_set_parameters(struct dwc2_hsotg *hsotg, - const struct dwc2_core_params *params) -{ - struct dwc2_hw_params *hw = &hsotg->hw_params; - struct dwc2_core_params *p = &hsotg->params; - bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH); - - dwc2_set_param_otg_cap(hsotg, params->otg_cap); if ((hsotg->dr_mode == USB_DR_MODE_HOST) || (hsotg->dr_mode == USB_DR_MODE_OTG)) { - dev_dbg(hsotg->dev, "Setting HOST parameters\n"); - - dwc2_set_param_bool(hsotg, &p->host_dma, - false, "host-dma", - dma_capable, false, - dma_capable); - dwc2_set_param_host_rx_fifo_size(hsotg, - params->host_rx_fifo_size); - dwc2_set_param_host_nperio_tx_fifo_size(hsotg, - params->host_nperio_tx_fifo_size); - dwc2_set_param_host_perio_tx_fifo_size(hsotg, - params->host_perio_tx_fifo_size); + CHECK_BOOL(host_dma, dma_capable); + CHECK_BOOL(dma_desc_enable, p->host_dma); + CHECK_BOOL(dma_desc_fs_enable, p->dma_desc_enable); + CHECK_BOOL(host_ls_low_power_phy_clk, + p->phy_type == DWC2_PHY_TYPE_PARAM_FS); + CHECK_RANGE(host_channels, + 1, hw->host_channels, + hw->host_channels); + CHECK_RANGE(host_rx_fifo_size, + 16, hw->rx_fifo_size, + hw->rx_fifo_size); + CHECK_RANGE(host_nperio_tx_fifo_size, + 16, hw->host_nperio_tx_fifo_size, + hw->host_nperio_tx_fifo_size); + CHECK_RANGE(host_perio_tx_fifo_size, + 16, hw->host_perio_tx_fifo_size, + hw->host_perio_tx_fifo_size); } - dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable); - dwc2_set_param_dma_desc_fs_enable(hsotg, params->dma_desc_fs_enable); - - dwc2_set_param_host_support_fs_ls_low_power(hsotg, - params->host_support_fs_ls_low_power); - dwc2_set_param_enable_dynamic_fifo(hsotg, - params->enable_dynamic_fifo); - dwc2_set_param_max_transfer_size(hsotg, - params->max_transfer_size); - dwc2_set_param_max_packet_count(hsotg, - params->max_packet_count); - dwc2_set_param_host_channels(hsotg, params->host_channels); - dwc2_set_param_phy_type(hsotg, params->phy_type); - dwc2_set_param_speed(hsotg, params->speed); - dwc2_set_param_host_ls_low_power_phy_clk(hsotg, - params->host_ls_low_power_phy_clk); - dwc2_set_param_phy_ulpi_ddr(hsotg, params->phy_ulpi_ddr); - dwc2_set_param_phy_ulpi_ext_vbus(hsotg, - params->phy_ulpi_ext_vbus); - dwc2_set_param_phy_utmi_width(hsotg, params->phy_utmi_width); - dwc2_set_param_ulpi_fs_ls(hsotg, params->ulpi_fs_ls); - dwc2_set_param_ts_dline(hsotg, params->ts_dline); - dwc2_set_param_i2c_enable(hsotg, params->i2c_enable); - dwc2_set_param_en_multiple_tx_fifo(hsotg, - params->en_multiple_tx_fifo); - dwc2_set_param_reload_ctl(hsotg, params->reload_ctl); - dwc2_set_param_ahbcfg(hsotg, params->ahbcfg); - dwc2_set_param_otg_ver(hsotg, params->otg_ver); - dwc2_set_param_uframe_sched(hsotg, params->uframe_sched); - dwc2_set_param_external_id_pin_ctl(hsotg, params->external_id_pin_ctl); - dwc2_set_param_hibernation(hsotg, params->hibernation); - /* - * Set devicetree-only parameters. These parameters do not - * take any values from @params. - */ if ((hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) || (hsotg->dr_mode == USB_DR_MODE_OTG)) { - dev_dbg(hsotg->dev, "Setting peripheral device properties\n"); - - dwc2_set_gadget_dma(hsotg); - - /* - * The values for g_rx_fifo_size (2048) and - * g_np_tx_fifo_size (1024) come from the legacy s3c - * gadget driver. These defaults have been hard-coded - * for some time so many platforms depend on these - * values. Leave them as defaults for now and only - * auto-detect if the hardware does not support the - * default. - */ - dwc2_set_param_u32(hsotg, &p->g_rx_fifo_size, - true, "g-rx-fifo-size", 2048, - hw->rx_fifo_size, - 16, hw->rx_fifo_size); - - dwc2_set_param_u32(hsotg, &p->g_np_tx_fifo_size, - true, "g-np-tx-fifo-size", 1024, - hw->dev_nperio_tx_fifo_size, - 16, hw->dev_nperio_tx_fifo_size); - - dwc2_set_param_tx_fifo_sizes(hsotg); + CHECK_BOOL(g_dma, dma_capable); + CHECK_BOOL(g_dma_desc, (p->g_dma && hw->dma_desc_enable)); + CHECK_RANGE(g_rx_fifo_size, + 16, hw->rx_fifo_size, + hw->rx_fifo_size); + CHECK_RANGE(g_np_tx_fifo_size, + 16, hw->dev_nperio_tx_fifo_size, + hw->dev_nperio_tx_fifo_size); + dwc2_check_param_tx_fifo_sizes(hsotg); } } @@ -1211,8 +553,6 @@ static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg) gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ); - dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz); - dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz); if (forced) dwc2_clear_force_mode(hsotg); @@ -1240,7 +580,6 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg) forced = dwc2_force_mode_if_needed(hsotg, false); gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); - dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz); if (forced) dwc2_clear_force_mode(hsotg); @@ -1286,12 +625,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) hwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4); grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ); - dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hwcfg1); - dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hwcfg2); - dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hwcfg3); - dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4); - dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz); - /* * Host specific hardware parameters. Reading these parameters * requires the controller to be in host mode. The mode will @@ -1351,73 +684,24 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> GRXFSIZ_DEPTH_SHIFT; - dev_dbg(hsotg->dev, "Detected values from hardware:\n"); - dev_dbg(hsotg->dev, " op_mode=%d\n", - hw->op_mode); - dev_dbg(hsotg->dev, " arch=%d\n", - hw->arch); - dev_dbg(hsotg->dev, " dma_desc_enable=%d\n", - hw->dma_desc_enable); - dev_dbg(hsotg->dev, " power_optimized=%d\n", - hw->power_optimized); - dev_dbg(hsotg->dev, " i2c_enable=%d\n", - hw->i2c_enable); - dev_dbg(hsotg->dev, " hs_phy_type=%d\n", - hw->hs_phy_type); - dev_dbg(hsotg->dev, " fs_phy_type=%d\n", - hw->fs_phy_type); - dev_dbg(hsotg->dev, " utmi_phy_data_width=%d\n", - hw->utmi_phy_data_width); - dev_dbg(hsotg->dev, " num_dev_ep=%d\n", - hw->num_dev_ep); - dev_dbg(hsotg->dev, " num_dev_perio_in_ep=%d\n", - hw->num_dev_perio_in_ep); - dev_dbg(hsotg->dev, " host_channels=%d\n", - hw->host_channels); - dev_dbg(hsotg->dev, " max_transfer_size=%d\n", - hw->max_transfer_size); - dev_dbg(hsotg->dev, " max_packet_count=%d\n", - hw->max_packet_count); - dev_dbg(hsotg->dev, " nperio_tx_q_depth=0x%0x\n", - hw->nperio_tx_q_depth); - dev_dbg(hsotg->dev, " host_perio_tx_q_depth=0x%0x\n", - hw->host_perio_tx_q_depth); - dev_dbg(hsotg->dev, " dev_token_q_depth=0x%0x\n", - hw->dev_token_q_depth); - dev_dbg(hsotg->dev, " enable_dynamic_fifo=%d\n", - hw->enable_dynamic_fifo); - dev_dbg(hsotg->dev, " en_multiple_tx_fifo=%d\n", - hw->en_multiple_tx_fifo); - dev_dbg(hsotg->dev, " total_fifo_size=%d\n", - hw->total_fifo_size); - dev_dbg(hsotg->dev, " rx_fifo_size=%d\n", - hw->rx_fifo_size); - dev_dbg(hsotg->dev, " host_nperio_tx_fifo_size=%d\n", - hw->host_nperio_tx_fifo_size); - dev_dbg(hsotg->dev, " host_perio_tx_fifo_size=%d\n", - hw->host_perio_tx_fifo_size); - dev_dbg(hsotg->dev, "\n"); - return 0; } int dwc2_init_params(struct dwc2_hsotg *hsotg) { const struct of_device_id *match; - struct dwc2_core_params params; + void (*set_params)(void *data); + + dwc2_set_default_params(hsotg); + dwc2_get_device_properties(hsotg); match = of_match_device(dwc2_of_match_table, hsotg->dev); - if (match && match->data) - params = *((struct dwc2_core_params *)match->data); - else - params = params_default; - - if (dwc2_is_fs_iot(hsotg)) { - params.speed = DWC2_SPEED_PARAM_FULL; - params.phy_type = DWC2_PHY_TYPE_PARAM_FS; + if (match && match->data) { + set_params = match->data; + set_params(hsotg); } - dwc2_set_parameters(hsotg, ¶ms); + dwc2_check_params(hsotg); return 0; } diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c index a23329e3d7cd..fdeb8c7bf30a 100644 --- a/drivers/usb/dwc2/pci.c +++ b/drivers/usb/dwc2/pci.c @@ -87,7 +87,7 @@ static void dwc2_pci_remove(struct pci_dev *pci) } static int dwc2_pci_probe(struct pci_dev *pci, - const struct pci_device_id *id) + const struct pci_device_id *id) { struct resource res[2]; struct platform_device *dwc2; diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 4fc8c603afb8..9564bc76c56f 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -111,7 +111,7 @@ static int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg) if (mode != hsotg->dr_mode) { dev_warn(hsotg->dev, - "Configuration mismatch. dr_mode forced to %s\n", + "Configuration mismatch. dr_mode forced to %s\n", mode == USB_DR_MODE_HOST ? "host" : "device"); hsotg->dr_mode = mode; @@ -136,11 +136,11 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) return ret; } - if (hsotg->uphy) + if (hsotg->uphy) { ret = usb_phy_init(hsotg->uphy); - else if (hsotg->plat && hsotg->plat->phy_init) + } else if (hsotg->plat && hsotg->plat->phy_init) { ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); - else { + } else { ret = phy_power_on(hsotg->phy); if (ret == 0) ret = phy_init(hsotg->phy); @@ -170,11 +170,11 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) struct platform_device *pdev = to_platform_device(hsotg->dev); int ret = 0; - if (hsotg->uphy) + if (hsotg->uphy) { usb_phy_shutdown(hsotg->uphy); - else if (hsotg->plat && hsotg->plat->phy_exit) + } else if (hsotg->plat && hsotg->plat->phy_exit) { ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); - else { + } else { ret = phy_exit(hsotg->phy); if (ret == 0) ret = phy_power_off(hsotg->phy); @@ -445,7 +445,7 @@ static int dwc2_driver_probe(struct platform_device *dev) } if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) { - retval = dwc2_hcd_init(hsotg, hsotg->irq); + retval = dwc2_hcd_init(hsotg); if (retval) { if (hsotg->gadget_enabled) dwc2_hsotg_remove(hsotg); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 14b760209680..2b9e4ca3c932 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -40,6 +40,7 @@ /* Global constants */ #define DWC3_PULL_UP_TIMEOUT 500 /* ms */ #define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */ +#define DWC3_BOUNCE_SIZE 1024 /* size of a superspeed bulk */ #define DWC3_EP0_BOUNCE_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 #define DWC3_XHCI_RESOURCES_NUM 2 @@ -724,6 +725,7 @@ struct dwc3_hwparams { * @epnum: endpoint number to which this request refers * @trb: pointer to struct dwc3_trb * @trb_dma: DMA address of @trb + * @unaligned: true for OUT endpoints with length not divisible by maxp * @direction: IN or OUT direction flag * @mapped: true when request has been dma-mapped * @queued: true when request has been queued to HW @@ -740,6 +742,7 @@ struct dwc3_request { struct dwc3_trb *trb; dma_addr_t trb_dma; + unsigned unaligned:1; unsigned direction:1; unsigned mapped:1; unsigned started:1; @@ -857,12 +860,14 @@ struct dwc3_scratchpad_array { struct dwc3 { struct usb_ctrlrequest *ctrl_req; struct dwc3_trb *ep0_trb; + void *bounce; void *ep0_bounce; void *zlp_buf; void *scratchbuf; u8 *setup_buf; dma_addr_t ctrl_req_addr; dma_addr_t ep0_trb_addr; + dma_addr_t bounce_addr; dma_addr_t ep0_bounce_addr; dma_addr_t scratch_addr; struct dwc3_request ep0_usb_req; diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index e956306d9b0f..1515d45ebcec 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -128,10 +128,8 @@ static int dwc3_exynos_probe(struct platform_device *pdev) clk_prepare_enable(exynos->clk); exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk"); - if (IS_ERR(exynos->susp_clk)) { - dev_info(dev, "no suspend clk specified\n"); + if (IS_ERR(exynos->susp_clk)) exynos->susp_clk = NULL; - } clk_prepare_enable(exynos->susp_clk); if (of_device_is_compatible(node, "samsung,exynos7-dwusb3")) { @@ -290,7 +288,6 @@ static struct platform_driver dwc3_exynos_driver = { module_platform_driver(dwc3_exynos_driver); -MODULE_ALIAS("platform:exynos-dwc3"); MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index eb1b9cb3f9d1..2092e46b1380 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -426,20 +426,20 @@ static int dwc3_omap_extcon_register(struct dwc3_omap *omap) } omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier; - ret = extcon_register_notifier(edev, EXTCON_USB, - &omap->vbus_nb); + ret = devm_extcon_register_notifier(omap->dev, edev, + EXTCON_USB, &omap->vbus_nb); if (ret < 0) dev_vdbg(omap->dev, "failed to register notifier for USB\n"); omap->id_nb.notifier_call = dwc3_omap_id_notifier; - ret = extcon_register_notifier(edev, EXTCON_USB_HOST, - &omap->id_nb); + ret = devm_extcon_register_notifier(omap->dev, edev, + EXTCON_USB_HOST, &omap->id_nb); if (ret < 0) dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n"); - if (extcon_get_cable_state_(edev, EXTCON_USB) == true) + if (extcon_get_state(edev, EXTCON_USB) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); - if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == true) + if (extcon_get_state(edev, EXTCON_USB_HOST) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); omap->edev = edev; @@ -528,17 +528,13 @@ static int dwc3_omap_probe(struct platform_device *pdev) ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { dev_err(&pdev->dev, "failed to create dwc3 core\n"); - goto err2; + goto err1; } dwc3_omap_enable_irqs(omap); enable_irq(omap->irq); return 0; -err2: - extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb); - extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); - err1: pm_runtime_put_sync(dev); pm_runtime_disable(dev); @@ -550,8 +546,6 @@ static int dwc3_omap_remove(struct platform_device *pdev) { struct dwc3_omap *omap = platform_get_drvdata(pdev); - extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb); - extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); dwc3_omap_disable_irqs(omap); disable_irq(omap->irq); of_platform_depopulate(omap->dev); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 9bb1f8526f3e..e689cede9b0e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -1123,7 +1123,21 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, dwc->ep0state = EP0_STATUS_PHASE; if (dwc->delayed_status) { + struct dwc3_ep *dep = dwc->eps[0]; + WARN_ON_ONCE(event->endpoint_number != 1); + /* + * We should handle the delay STATUS phase here if the + * request for handling delay STATUS has been queued + * into the list. + */ + if (!list_empty(&dep->pending_list)) { + dwc->delayed_status = false; + usb_gadget_set_state(&dwc->gadget, + USB_STATE_CONFIGURED); + dwc3_ep0_do_control_status(dwc, event); + } + return; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 204c754cc647..4db97ecae885 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -833,29 +833,14 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep, static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep); -/** - * dwc3_prepare_one_trb - setup one TRB from one request - * @dep: endpoint for which this request is prepared - * @req: dwc3_request pointer - */ -static void dwc3_prepare_one_trb(struct dwc3_ep *dep, - struct dwc3_request *req, dma_addr_t dma, - unsigned length, unsigned chain, unsigned node) +static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, + dma_addr_t dma, unsigned length, unsigned chain, unsigned node, + unsigned stream_id, unsigned short_not_ok, unsigned no_interrupt) { - struct dwc3_trb *trb; struct dwc3 *dwc = dep->dwc; struct usb_gadget *gadget = &dwc->gadget; enum usb_device_speed speed = gadget->speed; - trb = &dep->trb_pool[dep->trb_enqueue]; - - if (!req->trb) { - dwc3_gadget_move_started_request(req); - req->trb = trb; - req->trb_dma = dwc3_trb_dma_offset(dep, trb); - dep->queued_requests++; - } - dwc3_ep_inc_enq(dep); trb->size = DWC3_TRB_SIZE_LENGTH(length); @@ -900,11 +885,11 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, if (usb_endpoint_dir_out(dep->endpoint.desc)) { trb->ctrl |= DWC3_TRB_CTRL_CSP; - if (req->request.short_not_ok) + if (short_not_ok) trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; } - if ((!req->request.no_interrupt && !chain) || + if ((!no_interrupt && !chain) || (dwc3_calc_trbs_left(dep) == 0)) trb->ctrl |= DWC3_TRB_CTRL_IOC; @@ -912,7 +897,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl |= DWC3_TRB_CTRL_CHN; if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable) - trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id); + trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(stream_id); trb->ctrl |= DWC3_TRB_CTRL_HWO; @@ -920,6 +905,36 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, } /** + * dwc3_prepare_one_trb - setup one TRB from one request + * @dep: endpoint for which this request is prepared + * @req: dwc3_request pointer + * @chain: should this TRB be chained to the next? + * @node: only for isochronous endpoints. First TRB needs different type. + */ +static void dwc3_prepare_one_trb(struct dwc3_ep *dep, + struct dwc3_request *req, unsigned chain, unsigned node) +{ + struct dwc3_trb *trb; + unsigned length = req->request.length; + unsigned stream_id = req->request.stream_id; + unsigned short_not_ok = req->request.short_not_ok; + unsigned no_interrupt = req->request.no_interrupt; + dma_addr_t dma = req->request.dma; + + trb = &dep->trb_pool[dep->trb_enqueue]; + + if (!req->trb) { + dwc3_gadget_move_started_request(req); + req->trb = trb; + req->trb_dma = dwc3_trb_dma_offset(dep, trb); + dep->queued_requests++; + } + + __dwc3_prepare_one_trb(dep, trb, dma, length, chain, node, + stream_id, short_not_ok, no_interrupt); +} + +/** * dwc3_ep_prev_trb() - Returns the previous TRB in the ring * @dep: The endpoint with the TRB ring * @index: The index of the current TRB in the ring @@ -974,21 +989,36 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, { struct scatterlist *sg = req->sg; struct scatterlist *s; - unsigned int length; - dma_addr_t dma; int i; for_each_sg(sg, s, req->num_pending_sgs, i) { + unsigned int length = req->request.length; + unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); + unsigned int rem = length % maxp; unsigned chain = true; - length = sg_dma_len(s); - dma = sg_dma_address(s); - if (sg_is_last(s)) chain = false; - dwc3_prepare_one_trb(dep, req, dma, length, - chain, i); + if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) { + struct dwc3 *dwc = dep->dwc; + struct dwc3_trb *trb; + + req->unaligned = true; + + /* prepare normal TRB */ + dwc3_prepare_one_trb(dep, req, true, i); + + /* Now prepare one extra TRB to align transfer size */ + trb = &dep->trb_pool[dep->trb_enqueue]; + __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, + maxp - rem, false, 0, + req->request.stream_id, + req->request.short_not_ok, + req->request.no_interrupt); + } else { + dwc3_prepare_one_trb(dep, req, chain, i); + } if (!dwc3_calc_trbs_left(dep)) break; @@ -998,14 +1028,28 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, struct dwc3_request *req) { - unsigned int length; - dma_addr_t dma; + unsigned int length = req->request.length; + unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); + unsigned int rem = length % maxp; + + if (rem && usb_endpoint_dir_out(dep->endpoint.desc)) { + struct dwc3 *dwc = dep->dwc; + struct dwc3_trb *trb; - dma = req->request.dma; - length = req->request.length; + req->unaligned = true; - dwc3_prepare_one_trb(dep, req, dma, length, - false, 0); + /* prepare normal TRB */ + dwc3_prepare_one_trb(dep, req, true, 0); + + /* Now prepare one extra TRB to align transfer size */ + trb = &dep->trb_pool[dep->trb_enqueue]; + __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem, + false, 0, req->request.stream_id, + req->request.short_not_ok, + req->request.no_interrupt); + } else { + dwc3_prepare_one_trb(dep, req, false, 0); + } } /* @@ -1335,6 +1379,9 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) unsigned transfer_in_flight; unsigned started; + if (dep->flags & DWC3_EP_STALL) + return 0; + if (dep->number > 1) trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue); else @@ -1356,6 +1403,8 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) else dep->flags |= DWC3_EP_STALL; } else { + if (!(dep->flags & DWC3_EP_STALL)) + return 0; ret = dwc3_send_clear_stall_ep_cmd(dep); if (ret) @@ -1918,6 +1967,44 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, dep->endpoint.ops = &dwc3_gadget_ep0_ops; if (!epnum) dwc->gadget.ep0 = &dep->endpoint; + } else if (direction) { + int mdwidth; + int size; + int ret; + int num; + + mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); + /* MDWIDTH is represented in bits, we need it in bytes */ + mdwidth /= 8; + + size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(i)); + size = DWC3_GTXFIFOSIZ_TXFDEF(size); + + /* FIFO Depth is in MDWDITH bytes. Multiply */ + size *= mdwidth; + + num = size / 1024; + if (num == 0) + num = 1; + + /* + * FIFO sizes account an extra MDWIDTH * (num + 1) bytes for + * internal overhead. We don't really know how these are used, + * but documentation say it exists. + */ + size -= mdwidth * (num + 1); + size /= num; + + usb_ep_set_maxpacket_limit(&dep->endpoint, size); + + dep->endpoint.max_streams = 15; + dep->endpoint.ops = &dwc3_gadget_ep_ops; + list_add_tail(&dep->endpoint.ep_list, + &dwc->gadget.ep_list); + + ret = dwc3_alloc_trb_pool(dep); + if (ret) + return ret; } else { int ret; @@ -2029,6 +2116,16 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO)) trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + /* + * If we're dealing with unaligned size OUT transfer, we will be left + * with one TRB pending in the ring. We need to manually clear HWO bit + * from that TRB. + */ + if (req->unaligned && (trb->ctrl & DWC3_TRB_CTRL_HWO)) { + trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + return 1; + } + if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN) return 1; @@ -2118,6 +2215,13 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, event, status, chain); } + if (req->unaligned) { + trb = &dep->trb_pool[dep->trb_dequeue]; + ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, + event, status, false); + req->unaligned = false; + } + req->request.actual = length - req->remaining; if ((req->request.actual < length) && req->num_pending_sgs) @@ -3019,6 +3123,13 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err4; } + dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, + &dwc->bounce_addr, GFP_KERNEL); + if (!dwc->bounce) { + ret = -ENOMEM; + goto err5; + } + init_completion(&dwc->ep0_in_setup); dwc->gadget.ops = &dwc3_gadget_ops; @@ -3050,27 +3161,24 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc->gadget.max_speed = dwc->maximum_speed; /* - * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize - * on ep out. - */ - dwc->gadget.quirk_ep_out_aligned_size = true; - - /* * REVISIT: Here we should clear all pending IRQs to be * sure we're starting from a well known location. */ ret = dwc3_gadget_init_endpoints(dwc); if (ret) - goto err5; + goto err6; ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); - goto err5; + goto err6; } return 0; +err6: + dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, + dwc->bounce_addr); err5: kfree(dwc->zlp_buf); @@ -3103,6 +3211,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc3_gadget_free_endpoints(dwc); + dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, + dwc->bounce_addr); dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE, dwc->ep0_bounce, dwc->ep0_bounce_addr); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 487f0ff6ae25..76f0b0df37c1 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -54,11 +54,12 @@ out: int dwc3_host_init(struct dwc3 *dwc) { - struct property_entry props[2]; + struct property_entry props[3]; struct platform_device *xhci; int ret, irq; struct resource *res; struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); + int prop_idx = 0; irq = dwc3_host_get_irq(dwc); if (irq < 0) @@ -97,8 +98,22 @@ int dwc3_host_init(struct dwc3 *dwc) memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props)); - if (dwc->usb3_lpm_capable) { - props[0].name = "usb3-lpm-capable"; + if (dwc->usb3_lpm_capable) + props[prop_idx++].name = "usb3-lpm-capable"; + + /** + * WORKAROUND: dwc3 revisions <=3.00a have a limitation + * where Port Disable command doesn't work. + * + * The suggested workaround is that we avoid Port Disable + * completely. + * + * This following flag tells XHCI to do just that. + */ + if (dwc->revision <= DWC3_REVISION_300A) + props[prop_idx++].name = "quirk-broken-port-ped"; + + if (prop_idx) { ret = platform_device_add_properties(xhci, props); if (ret) { dev_err(dwc->dev, "failed to add properties to xHCI\n"); diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index ea73afb026d8..e2654443e8eb 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -580,7 +580,6 @@ try_again: USB_DEBUG_DEVNUM); goto err; } - devnum = USB_DEBUG_DEVNUM; dbgp_printk("debug device renamed to 127\n"); } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index e6a17455adac..87fccf611b69 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1230,7 +1230,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, desc = epfile->ep->descs[desc_idx]; spin_unlock_irq(&epfile->ffs->eps_lock); - ret = copy_to_user((void *)value, desc, sizeof(*desc)); + ret = copy_to_user((void *)value, desc, desc->bLength); if (ret) ret = -EFAULT; return ret; @@ -2101,7 +2101,7 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, case FFS_ENDPOINT: d = (void *)desc; helper->eps_count++; - if (helper->eps_count >= 15) + if (helper->eps_count >= FFS_MAX_EPS_COUNT) return -EINVAL; /* Check if descriptors for any speed were already parsed */ if (!helper->ffs->eps_count && !helper->ffs->interfaces_count) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 5f8139b8e601..89b48bcc377a 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -50,12 +50,12 @@ struct f_hidg { /* recv report */ struct list_head completed_out_req; - spinlock_t spinlock; + spinlock_t read_spinlock; wait_queue_head_t read_queue; unsigned int qlen; /* send report */ - struct mutex lock; + spinlock_t write_spinlock; bool write_pending; wait_queue_head_t write_queue; struct usb_request *req; @@ -258,28 +258,35 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; - spin_lock_irqsave(&hidg->spinlock, flags); + spin_lock_irqsave(&hidg->read_spinlock, flags); #define READ_COND (!list_empty(&hidg->completed_out_req)) /* wait for at least one buffer to complete */ while (!READ_COND) { - spin_unlock_irqrestore(&hidg->spinlock, flags); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(hidg->read_queue, READ_COND)) return -ERESTARTSYS; - spin_lock_irqsave(&hidg->spinlock, flags); + spin_lock_irqsave(&hidg->read_spinlock, flags); } /* pick the first one */ list = list_first_entry(&hidg->completed_out_req, struct f_hidg_req_list, list); + + /* + * Remove this from list to protect it from beign free() + * while host disables our function + */ + list_del(&list->list); + req = list->req; count = min_t(unsigned int, count, req->actual - list->pos); - spin_unlock_irqrestore(&hidg->spinlock, flags); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); /* copy to user outside spinlock */ count -= copy_to_user(buffer, req->buf + list->pos, count); @@ -292,15 +299,20 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, * call, taking into account its current read position. */ if (list->pos == req->actual) { - spin_lock_irqsave(&hidg->spinlock, flags); - list_del(&list->list); kfree(list); - spin_unlock_irqrestore(&hidg->spinlock, flags); req->length = hidg->report_length; ret = usb_ep_queue(hidg->out_ep, req, GFP_KERNEL); - if (ret < 0) + if (ret < 0) { + free_ep_req(hidg->out_ep, req); return ret; + } + } else { + spin_lock_irqsave(&hidg->read_spinlock, flags); + list_add(&list->list, &hidg->completed_out_req); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); + + wake_up(&hidg->read_queue); } return count; @@ -309,13 +321,16 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req) { struct f_hidg *hidg = (struct f_hidg *)ep->driver_data; + unsigned long flags; if (req->status != 0) { ERROR(hidg->func.config->cdev, "End Point Request ERROR: %d\n", req->status); } + spin_lock_irqsave(&hidg->write_spinlock, flags); hidg->write_pending = 0; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); wake_up(&hidg->write_queue); } @@ -323,18 +338,20 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, size_t count, loff_t *offp) { struct f_hidg *hidg = file->private_data; + struct usb_request *req; + unsigned long flags; ssize_t status = -ENOMEM; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; - mutex_lock(&hidg->lock); + spin_lock_irqsave(&hidg->write_spinlock, flags); #define WRITE_COND (!hidg->write_pending) - +try_again: /* write queue */ while (!WRITE_COND) { - mutex_unlock(&hidg->lock); + spin_unlock_irqrestore(&hidg->write_spinlock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; @@ -342,37 +359,59 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, hidg->write_queue, WRITE_COND)) return -ERESTARTSYS; - mutex_lock(&hidg->lock); + spin_lock_irqsave(&hidg->write_spinlock, flags); } + hidg->write_pending = 1; + req = hidg->req; count = min_t(unsigned, count, hidg->report_length); + + spin_unlock_irqrestore(&hidg->write_spinlock, flags); status = copy_from_user(hidg->req->buf, buffer, count); if (status != 0) { ERROR(hidg->func.config->cdev, "copy_from_user error\n"); - mutex_unlock(&hidg->lock); - return -EINVAL; + status = -EINVAL; + goto release_write_pending; } - hidg->req->status = 0; - hidg->req->zero = 0; - hidg->req->length = count; - hidg->req->complete = f_hidg_req_complete; - hidg->req->context = hidg; - hidg->write_pending = 1; + spin_lock_irqsave(&hidg->write_spinlock, flags); + + /* we our function has been disabled by host */ + if (!hidg->req) { + free_ep_req(hidg->in_ep, hidg->req); + /* + * TODO + * Should we fail with error here? + */ + goto try_again; + } + + req->status = 0; + req->zero = 0; + req->length = count; + req->complete = f_hidg_req_complete; + req->context = hidg; status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC); if (status < 0) { ERROR(hidg->func.config->cdev, "usb_ep_queue error on int endpoint %zd\n", status); - hidg->write_pending = 0; - wake_up(&hidg->write_queue); + goto release_write_pending_unlocked; } else { status = count; } + spin_unlock_irqrestore(&hidg->write_spinlock, flags); - mutex_unlock(&hidg->lock); + return status; +release_write_pending: + spin_lock_irqsave(&hidg->write_spinlock, flags); +release_write_pending_unlocked: + hidg->write_pending = 0; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); + + wake_up(&hidg->write_queue); return status; } @@ -425,20 +464,36 @@ static inline struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) { struct f_hidg *hidg = (struct f_hidg *) req->context; + struct usb_composite_dev *cdev = hidg->func.config->cdev; struct f_hidg_req_list *req_list; unsigned long flags; - req_list = kzalloc(sizeof(*req_list), GFP_ATOMIC); - if (!req_list) - return; + switch (req->status) { + case 0: + req_list = kzalloc(sizeof(*req_list), GFP_ATOMIC); + if (!req_list) { + ERROR(cdev, "Unable to allocate mem for req_list\n"); + goto free_req; + } - req_list->req = req; + req_list->req = req; - spin_lock_irqsave(&hidg->spinlock, flags); - list_add_tail(&req_list->list, &hidg->completed_out_req); - spin_unlock_irqrestore(&hidg->spinlock, flags); + spin_lock_irqsave(&hidg->read_spinlock, flags); + list_add_tail(&req_list->list, &hidg->completed_out_req); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); - wake_up(&hidg->read_queue); + wake_up(&hidg->read_queue); + break; + default: + ERROR(cdev, "Set report failed %d\n", req->status); + /* FALLTHROUGH */ + case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNRESET: /* request dequeued */ + case -ESHUTDOWN: /* disconnect from host */ +free_req: + free_ep_req(ep, req); + return; + } } static int hidg_setup(struct usb_function *f, @@ -544,20 +599,35 @@ static void hidg_disable(struct usb_function *f) { struct f_hidg *hidg = func_to_hidg(f); struct f_hidg_req_list *list, *next; + unsigned long flags; usb_ep_disable(hidg->in_ep); usb_ep_disable(hidg->out_ep); + spin_lock_irqsave(&hidg->read_spinlock, flags); list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) { + free_ep_req(hidg->out_ep, list->req); list_del(&list->list); kfree(list); } + spin_unlock_irqrestore(&hidg->read_spinlock, flags); + + spin_lock_irqsave(&hidg->write_spinlock, flags); + if (!hidg->write_pending) { + free_ep_req(hidg->in_ep, hidg->req); + hidg->write_pending = 1; + } + + hidg->req = NULL; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); } static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct usb_composite_dev *cdev = f->config->cdev; struct f_hidg *hidg = func_to_hidg(f); + struct usb_request *req_in = NULL; + unsigned long flags; int i, status = 0; VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt); @@ -578,6 +648,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) goto fail; } hidg->in_ep->driver_data = hidg; + + req_in = hidg_alloc_ep_req(hidg->in_ep, hidg->report_length); + if (!req_in) { + status = -ENOMEM; + goto disable_ep_in; + } } @@ -589,12 +665,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) hidg->out_ep); if (status) { ERROR(cdev, "config_ep_by_speed FAILED!\n"); - goto fail; + goto free_req_in; } status = usb_ep_enable(hidg->out_ep); if (status < 0) { ERROR(cdev, "Enable OUT endpoint FAILED!\n"); - goto fail; + goto free_req_in; } hidg->out_ep->driver_data = hidg; @@ -610,17 +686,37 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) req->context = hidg; status = usb_ep_queue(hidg->out_ep, req, GFP_ATOMIC); - if (status) + if (status) { ERROR(cdev, "%s queue req --> %d\n", hidg->out_ep->name, status); + free_ep_req(hidg->out_ep, req); + } } else { - usb_ep_disable(hidg->out_ep); status = -ENOMEM; - goto fail; + goto disable_out_ep; } } } + if (hidg->in_ep != NULL) { + spin_lock_irqsave(&hidg->write_spinlock, flags); + hidg->req = req_in; + hidg->write_pending = 0; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); + + wake_up(&hidg->write_queue); + } + return 0; +disable_out_ep: + usb_ep_disable(hidg->out_ep); +free_req_in: + if (req_in) + free_ep_req(hidg->in_ep, req_in); + +disable_ep_in: + if (hidg->in_ep) + usb_ep_disable(hidg->in_ep); + fail: return status; } @@ -669,12 +765,6 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) goto fail; hidg->out_ep = ep; - /* preallocate request and buffer */ - status = -ENOMEM; - hidg->req = alloc_ep_req(hidg->in_ep, hidg->report_length); - if (!hidg->req) - goto fail; - /* set descriptor dynamic values */ hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass; hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; @@ -711,8 +801,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto fail; - mutex_init(&hidg->lock); - spin_lock_init(&hidg->spinlock); + spin_lock_init(&hidg->write_spinlock); + hidg->write_pending = 1; + hidg->req = NULL; + spin_lock_init(&hidg->read_spinlock); init_waitqueue_head(&hidg->write_queue); init_waitqueue_head(&hidg->read_queue); INIT_LIST_HEAD(&hidg->completed_out_req); @@ -976,10 +1068,6 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) device_destroy(hidg_class, MKDEV(major, hidg->minor)); cdev_del(&hidg->cdev); - /* disable/free request and end point */ - usb_ep_disable(hidg->in_ep); - free_ep_req(hidg->in_ep, hidg->req); - usb_free_all_descriptors(f); } diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 8054da9276dd..8df244fc9d80 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -49,7 +49,6 @@ #include "u_printer.h" -#define PNP_STRING_LEN 1024 #define PRINTER_MINORS 4 #define GET_DEVICE_ID 0 #define GET_PORT_STATUS 1 @@ -907,8 +906,7 @@ static bool gprinter_req_match(struct usb_function *f, switch (ctrl->bRequest) { case GET_DEVICE_ID: w_index >>= 8; - if (w_length <= PNP_STRING_LEN && - (USB_DIR_IN & ctrl->bRequestType)) + if (USB_DIR_IN & ctrl->bRequestType) break; return false; case GET_PORT_STATUS: @@ -937,6 +935,7 @@ static int printer_func_setup(struct usb_function *f, struct printer_dev *dev = func_to_printer(f); struct usb_composite_dev *cdev = f->config->cdev; struct usb_request *req = cdev->req; + u8 *buf = req->buf; int value = -EOPNOTSUPP; u16 wIndex = le16_to_cpu(ctrl->wIndex); u16 wValue = le16_to_cpu(ctrl->wValue); @@ -953,10 +952,16 @@ static int printer_func_setup(struct usb_function *f, if ((wIndex>>8) != dev->interface) break; - value = (dev->pnp_string[0] << 8) | dev->pnp_string[1]; - memcpy(req->buf, dev->pnp_string, value); + if (!dev->pnp_string) { + value = 0; + break; + } + value = strlen(dev->pnp_string); + buf[0] = (value >> 8) & 0xFF; + buf[1] = value & 0xFF; + memcpy(buf + 2, dev->pnp_string, value); DBG(dev, "1284 PNP String: %x %s\n", value, - &dev->pnp_string[2]); + dev->pnp_string); break; case GET_PORT_STATUS: /* Get Port Status */ @@ -964,7 +969,7 @@ static int printer_func_setup(struct usb_function *f, if (wIndex != dev->interface) break; - *(u8 *)req->buf = dev->printer_status; + buf[0] = dev->printer_status; value = min_t(u16, wLength, 1); break; @@ -1157,10 +1162,21 @@ static ssize_t f_printer_opts_pnp_string_show(struct config_item *item, char *page) { struct f_printer_opts *opts = to_f_printer_opts(item); - int result; + int result = 0; mutex_lock(&opts->lock); - result = strlcpy(page, opts->pnp_string + 2, PNP_STRING_LEN - 2); + if (!opts->pnp_string) + goto unlock; + + result = strlcpy(page, opts->pnp_string, PAGE_SIZE); + if (result >= PAGE_SIZE) { + result = PAGE_SIZE; + } else if (page[result - 1] != '\n' && result + 1 < PAGE_SIZE) { + page[result++] = '\n'; + page[result] = '\0'; + } + +unlock: mutex_unlock(&opts->lock); return result; @@ -1170,13 +1186,24 @@ static ssize_t f_printer_opts_pnp_string_store(struct config_item *item, const char *page, size_t len) { struct f_printer_opts *opts = to_f_printer_opts(item); - int result, l; + char *new_pnp; + int result; mutex_lock(&opts->lock); - result = strlcpy(opts->pnp_string + 2, page, PNP_STRING_LEN - 2); - l = strlen(opts->pnp_string + 2) + 2; - opts->pnp_string[0] = (l >> 8) & 0xFF; - opts->pnp_string[1] = l & 0xFF; + + new_pnp = kstrndup(page, len, GFP_KERNEL); + if (!new_pnp) { + result = -ENOMEM; + goto unlock; + } + + if (opts->pnp_string_allocated) + kfree(opts->pnp_string); + + opts->pnp_string_allocated = true; + opts->pnp_string = new_pnp; + result = len; +unlock: mutex_unlock(&opts->lock); return result; @@ -1270,6 +1297,8 @@ static void gprinter_free_inst(struct usb_function_instance *f) mutex_unlock(&printer_ida_lock); + if (opts->pnp_string_allocated) + kfree(opts->pnp_string); kfree(opts); } diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 969cfe741380..f6a0d3a1311b 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -22,9 +22,6 @@ #include "u_uac2.h" -/* Keep everyone on toes */ -#define USB_XFERS 2 - /* * The driver implements a simple UAC_2 topology. * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture @@ -78,7 +75,7 @@ struct uac2_rtd_params { size_t period_size; unsigned max_psize; - struct uac2_req ureq[USB_XFERS]; + struct uac2_req *ureq; spinlock_t lock; }; @@ -269,6 +266,8 @@ static int uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); + struct audio_dev *agdev = uac2_to_agdev(uac2); + struct f_uac2_opts *uac2_opts = agdev_to_uac2_opts(agdev); struct uac2_rtd_params *prm; unsigned long flags; int err = 0; @@ -300,7 +299,7 @@ uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) /* Clear buffer after Play stops */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss) - memset(prm->rbuf, 0, prm->max_psize * USB_XFERS); + memset(prm->rbuf, 0, prm->max_psize * uac2_opts->req_number); return err; } @@ -943,6 +942,8 @@ static inline void free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) { struct snd_uac2_chip *uac2 = prm->uac2; + struct audio_dev *agdev = uac2_to_agdev(uac2); + struct f_uac2_opts *uac2_opts = agdev_to_uac2_opts(agdev); int i; if (!prm->ep_enabled) @@ -950,7 +951,7 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) prm->ep_enabled = false; - for (i = 0; i < USB_XFERS; i++) { + for (i = 0; i < uac2_opts->req_number; i++) { if (prm->ureq[i].req) { usb_ep_dequeue(ep, prm->ureq[i].req); usb_ep_free_request(ep, prm->ureq[i].req); @@ -1095,31 +1096,47 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm = &agdev->uac2.c_prm; prm->max_psize = hs_epout_desc.wMaxPacketSize; - prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); + prm->ureq = kcalloc(uac2_opts->req_number, sizeof(struct uac2_req), + GFP_KERNEL); + if (!prm->ureq) { + ret = -ENOMEM; + goto err_free_descs; + } + prm->rbuf = kcalloc(uac2_opts->req_number, prm->max_psize, GFP_KERNEL); if (!prm->rbuf) { prm->max_psize = 0; + ret = -ENOMEM; goto err_free_descs; } prm = &agdev->uac2.p_prm; prm->max_psize = hs_epin_desc.wMaxPacketSize; - prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); + prm->ureq = kcalloc(uac2_opts->req_number, sizeof(struct uac2_req), + GFP_KERNEL); + if (!prm->ureq) { + ret = -ENOMEM; + goto err_free_descs; + } + prm->rbuf = kcalloc(uac2_opts->req_number, prm->max_psize, GFP_KERNEL); if (!prm->rbuf) { prm->max_psize = 0; - goto err; + ret = -ENOMEM; + goto err_no_memory; } ret = alsa_uac2_init(agdev); if (ret) - goto err; + goto err_no_memory; return 0; -err: +err_no_memory: + kfree(agdev->uac2.p_prm.ureq); + kfree(agdev->uac2.c_prm.ureq); kfree(agdev->uac2.p_prm.rbuf); kfree(agdev->uac2.c_prm.rbuf); err_free_descs: usb_free_all_descriptors(fn); - return -EINVAL; + return ret; } static int @@ -1127,6 +1144,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) { struct usb_composite_dev *cdev = fn->config->cdev; struct audio_dev *agdev = func_to_agdev(fn); + struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev); struct snd_uac2_chip *uac2 = &agdev->uac2; struct usb_gadget *gadget = cdev->gadget; struct device *dev = &uac2->pdev.dev; @@ -1157,7 +1175,6 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) agdev->as_out_alt = alt; req_len = prm->max_psize; } else if (intf == agdev->as_in_intf) { - struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev); unsigned int factor, rate; struct usb_endpoint_descriptor *ep_desc; @@ -1203,7 +1220,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) prm->ep_enabled = true; usb_ep_enable(ep); - for (i = 0; i < USB_XFERS; i++) { + for (i = 0; i < opts->req_number; i++) { if (!prm->ureq[i].req) { req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (req == NULL) @@ -1487,6 +1504,7 @@ UAC2_ATTRIBUTE(p_ssize); UAC2_ATTRIBUTE(c_chmask); UAC2_ATTRIBUTE(c_srate); UAC2_ATTRIBUTE(c_ssize); +UAC2_ATTRIBUTE(req_number); static struct configfs_attribute *f_uac2_attrs[] = { &f_uac2_opts_attr_p_chmask, @@ -1495,6 +1513,7 @@ static struct configfs_attribute *f_uac2_attrs[] = { &f_uac2_opts_attr_c_chmask, &f_uac2_opts_attr_c_srate, &f_uac2_opts_attr_c_ssize, + &f_uac2_opts_attr_req_number, NULL, }; @@ -1532,6 +1551,7 @@ static struct usb_function_instance *afunc_alloc_inst(void) opts->c_chmask = UAC2_DEF_CCHMASK; opts->c_srate = UAC2_DEF_CSRATE; opts->c_ssize = UAC2_DEF_CSSIZE; + opts->req_number = UAC2_DEF_REQ_NUM; return &opts->func_inst; } @@ -1560,6 +1580,7 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f) prm = &agdev->uac2.c_prm; kfree(prm->rbuf); + kfree(prm->ureq); usb_free_all_descriptors(f); } diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index b4e5d6dfd549..c3cab77181d4 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -913,9 +913,16 @@ EXPORT_SYMBOL_GPL(gether_set_dev_addr); int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len) { struct eth_dev *dev; + int ret; dev = netdev_priv(net); - return get_ether_addr_str(dev->dev_mac, dev_addr, len); + ret = get_ether_addr_str(dev->dev_mac, dev_addr, len); + if (ret + 1 < len) { + dev_addr[ret++] = '\n'; + dev_addr[ret] = '\0'; + } + + return ret; } EXPORT_SYMBOL_GPL(gether_get_dev_addr); @@ -935,9 +942,16 @@ EXPORT_SYMBOL_GPL(gether_set_host_addr); int gether_get_host_addr(struct net_device *net, char *host_addr, int len) { struct eth_dev *dev; + int ret; dev = netdev_priv(net); - return get_ether_addr_str(dev->host_mac, host_addr, len); + ret = get_ether_addr_str(dev->host_mac, host_addr, len); + if (ret + 1 < len) { + host_addr[ret++] = '\n'; + host_addr[ret] = '\0'; + } + + return ret; } EXPORT_SYMBOL_GPL(gether_get_host_addr); @@ -984,10 +998,12 @@ EXPORT_SYMBOL_GPL(gether_get_qmult); int gether_get_ifname(struct net_device *net, char *name, int len) { + int ret; + rtnl_lock(); - strlcpy(name, netdev_name(net), len); + ret = snprintf(name, len, "%s\n", netdev_name(net)); rtnl_unlock(); - return strlen(name); + return ret < len ? ret : len; } EXPORT_SYMBOL_GPL(gether_get_ifname); diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index 4f47289fcf7c..c71133de17e7 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -108,7 +108,7 @@ mutex_lock(&opts->lock); \ qmult = gether_get_qmult(opts->net); \ mutex_unlock(&opts->lock); \ - return sprintf(page, "%d", qmult); \ + return sprintf(page, "%d\n", qmult); \ } \ \ static ssize_t _f_##_opts_qmult_store(struct config_item *item, \ diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index 60139854e0b1..4b6969451cdc 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -247,7 +247,8 @@ struct ffs_data { unsigned user_flags; - u8 eps_addrmap[15]; +#define FFS_MAX_EPS_COUNT 31 + u8 eps_addrmap[FFS_MAX_EPS_COUNT]; unsigned short strings_count; unsigned short interfaces_count; diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h index 0e2c49d4274e..8d30b7577f87 100644 --- a/drivers/usb/gadget/function/u_printer.h +++ b/drivers/usb/gadget/function/u_printer.h @@ -18,12 +18,11 @@ #include <linux/usb/composite.h> -#define PNP_STRING_LEN 1024 - struct f_printer_opts { struct usb_function_instance func_inst; int minor; - char pnp_string[PNP_STRING_LEN]; + char *pnp_string; + bool pnp_string_allocated; unsigned q_len; /* diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h index 78dd37279bd4..19eeb83538a5 100644 --- a/drivers/usb/gadget/function/u_uac2.h +++ b/drivers/usb/gadget/function/u_uac2.h @@ -24,6 +24,7 @@ #define UAC2_DEF_CCHMASK 0x3 #define UAC2_DEF_CSRATE 64000 #define UAC2_DEF_CSSIZE 2 +#define UAC2_DEF_REQ_NUM 2 struct f_uac2_opts { struct usb_function_instance func_inst; @@ -33,6 +34,7 @@ struct f_uac2_opts { int c_chmask; int c_srate; int c_ssize; + int req_number; bool bound; struct mutex lock; diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index 5d7b3c6a422b..8a39f42a4d56 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -229,6 +229,7 @@ static int audio_bind(struct usb_composite_dev *cdev) uac2_opts->c_chmask = c_chmask; uac2_opts->c_srate = c_srate; uac2_opts->c_ssize = c_ssize; + uac2_opts->req_number = UAC2_DEF_REQ_NUM; #else uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst); uac1_opts->fn_play = fn_play; diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 6f969a86175c..4c9cfff34a03 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -88,8 +88,8 @@ static const struct usb_descriptor_header *otg_desc[2]; static char product_desc [40] = DRIVER_DESC; static char serial_num [40] = "1"; -static char pnp_string[PNP_STRING_LEN] = - "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"; +static char *pnp_string = + "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"; /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -143,23 +143,29 @@ static int printer_do_config(struct usb_configuration *c) static int printer_bind(struct usb_composite_dev *cdev) { struct f_printer_opts *opts; - int ret, len; + int ret; fi_printer = usb_get_function_instance("printer"); if (IS_ERR(fi_printer)) return PTR_ERR(fi_printer); - if (iPNPstring) - strlcpy(&pnp_string[2], iPNPstring, PNP_STRING_LEN - 2); - - len = strlen(pnp_string); - pnp_string[0] = (len >> 8) & 0xFF; - pnp_string[1] = len & 0xFF; - opts = container_of(fi_printer, struct f_printer_opts, func_inst); opts->minor = 0; - memcpy(opts->pnp_string, pnp_string, PNP_STRING_LEN); opts->q_len = QLEN; + if (iPNPstring) { + opts->pnp_string = kstrdup(iPNPstring, GFP_KERNEL); + if (!opts->pnp_string) { + ret = -ENOMEM; + goto fail_put_func_inst; + } + opts->pnp_string_allocated = true; + /* + * we don't free this memory in case of error + * as printer cleanup func will do this for us + */ + } else { + opts->pnp_string = pnp_string; + } ret = usb_string_ids_tab(cdev, strings); if (ret < 0) diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 658b8da60915..4b69f28a9af9 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -60,6 +60,20 @@ config USB_ATMEL_USBA USBA is the integrated high-speed USB Device controller on the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. + The fifo_mode parameter is used to select endpoint allocation mode. + fifo_mode = 0 is used to let the driver autoconfigure the endpoints. + In this case 2 banks are allocated for isochronous endpoints and + only one bank is allocated for the rest of the endpoints. + + fifo_mode = 1 is a generic maximum fifo size (1024 bytes) configuration + allowing the usage of ep1 - ep6 + + fifo_mode = 2 is a generic performance maximum fifo size (1024 bytes) + configuration allowing the usage of ep1 - ep3 + + fifo_mode = 3 is a balanced performance configuration allowing the + the usage of ep1 - ep8 + config USB_BCM63XX_UDC tristate "Broadcom BCM63xx Peripheral Controller" depends on BCM63XX diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 12c7687216e6..11bbce28bc23 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -20,6 +20,7 @@ #include <linux/mfd/syscon.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/ctype.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/atmel_usba_udc.h> @@ -318,6 +319,91 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc) } #endif +static ushort fifo_mode; + +/* "modprobe ... fifo_mode=1" etc */ +module_param(fifo_mode, ushort, 0x0); +MODULE_PARM_DESC(fifo_mode, "Endpoint configuration mode"); + +/* mode 0 - uses autoconfig */ + +/* mode 1 - fits in 8KB, generic max fifo configuration */ +static struct usba_fifo_cfg mode_1_cfg[] = { +{ .hw_ep_num = 0, .fifo_size = 64, .nr_banks = 1, }, +{ .hw_ep_num = 1, .fifo_size = 1024, .nr_banks = 2, }, +{ .hw_ep_num = 2, .fifo_size = 1024, .nr_banks = 1, }, +{ .hw_ep_num = 3, .fifo_size = 1024, .nr_banks = 1, }, +{ .hw_ep_num = 4, .fifo_size = 1024, .nr_banks = 1, }, +{ .hw_ep_num = 5, .fifo_size = 1024, .nr_banks = 1, }, +{ .hw_ep_num = 6, .fifo_size = 1024, .nr_banks = 1, }, +}; + +/* mode 2 - fits in 8KB, performance max fifo configuration */ +static struct usba_fifo_cfg mode_2_cfg[] = { +{ .hw_ep_num = 0, .fifo_size = 64, .nr_banks = 1, }, +{ .hw_ep_num = 1, .fifo_size = 1024, .nr_banks = 3, }, +{ .hw_ep_num = 2, .fifo_size = 1024, .nr_banks = 2, }, +{ .hw_ep_num = 3, .fifo_size = 1024, .nr_banks = 2, }, +}; + +/* mode 3 - fits in 8KB, mixed fifo configuration */ +static struct usba_fifo_cfg mode_3_cfg[] = { +{ .hw_ep_num = 0, .fifo_size = 64, .nr_banks = 1, }, +{ .hw_ep_num = 1, .fifo_size = 1024, .nr_banks = 2, }, +{ .hw_ep_num = 2, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 3, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 4, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 5, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 6, .fifo_size = 512, .nr_banks = 2, }, +}; + +/* mode 4 - fits in 8KB, custom fifo configuration */ +static struct usba_fifo_cfg mode_4_cfg[] = { +{ .hw_ep_num = 0, .fifo_size = 64, .nr_banks = 1, }, +{ .hw_ep_num = 1, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 2, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 3, .fifo_size = 8, .nr_banks = 2, }, +{ .hw_ep_num = 4, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 5, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 6, .fifo_size = 16, .nr_banks = 2, }, +{ .hw_ep_num = 7, .fifo_size = 8, .nr_banks = 2, }, +{ .hw_ep_num = 8, .fifo_size = 8, .nr_banks = 2, }, +}; +/* Add additional configurations here */ + +int usba_config_fifo_table(struct usba_udc *udc) +{ + int n; + + switch (fifo_mode) { + default: + fifo_mode = 0; + case 0: + udc->fifo_cfg = NULL; + n = 0; + break; + case 1: + udc->fifo_cfg = mode_1_cfg; + n = ARRAY_SIZE(mode_1_cfg); + break; + case 2: + udc->fifo_cfg = mode_2_cfg; + n = ARRAY_SIZE(mode_2_cfg); + break; + case 3: + udc->fifo_cfg = mode_3_cfg; + n = ARRAY_SIZE(mode_3_cfg); + break; + case 4: + udc->fifo_cfg = mode_4_cfg; + n = ARRAY_SIZE(mode_4_cfg); + break; + } + DBG(DBG_HW, "Setup fifo_mode %d\n", fifo_mode); + + return n; +} + static inline u32 usba_int_enb_get(struct usba_udc *udc) { return udc->int_enb_cache; @@ -543,24 +629,17 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ep->is_isoc = 0; ep->is_in = 0; - if (maxpacket <= 8) - ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); - else - /* LSB is bit 1, not 0 */ - ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3); - - DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", + DBG(DBG_ERR, "%s: EPT_CFG = 0x%lx (maxpacket = %lu)\n", ep->ep.name, ept_cfg, maxpacket); if (usb_endpoint_dir_in(desc)) { ep->is_in = 1; - ept_cfg |= USBA_EPT_DIR_IN; + ep->ept_cfg |= USBA_EPT_DIR_IN; } switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); + ep->ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); break; case USB_ENDPOINT_XFER_ISOC: if (!ep->can_isoc) { @@ -578,24 +657,15 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) return -EINVAL; ep->is_isoc = 1; - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); + ep->ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); + ep->ept_cfg |= USBA_BF(NB_TRANS, nr_trans); - /* - * Do triple-buffering on high-bandwidth iso endpoints. - */ - if (nr_trans > 1 && ep->nr_banks == 3) - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE); - else - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); - ept_cfg |= USBA_BF(NB_TRANS, nr_trans); break; case USB_ENDPOINT_XFER_BULK: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + ep->ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); break; case USB_ENDPOINT_XFER_INT: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + ep->ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); break; } @@ -604,7 +674,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ep->ep.desc = desc; ep->ep.maxpacket = maxpacket; - usba_ep_writel(ep, CFG, ept_cfg); + usba_ep_writel(ep, CFG, ep->ept_cfg); usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); if (ep->can_dma) { @@ -1006,12 +1076,81 @@ static int atmel_usba_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver); static int atmel_usba_stop(struct usb_gadget *gadget); +static struct usb_ep *atmel_usba_match_ep( + struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp +) +{ + struct usb_ep *_ep; + struct usba_ep *ep; + + /* Look at endpoints until an unclaimed one looks usable */ + list_for_each_entry(_ep, &gadget->ep_list, ep_list) { + if (usb_gadget_ep_match_desc(gadget, _ep, desc, ep_comp)) + goto found_ep; + } + /* Fail */ + return NULL; + +found_ep: + + if (fifo_mode == 0) { + /* Optimize hw fifo size based on ep type and other info */ + ep = to_usba_ep(_ep); + + switch (usb_endpoint_type(desc)) { + + case USB_ENDPOINT_XFER_CONTROL: + break; + + case USB_ENDPOINT_XFER_ISOC: + ep->fifo_size = 1024; + ep->nr_banks = 2; + break; + + case USB_ENDPOINT_XFER_BULK: + ep->fifo_size = 512; + ep->nr_banks = 1; + break; + + case USB_ENDPOINT_XFER_INT: + if (desc->wMaxPacketSize == 0) + ep->fifo_size = + roundup_pow_of_two(_ep->maxpacket_limit); + else + ep->fifo_size = + roundup_pow_of_two(le16_to_cpu(desc->wMaxPacketSize)); + ep->nr_banks = 1; + break; + } + + /* It might be a little bit late to set this */ + usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size); + + /* Generate ept_cfg basd on FIFO size and number of banks */ + if (ep->fifo_size <= 8) + ep->ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); + else + /* LSB is bit 1, not 0 */ + ep->ept_cfg = + USBA_BF(EPT_SIZE, fls(ep->fifo_size - 1) - 3); + + ep->ept_cfg |= USBA_BF(BK_NUMBER, ep->nr_banks); + + ep->udc->configured_ep++; + } + +return _ep; +} + static const struct usb_gadget_ops usba_udc_ops = { .get_frame = usba_udc_get_frame, .wakeup = usba_udc_wakeup, .set_selfpowered = usba_udc_set_selfpowered, .udc_start = atmel_usba_start, .udc_stop = atmel_usba_stop, + .match_ep = atmel_usba_match_ep, }; static struct usb_endpoint_descriptor usba_ep0_desc = { @@ -1678,7 +1817,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) } if (status & USBA_END_OF_RESET) { - struct usba_ep *ep0; + struct usba_ep *ep0, *ep; + int i, n; usba_writel(udc, INT_CLR, USBA_END_OF_RESET); generate_bias_pulse(udc); @@ -1717,6 +1857,16 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED)) dev_dbg(&udc->pdev->dev, "ODD: EP0 configuration is invalid!\n"); + + /* Preallocate other endpoints */ + n = fifo_mode ? udc->num_ep : udc->configured_ep; + for (i = 1; i < n; i++) { + ep = &udc->usba_ep[i]; + usba_ep_writel(ep, CFG, ep->ept_cfg); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) + dev_dbg(&udc->pdev->dev, + "ODD: EP%d configuration is invalid!\n", i); + } } spin_unlock(&udc->lock); @@ -1864,6 +2014,9 @@ static int atmel_usba_stop(struct usb_gadget *gadget) if (gpio_is_valid(udc->vbus_pin)) disable_irq(gpio_to_irq(udc->vbus_pin)); + if (fifo_mode == 0) + udc->configured_ep = 1; + usba_stop(udc); udc->driver = NULL; @@ -1931,9 +2084,13 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, &flags); udc->vbus_pin_inverted = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; - pp = NULL; - while ((pp = of_get_next_child(np, pp))) - udc->num_ep++; + if (fifo_mode == 0) { + pp = NULL; + while ((pp = of_get_next_child(np, pp))) + udc->num_ep++; + udc->configured_ep = 1; + } else + udc->num_ep = usba_config_fifo_table(udc); eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep, GFP_KERNEL); @@ -1946,7 +2103,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, pp = NULL; i = 0; - while ((pp = of_get_next_child(np, pp))) { + while ((pp = of_get_next_child(np, pp)) && i < udc->num_ep) { ep = &eps[i]; ret = of_property_read_u32(pp, "reg", &val); @@ -1954,21 +2111,21 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, dev_err(&pdev->dev, "of_probe: reg error(%d)\n", ret); goto err; } - ep->index = val; + ep->index = fifo_mode ? udc->fifo_cfg[i].hw_ep_num : val; ret = of_property_read_u32(pp, "atmel,fifo-size", &val); if (ret) { dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret); goto err; } - ep->fifo_size = val; + ep->fifo_size = fifo_mode ? udc->fifo_cfg[i].fifo_size : val; ret = of_property_read_u32(pp, "atmel,nb-banks", &val); if (ret) { dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret); goto err; } - ep->nr_banks = val; + ep->nr_banks = fifo_mode ? udc->fifo_cfg[i].nr_banks : val; ep->can_dma = of_property_read_bool(pp, "atmel,can-dma"); ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); @@ -2000,6 +2157,21 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ep->ep.caps.dir_in = true; ep->ep.caps.dir_out = true; + if (fifo_mode != 0) { + /* + * Generate ept_cfg based on FIFO size and + * banks number + */ + if (ep->fifo_size <= 8) + ep->ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); + else + /* LSB is bit 1, not 0 */ + ep->ept_cfg = + USBA_BF(EPT_SIZE, fls(ep->fifo_size - 1) - 3); + + ep->ept_cfg |= USBA_BF(BK_NUMBER, ep->nr_banks); + } + if (i) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h index b03b2ebfc53a..9551b704bfd3 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.h +++ b/drivers/usb/gadget/udc/atmel_usba_udc.h @@ -275,6 +275,12 @@ struct usba_dma_desc { u32 ctrl; }; +struct usba_fifo_cfg { + u8 hw_ep_num; + u16 fifo_size; + u8 nr_banks; +}; + struct usba_ep { int state; void __iomem *ep_regs; @@ -293,7 +299,7 @@ struct usba_ep { unsigned int can_isoc:1; unsigned int is_isoc:1; unsigned int is_in:1; - + unsigned long ept_cfg; #ifdef CONFIG_USB_GADGET_DEBUG_FS u32 last_dma_status; struct dentry *debugfs_dir; @@ -338,6 +344,8 @@ struct usba_udc { int vbus_pin; int vbus_pin_inverted; int num_ep; + int configured_ep; + struct usba_fifo_cfg *fifo_cfg; struct clk *pclk; struct clk *hclk; struct usba_ep *usba_ep; diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 0402177f93cd..d685d82dcf48 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1080,6 +1080,24 @@ static void usb_udc_nop_release(struct device *dev) dev_vdbg(dev, "%s\n", __func__); } +/* should be called with udc_lock held */ +static int check_pending_gadget_drivers(struct usb_udc *udc) +{ + struct usb_gadget_driver *driver; + int ret = 0; + + list_for_each_entry(driver, &gadget_driver_pending_list, pending) + if (!driver->udc_name || strcmp(driver->udc_name, + dev_name(&udc->dev)) == 0) { + ret = udc_bind_to_driver(udc, driver); + if (ret != -EPROBE_DEFER) + list_del(&driver->pending); + break; + } + + return ret; +} + /** * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list * @parent: the parent device to this udc. Usually the controller driver's @@ -1093,7 +1111,6 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)) { struct usb_udc *udc; - struct usb_gadget_driver *driver; int ret = -ENOMEM; udc = kzalloc(sizeof(*udc), GFP_KERNEL); @@ -1136,17 +1153,9 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, udc->vbus = true; /* pick up one of pending gadget drivers */ - list_for_each_entry(driver, &gadget_driver_pending_list, pending) { - if (!driver->udc_name || strcmp(driver->udc_name, - dev_name(&udc->dev)) == 0) { - ret = udc_bind_to_driver(udc, driver); - if (ret != -EPROBE_DEFER) - list_del(&driver->pending); - if (ret) - goto err5; - break; - } - } + ret = check_pending_gadget_drivers(udc); + if (ret) + goto err5; mutex_unlock(&udc_lock); @@ -1356,14 +1365,22 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return -EINVAL; mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) + list_for_each_entry(udc, &udc_list, list) { if (udc->driver == driver) { usb_gadget_remove_driver(udc); usb_gadget_set_state(udc->gadget, - USB_STATE_NOTATTACHED); + USB_STATE_NOTATTACHED); + + /* Maybe there is someone waiting for this UDC? */ + check_pending_gadget_drivers(udc); + /* + * For now we ignore bind errors as probably it's + * not a valid reason to fail other's gadget unbind + */ ret = 0; break; } + } if (ret) { list_del(&driver->pending); diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index 6ba122cc7490..78d0204e3e20 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -527,7 +527,7 @@ static void fotg210_ep_fifo_flush(struct usb_ep *_ep) { } -static struct usb_ep_ops fotg210_ep_ops = { +static const struct usb_ep_ops fotg210_ep_ops = { .enable = fotg210_ep_enable, .disable = fotg210_ep_disable, @@ -1058,7 +1058,7 @@ static int fotg210_udc_stop(struct usb_gadget *g) return 0; } -static struct usb_gadget_ops fotg210_gadget_ops = { +static const struct usb_gadget_ops fotg210_gadget_ops = { .udc_start = fotg210_udc_start, .udc_stop = fotg210_udc_stop, }; diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 4fff51b8a18e..303328ce59ee 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -1847,7 +1847,7 @@ out: return status; } -static struct usb_ep_ops qe_ep_ops = { +static const struct usb_ep_ops qe_ep_ops = { .enable = qe_ep_enable, .disable = qe_ep_disable, diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 71094e479a96..2e41ef36b944 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1118,7 +1118,7 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep) } while (fsl_readl(&dr_regs->endptstatus) & bits); } -static struct usb_ep_ops fsl_ep_ops = { +static const struct usb_ep_ops fsl_ep_ops = { .enable = fsl_ep_enable, .disable = fsl_ep_disable, @@ -1248,6 +1248,12 @@ static const struct usb_gadget_ops fsl_gadget_ops = { .udc_stop = fsl_udc_stop, }; +/* + * Empty complete function used by this driver to fill in the req->complete + * field when creating a request since the complete field is mandatory. + */ +static void fsl_noop_complete(struct usb_ep *ep, struct usb_request *req) { } + /* Set protocol stall on ep0, protocol stall will automatically be cleared on new transaction */ static void ep0stall(struct fsl_udc *udc) @@ -1282,7 +1288,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction) req->req.length = 0; req->req.status = -EINPROGRESS; req->req.actual = 0; - req->req.complete = NULL; + req->req.complete = fsl_noop_complete; req->dtd_count = 0; ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); @@ -1365,7 +1371,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, req->req.length = 2; req->req.status = -EINPROGRESS; req->req.actual = 0; - req->req.complete = NULL; + req->req.complete = fsl_noop_complete; req->dtd_count = 0; ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c index 42ff308578df..e0c1b0099265 100644 --- a/drivers/usb/gadget/udc/fusb300_udc.c +++ b/drivers/usb/gadget/udc/fusb300_udc.c @@ -518,7 +518,7 @@ static void fusb300_fifo_flush(struct usb_ep *_ep) { } -static struct usb_ep_ops fusb300_ep_ops = { +static const struct usb_ep_ops fusb300_ep_ops = { .enable = fusb300_enable, .disable = fusb300_disable, diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 5107987bd353..8433c22900dc 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -968,7 +968,7 @@ static void goku_fifo_flush(struct usb_ep *_ep) command(regs, COMMAND_FIFO_CLEAR, ep->num); } -static struct usb_ep_ops goku_ep_ops = { +static const struct usb_ep_ops goku_ep_ops = { .enable = goku_ep_enable, .disable = goku_ep_disable, diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index b16f8af34050..1f9941145746 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -1841,7 +1841,7 @@ static void gr_fifo_flush(struct usb_ep *_ep) spin_unlock(&ep->dev->lock); } -static struct usb_ep_ops gr_ep_ops = { +static const struct usb_ep_ops gr_ep_ops = { .enable = gr_ep_enable, .disable = gr_ep_disable, diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index de3e03483659..46ce7bc15f2b 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1436,7 +1436,7 @@ static void m66592_fifo_flush(struct usb_ep *_ep) spin_unlock_irqrestore(&ep->m66592->lock, flags); } -static struct usb_ep_ops m66592_ep_ops = { +static const struct usb_ep_ops m66592_ep_ops = { .enable = m66592_enable, .disable = m66592_disable, diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index 8d726bd767fd..d365449a295a 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -995,7 +995,7 @@ static int mv_u3d_ep_set_wedge(struct usb_ep *_ep) return mv_u3d_ep_set_halt_wedge(_ep, 1, 1); } -static struct usb_ep_ops mv_u3d_ep_ops = { +static const struct usb_ep_ops mv_u3d_ep_ops = { .enable = mv_u3d_ep_enable, .disable = mv_u3d_ep_disable, diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index d82a91bddbd9..27ebb0d5449d 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -946,7 +946,7 @@ static int mv_ep_set_wedge(struct usb_ep *_ep) return mv_ep_set_halt_wedge(_ep, 1, 1); } -static struct usb_ep_ops mv_ep_ops = { +static const struct usb_ep_ops mv_ep_ops = { .enable = mv_ep_enable, .disable = mv_ep_disable, diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 078c91d546e0..7dc0102abdfe 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -181,7 +181,7 @@ static void net2272_dequeue_all(struct net2272_ep *); static int net2272_kick_dma(struct net2272_ep *, struct net2272_request *); static int net2272_fifo_status(struct usb_ep *); -static struct usb_ep_ops net2272_ep_ops; +static const struct usb_ep_ops net2272_ep_ops; /*---------------------------------------------------------------------------*/ @@ -1067,7 +1067,7 @@ net2272_fifo_flush(struct usb_ep *_ep) net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); } -static struct usb_ep_ops net2272_ep_ops = { +static const struct usb_ep_ops net2272_ep_ops = { .enable = net2272_enable, .disable = net2272_disable, diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index a8709f9e5648..f05ba6825bfe 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -1112,7 +1112,7 @@ done: return status; } -static struct usb_ep_ops omap_ep_ops = { +static const struct usb_ep_ops omap_ep_ops = { .enable = omap_ep_enable, .disable = omap_ep_disable, diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 7fa60f5b7ae4..e1335ad5bce9 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -1473,7 +1473,7 @@ static int pxa_ep_disable(struct usb_ep *_ep) return 0; } -static struct usb_ep_ops pxa_ep_ops = { +static const struct usb_ep_ops pxa_ep_ops = { .enable = pxa_ep_enable, .disable = pxa_ep_disable, diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index f2c8862093a2..118ad70f1af0 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1706,7 +1706,7 @@ static void r8a66597_fifo_flush(struct usb_ep *_ep) spin_unlock_irqrestore(&ep->r8a66597->lock, flags); } -static struct usb_ep_ops r8a66597_ep_ops = { +static const struct usb_ep_ops r8a66597_ep_ops = { .enable = r8a66597_enable, .disable = r8a66597_disable, diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index 82a9e2a3bedc..42587b738a1f 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -954,7 +954,7 @@ static int s3c_hsudc_dequeue(struct usb_ep *_ep, struct usb_request *_req) return 0; } -static struct usb_ep_ops s3c_hsudc_ep_ops = { +static const struct usb_ep_ops s3c_hsudc_ep_ops = { .enable = s3c_hsudc_ep_enable, .disable = s3c_hsudc_ep_disable, .alloc_request = s3c_hsudc_alloc_request, diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 6361fc739306..407d947b34ea 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -45,9 +45,9 @@ config USB_XHCI_PLATFORM If unsure, say N. config USB_XHCI_MTK - tristate "xHCI support for Mediatek MT65xx" + tristate "xHCI support for Mediatek MT65xx/MT7621" select MFD_SYSCON - depends on ARCH_MEDIATEK || COMPILE_TEST + depends on (MIPS && SOC_MT7621) || ARCH_MEDIATEK || COMPILE_TEST ---help--- Say 'Y' to enable the support for the xHCI host controller found in Mediatek MT65xx SoCs. diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 42e5b66353ef..7a603f66a9bc 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -77,10 +77,12 @@ static int exynos_ehci_get_phy(struct device *dev, if (IS_ERR(phy)) { ret = PTR_ERR(phy); if (ret == -EPROBE_DEFER) { + of_node_put(child); return ret; } else if (ret != -ENOSYS && ret != -ENODEV) { dev_err(dev, "Error retrieving usb2 phy: %d\n", ret); + of_node_put(child); return ret; } } diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 91701cc68082..3733aab46efe 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -600,7 +600,7 @@ static int ehci_fsl_drv_restore(struct device *dev) return 0; } -static struct dev_pm_ops ehci_fsl_pm_ops = { +static const struct dev_pm_ops ehci_fsl_pm_ops = { .suspend = ehci_fsl_drv_suspend, .resume = ehci_fsl_drv_resume, .restore = ehci_fsl_drv_restore, diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 2cd105be7319..6865b919403f 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -66,10 +66,12 @@ static int exynos_ohci_get_phy(struct device *dev, if (IS_ERR(phy)) { ret = PTR_ERR(phy); if (ret == -EPROBE_DEFER) { + of_node_put(child); return ret; } else if (ret != -ENOSYS && ret != -ENODEV) { dev_err(dev, "Error retrieving usb2 phy: %d\n", ret); + of_node_put(child); return ret; } } diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index ed678c17c4ea..248eb7702463 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -17,21 +17,21 @@ ohci_dbg (hc, \ "%s roothub.portstatus [%d] " \ "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \ - label, num, temp, \ - (temp & RH_PS_PRSC) ? " PRSC" : "", \ - (temp & RH_PS_OCIC) ? " OCIC" : "", \ - (temp & RH_PS_PSSC) ? " PSSC" : "", \ - (temp & RH_PS_PESC) ? " PESC" : "", \ - (temp & RH_PS_CSC) ? " CSC" : "", \ + label, num, value, \ + (value & RH_PS_PRSC) ? " PRSC" : "", \ + (value & RH_PS_OCIC) ? " OCIC" : "", \ + (value & RH_PS_PSSC) ? " PSSC" : "", \ + (value & RH_PS_PESC) ? " PESC" : "", \ + (value & RH_PS_CSC) ? " CSC" : "", \ \ - (temp & RH_PS_LSDA) ? " LSDA" : "", \ - (temp & RH_PS_PPS) ? " PPS" : "", \ - (temp & RH_PS_PRS) ? " PRS" : "", \ - (temp & RH_PS_POCI) ? " POCI" : "", \ - (temp & RH_PS_PSS) ? " PSS" : "", \ + (value & RH_PS_LSDA) ? " LSDA" : "", \ + (value & RH_PS_PPS) ? " PPS" : "", \ + (value & RH_PS_PRS) ? " PRS" : "", \ + (value & RH_PS_POCI) ? " POCI" : "", \ + (value & RH_PS_PSS) ? " PSS" : "", \ \ - (temp & RH_PS_PES) ? " PES" : "", \ - (temp & RH_PS_CCS) ? " CCS" : "" \ + (value & RH_PS_PES) ? " PES" : "", \ + (value & RH_PS_CCS) ? " CCS" : "" \ ); /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index b08e385399b9..a4d814b7f380 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -227,8 +227,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) return status; } } else { - dev_err(hcd->self.controller, "can't find phy\n"); - return -ENODEV; + return -EPROBE_DEFER; } ohci->start_hnp = start_hnp; } diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 4e4d601af35c..bcf531c44c70 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -2288,9 +2288,7 @@ restart: while (q.ptr != NULL) { union ehci_shadow temp; - int live; - live = HC_IS_RUNNING(oxu_to_hcd(oxu)->state); switch (type) { case Q_TYPE_QH: /* handle any completions */ diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 74c42f722678..363d125300ea 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -37,10 +37,8 @@ void xhci_dbg_regs(struct xhci_hcd *xhci) &xhci->cap_regs->hc_capbase, temp); xhci_dbg(xhci, "// CAPLENGTH: 0x%x\n", (unsigned int) HC_LENGTH(temp)); -#if 0 xhci_dbg(xhci, "// HCIVERSION: 0x%x\n", (unsigned int) HC_VERSION(temp)); -#endif xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs); @@ -177,7 +175,7 @@ static void xhci_print_ports(struct xhci_hcd *xhci) ports = HCS_MAX_PORTS(xhci->hcs_params1); addr = &xhci->op_regs->port_status_base; for (i = 0; i < ports; i++) { - for (j = 0; j < NUM_PORT_REGS; ++j) { + for (j = 0; j < NUM_PORT_REGS; j++) { xhci_dbg(xhci, "%p port %s reg = 0x%x\n", addr, names[j], (unsigned int) readl(addr)); @@ -240,7 +238,7 @@ void xhci_print_run_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, " %p: Microframe index = 0x%x\n", &xhci->run_regs->microframe_index, (unsigned int) temp); - for (i = 0; i < 7; ++i) { + for (i = 0; i < 7; i++) { temp = readl(&xhci->run_regs->rsvd[i]); if (temp != XHCI_INIT_VALUE) xhci_dbg(xhci, " WARN: %p: Rsvd[%i] = 0x%x\n", @@ -259,7 +257,7 @@ void xhci_print_registers(struct xhci_hcd *xhci) void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb) { int i; - for (i = 0; i < 4; ++i) + for (i = 0; i < 4; i++) xhci_dbg(xhci, "Offset 0x%x = 0x%x\n", i*4, trb->generic.field[i]); } @@ -332,7 +330,7 @@ void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg) u64 addr = seg->dma; union xhci_trb *trb = seg->trbs; - for (i = 0; i < TRBS_PER_SEGMENT; ++i) { + for (i = 0; i < TRBS_PER_SEGMENT; i++) { trb = &seg->trbs[i]; xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr, lower_32_bits(le64_to_cpu(trb->link.segment_ptr)), @@ -413,7 +411,7 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) int i; struct xhci_erst_entry *entry; - for (i = 0; i < erst->num_entries; ++i) { + for (i = 0; i < erst->num_entries; i++) { entry = &erst->entries[i]; xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr, @@ -440,7 +438,7 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma) { int i; - for (i = 0; i < 4; ++i) { + for (i = 0; i < 4; i++) { xhci_dbg(xhci, "@%p (virt) @%08llx " "(dma) %#08llx - rsvd64[%d]\n", &ctx[4 + i], (unsigned long long)dma, @@ -496,7 +494,7 @@ static void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx * &slot_ctx->dev_state, (unsigned long long)dma, slot_ctx->dev_state); dma += field_size; - for (i = 0; i < 4; ++i) { + for (i = 0; i < 4; i++) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &slot_ctx->reserved[i], (unsigned long long)dma, slot_ctx->reserved[i], i); @@ -519,7 +517,7 @@ static void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, if (last_ep < 31) last_ep_ctx = last_ep + 1; - for (i = 0; i < last_ep_ctx; ++i) { + for (i = 0; i < last_ep_ctx; i++) { unsigned int epaddr = xhci_get_endpoint_address(i); struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i); dma_addr_t dma = ctx->dma + @@ -544,7 +542,7 @@ static void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, &ep_ctx->tx_info, (unsigned long long)dma, ep_ctx->tx_info); dma += field_size; - for (j = 0; j < 3; ++j) { + for (j = 0; j < 3; j++) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &ep_ctx->reserved[j], (unsigned long long)dma, @@ -583,7 +581,7 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, &ctrl_ctx->add_flags, (unsigned long long)dma, ctrl_ctx->add_flags); dma += field_size; - for (i = 0; i < 6; ++i) { + for (i = 0; i < 6; i++) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd2[%d]\n", &ctrl_ctx->rsvd2[i], (unsigned long long)dma, ctrl_ctx->rsvd2[i], i); diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index e0244fb3903d..28deea584884 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -117,7 +117,7 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id) offset = XHCI_HCC_EXT_CAPS(val) << 2; if (!offset) return 0; - }; + } do { val = readl(base + offset); if (val == ~0) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 0ef16900efed..3bddeaa1e2d7 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -389,6 +389,8 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) if (!virt_dev) return -ENODEV; + trace_xhci_stop_device(virt_dev); + cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO); if (!cmd) { xhci_dbg(xhci, "Couldn't allocate command structure.\n"); @@ -418,7 +420,8 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) /* Wait for last stop endpoint command to finish */ wait_for_completion(cmd->completion); - if (cmd->status == COMP_CMD_ABORT || cmd->status == COMP_CMD_STOP) { + if (cmd->status == COMP_COMMAND_ABORTED || + cmd->status == COMP_STOPPED) { xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n"); ret = -ETIME; } @@ -458,6 +461,12 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, return; } + if (xhci->quirks & XHCI_BROKEN_PORT_PED) { + xhci_dbg(xhci, + "Broken Port Enabled/Disabled, ignoring port disable request.\n"); + return; + } + /* Write 1 to disable the port */ writel(port_status | PORT_PE, addr); port_status = readl(addr); @@ -990,8 +999,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = readl(port_array[wIndex]); if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) || (temp & PORT_PLS_MASK) >= XDEV_U3) { - xhci_warn(xhci, "USB core suspending device " - "not in U0/U1/U2.\n"); + xhci_warn(xhci, "USB core suspending device not in U0/U1/U2.\n"); goto error; } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8414ed2a02de..ba1853f4e407 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -936,6 +936,9 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) return; dev = xhci->devs[slot_id]; + + trace_xhci_free_virt_device(dev); + xhci->dcbaa->dev_context_ptrs[slot_id] = 0; if (!dev) return; @@ -943,7 +946,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) if (dev->tt_info) old_active_eps = dev->tt_info->active_eps; - for (i = 0; i < 31; ++i) { + for (i = 0; i < 31; i++) { if (dev->eps[i].ring) xhci_ring_free(xhci, dev->eps[i].ring); if (dev->eps[i].stream_info) @@ -1075,6 +1078,8 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, &xhci->dcbaa->dev_context_ptrs[slot_id], le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id])); + trace_xhci_alloc_virt_device(dev); + return 1; fail: xhci_free_virt_device(xhci, slot_id); @@ -1249,6 +1254,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma | dev->eps[0].ring->cycle_state); + trace_xhci_setup_addressable_virt_device(dev); + /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ return 0; @@ -1414,14 +1421,16 @@ static u32 xhci_get_endpoint_type(struct usb_host_endpoint *ep) in = usb_endpoint_dir_in(&ep->desc); - if (usb_endpoint_xfer_control(&ep->desc)) + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: return CTRL_EP; - if (usb_endpoint_xfer_bulk(&ep->desc)) + case USB_ENDPOINT_XFER_BULK: return in ? BULK_IN_EP : BULK_OUT_EP; - if (usb_endpoint_xfer_isoc(&ep->desc)) + case USB_ENDPOINT_XFER_ISOC: return in ? ISOC_IN_EP : ISOC_OUT_EP; - if (usb_endpoint_xfer_int(&ep->desc)) + case USB_ENDPOINT_XFER_INT: return in ? INT_IN_EP : INT_OUT_EP; + } return 0; } @@ -1587,7 +1596,7 @@ void xhci_update_bw_info(struct xhci_hcd *xhci, unsigned int ep_type; int i; - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { bw_info = &virt_dev->eps[i].bw_info; /* We can't tell what endpoint type is being dropped, but @@ -1808,10 +1817,7 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, void xhci_urb_free_priv(struct urb_priv *urb_priv) { - if (urb_priv) { - kfree(urb_priv->td[0]); - kfree(urb_priv); - } + kfree(urb_priv); } void xhci_free_command(struct xhci_hcd *xhci, @@ -2569,9 +2575,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * something other than the default (~1ms minimum between interrupts). * See section 5.5.1.2. */ - for (i = 0; i < MAX_HC_SLOTS; ++i) + for (i = 0; i < MAX_HC_SLOTS; i++) xhci->devs[i] = NULL; - for (i = 0; i < USB_MAXCHILDREN; ++i) { + for (i = 0; i < USB_MAXCHILDREN; i++) { xhci->bus_state[0].resume_done[i] = 0; xhci->bus_state[1].resume_done[i] = 0; /* Only the USB 2.0 completions will ever be used. */ diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index bac961cd24ad..9066ec9e0c2e 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -212,6 +212,12 @@ static int xhci_mtk_clks_enable(struct xhci_hcd_mtk *mtk) { int ret; + ret = clk_prepare_enable(mtk->ref_clk); + if (ret) { + dev_err(mtk->dev, "failed to enable ref_clk\n"); + goto ref_clk_err; + } + ret = clk_prepare_enable(mtk->sys_clk); if (ret) { dev_err(mtk->dev, "failed to enable sys_clk\n"); @@ -238,6 +244,8 @@ usb_p1_err: usb_p0_err: clk_disable_unprepare(mtk->sys_clk); sys_clk_err: + clk_disable_unprepare(mtk->ref_clk); +ref_clk_err: return -EINVAL; } @@ -248,6 +256,7 @@ static void xhci_mtk_clks_disable(struct xhci_hcd_mtk *mtk) clk_disable_unprepare(mtk->wk_deb_p0); } clk_disable_unprepare(mtk->sys_clk); + clk_disable_unprepare(mtk->ref_clk); } /* only clocks can be turn off for ip-sleep wakeup mode */ @@ -550,6 +559,19 @@ static int xhci_mtk_probe(struct platform_device *pdev) return PTR_ERR(mtk->sys_clk); } + /* + * reference clock is usually a "fixed-clock", make it optional + * for backward compatibility and ignore the error if it does + * not exist. + */ + mtk->ref_clk = devm_clk_get(dev, "ref_ck"); + if (IS_ERR(mtk->ref_clk)) { + if (PTR_ERR(mtk->ref_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + mtk->ref_clk = NULL; + } + mtk->lpm_support = of_property_read_bool(node, "usb3-lpm-capable"); ret = usb_wakeup_of_property_parse(mtk, node); diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index 2845c49efe1b..3aa5e1d25064 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -124,6 +124,7 @@ struct xhci_hcd_mtk { struct regulator *vusb33; struct regulator *vbus; struct clk *sys_clk; /* sys and mac clock */ + struct clk *ref_clk; struct clk *wk_deb_p0; /* port0's wakeup debounce clock */ struct clk *wk_deb_p1; struct regmap *pericfg; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 954abfd5014d..fc99f51d12e1 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -242,11 +242,7 @@ static int xhci_pci_setup(struct usb_hcd *hcd) xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); /* Find any debug ports */ - retval = xhci_pci_reinit(xhci, pdev); - if (!retval) - return retval; - - return retval; + return xhci_pci_reinit(xhci, pdev); } /* diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index e5834dd9bcde..6d33b42ffcf5 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -232,8 +232,8 @@ static int xhci_plat_probe(struct platform_device *pdev) if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable")) xhci->quirks |= XHCI_LPM_SUPPORT; - if (HCC_MAX_PSA(xhci->hcc_params) >= 4) - xhci->shared_hcd->can_do_streams = 1; + if (device_property_read_bool(&pdev->dev, "quirk-broken-port-ped")) + xhci->quirks |= XHCI_BROKEN_PORT_PED; hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); if (IS_ERR(hcd->usb_phy)) { @@ -251,6 +251,9 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) goto disable_usb_phy; + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) + xhci->shared_hcd->can_do_streams = 1; + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); if (ret) goto dealloc_usb2_hcd; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index e32029a31ca4..d9936c771fa0 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -119,14 +119,29 @@ static bool last_td_in_urb(struct xhci_td *td) { struct urb_priv *urb_priv = td->urb->hcpriv; - return urb_priv->td_cnt == urb_priv->length; + return urb_priv->num_tds_done == urb_priv->num_tds; } static void inc_td_cnt(struct urb *urb) { struct urb_priv *urb_priv = urb->hcpriv; - urb_priv->td_cnt++; + urb_priv->num_tds_done++; +} + +static void trb_to_noop(union xhci_trb *trb, u32 noop_type) +{ + if (trb_is_link(trb)) { + /* unchain chained link TRBs */ + trb->link.control &= cpu_to_le32(~TRB_CHAIN); + } else { + trb->generic.field[0] = 0; + trb->generic.field[1] = 0; + trb->generic.field[2] = 0; + /* Preserve only the cycle bit of this TRB */ + trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE); + trb->generic.field[3] |= cpu_to_le32(TRB_TYPE(noop_type)); + } } /* Updates trb to point to the next TRB in the ring, and updates seg if the next @@ -299,27 +314,19 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci, struct xhci_command *cur_cmd) { struct xhci_command *i_cmd; - u32 cycle_state; /* Turn all aborted commands in list to no-ops, then restart */ list_for_each_entry(i_cmd, &xhci->cmd_list, cmd_list) { - if (i_cmd->status != COMP_CMD_ABORT) + if (i_cmd->status != COMP_COMMAND_ABORTED) continue; - i_cmd->status = COMP_CMD_STOP; + i_cmd->status = COMP_STOPPED; xhci_dbg(xhci, "Turn aborted command %p to no-op\n", i_cmd->command_trb); - /* get cycle state from the original cmd trb */ - cycle_state = le32_to_cpu( - i_cmd->command_trb->generic.field[3]) & TRB_CYCLE; - /* modify the command trb to no-op command */ - i_cmd->command_trb->generic.field[0] = 0; - i_cmd->command_trb->generic.field[1] = 0; - i_cmd->command_trb->generic.field[2] = 0; - i_cmd->command_trb->generic.field[3] = cpu_to_le32( - TRB_TYPE(TRB_CMD_NOOP) | cycle_state); + + trb_to_noop(i_cmd->command_trb, TRB_CMD_NOOP); /* * caller waiting for completion is called when command @@ -362,19 +369,11 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags) ret = xhci_handshake(&xhci->op_regs->cmd_ring, CMD_RING_RUNNING, 0, 5 * 1000 * 1000); if (ret < 0) { - /* we are about to kill xhci, give it one more chance */ - xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, - &xhci->op_regs->cmd_ring); - udelay(1000); - ret = xhci_handshake(&xhci->op_regs->cmd_ring, - CMD_RING_RUNNING, 0, 3 * 1000 * 1000); - if (ret < 0) { - xhci_err(xhci, "Stopped the command ring failed, " - "maybe the host is dead\n"); - xhci->xhc_state |= XHCI_STATE_DYING; - xhci_halt(xhci); - return -ESHUTDOWN; - } + xhci_err(xhci, + "Stop command ring failed, maybe the host is dead\n"); + xhci->xhc_state |= XHCI_STATE_DYING; + xhci_halt(xhci); + return -ESHUTDOWN; } /* * Writing the CMD_RING_ABORT bit should cause a cmd completion event, @@ -410,7 +409,7 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, * pointer command pending because the device can choose to start any * stream once the endpoint is on the HW schedule. */ - if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) || + if ((ep_state & EP_STOP_CMD_PENDING) || (ep_state & SET_DEQ_PENDING) || (ep_state & EP_HALTED)) return; writel(DB_VALUE(ep_index, stream_id), db_addr); @@ -600,18 +599,8 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, union xhci_trb *trb = td->first_trb; while (1) { - if (trb_is_link(trb)) { - /* unchain chained link TRBs */ - trb->link.control &= cpu_to_le32(~TRB_CHAIN); - } else { - trb->generic.field[0] = 0; - trb->generic.field[1] = 0; - trb->generic.field[2] = 0; - /* Preserve only the cycle bit of this TRB */ - trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE); - trb->generic.field[3] |= cpu_to_le32( - TRB_TYPE(TRB_TR_NOOP)); - } + trb_to_noop(trb, TRB_TR_NOOP); + /* flip cycle if asked to */ if (flip_cycle && trb != td->first_trb && trb != td->last_trb) trb->generic.field[3] ^= cpu_to_le32(TRB_CYCLE); @@ -626,13 +615,9 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci, struct xhci_virt_ep *ep) { - ep->ep_state &= ~EP_HALT_PENDING; - /* Can't del_timer_sync in interrupt, so we attempt to cancel. If the - * timer is running on another CPU, we don't decrement stop_cmds_pending - * (since we didn't successfully stop the watchdog timer). - */ - if (del_timer(&ep->stop_cmd_timer)) - ep->stop_cmds_pending--; + ep->ep_state &= ~EP_STOP_CMD_PENDING; + /* Can't del_timer_sync in interrupt */ + del_timer(&ep->stop_cmd_timer); } /* @@ -657,6 +642,7 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&xhci->lock); usb_hcd_giveback_urb(hcd, urb, status); + trace_xhci_urb_giveback(urb); spin_lock(&xhci->lock); } @@ -667,7 +653,7 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, struct xhci_segment *seg = td->bounce_seg; struct urb *urb = td->urb; - if (!seg || !urb) + if (!ring || !seg || !urb) return; if (usb_urb_dir_out(urb)) { @@ -701,7 +687,6 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index; struct xhci_ring *ep_ring; struct xhci_virt_ep *ep; - struct list_head *entry; struct xhci_td *cur_td = NULL; struct xhci_td *last_unlinked_td; @@ -718,6 +703,8 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, memset(&deq_state, 0, sizeof(deq_state)); ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); ep = &xhci->devs[slot_id]->eps[ep_index]; + last_unlinked_td = list_last_entry(&ep->cancelled_td_list, + struct xhci_td, cancelled_td_list); if (list_empty(&ep->cancelled_td_list)) { xhci_stop_watchdog_timer_in_irq(xhci, ep); @@ -731,8 +718,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, * it. We're also in the event handler, so we can't get re-interrupted * if another Stop Endpoint command completes */ - list_for_each(entry, &ep->cancelled_td_list) { - cur_td = list_entry(entry, struct xhci_td, cancelled_td_list); + list_for_each_entry(cur_td, &ep->cancelled_td_list, cancelled_td_list) { xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Removing canceled TD starting at 0x%llx (dma).", (unsigned long long)xhci_trb_virt_to_dma( @@ -774,7 +760,7 @@ remove_finished_td: */ list_del_init(&cur_td->td_list); } - last_unlinked_td = cur_td; + xhci_stop_watchdog_timer_in_irq(xhci, ep); /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ @@ -796,7 +782,7 @@ remove_finished_td: * So stop when we've completed the URB for the last TD we unlinked. */ do { - cur_td = list_entry(ep->cancelled_td_list.next, + cur_td = list_first_entry(&ep->cancelled_td_list, struct xhci_td, cancelled_td_list); list_del_init(&cur_td->cancelled_td_list); @@ -805,8 +791,7 @@ remove_finished_td: * just overwrite it (because the URB has been unlinked). */ ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb); - if (ep_ring && cur_td->bounce_seg) - xhci_unmap_td_bounce_buffer(xhci, ep_ring, cur_td); + xhci_unmap_td_bounce_buffer(xhci, ep_ring, cur_td); inc_td_cnt(cur_td->urb); if (last_td_in_urb(cur_td)) xhci_giveback_urb_in_irq(xhci, cur_td, 0); @@ -824,16 +809,15 @@ remove_finished_td: static void xhci_kill_ring_urbs(struct xhci_hcd *xhci, struct xhci_ring *ring) { struct xhci_td *cur_td; + struct xhci_td *tmp; - while (!list_empty(&ring->td_list)) { - cur_td = list_first_entry(&ring->td_list, - struct xhci_td, td_list); + list_for_each_entry_safe(cur_td, tmp, &ring->td_list, td_list) { list_del_init(&cur_td->td_list); + if (!list_empty(&cur_td->cancelled_td_list)) list_del_init(&cur_td->cancelled_td_list); - if (cur_td->bounce_seg) - xhci_unmap_td_bounce_buffer(xhci, ring, cur_td); + xhci_unmap_td_bounce_buffer(xhci, ring, cur_td); inc_td_cnt(cur_td->urb); if (last_td_in_urb(cur_td)) @@ -845,6 +829,7 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, int slot_id, int ep_index) { struct xhci_td *cur_td; + struct xhci_td *tmp; struct xhci_virt_ep *ep; struct xhci_ring *ring; @@ -870,12 +855,12 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, slot_id, ep_index); xhci_kill_ring_urbs(xhci, ring); } - while (!list_empty(&ep->cancelled_td_list)) { - cur_td = list_first_entry(&ep->cancelled_td_list, - struct xhci_td, cancelled_td_list); - list_del_init(&cur_td->cancelled_td_list); + list_for_each_entry_safe(cur_td, tmp, &ep->cancelled_td_list, + cancelled_td_list) { + list_del_init(&cur_td->cancelled_td_list); inc_td_cnt(cur_td->urb); + if (last_td_in_urb(cur_td)) xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN); } @@ -895,10 +880,8 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, * simple flag to say whether there is a pending stop endpoint command for a * particular endpoint. * - * Instead we use a combination of that flag and a counter for the number of - * pending stop endpoint commands. If the timer is the tail end of the last - * stop endpoint command, and the endpoint's command is still pending, we assume - * the host is dying. + * Instead we use a combination of that flag and checking if a new timer is + * pending. */ void xhci_stop_endpoint_command_watchdog(unsigned long arg) { @@ -912,12 +895,11 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) spin_lock_irqsave(&xhci->lock, flags); - ep->stop_cmds_pending--; - if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { - xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, - "Stop EP timer ran, but no command pending, " - "exiting."); + /* bail out if cmd completed but raced with stop ep watchdog timer.*/ + if (!(ep->ep_state & EP_STOP_CMD_PENDING) || + timer_pending(&ep->stop_cmd_timer)) { spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "Stop EP timer raced with cmd completion, exit"); return; } @@ -926,7 +908,10 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) /* Oops, HC is dead or dying or at least not responding to the stop * endpoint command. */ + xhci->xhc_state |= XHCI_STATE_DYING; + ep->ep_state &= ~EP_STOP_CMD_PENDING; + /* Disable interrupts from the host controller and start halting it */ xhci_quiesce(xhci); spin_unlock_irqrestore(&xhci->lock, flags); @@ -1050,10 +1035,10 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, unsigned int slot_state; switch (cmd_comp_code) { - case COMP_TRB_ERR: + case COMP_TRB_ERROR: xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because of stream ID configuration\n"); break; - case COMP_CTX_STATE: + case COMP_CONTEXT_STATE_ERROR: xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due to incorrect slot or ep state.\n"); ep_state = GET_EP_CTX_STATE(ep_ctx); slot_state = le32_to_cpu(slot_ctx->dev_state); @@ -1062,7 +1047,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, "Slot state = %u, EP state = %u", slot_state, ep_state); break; - case COMP_EBADSLT: + case COMP_SLOT_NOT_ENABLED_ERROR: xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because slot %u was not enabled.\n", slot_id); break; @@ -1259,7 +1244,7 @@ void xhci_cleanup_command_queue(struct xhci_hcd *xhci) { struct xhci_command *cur_cmd, *tmp_cmd; list_for_each_entry_safe(cur_cmd, tmp_cmd, &xhci->cmd_list, cmd_list) - xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT); + xhci_complete_del_and_free_cmd(cur_cmd, COMP_COMMAND_ABORTED); } void xhci_handle_command_timeout(struct work_struct *work) @@ -1282,7 +1267,7 @@ void xhci_handle_command_timeout(struct work_struct *work) return; } /* mark this command to be cancelled */ - xhci->current_cmd->status = COMP_CMD_ABORT; + xhci->current_cmd->status = COMP_COMMAND_ABORTED; /* Make sure command ring is running before aborting it */ hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); @@ -1335,6 +1320,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, cmd_dma = le64_to_cpu(event->cmd_trb); cmd_trb = xhci->cmd_ring->dequeue; + + trace_xhci_handle_command(xhci->cmd_ring, &cmd_trb->generic); + cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, cmd_trb); /* @@ -1347,16 +1335,14 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, return; } - cmd = list_entry(xhci->cmd_list.next, struct xhci_command, cmd_list); + cmd = list_first_entry(&xhci->cmd_list, struct xhci_command, cmd_list); cancel_delayed_work(&xhci->cmd_timer); - trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event); - cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status)); /* If CMD ring stopped we own the trbs between enqueue and dequeue */ - if (cmd_comp_code == COMP_CMD_STOP) { + if (cmd_comp_code == COMP_STOPPED) { complete_all(&xhci->cmd_ring_stop_completion); return; } @@ -1373,9 +1359,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, * The command ring is stopped now, but the xHC will issue a Command * Ring Stopped event which will cause us to restart it. */ - if (cmd_comp_code == COMP_CMD_ABORT) { + if (cmd_comp_code == COMP_COMMAND_ABORTED) { xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; - if (cmd->status == COMP_CMD_ABORT) { + if (cmd->status == COMP_COMMAND_ABORTED) { if (xhci->current_cmd == cmd) xhci->current_cmd = NULL; goto event_handled; @@ -1411,8 +1397,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, break; case TRB_CMD_NOOP: /* Is this an aborted command turned to NO-OP? */ - if (cmd->status == COMP_CMD_STOP) - cmd_comp_code = COMP_CMD_STOP; + if (cmd->status == COMP_STOPPED) + cmd_comp_code = COMP_STOPPED; break; case TRB_RESET_EP: WARN_ON(slot_id != TRB_TO_SLOT_ID( @@ -1437,9 +1423,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, } /* restart timer if this wasn't the last command */ - if (cmd->cmd_list.next != &xhci->cmd_list) { - xhci->current_cmd = list_entry(cmd->cmd_list.next, - struct xhci_command, cmd_list); + if (!list_is_singular(&xhci->cmd_list)) { + xhci->current_cmd = list_first_entry(&cmd->cmd_list, + struct xhci_command, cmd_list); xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); } else if (xhci->current_cmd == cmd) { xhci->current_cmd = NULL; @@ -1805,9 +1791,9 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci, unsigned int trb_comp_code) { /* TRB completion codes that may require a manual halt cleanup */ - if (trb_comp_code == COMP_TX_ERR || - trb_comp_code == COMP_BABBLE || - trb_comp_code == COMP_SPLIT_ERR) + if (trb_comp_code == COMP_USB_TRANSACTION_ERROR || + trb_comp_code == COMP_BABBLE_DETECTED_ERROR || + trb_comp_code == COMP_SPLIT_TRANSACTION_ERROR) /* The 0.95 spec says a babbling control endpoint * is not halted. The 0.96 spec says it is. Some HW * claims to be 0.95 compliant, but it halts the control @@ -1834,22 +1820,64 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code) return 0; } -/* - * Finish the td processing, remove the td from td list; - * Return 1 if the urb can be given back. - */ +static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, + struct xhci_ring *ep_ring, int *status) +{ + struct urb_priv *urb_priv; + struct urb *urb = NULL; + + /* Clean up the endpoint's TD list */ + urb = td->urb; + urb_priv = urb->hcpriv; + + /* if a bounce buffer was used to align this td then unmap it */ + xhci_unmap_td_bounce_buffer(xhci, ep_ring, td); + + /* Do one last check of the actual transfer length. + * If the host controller said we transferred more data than the buffer + * length, urb->actual_length will be a very big number (since it's + * unsigned). Play it safe and say we didn't transfer anything. + */ + if (urb->actual_length > urb->transfer_buffer_length) { + xhci_warn(xhci, "URB req %u and actual %u transfer length mismatch\n", + urb->transfer_buffer_length, urb->actual_length); + urb->actual_length = 0; + *status = 0; + } + list_del_init(&td->td_list); + /* Was this TD slated to be cancelled but completed anyway? */ + if (!list_empty(&td->cancelled_td_list)) + list_del_init(&td->cancelled_td_list); + + inc_td_cnt(urb); + /* Giveback the urb when all the tds are completed */ + if (last_td_in_urb(td)) { + if ((urb->actual_length != urb->transfer_buffer_length && + (urb->transfer_flags & URB_SHORT_NOT_OK)) || + (*status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) + xhci_dbg(xhci, "Giveback URB %p, len = %d, expected = %d, status = %d\n", + urb, urb->actual_length, + urb->transfer_buffer_length, *status); + + /* set isoc urb status to 0 just as EHCI, UHCI, and OHCI */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + *status = 0; + xhci_giveback_urb_in_irq(xhci, td, *status); + } + + return 0; +} + static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, union xhci_trb *ep_trb, struct xhci_transfer_event *event, struct xhci_virt_ep *ep, int *status, bool skip) { struct xhci_virt_device *xdev; + struct xhci_ep_ctx *ep_ctx; struct xhci_ring *ep_ring; unsigned int slot_id; - int ep_index; - struct urb *urb = NULL; - struct xhci_ep_ctx *ep_ctx; - struct urb_priv *urb_priv; u32 trb_comp_code; + int ep_index; slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); xdev = xhci->devs[slot_id]; @@ -1861,9 +1889,9 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, if (skip) goto td_cleanup; - if (trb_comp_code == COMP_STOP_INVAL || - trb_comp_code == COMP_STOP || - trb_comp_code == COMP_STOP_SHORT) { + if (trb_comp_code == COMP_STOPPED_LENGTH_INVALID || + trb_comp_code == COMP_STOPPED || + trb_comp_code == COMP_STOPPED_SHORT_PACKET) { /* The Endpoint Stop Command completion will take care of any * stopped TDs. A stopped TD may be restarted, so don't update * the ring dequeue pointer or take this TD off any lists yet. @@ -1871,7 +1899,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, ep->stopped_td = td; return 0; } - if (trb_comp_code == COMP_STALL || + if (trb_comp_code == COMP_STALL_ERROR || xhci_requires_manual_halt_cleanup(xhci, ep_ctx, trb_comp_code)) { /* Issue a reset endpoint command to clear the host side @@ -1889,46 +1917,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, } td_cleanup: - /* Clean up the endpoint's TD list */ - urb = td->urb; - urb_priv = urb->hcpriv; - - /* if a bounce buffer was used to align this td then unmap it */ - if (td->bounce_seg) - xhci_unmap_td_bounce_buffer(xhci, ep_ring, td); - - /* Do one last check of the actual transfer length. - * If the host controller said we transferred more data than the buffer - * length, urb->actual_length will be a very big number (since it's - * unsigned). Play it safe and say we didn't transfer anything. - */ - if (urb->actual_length > urb->transfer_buffer_length) { - xhci_warn(xhci, "URB req %u and actual %u transfer length mismatch\n", - urb->transfer_buffer_length, urb->actual_length); - urb->actual_length = 0; - *status = 0; - } - list_del_init(&td->td_list); - /* Was this TD slated to be cancelled but completed anyway? */ - if (!list_empty(&td->cancelled_td_list)) - list_del_init(&td->cancelled_td_list); - - inc_td_cnt(urb); - /* Giveback the urb when all the tds are completed */ - if (last_td_in_urb(td)) { - if ((urb->actual_length != urb->transfer_buffer_length && - (urb->transfer_flags & URB_SHORT_NOT_OK)) || - (*status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) - xhci_dbg(xhci, "Giveback URB %p, len = %d, expected = %d, status = %d\n", - urb, urb->actual_length, - urb->transfer_buffer_length, *status); - - /* set isoc urb status to 0 just as EHCI, UHCI, and OHCI */ - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) - *status = 0; - xhci_giveback_urb_in_irq(xhci, td, *status); - } - return 0; + return xhci_td_cleanup(xhci, td, ep_ring, status); } /* sum trb lengths from ring dequeue up to stop_trb, _excluding_ stop_trb */ @@ -1982,16 +1971,16 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, } *status = 0; break; - case COMP_SHORT_TX: + case COMP_SHORT_PACKET: *status = 0; break; - case COMP_STOP_SHORT: + case COMP_STOPPED_SHORT_PACKET: if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) td->urb->actual_length = remaining; else xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n"); goto finish_td; - case COMP_STOP: + case COMP_STOPPED: switch (trb_type) { case TRB_SETUP: td->urb->actual_length = 0; @@ -2005,7 +1994,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, trb_type); goto finish_td; } - case COMP_STOP_INVAL: + case COMP_STOPPED_LENGTH_INVALID: goto finish_td; default: if (!xhci_requires_manual_halt_cleanup(xhci, @@ -2014,7 +2003,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, xhci_dbg(xhci, "TRB error %u, halted endpoint index = %u\n", trb_comp_code, ep_index); /* else fall through */ - case COMP_STALL: + case COMP_STALL_ERROR: /* Did we transfer part of the data (middle) phase? */ if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) td->urb->actual_length = requested - remaining; @@ -2066,7 +2055,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); urb_priv = td->urb->hcpriv; - idx = urb_priv->td_cnt; + idx = urb_priv->num_tds_done; frame = &td->urb->iso_frame_desc[idx]; requested = frame->length; remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); @@ -2085,35 +2074,35 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, } frame->status = 0; break; - case COMP_SHORT_TX: + case COMP_SHORT_PACKET: frame->status = short_framestatus; sum_trbs_for_length = true; break; - case COMP_BW_OVER: + case COMP_BANDWIDTH_OVERRUN_ERROR: frame->status = -ECOMM; break; - case COMP_BUFF_OVER: - case COMP_BABBLE: + case COMP_ISOCH_BUFFER_OVERRUN: + case COMP_BABBLE_DETECTED_ERROR: frame->status = -EOVERFLOW; break; - case COMP_DEV_ERR: - case COMP_STALL: + case COMP_INCOMPATIBLE_DEVICE_ERROR: + case COMP_STALL_ERROR: frame->status = -EPROTO; break; - case COMP_TX_ERR: + case COMP_USB_TRANSACTION_ERROR: frame->status = -EPROTO; if (ep_trb != td->last_trb) return 0; break; - case COMP_STOP: + case COMP_STOPPED: sum_trbs_for_length = true; break; - case COMP_STOP_SHORT: + case COMP_STOPPED_SHORT_PACKET: /* field normally containing residue now contains tranferred */ frame->status = short_framestatus; requested = remaining; break; - case COMP_STOP_INVAL: + case COMP_STOPPED_LENGTH_INVALID: requested = 0; remaining = 0; break; @@ -2145,7 +2134,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); urb_priv = td->urb->hcpriv; - idx = urb_priv->td_cnt; + idx = urb_priv->num_tds_done; frame = &td->urb->iso_frame_desc[idx]; /* The transfer is partly done. */ @@ -2190,16 +2179,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, } *status = 0; break; - case COMP_SHORT_TX: + case COMP_SHORT_PACKET: xhci_dbg(xhci, "ep %#x - asked for %d bytes, %d bytes untransferred\n", td->urb->ep->desc.bEndpointAddress, requested, remaining); *status = 0; break; - case COMP_STOP_SHORT: + case COMP_STOPPED_SHORT_PACKET: td->urb->actual_length = remaining; goto finish_td; - case COMP_STOP_INVAL: + case COMP_STOPPED_LENGTH_INVALID: /* stopped on ep trb with invalid length, exclude it */ ep_trb_len = 0; remaining = 0; @@ -2231,8 +2220,6 @@ finish_td: */ static int handle_tx_event(struct xhci_hcd *xhci, struct xhci_transfer_event *event) - __releases(&xhci->lock) - __acquires(&xhci->lock) { struct xhci_virt_device *xdev; struct xhci_virt_ep *ep; @@ -2305,50 +2292,50 @@ static int handle_tx_event(struct xhci_hcd *xhci, if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) break; if (xhci->quirks & XHCI_TRUST_TX_LENGTH) - trb_comp_code = COMP_SHORT_TX; + trb_comp_code = COMP_SHORT_PACKET; else xhci_warn_ratelimited(xhci, "WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk?\n"); - case COMP_SHORT_TX: + case COMP_SHORT_PACKET: break; - case COMP_STOP: + case COMP_STOPPED: xhci_dbg(xhci, "Stopped on Transfer TRB\n"); break; - case COMP_STOP_INVAL: + case COMP_STOPPED_LENGTH_INVALID: xhci_dbg(xhci, "Stopped on No-op or Link TRB\n"); break; - case COMP_STOP_SHORT: + case COMP_STOPPED_SHORT_PACKET: xhci_dbg(xhci, "Stopped with short packet transfer detected\n"); break; - case COMP_STALL: + case COMP_STALL_ERROR: xhci_dbg(xhci, "Stalled endpoint\n"); ep->ep_state |= EP_HALTED; status = -EPIPE; break; - case COMP_TRB_ERR: + case COMP_TRB_ERROR: xhci_warn(xhci, "WARN: TRB error on endpoint\n"); status = -EILSEQ; break; - case COMP_SPLIT_ERR: - case COMP_TX_ERR: + case COMP_SPLIT_TRANSACTION_ERROR: + case COMP_USB_TRANSACTION_ERROR: xhci_dbg(xhci, "Transfer error on endpoint\n"); status = -EPROTO; break; - case COMP_BABBLE: + case COMP_BABBLE_DETECTED_ERROR: xhci_dbg(xhci, "Babble error on endpoint\n"); status = -EOVERFLOW; break; - case COMP_DB_ERR: + case COMP_DATA_BUFFER_ERROR: xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n"); status = -ENOSR; break; - case COMP_BW_OVER: + case COMP_BANDWIDTH_OVERRUN_ERROR: xhci_warn(xhci, "WARN: bandwidth overrun event on endpoint\n"); break; - case COMP_BUFF_OVER: + case COMP_ISOCH_BUFFER_OVERRUN: xhci_warn(xhci, "WARN: buffer overrun event on endpoint\n"); break; - case COMP_UNDERRUN: + case COMP_RING_UNDERRUN: /* * When the Isoch ring is empty, the xHC will generate * a Ring Overrun Event for IN Isoch endpoint or Ring @@ -2361,7 +2348,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); goto cleanup; - case COMP_OVERRUN: + case COMP_RING_OVERRUN: xhci_dbg(xhci, "overrun event on endpoint\n"); if (!list_empty(&ep_ring->td_list)) xhci_dbg(xhci, "Overrun Event for slot %d ep %d " @@ -2369,11 +2356,11 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); goto cleanup; - case COMP_DEV_ERR: + case COMP_INCOMPATIBLE_DEVICE_ERROR: xhci_warn(xhci, "WARN: detect an incompatible device"); status = -EPROTO; break; - case COMP_MISSED_INT: + case COMP_MISSED_SERVICE_ERROR: /* * When encounter missed service error, one or more isoc tds * may be missed by xHC. @@ -2383,7 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep->skip = true; xhci_dbg(xhci, "Miss service interval error, set skip flag\n"); goto cleanup; - case COMP_PING_ERR: + case COMP_NO_PING_RESPONSE_ERROR: ep->skip = true; xhci_dbg(xhci, "No Ping response error, Skip one Isoc TD\n"); goto cleanup; @@ -2407,8 +2394,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, * event if the device was suspended. Don't print * warnings. */ - if (!(trb_comp_code == COMP_STOP || - trb_comp_code == COMP_STOP_INVAL)) { + if (!(trb_comp_code == COMP_STOPPED || + trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) { xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); @@ -2433,7 +2420,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, goto cleanup; } - td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); + td = list_first_entry(&ep_ring->td_list, struct xhci_td, + td_list); if (ep->skip) td_num--; @@ -2449,8 +2437,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, * last TRB of the previous TD. The command completion handle * will take care the rest. */ - if (!ep_seg && (trb_comp_code == COMP_STOP || - trb_comp_code == COMP_STOP_INVAL)) { + if (!ep_seg && (trb_comp_code == COMP_STOPPED || + trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) { goto cleanup; } @@ -2481,7 +2469,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, skip_isoc_td(xhci, td, event, ep, &status); goto cleanup; } - if (trb_comp_code == COMP_SHORT_TX) + if (trb_comp_code == COMP_SHORT_PACKET) ep_ring->last_td_was_short = true; else ep_ring->last_td_was_short = false; @@ -2493,6 +2481,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)]; + + trace_xhci_handle_transfer(ep_ring, + (struct xhci_generic_trb *) ep_trb); + /* * No-op TRB should not trigger interrupts. * If ep_trb is a no-op TRB, it means the @@ -2514,8 +2506,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, &status); cleanup: handling_skipped_tds = ep->skip && - trb_comp_code != COMP_MISSED_INT && - trb_comp_code != COMP_PING_ERR; + trb_comp_code != COMP_MISSED_SERVICE_ERROR && + trb_comp_code != COMP_NO_PING_RESPONSE_ERROR; /* * Do not update event ring dequeue pointer if we're in a loop @@ -2559,6 +2551,8 @@ static int xhci_handle_event(struct xhci_hcd *xhci) xhci->event_ring->cycle_state) return 0; + trace_xhci_handle_event(xhci->event_ring, &event->generic); + /* * Barrier between reading the TRB_CYCLE (valid) flag above and any * speculative reads of the event's flags/data below. @@ -2617,27 +2611,28 @@ static int xhci_handle_event(struct xhci_hcd *xhci) irqreturn_t xhci_irq(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - u32 status; - u64 temp_64; union xhci_trb *event_ring_deq; + irqreturn_t ret = IRQ_NONE; dma_addr_t deq; + u64 temp_64; + u32 status; spin_lock(&xhci->lock); /* Check if the xHC generated the interrupt, or the irq is shared */ status = readl(&xhci->op_regs->status); - if (status == 0xffffffff) - goto hw_died; - - if (!(status & STS_EINT)) { - spin_unlock(&xhci->lock); - return IRQ_NONE; + if (status == 0xffffffff) { + ret = IRQ_HANDLED; + goto out; } + + if (!(status & STS_EINT)) + goto out; + if (status & STS_FATAL) { xhci_warn(xhci, "WARNING: Host System Error\n"); xhci_halt(xhci); -hw_died: - spin_unlock(&xhci->lock); - return IRQ_HANDLED; + ret = IRQ_HANDLED; + goto out; } /* @@ -2668,9 +2663,8 @@ hw_died: temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue); - spin_unlock(&xhci->lock); - - return IRQ_HANDLED; + ret = IRQ_HANDLED; + goto out; } event_ring_deq = xhci->event_ring->dequeue; @@ -2695,10 +2689,12 @@ hw_died: /* Clear the event handler busy flag (RW1C); event ring is empty. */ temp_64 |= ERST_EHB; xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue); + ret = IRQ_HANDLED; +out: spin_unlock(&xhci->lock); - return IRQ_HANDLED; + return ret; } irqreturn_t xhci_msi_irq(int irq, void *hcd) @@ -2726,6 +2722,9 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, trb->field[1] = cpu_to_le32(field2); trb->field[2] = cpu_to_le32(field3); trb->field[3] = cpu_to_le32(field4); + + trace_xhci_queue_trb(ring, trb); + inc_enq(xhci, ring, more_trbs_coming); } @@ -2839,7 +2838,7 @@ static int prepare_transfer(struct xhci_hcd *xhci, return ret; urb_priv = urb->hcpriv; - td = urb_priv->td[td_index]; + td = &urb_priv->td[td_index]; INIT_LIST_HEAD(&td->td_list); INIT_LIST_HEAD(&td->cancelled_td_list); @@ -2856,8 +2855,6 @@ static int prepare_transfer(struct xhci_hcd *xhci, td->start_seg = ep_ring->enq_seg; td->first_trb = ep_ring->enqueue; - urb_priv->td[td_index] = td; - return 0; } @@ -3134,10 +3131,10 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, urb_priv = urb->hcpriv; /* Deal with URB_ZERO_PACKET - need one more td/trb */ - if (urb->transfer_flags & URB_ZERO_PACKET && urb_priv->length > 1) + if (urb->transfer_flags & URB_ZERO_PACKET && urb_priv->num_tds > 1) need_zero_pkt = true; - td = urb_priv->td[0]; + td = &urb_priv->td[0]; /* * Don't give the first TRB to the hardware (by toggling the cycle bit) @@ -3230,7 +3227,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, 1, urb, 1, mem_flags); - urb_priv->td[1]->last_trb = ring->enqueue; + urb_priv->td[1].last_trb = ring->enqueue; field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC; queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field); } @@ -3251,7 +3248,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct usb_ctrlrequest *setup; struct xhci_generic_trb *start_trb; int start_cycle; - u32 field, length_field, remainder; + u32 field; struct urb_priv *urb_priv; struct xhci_td *td; @@ -3282,7 +3279,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return ret; urb_priv = urb->hcpriv; - td = urb_priv->td[0]; + td = &urb_priv->td[0]; /* * Don't give the first TRB to the hardware (by toggling the cycle bit) @@ -3324,16 +3321,16 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, else field = TRB_TYPE(TRB_DATA); - remainder = xhci_td_remainder(xhci, 0, - urb->transfer_buffer_length, - urb->transfer_buffer_length, - urb, 1); - - length_field = TRB_LEN(urb->transfer_buffer_length) | - TRB_TD_SIZE(remainder) | - TRB_INTR_TARGET(0); - if (urb->transfer_buffer_length > 0) { + u32 length_field, remainder; + + remainder = xhci_td_remainder(xhci, 0, + urb->transfer_buffer_length, + urb->transfer_buffer_length, + urb, 1); + length_field = TRB_LEN(urb->transfer_buffer_length) | + TRB_TD_SIZE(remainder) | + TRB_INTR_TARGET(0); if (setup->bRequestType & USB_DIR_IN) field |= TRB_DIR_IN; queue_trb(xhci, ep_ring, true, @@ -3570,7 +3567,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return ret; goto cleanup; } - td = urb_priv->td[i]; + td = &urb_priv->td[i]; /* use SIA as default, if frame id is used overwrite it */ sia_frame_id = TRB_SIA; @@ -3677,20 +3674,20 @@ cleanup: /* Clean up a partially enqueued isoc transfer. */ for (i--; i >= 0; i--) - list_del_init(&urb_priv->td[i]->td_list); + list_del_init(&urb_priv->td[i].td_list); /* Use the first TD as a temporary variable to turn the TDs we've queued * into No-ops with a software-owned cycle bit. That way the hardware * won't accidentally start executing bogus TDs when we partially * overwrite them. td->first_trb and td->start_seg are already set. */ - urb_priv->td[0]->last_trb = ep_ring->enqueue; + urb_priv->td[0].last_trb = ep_ring->enqueue; /* Every TRB except the first & last will have its cycle bit flipped. */ - td_to_noop(xhci, ep_ring, urb_priv->td[0], true); + td_to_noop(xhci, ep_ring, &urb_priv->td[0], true); /* Reset the ring enqueue back to the first TRB and its cycle bit. */ - ep_ring->enqueue = urb_priv->td[0]->first_trb; - ep_ring->enq_seg = urb_priv->td[0]->start_seg; + ep_ring->enqueue = urb_priv->td[0].first_trb; + ep_ring->enq_seg = urb_priv->td[0].start_seg; ep_ring->cycle_state = start_cycle; ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp; usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); @@ -3816,15 +3813,15 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, } cmd->command_trb = xhci->cmd_ring->enqueue; - list_add_tail(&cmd->cmd_list, &xhci->cmd_list); /* if there are no other commands queued we start the timeout timer */ - if (xhci->cmd_list.next == &cmd->cmd_list && - !delayed_work_pending(&xhci->cmd_timer)) { + if (list_empty(&xhci->cmd_list)) { xhci->current_cmd = cmd; xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); } + list_add_tail(&cmd->cmd_list, &xhci->cmd_list); + queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3, field4 | xhci->cmd_ring->cycle_state); return 0; diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 59c05653b2ea..1ac2cdf8eece 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -103,7 +103,7 @@ DECLARE_EVENT_CLASS(xhci_log_ctx, ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 32) * ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1)); ), - TP_printk("\nctx_64=%d, ctx_type=%u, ctx_dma=@%llx, ctx_va=@%p", + TP_printk("ctx_64=%d, ctx_type=%u, ctx_dma=@%llx, ctx_va=@%p", __entry->ctx_64, __entry->ctx_type, (unsigned long long) __entry->ctx_dma, __entry->ctx_va ) @@ -115,34 +115,174 @@ DEFINE_EVENT(xhci_log_ctx, xhci_address_ctx, TP_ARGS(xhci, ctx, ep_num) ); -DECLARE_EVENT_CLASS(xhci_log_event, - TP_PROTO(void *trb_va, struct xhci_generic_trb *ev), - TP_ARGS(trb_va, ev), +DECLARE_EVENT_CLASS(xhci_log_trb, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb), TP_STRUCT__entry( - __field(void *, va) - __field(u64, dma) - __field(u32, status) - __field(u32, flags) - __dynamic_array(u8, trb, sizeof(struct xhci_generic_trb)) + __field(u32, type) + __field(u32, field0) + __field(u32, field1) + __field(u32, field2) + __field(u32, field3) ), TP_fast_assign( - __entry->va = trb_va; - __entry->dma = ((u64)le32_to_cpu(ev->field[1])) << 32 | - le32_to_cpu(ev->field[0]); - __entry->status = le32_to_cpu(ev->field[2]); - __entry->flags = le32_to_cpu(ev->field[3]); - memcpy(__get_dynamic_array(trb), trb_va, - sizeof(struct xhci_generic_trb)); + __entry->type = ring->type; + __entry->field0 = le32_to_cpu(trb->field[0]); + __entry->field1 = le32_to_cpu(trb->field[1]); + __entry->field2 = le32_to_cpu(trb->field[2]); + __entry->field3 = le32_to_cpu(trb->field[3]); ), - TP_printk("\ntrb_dma=@%llx, trb_va=@%p, status=%08x, flags=%08x", - (unsigned long long) __entry->dma, __entry->va, - __entry->status, __entry->flags + TP_printk("%s: %s", xhci_ring_type_string(__entry->type), + xhci_decode_trb(__entry->field0, __entry->field1, + __entry->field2, __entry->field3) ) ); -DEFINE_EVENT(xhci_log_event, xhci_cmd_completion, - TP_PROTO(void *trb_va, struct xhci_generic_trb *ev), - TP_ARGS(trb_va, ev) +DEFINE_EVENT(xhci_log_trb, xhci_handle_event, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb) +); + +DEFINE_EVENT(xhci_log_trb, xhci_handle_command, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb) +); + +DEFINE_EVENT(xhci_log_trb, xhci_handle_transfer, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb) +); + +DEFINE_EVENT(xhci_log_trb, xhci_queue_trb, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb) +); + +DECLARE_EVENT_CLASS(xhci_log_virt_dev, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev), + TP_STRUCT__entry( + __field(void *, vdev) + __field(unsigned long long, out_ctx) + __field(unsigned long long, in_ctx) + __field(int, devnum) + __field(int, state) + __field(int, speed) + __field(u8, portnum) + __field(u8, level) + __field(int, slot_id) + ), + TP_fast_assign( + __entry->vdev = vdev; + __entry->in_ctx = (unsigned long long) vdev->in_ctx->dma; + __entry->out_ctx = (unsigned long long) vdev->out_ctx->dma; + __entry->devnum = vdev->udev->devnum; + __entry->state = vdev->udev->state; + __entry->speed = vdev->udev->speed; + __entry->portnum = vdev->udev->portnum; + __entry->level = vdev->udev->level; + __entry->slot_id = vdev->udev->slot_id; + ), + TP_printk("vdev %p ctx %llx | %llx num %d state %d speed %d port %d level %d slot %d", + __entry->vdev, __entry->in_ctx, __entry->out_ctx, + __entry->devnum, __entry->state, __entry->speed, + __entry->portnum, __entry->level, __entry->slot_id + ) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_alloc_virt_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_free_virt_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_setup_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_setup_addressable_virt_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_stop_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DECLARE_EVENT_CLASS(xhci_log_urb, + TP_PROTO(struct urb *urb), + TP_ARGS(urb), + TP_STRUCT__entry( + __field(void *, urb) + __field(unsigned int, pipe) + __field(unsigned int, stream) + __field(int, status) + __field(unsigned int, flags) + __field(int, num_mapped_sgs) + __field(int, num_sgs) + __field(int, length) + __field(int, actual) + __field(int, epnum) + __field(int, dir_in) + __field(int, type) + ), + TP_fast_assign( + __entry->urb = urb; + __entry->pipe = urb->pipe; + __entry->stream = urb->stream_id; + __entry->status = urb->status; + __entry->flags = urb->transfer_flags; + __entry->num_mapped_sgs = urb->num_mapped_sgs; + __entry->num_sgs = urb->num_sgs; + __entry->length = urb->transfer_buffer_length; + __entry->actual = urb->actual_length; + __entry->epnum = usb_endpoint_num(&urb->ep->desc); + __entry->dir_in = usb_endpoint_dir_in(&urb->ep->desc); + __entry->type = usb_endpoint_type(&urb->ep->desc); + ), + TP_printk("ep%d%s-%s: urb %p pipe %u length %d/%d sgs %d/%d stream %d flags %08x", + __entry->epnum, __entry->dir_in ? "in" : "out", + ({ char *s; + switch (__entry->type) { + case USB_ENDPOINT_XFER_INT: + s = "intr"; + break; + case USB_ENDPOINT_XFER_CONTROL: + s = "control"; + break; + case USB_ENDPOINT_XFER_BULK: + s = "bulk"; + break; + case USB_ENDPOINT_XFER_ISOC: + s = "isoc"; + break; + default: + s = "UNKNOWN"; + } s; }), __entry->urb, __entry->pipe, __entry->actual, + __entry->length, __entry->num_mapped_sgs, + __entry->num_sgs, __entry->stream, __entry->flags + ) +); + +DEFINE_EVENT(xhci_log_urb, xhci_urb_enqueue, + TP_PROTO(struct urb *urb), + TP_ARGS(urb) +); + +DEFINE_EVENT(xhci_log_urb, xhci_urb_giveback, + TP_PROTO(struct urb *urb), + TP_ARGS(urb) +); + +DEFINE_EVENT(xhci_log_urb, xhci_urb_dequeue, + TP_PROTO(struct urb *urb), + TP_ARGS(urb) ); #endif /* __XHCI_TRACE_H */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9a0ec116654a..6d6c46000e56 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -207,7 +207,7 @@ int xhci_reset(struct xhci_hcd *xhci) ret = xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, 10 * 1000 * 1000); - for (i = 0; i < 2; ++i) { + for (i = 0; i < 2; i++) { xhci->bus_state[i].port_c_suspend = 0; xhci->bus_state[i].suspended_ports = 0; xhci->bus_state[i].resuming_ports = 0; @@ -1332,12 +1332,11 @@ command_cleanup: int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct xhci_td *buffer; unsigned long flags; int ret = 0; - unsigned int slot_id, ep_index; + unsigned int slot_id, ep_index, ep_state; struct urb_priv *urb_priv; - int size, i; + int num_tds; if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, true, __func__) <= 0) @@ -1349,40 +1348,30 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) if (!HCD_HW_ACCESSIBLE(hcd)) { if (!in_interrupt()) xhci_dbg(xhci, "urb submitted during PCI suspend\n"); - ret = -ESHUTDOWN; - goto exit; + return -ESHUTDOWN; } if (usb_endpoint_xfer_isoc(&urb->ep->desc)) - size = urb->number_of_packets; + num_tds = urb->number_of_packets; else if (usb_endpoint_is_bulk_out(&urb->ep->desc) && urb->transfer_buffer_length > 0 && urb->transfer_flags & URB_ZERO_PACKET && !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc))) - size = 2; + num_tds = 2; else - size = 1; + num_tds = 1; urb_priv = kzalloc(sizeof(struct urb_priv) + - size * sizeof(struct xhci_td *), mem_flags); + num_tds * sizeof(struct xhci_td), mem_flags); if (!urb_priv) return -ENOMEM; - buffer = kzalloc(size * sizeof(struct xhci_td), mem_flags); - if (!buffer) { - kfree(urb_priv); - return -ENOMEM; - } - - for (i = 0; i < size; i++) { - urb_priv->td[i] = buffer; - buffer++; - } - - urb_priv->length = size; - urb_priv->td_cnt = 0; + urb_priv->num_tds = num_tds; + urb_priv->num_tds_done = 0; urb->hcpriv = urb_priv; + trace_xhci_urb_enqueue(urb); + if (usb_endpoint_xfer_control(&urb->ep->desc)) { /* Check to see if the max packet size for the default control * endpoint changed during FS device enumeration @@ -1396,69 +1385,51 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) return ret; } } + } - /* We have a spinlock and interrupts disabled, so we must pass - * atomic context to this function, which may allocate memory. - */ - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; + spin_lock_irqsave(&xhci->lock, flags); + + if (xhci->xhc_state & XHCI_STATE_DYING) { + xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for non-responsive xHCI host.\n", + urb->ep->desc.bEndpointAddress, urb); + ret = -ESHUTDOWN; + goto free_priv; + } + + switch (usb_endpoint_type(&urb->ep->desc)) { + + case USB_ENDPOINT_XFER_CONTROL: ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb, - slot_id, ep_index); - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) { - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; - if (xhci->devs[slot_id]->eps[ep_index].ep_state & - EP_GETTING_STREAMS) { - xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep " - "is transitioning to using streams.\n"); - ret = -EINVAL; - } else if (xhci->devs[slot_id]->eps[ep_index].ep_state & - EP_GETTING_NO_STREAMS) { - xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep " - "is transitioning to " - "not having streams.\n"); + slot_id, ep_index); + break; + case USB_ENDPOINT_XFER_BULK: + ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; + if (ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) { + xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n", + ep_state); ret = -EINVAL; - } else { - ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, - slot_id, ep_index); + break; } - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } else if (usb_endpoint_xfer_int(&urb->ep->desc)) { - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; + ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, + slot_id, ep_index); + break; + + + case USB_ENDPOINT_XFER_INT: ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } else { - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; + break; + + case USB_ENDPOINT_XFER_ISOC: ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb, slot_id, ep_index); - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); } -exit: - return ret; -dying: - xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for " - "non-responsive xHCI host.\n", - urb->ep->desc.bEndpointAddress, urb); - ret = -ESHUTDOWN; + + if (ret) { free_priv: - xhci_urb_free_priv(urb_priv); - urb->hcpriv = NULL; + xhci_urb_free_priv(urb_priv); + urb->hcpriv = NULL; + } spin_unlock_irqrestore(&xhci->lock, flags); return ret; } @@ -1509,6 +1480,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) xhci = hcd_to_xhci(hcd); spin_lock_irqsave(&xhci->lock, flags); + + trace_xhci_urb_dequeue(urb); + /* Make sure the URB hasn't completed or been unlinked already */ ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret || !urb->hcpriv) @@ -1518,10 +1492,10 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "HW died, freeing TD."); urb_priv = urb->hcpriv; - for (i = urb_priv->td_cnt; - i < urb_priv->length && xhci->devs[urb->dev->slot_id]; + for (i = urb_priv->num_tds_done; + i < urb_priv->num_tds && xhci->devs[urb->dev->slot_id]; i++) { - td = urb_priv->td[i]; + td = &urb_priv->td[i]; if (!list_empty(&td->td_list)) list_del_init(&td->td_list); if (!list_empty(&td->cancelled_td_list)) @@ -1544,33 +1518,32 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) } urb_priv = urb->hcpriv; - i = urb_priv->td_cnt; - if (i < urb_priv->length) + i = urb_priv->num_tds_done; + if (i < urb_priv->num_tds) xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Cancel URB %p, dev %s, ep 0x%x, " "starting at offset 0x%llx", urb, urb->dev->devpath, urb->ep->desc.bEndpointAddress, (unsigned long long) xhci_trb_virt_to_dma( - urb_priv->td[i]->start_seg, - urb_priv->td[i]->first_trb)); + urb_priv->td[i].start_seg, + urb_priv->td[i].first_trb)); - for (; i < urb_priv->length; i++) { - td = urb_priv->td[i]; + for (; i < urb_priv->num_tds; i++) { + td = &urb_priv->td[i]; list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); } /* Queue a stop endpoint command, but only if this is * the first cancellation to be handled. */ - if (!(ep->ep_state & EP_HALT_PENDING)) { + if (!(ep->ep_state & EP_STOP_CMD_PENDING)) { command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); if (!command) { ret = -ENOMEM; goto done; } - ep->ep_state |= EP_HALT_PENDING; - ep->stop_cmds_pending++; + ep->ep_state |= EP_STOP_CMD_PENDING; ep->stop_cmd_timer.expires = jiffies + XHCI_STOP_EP_CMD_TIMEOUT * HZ; add_timer(&ep->stop_cmd_timer); @@ -1809,7 +1782,7 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK); /* Endpoint 0 is always valid */ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1)); - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i); ep_ctx->ep_info = 0; ep_ctx->ep_info2 = 0; @@ -1824,32 +1797,32 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, int ret; switch (*cmd_status) { - case COMP_CMD_ABORT: - case COMP_CMD_STOP: + case COMP_COMMAND_ABORTED: + case COMP_STOPPED: xhci_warn(xhci, "Timeout while waiting for configure endpoint command\n"); ret = -ETIME; break; - case COMP_ENOMEM: + case COMP_RESOURCE_ERROR: dev_warn(&udev->dev, "Not enough host controller resources for new device state.\n"); ret = -ENOMEM; /* FIXME: can we allocate more resources for the HC? */ break; - case COMP_BW_ERR: - case COMP_2ND_BW_ERR: + case COMP_BANDWIDTH_ERROR: + case COMP_SECONDARY_BANDWIDTH_ERROR: dev_warn(&udev->dev, "Not enough bandwidth for new device state.\n"); ret = -ENOSPC; /* FIXME: can we go back to the old state? */ break; - case COMP_TRB_ERR: + case COMP_TRB_ERROR: /* the HCD set up something wrong */ dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, " "add flag = 1, " "and endpoint is not disabled.\n"); ret = -EINVAL; break; - case COMP_DEV_ERR: + case COMP_INCOMPATIBLE_DEVICE_ERROR: dev_warn(&udev->dev, "ERROR: Incompatible device for endpoint configure command.\n"); ret = -ENODEV; @@ -1875,33 +1848,33 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; switch (*cmd_status) { - case COMP_CMD_ABORT: - case COMP_CMD_STOP: + case COMP_COMMAND_ABORTED: + case COMP_STOPPED: xhci_warn(xhci, "Timeout while waiting for evaluate context command\n"); ret = -ETIME; break; - case COMP_EINVAL: + case COMP_PARAMETER_ERROR: dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate context command.\n"); ret = -EINVAL; break; - case COMP_EBADSLT: + case COMP_SLOT_NOT_ENABLED_ERROR: dev_warn(&udev->dev, "WARN: slot not enabled for evaluate context command.\n"); ret = -EINVAL; break; - case COMP_CTX_STATE: + case COMP_CONTEXT_STATE_ERROR: dev_warn(&udev->dev, "WARN: invalid context state for evaluate context command.\n"); xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1); ret = -EINVAL; break; - case COMP_DEV_ERR: + case COMP_INCOMPATIBLE_DEVICE_ERROR: dev_warn(&udev->dev, "ERROR: Incompatible device for evaluate context command.\n"); ret = -ENODEV; break; - case COMP_MEL_ERR: + case COMP_MAX_EXIT_LATENCY_TOO_LARGE_ERROR: /* Max Exit Latency too large error */ dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n"); ret = -EINVAL; @@ -2781,7 +2754,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info))); /* Free any rings that were dropped, but not changed. */ - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) && !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) { xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); @@ -2793,7 +2766,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) * Install any rings for completely new endpoints or changed endpoints, * and free or cache any old rings from changed endpoints. */ - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { if (!virt_dev->eps[i].new_ring) continue; /* Only cache or free the old ring if it exists. @@ -2827,7 +2800,7 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); virt_dev = xhci->devs[udev->slot_id]; /* Free any rings allocated for added endpoints */ - for (i = 0; i < 31; ++i) { + for (i = 0; i < 31; i++) { if (virt_dev->eps[i].new_ring) { xhci_ring_free(xhci, virt_dev->eps[i].new_ring); virt_dev->eps[i].new_ring = NULL; @@ -3497,13 +3470,13 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) */ ret = reset_device_cmd->status; switch (ret) { - case COMP_CMD_ABORT: - case COMP_CMD_STOP: + case COMP_COMMAND_ABORTED: + case COMP_STOPPED: xhci_warn(xhci, "Timeout waiting for reset device command\n"); ret = -ETIME; goto command_cleanup; - case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */ - case COMP_CTX_STATE: /* 0.96 completion code for same thing */ + case COMP_SLOT_NOT_ENABLED_ERROR: /* 0.95 completion for bad slot ID */ + case COMP_CONTEXT_STATE_ERROR: /* 0.96 completion code for same thing */ xhci_dbg(xhci, "Can't reset device (slot ID %u) in %s state\n", slot_id, xhci_get_slot_state(xhci, virt_dev->out_ctx)); @@ -3533,7 +3506,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Everything but endpoint 0 is disabled, so free or cache the rings. */ last_freed_endpoint = 1; - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { struct xhci_virt_ep *ep = &virt_dev->eps[i]; if (ep->ep_state & EP_HAS_STREAMS) { @@ -3609,8 +3582,8 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) virt_dev = xhci->devs[udev->slot_id]; /* Stop any wayward timer functions (which may grab the lock) */ - for (i = 0; i < 31; ++i) { - virt_dev->eps[i].ep_state &= ~EP_HALT_PENDING; + for (i = 0; i < 31; i++) { + virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING; del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); } @@ -3844,6 +3817,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, le32_to_cpu(slot_ctx->dev_info) >> 27); spin_lock_irqsave(&xhci->lock, flags); + trace_xhci_setup_device(virt_dev); ret = xhci_queue_address_device(xhci, command, virt_dev->in_ctx->dma, udev->slot_id, setup); if (ret) { @@ -3863,22 +3837,22 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, * command on a timeout. */ switch (command->status) { - case COMP_CMD_ABORT: - case COMP_CMD_STOP: + case COMP_COMMAND_ABORTED: + case COMP_STOPPED: xhci_warn(xhci, "Timeout while waiting for setup device command\n"); ret = -ETIME; break; - case COMP_CTX_STATE: - case COMP_EBADSLT: + case COMP_CONTEXT_STATE_ERROR: + case COMP_SLOT_NOT_ENABLED_ERROR: xhci_err(xhci, "Setup ERROR: setup %s command for slot %d.\n", act, udev->slot_id); ret = -EINVAL; break; - case COMP_TX_ERR: + case COMP_USB_TRANSACTION_ERROR: dev_warn(&udev->dev, "Device not responding to setup %s.\n", act); ret = -EPROTO; break; - case COMP_DEV_ERR: + case COMP_INCOMPATIBLE_DEVICE_ERROR: dev_warn(&udev->dev, "ERROR: Incompatible device for setup %s command\n", act); ret = -ENODEV; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2d7b6374b58d..da3eb695fe54 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -912,7 +912,7 @@ struct xhci_virt_ep { unsigned int ep_state; #define SET_DEQ_PENDING (1 << 0) #define EP_HALTED (1 << 1) /* For stall handling */ -#define EP_HALT_PENDING (1 << 2) /* For URB cancellation */ +#define EP_STOP_CMD_PENDING (1 << 2) /* For URB cancellation */ /* Transitioning the endpoint to using streams, don't enqueue URBs */ #define EP_GETTING_STREAMS (1 << 3) #define EP_HAS_STREAMS (1 << 4) @@ -924,7 +924,6 @@ struct xhci_virt_ep { unsigned int stopped_stream; /* Watchdog timer for stop endpoint command to cancel URBs */ struct timer_list stop_cmd_timer; - int stop_cmds_pending; struct xhci_hcd *xhci; /* Dequeue pointer and dequeue segment for a submitted Set TR Dequeue * command. We'll need to update the ring's dequeue segment and dequeue @@ -1061,76 +1060,122 @@ struct xhci_transfer_event { /* Completion Code - only applicable for some types of TRBs */ #define COMP_CODE_MASK (0xff << 24) #define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24) -#define COMP_SUCCESS 1 -/* Data Buffer Error */ -#define COMP_DB_ERR 2 -/* Babble Detected Error */ -#define COMP_BABBLE 3 -/* USB Transaction Error */ -#define COMP_TX_ERR 4 -/* TRB Error - some TRB field is invalid */ -#define COMP_TRB_ERR 5 -/* Stall Error - USB device is stalled */ -#define COMP_STALL 6 -/* Resource Error - HC doesn't have memory for that device configuration */ -#define COMP_ENOMEM 7 -/* Bandwidth Error - not enough room in schedule for this dev config */ -#define COMP_BW_ERR 8 -/* No Slots Available Error - HC ran out of device slots */ -#define COMP_ENOSLOTS 9 -/* Invalid Stream Type Error */ -#define COMP_STREAM_ERR 10 -/* Slot Not Enabled Error - doorbell rung for disabled device slot */ -#define COMP_EBADSLT 11 -/* Endpoint Not Enabled Error */ -#define COMP_EBADEP 12 -/* Short Packet */ -#define COMP_SHORT_TX 13 -/* Ring Underrun - doorbell rung for an empty isoc OUT ep ring */ -#define COMP_UNDERRUN 14 -/* Ring Overrun - isoc IN ep ring is empty when ep is scheduled to RX */ -#define COMP_OVERRUN 15 -/* Virtual Function Event Ring Full Error */ -#define COMP_VF_FULL 16 -/* Parameter Error - Context parameter is invalid */ -#define COMP_EINVAL 17 -/* Bandwidth Overrun Error - isoc ep exceeded its allocated bandwidth */ -#define COMP_BW_OVER 18 -/* Context State Error - illegal context state transition requested */ -#define COMP_CTX_STATE 19 -/* No Ping Response Error - HC didn't get PING_RESPONSE in time to TX */ -#define COMP_PING_ERR 20 -/* Event Ring is full */ -#define COMP_ER_FULL 21 -/* Incompatible Device Error */ -#define COMP_DEV_ERR 22 -/* Missed Service Error - HC couldn't service an isoc ep within interval */ -#define COMP_MISSED_INT 23 -/* Successfully stopped command ring */ -#define COMP_CMD_STOP 24 -/* Successfully aborted current command and stopped command ring */ -#define COMP_CMD_ABORT 25 -/* Stopped - transfer was terminated by a stop endpoint command */ -#define COMP_STOP 26 -/* Same as COMP_EP_STOPPED, but the transferred length in the event is invalid */ -#define COMP_STOP_INVAL 27 -/* Same as COMP_EP_STOPPED, but a short packet detected */ -#define COMP_STOP_SHORT 28 -/* Max Exit Latency Too Large Error */ -#define COMP_MEL_ERR 29 -/* TRB type 30 reserved */ -/* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */ -#define COMP_BUFF_OVER 31 -/* Event Lost Error - xHC has an "internal event overrun condition" */ -#define COMP_ISSUES 32 -/* Undefined Error - reported when other error codes don't apply */ -#define COMP_UNKNOWN 33 -/* Invalid Stream ID Error */ -#define COMP_STRID_ERR 34 -/* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */ -#define COMP_2ND_BW_ERR 35 -/* Split Transaction Error */ -#define COMP_SPLIT_ERR 36 +#define COMP_INVALID 0 +#define COMP_SUCCESS 1 +#define COMP_DATA_BUFFER_ERROR 2 +#define COMP_BABBLE_DETECTED_ERROR 3 +#define COMP_USB_TRANSACTION_ERROR 4 +#define COMP_TRB_ERROR 5 +#define COMP_STALL_ERROR 6 +#define COMP_RESOURCE_ERROR 7 +#define COMP_BANDWIDTH_ERROR 8 +#define COMP_NO_SLOTS_AVAILABLE_ERROR 9 +#define COMP_INVALID_STREAM_TYPE_ERROR 10 +#define COMP_SLOT_NOT_ENABLED_ERROR 11 +#define COMP_ENDPOINT_NOT_ENABLED_ERROR 12 +#define COMP_SHORT_PACKET 13 +#define COMP_RING_UNDERRUN 14 +#define COMP_RING_OVERRUN 15 +#define COMP_VF_EVENT_RING_FULL_ERROR 16 +#define COMP_PARAMETER_ERROR 17 +#define COMP_BANDWIDTH_OVERRUN_ERROR 18 +#define COMP_CONTEXT_STATE_ERROR 19 +#define COMP_NO_PING_RESPONSE_ERROR 20 +#define COMP_EVENT_RING_FULL_ERROR 21 +#define COMP_INCOMPATIBLE_DEVICE_ERROR 22 +#define COMP_MISSED_SERVICE_ERROR 23 +#define COMP_COMMAND_RING_STOPPED 24 +#define COMP_COMMAND_ABORTED 25 +#define COMP_STOPPED 26 +#define COMP_STOPPED_LENGTH_INVALID 27 +#define COMP_STOPPED_SHORT_PACKET 28 +#define COMP_MAX_EXIT_LATENCY_TOO_LARGE_ERROR 29 +#define COMP_ISOCH_BUFFER_OVERRUN 31 +#define COMP_EVENT_LOST_ERROR 32 +#define COMP_UNDEFINED_ERROR 33 +#define COMP_INVALID_STREAM_ID_ERROR 34 +#define COMP_SECONDARY_BANDWIDTH_ERROR 35 +#define COMP_SPLIT_TRANSACTION_ERROR 36 + +static inline const char *xhci_trb_comp_code_string(u8 status) +{ + switch (status) { + case COMP_INVALID: + return "Invalid"; + case COMP_SUCCESS: + return "Success"; + case COMP_DATA_BUFFER_ERROR: + return "Data Buffer Error"; + case COMP_BABBLE_DETECTED_ERROR: + return "Babble Detected"; + case COMP_USB_TRANSACTION_ERROR: + return "USB Transaction Error"; + case COMP_TRB_ERROR: + return "TRB Error"; + case COMP_STALL_ERROR: + return "Stall Error"; + case COMP_RESOURCE_ERROR: + return "Resource Error"; + case COMP_BANDWIDTH_ERROR: + return "Bandwidth Error"; + case COMP_NO_SLOTS_AVAILABLE_ERROR: + return "No Slots Available Error"; + case COMP_INVALID_STREAM_TYPE_ERROR: + return "Invalid Stream Type Error"; + case COMP_SLOT_NOT_ENABLED_ERROR: + return "Slot Not Enabled Error"; + case COMP_ENDPOINT_NOT_ENABLED_ERROR: + return "Endpoint Not Enabled Error"; + case COMP_SHORT_PACKET: + return "Short Packet"; + case COMP_RING_UNDERRUN: + return "Ring Underrun"; + case COMP_RING_OVERRUN: + return "Ring Overrun"; + case COMP_VF_EVENT_RING_FULL_ERROR: + return "VF Event Ring Full Error"; + case COMP_PARAMETER_ERROR: + return "Parameter Error"; + case COMP_BANDWIDTH_OVERRUN_ERROR: + return "Bandwidth Overrun Error"; + case COMP_CONTEXT_STATE_ERROR: + return "Context State Error"; + case COMP_NO_PING_RESPONSE_ERROR: + return "No Ping Response Error"; + case COMP_EVENT_RING_FULL_ERROR: + return "Event Ring Full Error"; + case COMP_INCOMPATIBLE_DEVICE_ERROR: + return "Incompatible Device Error"; + case COMP_MISSED_SERVICE_ERROR: + return "Missed Service Error"; + case COMP_COMMAND_RING_STOPPED: + return "Command Ring Stopped"; + case COMP_COMMAND_ABORTED: + return "Command Aborted"; + case COMP_STOPPED: + return "Stopped"; + case COMP_STOPPED_LENGTH_INVALID: + return "Stopped - Length Invalid"; + case COMP_STOPPED_SHORT_PACKET: + return "Stopped - Short Packet"; + case COMP_MAX_EXIT_LATENCY_TOO_LARGE_ERROR: + return "Max Exit Latency Too Large Error"; + case COMP_ISOCH_BUFFER_OVERRUN: + return "Isoch Buffer Overrun"; + case COMP_EVENT_LOST_ERROR: + return "Event Lost Error"; + case COMP_UNDEFINED_ERROR: + return "Undefined Error"; + case COMP_INVALID_STREAM_ID_ERROR: + return "Invalid Stream ID Error"; + case COMP_SECONDARY_BANDWIDTH_ERROR: + return "Secondary Bandwidth Error"; + case COMP_SPLIT_TRANSACTION_ERROR: + return "Split Transaction Error"; + default: + return "Unknown!!"; + } +} struct xhci_link_trb { /* 64-bit segment pointer*/ @@ -1154,6 +1199,27 @@ struct xhci_event_cmd { /* Address device - disable SetAddress */ #define TRB_BSR (1<<9) + +/* Configure Endpoint - Deconfigure */ +#define TRB_DC (1<<9) + +/* Stop Ring - Transfer State Preserve */ +#define TRB_TSP (1<<9) + +/* Force Event */ +#define TRB_TO_VF_INTR_TARGET(p) (((p) & (0x3ff << 22)) >> 22) +#define TRB_TO_VF_ID(p) (((p) & (0xff << 16)) >> 16) + +/* Set Latency Tolerance Value */ +#define TRB_TO_BELT(p) (((p) & (0xfff << 16)) >> 16) + +/* Get Port Bandwidth */ +#define TRB_TO_DEV_SPEED(p) (((p) & (0xf << 16)) >> 16) + +/* Force Header */ +#define TRB_TO_PACKET_TYPE(p) ((p) & 0x1f) +#define TRB_TO_ROOTHUB_PORT(p) (((p) & (0xff << 24)) >> 24) + enum xhci_setup_dev { SETUP_CONTEXT_ONLY, SETUP_CONTEXT_ADDRESS, @@ -1177,16 +1243,21 @@ enum xhci_setup_dev { #define STREAM_ID_FOR_TRB(p) ((((p)) & 0xffff) << 16) #define SCT_FOR_TRB(p) (((p) << 1) & 0x7) +/* Link TRB specific fields */ +#define TRB_TC (1<<1) /* Port Status Change Event TRB fields */ /* Port ID - bits 31:24 */ #define GET_PORT_ID(p) (((p) & (0xff << 24)) >> 24) +#define EVENT_DATA (1 << 2) + /* Normal TRB fields */ /* transfer_len bitmasks - bits 0:16 */ #define TRB_LEN(p) ((p) & 0x1ffff) /* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */ #define TRB_TD_SIZE(p) (min((p), (u32)31) << 17) +#define GET_TD_SIZE(p) (((p) & 0x3e0000) >> 17) /* xhci 1.1 uses the TD_SIZE field for TBC if Extended TBC is enabled (ETE) */ #define TRB_TD_SIZE_TBC(p) (min((p), (u32)31) << 17) /* Interrupter Target - which MSI-X vector to target the completion event at */ @@ -1314,6 +1385,80 @@ union xhci_trb { /* Get NEC firmware revision. */ #define TRB_NEC_GET_FW 49 +static inline const char *xhci_trb_type_string(u8 type) +{ + switch (type) { + case TRB_NORMAL: + return "Normal"; + case TRB_SETUP: + return "Setup Stage"; + case TRB_DATA: + return "Data Stage"; + case TRB_STATUS: + return "Status Stage"; + case TRB_ISOC: + return "Isoch"; + case TRB_LINK: + return "Link"; + case TRB_EVENT_DATA: + return "Event Data"; + case TRB_TR_NOOP: + return "No-Op"; + case TRB_ENABLE_SLOT: + return "Enable Slot Command"; + case TRB_DISABLE_SLOT: + return "Disable Slot Command"; + case TRB_ADDR_DEV: + return "Address Device Command"; + case TRB_CONFIG_EP: + return "Configure Endpoint Command"; + case TRB_EVAL_CONTEXT: + return "Evaluate Context Command"; + case TRB_RESET_EP: + return "Reset Endpoint Command"; + case TRB_STOP_RING: + return "Stop Ring Command"; + case TRB_SET_DEQ: + return "Set TR Dequeue Pointer Command"; + case TRB_RESET_DEV: + return "Reset Device Command"; + case TRB_FORCE_EVENT: + return "Force Event Command"; + case TRB_NEG_BANDWIDTH: + return "Negotiate Bandwidth Command"; + case TRB_SET_LT: + return "Set Latency Tolerance Value Command"; + case TRB_GET_BW: + return "Get Port Bandwidth Command"; + case TRB_FORCE_HEADER: + return "Force Header Command"; + case TRB_CMD_NOOP: + return "No-Op Command"; + case TRB_TRANSFER: + return "Transfer Event"; + case TRB_COMPLETION: + return "Command Completion Event"; + case TRB_PORT_STATUS: + return "Port Status Change Event"; + case TRB_BANDWIDTH_EVENT: + return "Bandwidth Request Event"; + case TRB_DOORBELL: + return "Doorbell Event"; + case TRB_HC_EVENT: + return "Host Controller Event"; + case TRB_DEV_NOTE: + return "Device Notification Event"; + case TRB_MFINDEX_WRAP: + return "MFINDEX Wrap Event"; + case TRB_NEC_CMD_COMP: + return "NEC Command Completion Event"; + case TRB_NEC_GET_FW: + return "NET Get Firmware Revision Command"; + default: + return "UNKNOWN"; + } +} + #define TRB_TYPE_LINK(x) (((x) & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) /* Above, but for __le32 types -- can avoid work by swapping constants: */ #define TRB_TYPE_LINK_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \ @@ -1390,6 +1535,28 @@ enum xhci_ring_type { TYPE_EVENT, }; +static inline const char *xhci_ring_type_string(enum xhci_ring_type type) +{ + switch (type) { + case TYPE_CTRL: + return "CTRL"; + case TYPE_ISOC: + return "ISOC"; + case TYPE_BULK: + return "BULK"; + case TYPE_INTR: + return "INTR"; + case TYPE_STREAM: + return "STREAM"; + case TYPE_COMMAND: + return "CMD"; + case TYPE_EVENT: + return "EVENT"; + } + + return "UNKNOWN"; +} + struct xhci_ring { struct xhci_segment *first_seg; struct xhci_segment *last_seg; @@ -1441,9 +1608,9 @@ struct xhci_scratchpad { }; struct urb_priv { - int length; - int td_cnt; - struct xhci_td *td[0]; + int num_tds; + int num_tds_done; + struct xhci_td td[0]; }; /* @@ -1549,7 +1716,6 @@ struct xhci_hcd { u8 max_ports; u8 isoc_threshold; int event_ring_max; - int addr_64; /* 4KB min, 128MB max */ int page_size; /* Valid values are 12 to 20, inclusive */ @@ -1650,6 +1816,9 @@ struct xhci_hcd { #define XHCI_SSIC_PORT_UNUSED (1 << 22) #define XHCI_NO_64BIT_SUPPORT (1 << 23) #define XHCI_MISSING_CAS (1 << 24) +/* For controller with a broken Port Disable implementation */ +#define XHCI_BROKEN_PORT_PED (1 << 25) + unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ @@ -1984,4 +2153,211 @@ static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, urb->stream_id); } +static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2, + u32 field3) +{ + static char str[256]; + int type = TRB_FIELD_TO_TYPE(field3); + + switch (type) { + case TRB_LINK: + sprintf(str, + "TRB %08x%08x status '%s' len %d slot %d ep %d type '%s' flags %c:%c", + field1, field0, + xhci_trb_comp_code_string(GET_COMP_CODE(field2)), + EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & EVENT_DATA ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_TRANSFER: + case TRB_COMPLETION: + case TRB_PORT_STATUS: + case TRB_BANDWIDTH_EVENT: + case TRB_DOORBELL: + case TRB_HC_EVENT: + case TRB_DEV_NOTE: + case TRB_MFINDEX_WRAP: + sprintf(str, + "TRB %08x%08x status '%s' len %d slot %d ep %d type '%s' flags %c:%c", + field1, field0, + xhci_trb_comp_code_string(GET_COMP_CODE(field2)), + EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & EVENT_DATA ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); + + break; + case TRB_SETUP: + sprintf(str, + "bRequestType %02x bRequest %02x wValue %02x%02x wIndex %02x%02x wLength %d length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c:%c:%c:%c:%c", + field0 & 0xff, + (field0 & 0xff00) >> 8, + (field0 & 0xff000000) >> 24, + (field0 & 0xff0000) >> 16, + (field1 & 0xff00) >> 8, + field1 & 0xff, + (field1 & 0xff000000) >> 16 | + (field1 & 0xff0000) >> 16, + TRB_LEN(field2), GET_TD_SIZE(field2), + GET_INTR_TARGET(field2), + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & TRB_BEI ? 'B' : 'b', + field3 & TRB_IDT ? 'I' : 'i', + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CHAIN ? 'C' : 'c', + field3 & TRB_NO_SNOOP ? 'S' : 's', + field3 & TRB_ISP ? 'I' : 'i', + field3 & TRB_ENT ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_NORMAL: + case TRB_DATA: + case TRB_STATUS: + case TRB_ISOC: + case TRB_EVENT_DATA: + case TRB_TR_NOOP: + sprintf(str, + "Buffer %08x%08x length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c:%c:%c:%c:%c", + field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2), + GET_INTR_TARGET(field2), + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & TRB_BEI ? 'B' : 'b', + field3 & TRB_IDT ? 'I' : 'i', + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CHAIN ? 'C' : 'c', + field3 & TRB_NO_SNOOP ? 'S' : 's', + field3 & TRB_ISP ? 'I' : 'i', + field3 & TRB_ENT ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + + case TRB_CMD_NOOP: + case TRB_ENABLE_SLOT: + sprintf(str, + "%s: flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_DISABLE_SLOT: + case TRB_NEG_BANDWIDTH: + sprintf(str, + "%s: slot %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_ADDR_DEV: + sprintf(str, + "%s: ctx %08x%08x slot %d flags %c:%c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_BSR ? 'B' : 'b', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_CONFIG_EP: + sprintf(str, + "%s: ctx %08x%08x slot %d flags %c:%c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_DC ? 'D' : 'd', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_EVAL_CONTEXT: + sprintf(str, + "%s: ctx %08x%08x slot %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_RESET_EP: + sprintf(str, + "%s: ctx %08x%08x slot %d ep %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_STOP_RING: + sprintf(str, + "%s: slot %d sp %d ep %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + TRB_TO_SLOT_ID(field3), + TRB_TO_SUSPEND_PORT(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_SET_DEQ: + sprintf(str, + "%s: deq %08x%08x stream %d slot %d ep %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_STREAM_ID(field2), + TRB_TO_SLOT_ID(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_RESET_DEV: + sprintf(str, + "%s: slot %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_FORCE_EVENT: + sprintf(str, + "%s: event %08x%08x vf intr %d vf id %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_VF_INTR_TARGET(field2), + TRB_TO_VF_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_SET_LT: + sprintf(str, + "%s: belt %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + TRB_TO_BELT(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_GET_BW: + sprintf(str, + "%s: ctx %08x%08x slot %d speed %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + TRB_TO_DEV_SPEED(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_FORCE_HEADER: + sprintf(str, + "%s: info %08x%08x%08x pkt type %d roothub port %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field2, field1, field0 & 0xffffffe0, + TRB_TO_PACKET_TYPE(field0), + TRB_TO_ROOTHUB_PORT(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + default: + sprintf(str, + "type '%s' -> raw %08x %08x %08x %08x", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field0, field1, field2, field3); + } + + return str; +} + + #endif /* __LINUX_XHCI_HCD_H */ diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index 1c3d0fd658fa..69400f3da886 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1250,7 +1250,7 @@ static int isp1760_udc_stop(struct usb_gadget *gadget) return 0; } -static struct usb_gadget_ops isp1760_udc_ops = { +static const struct usb_gadget_ops isp1760_udc_ops = { .get_frame = isp1760_udc_get_frame, .wakeup = isp1760_udc_wakeup, .set_selfpowered = isp1760_udc_set_selfpowered, diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 47b357760afc..1d1d70d62a19 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -233,6 +233,15 @@ config USB_EZUSB_FX2 Say Y here if you need EZUSB device support. (Cypress FX/FX2/FX2LP microcontrollers) +config USB_HUB_USB251XB + tristate "USB251XB Hub Controller Configuration Driver" + depends on I2C + help + This option enables support for configuration via SMBus of the + Microchip USB251xB/xBi USB 2.0 Hub Controller series. + Configuration parameters may be set in devicetree or platform data. + Say Y or M here if you need to configure such a device via SMBus. + config USB_HSIC_USB3503 tristate "USB3503 HSIC to USB20 Driver" depends on I2C diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 3d1992750da4..f6ac6c99a6e6 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o obj-$(CONFIG_USB_YUREX) += yurex.o +obj-$(CONFIG_USB_HUB_USB251XB) += usb251xb.o obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o obj-$(CONFIG_USB_HSIC_USB4604) += usb4604.o obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 564268fca07a..a540e4f206c4 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -389,10 +389,6 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, dev->secondary_head += (amount - i); bytes_read += (amount - i); bytes_to_read -= (amount - i); - if (i) { - retval = bytes_read ? bytes_read : -EFAULT; - goto exit; - } } else { /* we check the primary buffer */ spin_lock_irqsave (&dev->buflock, flags); diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 05bd39d62568..440d7fef58cc 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1831,16 +1831,10 @@ static int sisusb_set_default_mode(struct sisusb_usb_data *sisusb, SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5)); SETIREG(SISCR, 0x14, 0x4f); du = (modex / 16) * (bpp * 2); /* offset/pitch */ - if (modex % 16) - du += bpp; - SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f)); SETIREG(SISCR, 0x13, (du & 0xff)); du <<= 5; tmp8 = du >> 8; - if (du & 0xff) - tmp8++; - SETIREG(SISSR, 0x10, tmp8); SETIREG(SISSR, 0x31, 0x00); /* VCLK */ SETIREG(SISSR, 0x2b, 0x1b); diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c new file mode 100644 index 000000000000..4e18600dc9b4 --- /dev/null +++ b/drivers/usb/misc/usb251xb.c @@ -0,0 +1,605 @@ +/* + * Driver for Microchip USB251xB USB 2.0 Hi-Speed Hub Controller + * Configuration via SMBus. + * + * Copyright (c) 2017 SKIDATA AG + * + * This work is based on the USB3503 driver by Dongjin Kim and + * a not-accepted patch by Fabien Lahoudere, see: + * https://patchwork.kernel.org/patch/9257715/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/nls.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/slab.h> + +/* Internal Register Set Addresses & Default Values acc. to DS00001692C */ +#define USB251XB_ADDR_VENDOR_ID_LSB 0x00 +#define USB251XB_ADDR_VENDOR_ID_MSB 0x01 +#define USB251XB_DEF_VENDOR_ID 0x0424 + +#define USB251XB_ADDR_PRODUCT_ID_LSB 0x02 +#define USB251XB_ADDR_PRODUCT_ID_MSB 0x03 +#define USB251XB_DEF_PRODUCT_ID_12 0x2512 /* USB2512B/12Bi */ +#define USB251XB_DEF_PRODUCT_ID_13 0x2513 /* USB2513B/13Bi */ +#define USB251XB_DEF_PRODUCT_ID_14 0x2514 /* USB2514B/14Bi */ + +#define USB251XB_ADDR_DEVICE_ID_LSB 0x04 +#define USB251XB_ADDR_DEVICE_ID_MSB 0x05 +#define USB251XB_DEF_DEVICE_ID 0x0BB3 + +#define USB251XB_ADDR_CONFIG_DATA_1 0x06 +#define USB251XB_DEF_CONFIG_DATA_1 0x9B +#define USB251XB_ADDR_CONFIG_DATA_2 0x07 +#define USB251XB_DEF_CONFIG_DATA_2 0x20 +#define USB251XB_ADDR_CONFIG_DATA_3 0x08 +#define USB251XB_DEF_CONFIG_DATA_3 0x02 + +#define USB251XB_ADDR_NON_REMOVABLE_DEVICES 0x09 +#define USB251XB_DEF_NON_REMOVABLE_DEVICES 0x00 + +#define USB251XB_ADDR_PORT_DISABLE_SELF 0x0A +#define USB251XB_DEF_PORT_DISABLE_SELF 0x00 +#define USB251XB_ADDR_PORT_DISABLE_BUS 0x0B +#define USB251XB_DEF_PORT_DISABLE_BUS 0x00 + +#define USB251XB_ADDR_MAX_POWER_SELF 0x0C +#define USB251XB_DEF_MAX_POWER_SELF 0x01 +#define USB251XB_ADDR_MAX_POWER_BUS 0x0D +#define USB251XB_DEF_MAX_POWER_BUS 0x32 + +#define USB251XB_ADDR_MAX_CURRENT_SELF 0x0E +#define USB251XB_DEF_MAX_CURRENT_SELF 0x01 +#define USB251XB_ADDR_MAX_CURRENT_BUS 0x0F +#define USB251XB_DEF_MAX_CURRENT_BUS 0x32 + +#define USB251XB_ADDR_POWER_ON_TIME 0x10 +#define USB251XB_DEF_POWER_ON_TIME 0x32 + +#define USB251XB_ADDR_LANGUAGE_ID_HIGH 0x11 +#define USB251XB_ADDR_LANGUAGE_ID_LOW 0x12 +#define USB251XB_DEF_LANGUAGE_ID 0x0000 + +#define USB251XB_STRING_BUFSIZE 62 +#define USB251XB_ADDR_MANUFACTURER_STRING_LEN 0x13 +#define USB251XB_ADDR_MANUFACTURER_STRING 0x16 +#define USB251XB_DEF_MANUFACTURER_STRING "Microchip" + +#define USB251XB_ADDR_PRODUCT_STRING_LEN 0x14 +#define USB251XB_ADDR_PRODUCT_STRING 0x54 +#define USB251XB_DEF_PRODUCT_STRING "USB251xB/xBi" + +#define USB251XB_ADDR_SERIAL_STRING_LEN 0x15 +#define USB251XB_ADDR_SERIAL_STRING 0x92 +#define USB251XB_DEF_SERIAL_STRING "" + +#define USB251XB_ADDR_BATTERY_CHARGING_ENABLE 0xD0 +#define USB251XB_DEF_BATTERY_CHARGING_ENABLE 0x00 + +#define USB251XB_ADDR_BOOST_UP 0xF6 +#define USB251XB_DEF_BOOST_UP 0x00 +#define USB251XB_ADDR_BOOST_X 0xF8 +#define USB251XB_DEF_BOOST_X 0x00 + +#define USB251XB_ADDR_PORT_SWAP 0xFA +#define USB251XB_DEF_PORT_SWAP 0x00 + +#define USB251XB_ADDR_PORT_MAP_12 0xFB +#define USB251XB_DEF_PORT_MAP_12 0x00 +#define USB251XB_ADDR_PORT_MAP_34 0xFC +#define USB251XB_DEF_PORT_MAP_34 0x00 /* USB2513B/i & USB2514B/i only */ + +#define USB251XB_ADDR_STATUS_COMMAND 0xFF +#define USB251XB_STATUS_COMMAND_SMBUS_DOWN 0x04 +#define USB251XB_STATUS_COMMAND_RESET 0x02 +#define USB251XB_STATUS_COMMAND_ATTACH 0x01 + +#define USB251XB_I2C_REG_SZ 0x100 +#define USB251XB_I2C_WRITE_SZ 0x10 + +#define DRIVER_NAME "usb251xb" +#define DRIVER_DESC "Microchip USB 2.0 Hi-Speed Hub Controller" +#define DRIVER_VERSION "1.0" + +struct usb251xb { + struct device *dev; + struct i2c_client *i2c; + u8 skip_config; + int gpio_reset; + u16 vendor_id; + u16 product_id; + u16 device_id; + u8 conf_data1; + u8 conf_data2; + u8 conf_data3; + u8 non_rem_dev; + u8 port_disable_sp; + u8 port_disable_bp; + u8 max_power_sp; + u8 max_power_bp; + u8 max_current_sp; + u8 max_current_bp; + u8 power_on_time; + u16 lang_id; + u8 manufacturer_len; + u8 product_len; + u8 serial_len; + char manufacturer[USB251XB_STRING_BUFSIZE]; + char product[USB251XB_STRING_BUFSIZE]; + char serial[USB251XB_STRING_BUFSIZE]; + u8 bat_charge_en; + u8 boost_up; + u8 boost_x; + u8 port_swap; + u8 port_map12; + u8 port_map34; + u8 status; +}; + +struct usb251xb_data { + u16 product_id; + char product_str[USB251XB_STRING_BUFSIZE / 2]; /* ASCII string */ +}; + +static const struct usb251xb_data usb2512b_data = { + .product_id = 0x2512, + .product_str = "USB2512B", +}; + +static const struct usb251xb_data usb2512bi_data = { + .product_id = 0x2512, + .product_str = "USB2512Bi", +}; + +static const struct usb251xb_data usb2513b_data = { + .product_id = 0x2513, + .product_str = "USB2513B", +}; + +static const struct usb251xb_data usb2513bi_data = { + .product_id = 0x2513, + .product_str = "USB2513Bi", +}; + +static const struct usb251xb_data usb2514b_data = { + .product_id = 0x2514, + .product_str = "USB2514B", +}; + +static const struct usb251xb_data usb2514bi_data = { + .product_id = 0x2514, + .product_str = "USB2514Bi", +}; + +static void usb251xb_reset(struct usb251xb *hub, int state) +{ + if (!gpio_is_valid(hub->gpio_reset)) + return; + + gpio_set_value_cansleep(hub->gpio_reset, state); + + /* wait for hub recovery/stabilization */ + if (state) + usleep_range(500, 750); /* >=500us at power on */ + else + usleep_range(1, 10); /* >=1us at power down */ +} + +static int usb251xb_connect(struct usb251xb *hub) +{ + struct device *dev = hub->dev; + int err, i; + char i2c_wb[USB251XB_I2C_REG_SZ]; + + memset(i2c_wb, 0, USB251XB_I2C_REG_SZ); + + if (hub->skip_config) { + dev_info(dev, "Skip hub configuration, only attach.\n"); + i2c_wb[0] = 0x01; + i2c_wb[1] = USB251XB_STATUS_COMMAND_ATTACH; + + usb251xb_reset(hub, 1); + + err = i2c_smbus_write_i2c_block_data(hub->i2c, + USB251XB_ADDR_STATUS_COMMAND, 2, i2c_wb); + if (err) { + dev_err(dev, "attaching hub failed: %d\n", err); + return err; + } + return 0; + } + + i2c_wb[USB251XB_ADDR_VENDOR_ID_MSB] = (hub->vendor_id >> 8) & 0xFF; + i2c_wb[USB251XB_ADDR_VENDOR_ID_LSB] = hub->vendor_id & 0xFF; + i2c_wb[USB251XB_ADDR_PRODUCT_ID_MSB] = (hub->product_id >> 8) & 0xFF; + i2c_wb[USB251XB_ADDR_PRODUCT_ID_LSB] = hub->product_id & 0xFF; + i2c_wb[USB251XB_ADDR_DEVICE_ID_MSB] = (hub->device_id >> 8) & 0xFF; + i2c_wb[USB251XB_ADDR_DEVICE_ID_LSB] = hub->device_id & 0xFF; + i2c_wb[USB251XB_ADDR_CONFIG_DATA_1] = hub->conf_data1; + i2c_wb[USB251XB_ADDR_CONFIG_DATA_2] = hub->conf_data2; + i2c_wb[USB251XB_ADDR_CONFIG_DATA_3] = hub->conf_data3; + i2c_wb[USB251XB_ADDR_NON_REMOVABLE_DEVICES] = hub->non_rem_dev; + i2c_wb[USB251XB_ADDR_PORT_DISABLE_SELF] = hub->port_disable_sp; + i2c_wb[USB251XB_ADDR_PORT_DISABLE_BUS] = hub->port_disable_bp; + i2c_wb[USB251XB_ADDR_MAX_POWER_SELF] = hub->max_power_sp; + i2c_wb[USB251XB_ADDR_MAX_POWER_BUS] = hub->max_power_bp; + i2c_wb[USB251XB_ADDR_MAX_CURRENT_SELF] = hub->max_current_sp; + i2c_wb[USB251XB_ADDR_MAX_CURRENT_BUS] = hub->max_current_bp; + i2c_wb[USB251XB_ADDR_POWER_ON_TIME] = hub->power_on_time; + i2c_wb[USB251XB_ADDR_LANGUAGE_ID_HIGH] = (hub->lang_id >> 8) & 0xFF; + i2c_wb[USB251XB_ADDR_LANGUAGE_ID_LOW] = hub->lang_id & 0xFF; + i2c_wb[USB251XB_ADDR_MANUFACTURER_STRING_LEN] = hub->manufacturer_len; + i2c_wb[USB251XB_ADDR_PRODUCT_STRING_LEN] = hub->product_len; + i2c_wb[USB251XB_ADDR_SERIAL_STRING_LEN] = hub->serial_len; + memcpy(&i2c_wb[USB251XB_ADDR_MANUFACTURER_STRING], hub->manufacturer, + USB251XB_STRING_BUFSIZE); + memcpy(&i2c_wb[USB251XB_ADDR_SERIAL_STRING], hub->serial, + USB251XB_STRING_BUFSIZE); + memcpy(&i2c_wb[USB251XB_ADDR_PRODUCT_STRING], hub->product, + USB251XB_STRING_BUFSIZE); + i2c_wb[USB251XB_ADDR_BATTERY_CHARGING_ENABLE] = hub->bat_charge_en; + i2c_wb[USB251XB_ADDR_BOOST_UP] = hub->boost_up; + i2c_wb[USB251XB_ADDR_BOOST_X] = hub->boost_x; + i2c_wb[USB251XB_ADDR_PORT_SWAP] = hub->port_swap; + i2c_wb[USB251XB_ADDR_PORT_MAP_12] = hub->port_map12; + i2c_wb[USB251XB_ADDR_PORT_MAP_34] = hub->port_map34; + i2c_wb[USB251XB_ADDR_STATUS_COMMAND] = USB251XB_STATUS_COMMAND_ATTACH; + + usb251xb_reset(hub, 1); + + /* write registers */ + for (i = 0; i < (USB251XB_I2C_REG_SZ / USB251XB_I2C_WRITE_SZ); i++) { + int offset = i * USB251XB_I2C_WRITE_SZ; + char wbuf[USB251XB_I2C_WRITE_SZ + 1]; + + /* The first data byte transferred tells the hub how many data + * bytes will follow (byte count). + */ + wbuf[0] = USB251XB_I2C_WRITE_SZ; + memcpy(&wbuf[1], &i2c_wb[offset], USB251XB_I2C_WRITE_SZ); + + dev_dbg(dev, "writing %d byte block %d to 0x%02X\n", + USB251XB_I2C_WRITE_SZ, i, offset); + + err = i2c_smbus_write_i2c_block_data(hub->i2c, offset, + USB251XB_I2C_WRITE_SZ + 1, + wbuf); + if (err) + goto out_err; + } + + dev_info(dev, "Hub configuration was successful.\n"); + return 0; + +out_err: + dev_err(dev, "configuring block %d failed: %d\n", i, err); + return err; +} + +#ifdef CONFIG_OF +static int usb251xb_get_ofdata(struct usb251xb *hub, + struct usb251xb_data *data) +{ + struct device *dev = hub->dev; + struct device_node *np = dev->of_node; + int len, err, i; + u32 *property_u32 = NULL; + const u32 *cproperty_u32; + const char *cproperty_char; + char str[USB251XB_STRING_BUFSIZE / 2]; + + if (!np) { + dev_err(dev, "failed to get ofdata\n"); + return -ENODEV; + } + + if (of_get_property(np, "skip-config", NULL)) + hub->skip_config = 1; + else + hub->skip_config = 0; + + hub->gpio_reset = of_get_named_gpio(np, "reset-gpios", 0); + if (hub->gpio_reset == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(hub->gpio_reset)) { + err = devm_gpio_request_one(dev, hub->gpio_reset, + GPIOF_OUT_INIT_LOW, + "usb251xb reset"); + if (err) { + dev_err(dev, + "unable to request GPIO %d as reset pin (%d)\n", + hub->gpio_reset, err); + return err; + } + } + + if (of_property_read_u16_array(np, "vendor-id", &hub->vendor_id, 1)) + hub->vendor_id = USB251XB_DEF_VENDOR_ID; + + if (of_property_read_u16_array(np, "product-id", + &hub->product_id, 1)) + hub->product_id = data->product_id; + + if (of_property_read_u16_array(np, "device-id", &hub->device_id, 1)) + hub->device_id = USB251XB_DEF_DEVICE_ID; + + hub->conf_data1 = USB251XB_DEF_CONFIG_DATA_1; + if (of_get_property(np, "self-powered", NULL)) { + hub->conf_data1 |= BIT(7); + + /* Configure Over-Current sens when self-powered */ + hub->conf_data1 &= ~BIT(2); + if (of_get_property(np, "ganged-sensing", NULL)) + hub->conf_data1 &= ~BIT(1); + else if (of_get_property(np, "individual-sensing", NULL)) + hub->conf_data1 |= BIT(1); + } else if (of_get_property(np, "bus-powered", NULL)) { + hub->conf_data1 &= ~BIT(7); + + /* Disable Over-Current sense when bus-powered */ + hub->conf_data1 |= BIT(2); + } + + if (of_get_property(np, "disable-hi-speed", NULL)) + hub->conf_data1 |= BIT(5); + + if (of_get_property(np, "multi-tt", NULL)) + hub->conf_data1 |= BIT(4); + else if (of_get_property(np, "single-tt", NULL)) + hub->conf_data1 &= ~BIT(4); + + if (of_get_property(np, "disable-eop", NULL)) + hub->conf_data1 |= BIT(3); + + if (of_get_property(np, "individual-port-switching", NULL)) + hub->conf_data1 |= BIT(0); + else if (of_get_property(np, "ganged-port-switching", NULL)) + hub->conf_data1 &= ~BIT(0); + + hub->conf_data2 = USB251XB_DEF_CONFIG_DATA_2; + if (of_get_property(np, "dynamic-power-switching", NULL)) + hub->conf_data2 |= BIT(7); + + if (of_get_property(np, "oc-delay-100us", NULL)) { + hub->conf_data2 &= ~BIT(5); + hub->conf_data2 &= ~BIT(4); + } else if (of_get_property(np, "oc-delay-4ms", NULL)) { + hub->conf_data2 &= ~BIT(5); + hub->conf_data2 |= BIT(4); + } else if (of_get_property(np, "oc-delay-8ms", NULL)) { + hub->conf_data2 |= BIT(5); + hub->conf_data2 &= ~BIT(4); + } else if (of_get_property(np, "oc-delay-16ms", NULL)) { + hub->conf_data2 |= BIT(5); + hub->conf_data2 |= BIT(4); + } + + if (of_get_property(np, "compound-device", NULL)) + hub->conf_data2 |= BIT(3); + + hub->conf_data3 = USB251XB_DEF_CONFIG_DATA_3; + if (of_get_property(np, "port-mapping-mode", NULL)) + hub->conf_data3 |= BIT(3); + + if (of_get_property(np, "string-support", NULL)) + hub->conf_data3 |= BIT(0); + + hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; + cproperty_u32 = of_get_property(np, "non-removable-ports", &len); + if (cproperty_u32 && (len / sizeof(u32)) > 0) { + for (i = 0; i < len / sizeof(u32); i++) { + u32 port = be32_to_cpu(cproperty_u32[i]); + + if ((port >= 1) && (port <= 4)) + hub->non_rem_dev |= BIT(port); + } + } + + hub->port_disable_sp = USB251XB_DEF_PORT_DISABLE_SELF; + cproperty_u32 = of_get_property(np, "sp-disabled-ports", &len); + if (cproperty_u32 && (len / sizeof(u32)) > 0) { + for (i = 0; i < len / sizeof(u32); i++) { + u32 port = be32_to_cpu(cproperty_u32[i]); + + if ((port >= 1) && (port <= 4)) + hub->port_disable_sp |= BIT(port); + } + } + + hub->port_disable_bp = USB251XB_DEF_PORT_DISABLE_BUS; + cproperty_u32 = of_get_property(np, "bp-disabled-ports", &len); + if (cproperty_u32 && (len / sizeof(u32)) > 0) { + for (i = 0; i < len / sizeof(u32); i++) { + u32 port = be32_to_cpu(cproperty_u32[i]); + + if ((port >= 1) && (port <= 4)) + hub->port_disable_bp |= BIT(port); + } + } + + hub->max_power_sp = USB251XB_DEF_MAX_POWER_SELF; + if (!of_property_read_u32(np, "max-sp-power", property_u32)) + hub->max_power_sp = min_t(u8, be32_to_cpu(*property_u32) / 2, + 250); + + hub->max_power_bp = USB251XB_DEF_MAX_POWER_BUS; + if (!of_property_read_u32(np, "max-bp-power", property_u32)) + hub->max_power_bp = min_t(u8, be32_to_cpu(*property_u32) / 2, + 250); + + hub->max_current_sp = USB251XB_DEF_MAX_CURRENT_SELF; + if (!of_property_read_u32(np, "max-sp-current", property_u32)) + hub->max_current_sp = min_t(u8, be32_to_cpu(*property_u32) / 2, + 250); + + hub->max_current_bp = USB251XB_DEF_MAX_CURRENT_BUS; + if (!of_property_read_u32(np, "max-bp-current", property_u32)) + hub->max_current_bp = min_t(u8, be32_to_cpu(*property_u32) / 2, + 250); + + hub->power_on_time = USB251XB_DEF_POWER_ON_TIME; + if (!of_property_read_u32(np, "power-on-time", property_u32)) + hub->power_on_time = min_t(u8, be32_to_cpu(*property_u32) / 2, + 255); + + if (of_property_read_u16_array(np, "language-id", &hub->lang_id, 1)) + hub->lang_id = USB251XB_DEF_LANGUAGE_ID; + + cproperty_char = of_get_property(np, "manufacturer", NULL); + strlcpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING, + sizeof(str)); + hub->manufacturer_len = strlen(str) & 0xFF; + memset(hub->manufacturer, 0, USB251XB_STRING_BUFSIZE); + len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str)); + len = utf8s_to_utf16s(str, len, UTF16_LITTLE_ENDIAN, + (wchar_t *)hub->manufacturer, + USB251XB_STRING_BUFSIZE); + + cproperty_char = of_get_property(np, "product", NULL); + strlcpy(str, cproperty_char ? : data->product_str, sizeof(str)); + hub->product_len = strlen(str) & 0xFF; + memset(hub->product, 0, USB251XB_STRING_BUFSIZE); + len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str)); + len = utf8s_to_utf16s(str, len, UTF16_LITTLE_ENDIAN, + (wchar_t *)hub->product, + USB251XB_STRING_BUFSIZE); + + cproperty_char = of_get_property(np, "serial", NULL); + strlcpy(str, cproperty_char ? : USB251XB_DEF_SERIAL_STRING, + sizeof(str)); + hub->serial_len = strlen(str) & 0xFF; + memset(hub->serial, 0, USB251XB_STRING_BUFSIZE); + len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str)); + len = utf8s_to_utf16s(str, len, UTF16_LITTLE_ENDIAN, + (wchar_t *)hub->serial, + USB251XB_STRING_BUFSIZE); + + /* The following parameters are currently not exposed to devicetree, but + * may be as soon as needed. + */ + hub->bat_charge_en = USB251XB_DEF_BATTERY_CHARGING_ENABLE; + hub->boost_up = USB251XB_DEF_BOOST_UP; + hub->boost_x = USB251XB_DEF_BOOST_X; + hub->port_swap = USB251XB_DEF_PORT_SWAP; + hub->port_map12 = USB251XB_DEF_PORT_MAP_12; + hub->port_map34 = USB251XB_DEF_PORT_MAP_34; + + return 0; +} + +static const struct of_device_id usb251xb_of_match[] = { + { + .compatible = "microchip,usb2512b", + .data = &usb2512b_data, + }, { + .compatible = "microchip,usb2512bi", + .data = &usb2512bi_data, + }, { + .compatible = "microchip,usb2513b", + .data = &usb2513b_data, + }, { + .compatible = "microchip,usb2513bi", + .data = &usb2513bi_data, + }, { + .compatible = "microchip,usb2514b", + .data = &usb2514b_data, + }, { + .compatible = "microchip,usb2514bi", + .data = &usb2514bi_data, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, usb251xb_of_match); +#else /* CONFIG_OF */ +static int usb251xb_get_ofdata(struct usb251xb *hub, + struct usb251xb_data *data) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static int usb251xb_probe(struct usb251xb *hub) +{ + struct device *dev = hub->dev; + struct device_node *np = dev->of_node; + const struct of_device_id *of_id = of_match_device(usb251xb_of_match, + dev); + int err; + + if (np) { + err = usb251xb_get_ofdata(hub, + (struct usb251xb_data *)of_id->data); + if (err) { + dev_err(dev, "failed to get ofdata: %d\n", err); + return err; + } + } + + err = usb251xb_connect(hub); + if (err) { + dev_err(dev, "Failed to connect hub (%d)\n", err); + return err; + } + + dev_info(dev, "Hub probed successfully\n"); + + return 0; +} + +static int usb251xb_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct usb251xb *hub; + + hub = devm_kzalloc(&i2c->dev, sizeof(struct usb251xb), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + i2c_set_clientdata(i2c, hub); + hub->dev = &i2c->dev; + hub->i2c = i2c; + + return usb251xb_probe(hub); +} + +static const struct i2c_device_id usb251xb_id[] = { + { "usb2512b", 0 }, + { "usb2512bi", 0 }, + { "usb2513b", 0 }, + { "usb2513bi", 0 }, + { "usb2514b", 0 }, + { "usb2514bi", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, usb251xb_id); + +static struct i2c_driver usb251xb_i2c_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(usb251xb_of_match), + }, + .probe = usb251xb_i2c_probe, + .id_table = usb251xb_id, +}; + +module_i2c_driver(usb251xb_i2c_driver); + +MODULE_AUTHOR("Richard Leitner <richard.leitner@skidata.com>"); +MODULE_DESCRIPTION("USB251xB/xBi USB 2.0 Hub Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 3525626bf086..17c081068257 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -992,7 +992,7 @@ static int ch9_postconfig(struct usbtest_dev *dev) dev_err(&iface->dev, "hs dev qualifier --> %d\n", retval); - return (retval < 0) ? retval : -EDOM; + return retval; } /* usb2.0 but not high-speed capable; fine */ } else if (retval != sizeof(struct usb_qualifier_descriptor)) { diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index ba9df719f363..aa6fd6a51221 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -225,6 +225,7 @@ struct ssusb_mtk { /* common power & clock */ struct regulator *vusb33; struct clk *sys_clk; + struct clk *ref_clk; /* otg */ struct otg_switch_mtk otg_switch; enum usb_dr_mode dr_mode; diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 783367805c99..42550c7db3e7 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -123,7 +123,13 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb) ret = clk_prepare_enable(ssusb->sys_clk); if (ret) { dev_err(ssusb->dev, "failed to enable sys_clk\n"); - goto clk_err; + goto sys_clk_err; + } + + ret = clk_prepare_enable(ssusb->ref_clk); + if (ret) { + dev_err(ssusb->dev, "failed to enable ref_clk\n"); + goto ref_clk_err; } ret = ssusb_phy_init(ssusb); @@ -143,8 +149,10 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb) phy_err: ssusb_phy_exit(ssusb); phy_init_err: + clk_disable_unprepare(ssusb->ref_clk); +ref_clk_err: clk_disable_unprepare(ssusb->sys_clk); -clk_err: +sys_clk_err: regulator_disable(ssusb->vusb33); vusb33_err: @@ -154,6 +162,7 @@ vusb33_err: static void ssusb_rscs_exit(struct ssusb_mtk *ssusb) { clk_disable_unprepare(ssusb->sys_clk); + clk_disable_unprepare(ssusb->ref_clk); regulator_disable(ssusb->vusb33); ssusb_phy_power_off(ssusb); ssusb_phy_exit(ssusb); @@ -204,6 +213,31 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) int i; int ret; + ssusb->vusb33 = devm_regulator_get(&pdev->dev, "vusb33"); + if (IS_ERR(ssusb->vusb33)) { + dev_err(dev, "failed to get vusb33\n"); + return PTR_ERR(ssusb->vusb33); + } + + ssusb->sys_clk = devm_clk_get(dev, "sys_ck"); + if (IS_ERR(ssusb->sys_clk)) { + dev_err(dev, "failed to get sys clock\n"); + return PTR_ERR(ssusb->sys_clk); + } + + /* + * reference clock is usually a "fixed-clock", make it optional + * for backward compatibility and ignore the error if it does + * not exist. + */ + ssusb->ref_clk = devm_clk_get(dev, "ref_ck"); + if (IS_ERR(ssusb->ref_clk)) { + if (PTR_ERR(ssusb->ref_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + ssusb->ref_clk = NULL; + } + ssusb->num_phys = of_count_phandle_with_args(node, "phys", "#phy-cells"); if (ssusb->num_phys > 0) { @@ -225,22 +259,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ippc"); ssusb->ippc_base = devm_ioremap_resource(dev, res); - if (IS_ERR(ssusb->ippc_base)) { - dev_err(dev, "failed to map memory for ippc\n"); + if (IS_ERR(ssusb->ippc_base)) return PTR_ERR(ssusb->ippc_base); - } - - ssusb->vusb33 = devm_regulator_get(&pdev->dev, "vusb33"); - if (IS_ERR(ssusb->vusb33)) { - dev_err(dev, "failed to get vusb33\n"); - return PTR_ERR(ssusb->vusb33); - } - - ssusb->sys_clk = devm_clk_get(dev, "sys_ck"); - if (IS_ERR(ssusb->sys_clk)) { - dev_err(dev, "failed to get sys clock\n"); - return PTR_ERR(ssusb->sys_clk); - } ssusb->dr_mode = usb_get_dr_mode(dev); if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN) { @@ -428,6 +448,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev) ssusb_host_disable(ssusb, true); ssusb_phy_power_off(ssusb); clk_disable_unprepare(ssusb->sys_clk); + clk_disable_unprepare(ssusb->ref_clk); ssusb_wakeup_enable(ssusb); return 0; @@ -445,6 +466,7 @@ static int __maybe_unused mtu3_resume(struct device *dev) ssusb_wakeup_disable(ssusb); clk_prepare_enable(ssusb->sys_clk); + clk_prepare_enable(ssusb->ref_clk); ssusb_phy_power_on(ssusb); ssusb_host_enable(ssusb); diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 50ca8052bc8e..02fbb4fe3745 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -121,7 +121,6 @@ static void am35x_musb_disable(struct musb *musb) musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, AM35X_INTR_USB_MASK); musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG, AM35X_TX_INTR_MASK | AM35X_RX_INTR_MASK); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writel(reg_base, USB_END_OF_INTR_REG, 0); } diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 896798071817..4418574a36a1 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -581,8 +581,7 @@ static int bfin_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int bfin_suspend(struct device *dev) +static int __maybe_unused bfin_suspend(struct device *dev) { struct bfin_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); @@ -599,7 +598,7 @@ static int bfin_suspend(struct device *dev) return 0; } -static int bfin_resume(struct device *dev) +static int __maybe_unused bfin_resume(struct device *dev) { struct bfin_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); @@ -608,7 +607,6 @@ static int bfin_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume); diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 1ae48e64e975..c4fabe952ca6 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -224,7 +224,7 @@ static void cppi_controller_stop(struct cppi *controller) int i; struct musb *musb; - musb = controller->musb; + musb = controller->controller.musb; tibase = controller->tibase; /* DISABLE INDIVIDUAL CHANNEL Interrupts */ @@ -288,7 +288,7 @@ cppi_channel_allocate(struct dma_controller *c, controller = container_of(c, struct cppi, controller); tibase = controller->tibase; - musb = controller->musb; + musb = c->musb; /* ep0 doesn't use DMA; remember cppi indices are 0..N-1 */ index = ep->epnum - 1; @@ -336,7 +336,7 @@ static void cppi_channel_release(struct dma_channel *channel) c = container_of(channel, struct cppi_channel, channel); tibase = c->controller->tibase; if (!c->hw_ep) - musb_dbg(c->controller->musb, + musb_dbg(c->controller->controller.musb, "releasing idle DMA channel %p", c); else if (!c->transmit) core_rxirq_enable(tibase, c->index + 1); @@ -355,7 +355,7 @@ cppi_dump_rx(int level, struct cppi_channel *c, const char *tag) musb_ep_select(base, c->index + 1); - musb_dbg(c->controller->musb, + musb_dbg(c->controller->controller.musb, "RX DMA%d%s: %d left, csr %04x, " "%08x H%08x S%08x C%08x, " "B%08x L%08x %08x .. %08x", @@ -385,7 +385,7 @@ cppi_dump_tx(int level, struct cppi_channel *c, const char *tag) musb_ep_select(base, c->index + 1); - musb_dbg(c->controller->musb, + musb_dbg(c->controller->controller.musb, "TX DMA%d%s: csr %04x, " "H%08x S%08x C%08x %08x, " "F%08x L%08x .. %08x", @@ -954,7 +954,7 @@ static int cppi_channel_program(struct dma_channel *ch, cppi_ch = container_of(ch, struct cppi_channel, channel); controller = cppi_ch->controller; - musb = controller->musb; + musb = controller->controller.musb; switch (ch->status) { case MUSB_DMA_STATUS_BUS_ABORT: @@ -1009,7 +1009,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) int i; dma_addr_t safe2ack; void __iomem *regs = rx->hw_ep->regs; - struct musb *musb = cppi->musb; + struct musb *musb = cppi->controller.musb; cppi_dump_rx(6, rx, "/K"); @@ -1121,7 +1121,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) * setting it here "should" be racey, but seems to work */ csr = musb_readw(rx->hw_ep->regs, MUSB_RXCSR); - if (is_host_active(cppi->musb) + if (is_host_active(cppi->controller.musb) && bd && !(csr & MUSB_RXCSR_H_REQPKT)) { csr |= MUSB_RXCSR_H_REQPKT; @@ -1311,7 +1311,7 @@ cppi_dma_controller_create(struct musb *musb, void __iomem *mregs) controller->mregs = mregs; controller->tibase = mregs - DAVINCI_BASE_OFFSET; - controller->musb = musb; + controller->controller.musb = musb; controller->controller.channel_alloc = cppi_channel_allocate; controller->controller.channel_release = cppi_channel_release; controller->controller.channel_program = cppi_channel_program; @@ -1323,7 +1323,7 @@ cppi_dma_controller_create(struct musb *musb, void __iomem *mregs) /* setup BufferPool */ controller->pool = dma_pool_create("cppi", - controller->musb->controller, + controller->controller.musb->controller, sizeof(struct cppi_descriptor), CPPI_DESCRIPTOR_ALIGN, 0); if (!controller->pool) { @@ -1357,7 +1357,7 @@ void cppi_dma_controller_destroy(struct dma_controller *c) cppi_controller_stop(cppi); if (cppi->irq) - free_irq(cppi->irq, cppi->musb); + free_irq(cppi->irq, cppi->controller.musb); /* assert: caller stopped the controller first */ dma_pool_destroy(cppi->pool); @@ -1469,7 +1469,7 @@ static int cppi_channel_abort(struct dma_channel *channel) core_rxirq_disable(tibase, cppi_ch->index + 1); /* for host, ensure ReqPkt is never set again */ - if (is_host_active(cppi_ch->controller->musb)) { + if (is_host_active(cppi_ch->controller->controller.musb)) { value = musb_readl(tibase, DAVINCI_AUTOREQ_REG); value &= ~((0x3) << (cppi_ch->index * 2)); musb_writel(tibase, DAVINCI_AUTOREQ_REG, value); @@ -1478,7 +1478,7 @@ static int cppi_channel_abort(struct dma_channel *channel) csr = musb_readw(regs, MUSB_RXCSR); /* for host, clear (just) ReqPkt at end of current packet(s) */ - if (is_host_active(cppi_ch->controller->musb)) { + if (is_host_active(cppi_ch->controller->controller.musb)) { csr |= MUSB_RXCSR_H_WZC_BITS; csr &= ~MUSB_RXCSR_H_REQPKT; } else diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h index 7fdfb71a8f09..9bb7c5e45c85 100644 --- a/drivers/usb/musb/cppi_dma.h +++ b/drivers/usb/musb/cppi_dma.h @@ -107,7 +107,6 @@ struct cppi_channel { /* CPPI DMA controller object */ struct cppi { struct dma_controller controller; - struct musb *musb; void __iomem *mregs; /* Mentor regs */ void __iomem *tibase; /* TI/CPPI regs */ diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index e89708d839e5..d79c288ccbf2 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -125,7 +125,6 @@ static void da8xx_musb_disable(struct musb *musb) musb_writel(reg_base, DA8XX_USB_INTR_MASK_CLEAR_REG, DA8XX_INTR_USB_MASK | DA8XX_INTR_TX_MASK | DA8XX_INTR_RX_MASK); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0); } @@ -458,15 +457,11 @@ static inline u8 get_vbus_power(struct device *dev) } static const struct musb_platform_ops da8xx_ops = { - .quirks = MUSB_DMA_CPPI | MUSB_INDEXED_EP, + .quirks = MUSB_INDEXED_EP | MUSB_PRESERVE_SESSION, .init = da8xx_musb_init, .exit = da8xx_musb_exit, .fifo_mode = 2, -#ifdef CONFIG_USB_TI_CPPI_DMA - .dma_init = cppi_dma_controller_create, - .dma_exit = cppi_dma_controller_destroy, -#endif .enable = da8xx_musb_enable, .disable = da8xx_musb_disable, @@ -578,6 +573,34 @@ static int da8xx_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int da8xx_suspend(struct device *dev) +{ + int ret; + struct da8xx_glue *glue = dev_get_drvdata(dev); + + ret = phy_power_off(glue->phy); + if (ret) + return ret; + clk_disable_unprepare(glue->clk); + + return 0; +} + +static int da8xx_resume(struct device *dev) +{ + int ret; + struct da8xx_glue *glue = dev_get_drvdata(dev); + + ret = clk_prepare_enable(glue->clk); + if (ret) + return ret; + return phy_power_on(glue->phy); +} +#endif + +static SIMPLE_DEV_PM_OPS(da8xx_pm_ops, da8xx_suspend, da8xx_resume); + #ifdef CONFIG_OF static const struct of_device_id da8xx_id_table[] = { { @@ -593,6 +616,7 @@ static struct platform_driver da8xx_driver = { .remove = da8xx_remove, .driver = { .name = "musb-da8xx", + .pm = &da8xx_pm_ops, .of_match_table = of_match_ptr(da8xx_id_table), }, }; diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index cee61a51645e..52b491d3d5d8 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -133,7 +133,6 @@ static void davinci_musb_disable(struct musb *musb) DAVINCI_USB_USBINT_MASK | DAVINCI_USB_TXINT_MASK | DAVINCI_USB_RXINT_MASK); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0); if (is_dma_capable() && !dma_off) diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index bc8889956d17..40c68c23d553 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -63,7 +63,7 @@ static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = { { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, }, }; -static struct musb_hdrc_config jz4740_musb_config = { +static const struct musb_hdrc_config jz4740_musb_config = { /* Silicon does not implement USB OTG. */ .multipoint = 0, /* Max EPs scanned, driver will decide which EP can be used. */ diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 772f15821242..d8bae6ca8904 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1040,16 +1040,6 @@ static void musb_enable_interrupts(struct musb *musb) } -static void musb_generic_disable(struct musb *musb) -{ - void __iomem *mbase = musb->mregs; - - musb_disable_interrupts(musb); - - /* off */ - musb_writeb(mbase, MUSB_DEVCTL, 0); -} - /* * Program the HDRC to start (enable interrupts, dma, etc.). */ @@ -1106,8 +1096,8 @@ void musb_stop(struct musb *musb) { /* stop IRQs, timers, ... */ musb_platform_disable(musb); - musb_generic_disable(musb); - musb_dbg(musb, "HDRC disabled"); + musb_disable_interrupts(musb); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); /* FIXME * - mark host and/or peripheral drivers unusable/inactive @@ -1879,6 +1869,7 @@ static void musb_pm_runtime_check_session(struct musb *musb) return; } + /* fall through */ case MUSB_QUIRK_A_DISCONNECT_19: if (musb->quirk_retries--) { musb_dbg(musb, @@ -2323,7 +2314,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) /* be sure interrupts are disabled before connecting ISR */ musb_platform_disable(musb); - musb_generic_disable(musb); + musb_disable_interrupts(musb); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); /* Init IRQ workqueue before request_irq */ INIT_DELAYED_WORK(&musb->irq_work, musb_irq_work); @@ -2497,11 +2489,13 @@ static int musb_remove(struct platform_device *pdev) pm_runtime_get_sync(musb->controller); musb_host_cleanup(musb); musb_gadget_cleanup(musb); + spin_lock_irqsave(&musb->lock, flags); musb_platform_disable(musb); - musb_generic_disable(musb); - spin_unlock_irqrestore(&musb->lock, flags); + musb_disable_interrupts(musb); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + spin_unlock_irqrestore(&musb->lock, flags); + pm_runtime_dont_use_autosuspend(musb->controller); pm_runtime_put_sync(musb->controller); pm_runtime_disable(musb->controller); @@ -2676,7 +2670,9 @@ static int musb_suspend(struct device *dev) unsigned long flags; musb_platform_disable(musb); - musb_generic_disable(musb); + musb_disable_interrupts(musb); + if (!(musb->io.quirks & MUSB_PRESERVE_SESSION)) + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); WARN_ON(!list_empty(&musb->pending_list)); spin_lock_irqsave(&musb->lock, flags); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index ce5a18c98c6d..5b708be6d1d1 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -172,6 +172,7 @@ struct musb_io; */ struct musb_platform_ops { +#define MUSB_PRESERVE_SESSION BIT(7) #define MUSB_DMA_UX500 BIT(6) #define MUSB_DMA_CPPI41 BIT(5) #define MUSB_DMA_CPPI BIT(4) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 16363852c034..00e272bfee39 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -30,7 +30,6 @@ struct cppi41_dma_controller { struct dma_controller controller; struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS]; struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS]; - struct musb *musb; struct hrtimer early_tx; struct list_head early_tx_list; u32 rx_mode; @@ -45,7 +44,7 @@ static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel) if (cppi41_channel->is_tx) return; - if (!is_host_active(cppi41_channel->controller->musb)) + if (!is_host_active(cppi41_channel->controller->controller.musb)) return; csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); @@ -78,8 +77,7 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) if (!toggle && toggle == cppi41_channel->usb_toggle) { csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE; musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr); - musb_dbg(cppi41_channel->controller->musb, - "Restoring DATA1 toggle."); + musb_dbg(musb, "Restoring DATA1 toggle."); } cppi41_channel->usb_toggle = toggle; @@ -99,7 +97,8 @@ static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep) return true; } -static void cppi41_dma_callback(void *private_data); +static void cppi41_dma_callback(void *private_data, + const struct dmaengine_result *result); static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) { @@ -154,7 +153,7 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) if (WARN_ON(!dma_desc)) return; - dma_desc->callback = cppi41_dma_callback; + dma_desc->callback_result = cppi41_dma_callback; dma_desc->callback_param = &cppi41_channel->channel; cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); trace_musb_cppi41_cont(cppi41_channel); @@ -179,7 +178,7 @@ static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) controller = container_of(timer, struct cppi41_dma_controller, early_tx); - musb = controller->musb; + musb = controller->controller.musb; spin_lock_irqsave(&musb->lock, flags); list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list, @@ -204,7 +203,8 @@ static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) return ret; } -static void cppi41_dma_callback(void *private_data) +static void cppi41_dma_callback(void *private_data, + const struct dmaengine_result *result) { struct dma_channel *channel = private_data; struct cppi41_dma_channel *cppi41_channel = channel->private_data; @@ -217,6 +217,13 @@ static void cppi41_dma_callback(void *private_data) int is_hs = 0; bool empty; + controller = cppi41_channel->controller; + if (controller->controller.dma_callback) + controller->controller.dma_callback(&controller->controller); + + if (result->result == DMA_TRANS_ABORTED) + return; + spin_lock_irqsave(&musb->lock, flags); dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, @@ -249,8 +256,6 @@ static void cppi41_dma_callback(void *private_data) * We spin on HS (no longer than than 25us and setup a timer on * FS to check for the bit and complete the transfer. */ - controller = cppi41_channel->controller; - if (is_host_active(musb)) { if (musb->port1_status & USB_PORT_STAT_HIGH_SPEED) is_hs = 1; @@ -302,6 +307,7 @@ static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel, unsigned mode) { struct cppi41_dma_controller *controller = cppi41_channel->controller; + struct musb *musb = controller->controller.musb; u32 port; u32 new_mode; u32 old_mode; @@ -317,12 +323,10 @@ static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel, return; if (cppi41_channel->is_tx) { controller->tx_mode = new_mode; - musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE, - new_mode); + musb_writel(musb->ctrl_base, USB_CTRL_TX_MODE, new_mode); } else { controller->rx_mode = new_mode; - musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE, - new_mode); + musb_writel(musb->ctrl_base, USB_CTRL_RX_MODE, new_mode); } } @@ -341,7 +345,8 @@ static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel, if (new_mode == old_mode) return; controller->auto_req = new_mode; - musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode); + musb_writel(controller->controller.musb->ctrl_base, USB_CTRL_AUTOREQ, + new_mode); } static bool cppi41_configure_channel(struct dma_channel *channel, @@ -352,7 +357,7 @@ static bool cppi41_configure_channel(struct dma_channel *channel, struct dma_chan *dc = cppi41_channel->dc; struct dma_async_tx_descriptor *dma_desc; enum dma_transfer_direction direction; - struct musb *musb = cppi41_channel->controller->musb; + struct musb *musb = cppi41_channel->controller->controller.musb; unsigned use_gen_rndis = 0; cppi41_channel->buf_addr = dma_addr; @@ -401,7 +406,7 @@ static bool cppi41_configure_channel(struct dma_channel *channel, if (!dma_desc) return false; - dma_desc->callback = cppi41_dma_callback; + dma_desc->callback_result = cppi41_dma_callback; dma_desc->callback_param = channel; cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); cppi41_channel->channel.rx_packet_done = false; @@ -465,7 +470,7 @@ static int cppi41_dma_channel_program(struct dma_channel *channel, BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || channel->status == MUSB_DMA_STATUS_BUSY); - if (is_host_active(cppi41_channel->controller->musb)) { + if (is_host_active(cppi41_channel->controller->controller.musb)) { if (cppi41_channel->is_tx) hb_mult = cppi41_channel->hw_ep->out_qh->hb_mult; else @@ -490,7 +495,7 @@ static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, { struct cppi41_dma_channel *cppi41_channel = channel->private_data; struct cppi41_dma_controller *controller = cppi41_channel->controller; - struct musb *musb = controller->musb; + struct musb *musb = controller->controller.musb; if (is_host_active(musb)) { WARN_ON(1); @@ -508,7 +513,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel) { struct cppi41_dma_channel *cppi41_channel = channel->private_data; struct cppi41_dma_controller *controller = cppi41_channel->controller; - struct musb *musb = controller->musb; + struct musb *musb = controller->controller.musb; void __iomem *epio = cppi41_channel->hw_ep->regs; int tdbit; int ret; @@ -593,7 +598,7 @@ static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller) static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) { - struct musb *musb = controller->musb; + struct musb *musb = controller->controller.musb; struct device *dev = musb->controller; struct device_node *np = dev->parent->of_node; struct cppi41_dma_channel *cppi41_channel; @@ -688,13 +693,13 @@ cppi41_dma_controller_create(struct musb *musb, void __iomem *base) hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); controller->early_tx.function = cppi41_recheck_tx_req; INIT_LIST_HEAD(&controller->early_tx_list); - controller->musb = musb; controller->controller.channel_alloc = cppi41_dma_channel_allocate; controller->controller.channel_release = cppi41_dma_channel_release; controller->controller.channel_program = cppi41_dma_channel_program; controller->controller.channel_abort = cppi41_dma_channel_abort; controller->controller.is_compatible = cppi41_is_compatible; + controller->controller.musb = musb; ret = cppi41_dma_controller_start(controller); if (ret) diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index dd70c88419d2..952733ceaac8 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -153,28 +153,34 @@ static int musb_test_mode_show(struct seq_file *s, void *unused) pm_runtime_mark_last_busy(musb->controller); pm_runtime_put_autosuspend(musb->controller); - if (test & MUSB_TEST_FORCE_HOST) + if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS)) + seq_printf(s, "force host full-speed\n"); + + else if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS)) + seq_printf(s, "force host high-speed\n"); + + else if (test == MUSB_TEST_FORCE_HOST) seq_printf(s, "force host\n"); - if (test & MUSB_TEST_FIFO_ACCESS) + else if (test == MUSB_TEST_FIFO_ACCESS) seq_printf(s, "fifo access\n"); - if (test & MUSB_TEST_FORCE_FS) + else if (test == MUSB_TEST_FORCE_FS) seq_printf(s, "force full-speed\n"); - if (test & MUSB_TEST_FORCE_HS) + else if (test == MUSB_TEST_FORCE_HS) seq_printf(s, "force high-speed\n"); - if (test & MUSB_TEST_PACKET) + else if (test == MUSB_TEST_PACKET) seq_printf(s, "test packet\n"); - if (test & MUSB_TEST_K) + else if (test == MUSB_TEST_K) seq_printf(s, "test K\n"); - if (test & MUSB_TEST_J) + else if (test == MUSB_TEST_J) seq_printf(s, "test J\n"); - if (test & MUSB_TEST_SE0_NAK) + else if (test == MUSB_TEST_SE0_NAK) seq_printf(s, "test SE0 NAK\n"); return 0; @@ -198,7 +204,7 @@ static ssize_t musb_test_mode_write(struct file *file, struct seq_file *s = file->private_data; struct musb *musb = s->private; u8 test; - char buf[18]; + char buf[24]; pm_runtime_get_sync(musb->controller); test = musb_readb(musb->mregs, MUSB_TESTMODE); @@ -213,30 +219,36 @@ static ssize_t musb_test_mode_write(struct file *file, if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; - if (strstarts(buf, "force host")) + if (strstarts(buf, "force host full-speed")) + test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS; + + else if (strstarts(buf, "force host high-speed")) + test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS; + + else if (strstarts(buf, "force host")) test = MUSB_TEST_FORCE_HOST; - if (strstarts(buf, "fifo access")) + else if (strstarts(buf, "fifo access")) test = MUSB_TEST_FIFO_ACCESS; - if (strstarts(buf, "force full-speed")) + else if (strstarts(buf, "force full-speed")) test = MUSB_TEST_FORCE_FS; - if (strstarts(buf, "force high-speed")) + else if (strstarts(buf, "force high-speed")) test = MUSB_TEST_FORCE_HS; - if (strstarts(buf, "test packet")) { + else if (strstarts(buf, "test packet")) { test = MUSB_TEST_PACKET; musb_load_testpacket(musb); } - if (strstarts(buf, "test K")) + else if (strstarts(buf, "test K")) test = MUSB_TEST_K; - if (strstarts(buf, "test J")) + else if (strstarts(buf, "test J")) test = MUSB_TEST_J; - if (strstarts(buf, "test SE0 NAK")) + else if (strstarts(buf, "test SE0 NAK")) test = MUSB_TEST_SE0_NAK; musb_writeb(musb->mregs, MUSB_TESTMODE, test); diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 46357e183b4c..04c3bd86bd62 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -173,6 +173,7 @@ dma_channel_status(struct dma_channel *c) /** * struct dma_controller - A DMA Controller. + * @musb: the usb controller * @start: call this to start a DMA controller; * return 0 on success, else negative errno * @stop: call this to stop a DMA controller @@ -181,10 +182,13 @@ dma_channel_status(struct dma_channel *c) * @channel_release: call this to release a DMA channel * @channel_abort: call this to abort a pending DMA transaction, * returning it to FREE (but allocated) state + * @dma_callback: invoked on DMA completion, useful to run platform + * code such IRQ acknowledgment. * * Controllers manage dma channels. */ struct dma_controller { + struct musb *musb; struct dma_channel *(*channel_alloc)(struct dma_controller *, struct musb_hw_ep *, u8 is_tx); void (*channel_release)(struct dma_channel *); @@ -196,6 +200,7 @@ struct dma_controller { int (*is_compatible)(struct dma_channel *channel, u16 maxpacket, void *buf, u32 length); + void (*dma_callback)(struct dma_controller *); }; /* called after channel_program(), may indicate a fault */ diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 9f125e179acd..7c047c4a2565 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -118,9 +118,11 @@ struct dsps_glue { struct device *dev; struct platform_device *musb; /* child musb pdev */ const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ + int vbus_irq; /* optional vbus irq */ struct timer_list timer; /* otg_workaround timer */ unsigned long last_timer; /* last timer data for each instance */ bool sw_babble_enabled; + void __iomem *usbss_base; struct dsps_context context; struct debugfs_regset32 regset; @@ -145,6 +147,36 @@ static const struct debugfs_reg32 dsps_musb_regs[] = { { "mode", 0xe8 }, }; +static void dsps_mod_timer(struct dsps_glue *glue, int wait_ms) +{ + int wait; + + if (wait_ms < 0) + wait = msecs_to_jiffies(glue->wrp->poll_timeout); + else + wait = msecs_to_jiffies(wait_ms); + + mod_timer(&glue->timer, jiffies + wait); +} + +/* + * If no vbus irq from the PMIC is configured, we need to poll VBUS status. + */ +static void dsps_mod_timer_optional(struct dsps_glue *glue) +{ + if (glue->vbus_irq) + return; + + dsps_mod_timer(glue, -1); +} + +/* USBSS / USB AM335x */ +#define USBSS_IRQ_STATUS 0x28 +#define USBSS_IRQ_ENABLER 0x2c +#define USBSS_IRQ_CLEARR 0x30 + +#define USBSS_IRQ_PD_COMP (1 << 2) + /** * dsps_musb_enable - enable interrupts */ @@ -167,8 +199,7 @@ static void dsps_musb_enable(struct musb *musb) /* start polling for ID change in dual-role idle mode */ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer(glue, -1); } /** @@ -186,7 +217,6 @@ static void dsps_musb_disable(struct musb *musb) musb_writel(reg_base, wrp->epintr_clear, wrp->txep_bitmap | wrp->rxep_bitmap); del_timer_sync(&glue->timer); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); } /* Caller must take musb->lock */ @@ -199,6 +229,9 @@ static int dsps_check_status(struct musb *musb, void *unused) u8 devctl; int skip_session = 0; + if (glue->vbus_irq) + del_timer(&glue->timer); + /* * We poll because DSPS IP's won't expose several OTG-critical * status change events (from the transceiver) otherwise. @@ -209,8 +242,7 @@ static int dsps_check_status(struct musb *musb, void *unused) switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_VRISE: - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); break; case OTG_STATE_A_WAIT_BCON: musb_writeb(musb->mregs, MUSB_DEVCTL, 0); @@ -219,17 +251,19 @@ static int dsps_check_status(struct musb *musb, void *unused) case OTG_STATE_A_IDLE: case OTG_STATE_B_IDLE: - if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->otg->state = OTG_STATE_B_IDLE; - MUSB_DEV_MODE(musb); - } else { - musb->xceiv->otg->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); + if (!glue->vbus_irq) { + if (devctl & MUSB_DEVCTL_BDEVICE) { + musb->xceiv->otg->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + } else { + musb->xceiv->otg->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + } + if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) + musb_writeb(mregs, MUSB_DEVCTL, + MUSB_DEVCTL_SESSION); } - if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) - musb_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); break; case OTG_STATE_A_WAIT_VFALL: musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; @@ -267,7 +301,7 @@ static void otg_timer(unsigned long _musb) pm_runtime_put_autosuspend(dev); } -void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) +static void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) { u32 epintr; struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); @@ -332,15 +366,13 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); @@ -364,8 +396,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) switch (musb->xceiv->otg->state) { case OTG_STATE_B_IDLE: case OTG_STATE_A_WAIT_BCON: - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); break; default: break; @@ -469,8 +500,7 @@ static int dsps_musb_init(struct musb *musb) musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val); } - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(glue->wrp->poll_timeout)); + dsps_mod_timer(glue, -1); return dsps_musb_dbg_init(musb, glue); } @@ -619,14 +649,76 @@ static void dsps_read_fifo32(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) } } +#ifdef CONFIG_USB_TI_CPPI41_DMA +static void dsps_dma_controller_callback(struct dma_controller *c) +{ + struct musb *musb = c->musb; + struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); + void __iomem *usbss_base = glue->usbss_base; + u32 status; + + status = musb_readl(usbss_base, USBSS_IRQ_STATUS); + if (status & USBSS_IRQ_PD_COMP) + musb_writel(usbss_base, USBSS_IRQ_STATUS, USBSS_IRQ_PD_COMP); +} + +static struct dma_controller * +dsps_dma_controller_create(struct musb *musb, void __iomem *base) +{ + struct dma_controller *controller; + struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); + void __iomem *usbss_base = glue->usbss_base; + + controller = cppi41_dma_controller_create(musb, base); + if (IS_ERR_OR_NULL(controller)) + return controller; + + musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); + controller->dma_callback = dsps_dma_controller_callback; + + return controller; +} + +static void dsps_dma_controller_destroy(struct dma_controller *c) +{ + struct musb *musb = c->musb; + struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); + void __iomem *usbss_base = glue->usbss_base; + + musb_writel(usbss_base, USBSS_IRQ_CLEARR, USBSS_IRQ_PD_COMP); + cppi41_dma_controller_destroy(c); +} + +#ifdef CONFIG_PM_SLEEP +static void dsps_dma_controller_suspend(struct dsps_glue *glue) +{ + void __iomem *usbss_base = glue->usbss_base; + + musb_writel(usbss_base, USBSS_IRQ_CLEARR, USBSS_IRQ_PD_COMP); +} + +static void dsps_dma_controller_resume(struct dsps_glue *glue) +{ + void __iomem *usbss_base = glue->usbss_base; + + musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); +} +#endif +#else /* CONFIG_USB_TI_CPPI41_DMA */ +#ifdef CONFIG_PM_SLEEP +static void dsps_dma_controller_suspend(struct dsps_glue *glue) {} +static void dsps_dma_controller_resume(struct dsps_glue *glue) {} +#endif +#endif /* CONFIG_USB_TI_CPPI41_DMA */ + static struct musb_platform_ops dsps_ops = { .quirks = MUSB_DMA_CPPI41 | MUSB_INDEXED_EP, .init = dsps_musb_init, .exit = dsps_musb_exit, #ifdef CONFIG_USB_TI_CPPI41_DMA - .dma_init = cppi41_dma_controller_create, - .dma_exit = cppi41_dma_controller_destroy, + .dma_init = dsps_dma_controller_create, + .dma_exit = dsps_dma_controller_destroy, #endif .enable = dsps_musb_enable, .disable = dsps_musb_disable, @@ -696,7 +788,8 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, resources[1] = *res; /* allocate the child platform device */ - musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); + musb = platform_device_alloc("musb-hdrc", + (resources[0].start & 0xFFF) == 0x400 ? 0 : 1); if (!musb) { dev_err(dev, "failed to allocate musb device\n"); return -ENOMEM; @@ -765,6 +858,47 @@ err: return ret; } +static irqreturn_t dsps_vbus_threaded_irq(int irq, void *priv) +{ + struct dsps_glue *glue = priv; + struct musb *musb = platform_get_drvdata(glue->musb); + + if (!musb) + return IRQ_NONE; + + dev_dbg(glue->dev, "VBUS interrupt\n"); + dsps_mod_timer(glue, 0); + + return IRQ_HANDLED; +} + +static int dsps_setup_optional_vbus_irq(struct platform_device *pdev, + struct dsps_glue *glue) +{ + int error; + + glue->vbus_irq = platform_get_irq_byname(pdev, "vbus"); + if (glue->vbus_irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + + if (glue->vbus_irq <= 0) { + glue->vbus_irq = 0; + return 0; + } + + error = devm_request_threaded_irq(glue->dev, glue->vbus_irq, + NULL, dsps_vbus_threaded_irq, + IRQF_ONESHOT, + "vbus", glue); + if (error) { + glue->vbus_irq = 0; + return error; + } + dev_dbg(glue->dev, "VBUS irq %i configured\n", glue->vbus_irq); + + return 0; +} + static int dsps_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -792,6 +926,15 @@ static int dsps_probe(struct platform_device *pdev) glue->dev = &pdev->dev; glue->wrp = wrp; + glue->usbss_base = of_iomap(pdev->dev.parent->of_node, 0); + if (!glue->usbss_base) + return -ENXIO; + + if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL) { + ret = dsps_setup_optional_vbus_irq(pdev, glue); + if (ret) + return ret; + } platform_set_drvdata(pdev, glue); pm_runtime_enable(&pdev->dev); @@ -880,6 +1023,8 @@ static int dsps_suspend(struct device *dev) glue->context.tx_mode = musb_readl(mbase, wrp->tx_mode); glue->context.rx_mode = musb_readl(mbase, wrp->rx_mode); + dsps_dma_controller_suspend(glue); + return 0; } @@ -893,6 +1038,8 @@ static int dsps_resume(struct device *dev) if (!musb) return 0; + dsps_dma_controller_resume(glue); + mbase = musb->ctrl_base; musb_writel(mbase, wrp->control, glue->context.control); musb_writel(mbase, wrp->epintr_set, glue->context.epintr); @@ -903,8 +1050,7 @@ static int dsps_resume(struct device *dev) musb_writel(mbase, wrp->rx_mode, glue->context.rx_mode); if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer(glue, -1); return 0; } diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 8b73214a9ea3..456f3e6ecf03 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -575,7 +575,7 @@ static int omap2430_runtime_resume(struct device *dev) return 0; } -static struct dev_pm_ops omap2430_pm_ops = { +static const struct dev_pm_ops omap2430_pm_ops = { .runtime_suspend = omap2430_runtime_suspend, .runtime_resume = omap2430_runtime_resume, }; diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index d0be0eadd0d9..c9a09b5bb6e5 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -251,14 +251,14 @@ static int sunxi_musb_init(struct musb *musb) writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0); /* Register notifier before calling phy_init() */ - ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, - &glue->host_nb); + ret = devm_extcon_register_notifier(glue->dev, glue->extcon, + EXTCON_USB_HOST, &glue->host_nb); if (ret) goto error_reset_assert; ret = phy_init(glue->phy); if (ret) - goto error_unregister_notifier; + goto error_reset_assert; musb->isr = sunxi_musb_interrupt; @@ -267,9 +267,6 @@ static int sunxi_musb_init(struct musb *musb) return 0; -error_unregister_notifier: - extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, - &glue->host_nb); error_reset_assert: if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) reset_control_assert(glue->rst); @@ -293,9 +290,6 @@ static int sunxi_musb_exit(struct musb *musb) phy_exit(glue->phy); - extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, - &glue->host_nb); - if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) reset_control_assert(glue->rst); @@ -645,7 +639,21 @@ static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = { MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512), }; -static struct musb_hdrc_config sunxi_musb_hdrc_config = { +/* H3/V3s OTG supports only 4 endpoints */ +#define SUNXI_MUSB_MAX_EP_NUM_H3 5 + +static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = { + MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512), +}; + +static const struct musb_hdrc_config sunxi_musb_hdrc_config = { .fifo_cfg = sunxi_musb_mode_cfg, .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg), .multipoint = true, @@ -656,6 +664,18 @@ static struct musb_hdrc_config sunxi_musb_hdrc_config = { .dma = 0, }; +static struct musb_hdrc_config sunxi_musb_hdrc_config_h3 = { + .fifo_cfg = sunxi_musb_mode_cfg_h3, + .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg_h3), + .multipoint = true, + .dyn_fifo = true, + .soft_con = true, + .num_eps = SUNXI_MUSB_MAX_EP_NUM_H3, + .ram_bits = SUNXI_MUSB_RAM_BITS, + .dma = 0, +}; + + static int sunxi_musb_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data pdata; @@ -698,7 +718,10 @@ static int sunxi_musb_probe(struct platform_device *pdev) return -EINVAL; } pdata.platform_ops = &sunxi_musb_ops; - pdata.config = &sunxi_musb_hdrc_config; + if (!of_device_is_compatible(np, "allwinner,sun8i-h3-musb")) + pdata.config = &sunxi_musb_hdrc_config; + else + pdata.config = &sunxi_musb_hdrc_config_h3; glue->dev = &pdev->dev; INIT_WORK(&glue->work, sunxi_musb_work); @@ -710,7 +733,8 @@ static int sunxi_musb_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb")) set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); - if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb")) { + if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb") || + of_device_is_compatible(np, "allwinner,sun8i-h3-musb")) { set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags); } @@ -804,6 +828,7 @@ static const struct of_device_id sunxi_musb_match[] = { { .compatible = "allwinner,sun4i-a10-musb", }, { .compatible = "allwinner,sun6i-a31-musb", }, { .compatible = "allwinner,sun8i-a33-musb", }, + { .compatible = "allwinner,sun8i-h3-musb", }, {} }; MODULE_DEVICE_TABLE(of, sunxi_musb_match); diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index e6959ccb4453..8b43c4b99f04 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -56,7 +56,6 @@ struct tusb_omap_dma_ch { struct tusb_omap_dma { struct dma_controller controller; - struct musb *musb; void __iomem *tbase; int ch; @@ -497,7 +496,7 @@ tusb_omap_dma_allocate(struct dma_controller *c, u32 reg; tusb_dma = container_of(c, struct tusb_omap_dma, controller); - musb = tusb_dma->musb; + musb = tusb_dma->controller.musb; tbase = musb->ctrl_base; reg = musb_readl(tbase, TUSB_DMA_INT_MASK); @@ -534,7 +533,7 @@ tusb_omap_dma_allocate(struct dma_controller *c, dev_name = "TUSB receive"; } - chdat->musb = tusb_dma->musb; + chdat->musb = tusb_dma->controller.musb; chdat->tbase = tusb_dma->tbase; chdat->hw_ep = hw_ep; chdat->epnum = hw_ep->epnum; @@ -667,7 +666,7 @@ tusb_dma_controller_create(struct musb *musb, void __iomem *base) if (!tusb_dma) goto out; - tusb_dma->musb = musb; + tusb_dma->controller.musb = musb; tusb_dma->tbase = musb->ctrl_base; tusb_dma->ch = -1; diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 3eaa4ba6867d..5a572500c418 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -30,7 +30,7 @@ #include "musb_core.h" -static struct musb_hdrc_config ux500_musb_hdrc_config = { +static const struct musb_hdrc_config ux500_musb_hdrc_config = { .multipoint = true, .dyn_fifo = true, .num_eps = 16, diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index a03caf4b1327..61bf2285d5b1 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -1023,38 +1023,6 @@ static void ab8500_usb_vbus_turn_on_event_work(struct work_struct *work) ab->enabled_charging_detection = true; } -static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) -{ - /* - * AB8500 V2 has eye diagram issues when drawing more than 100mA from - * VBUS. Set charging current to 100mA in case of standard host - */ - if (is_ab8500_2p0_or_earlier(ab->ab8500)) - if (mA > 100) - mA = 100; - - return mA; -} - -static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) -{ - struct ab8500_usb *ab; - - if (!phy) - return -ENODEV; - - ab = phy_to_ab(phy); - - mA = ab8500_eyediagram_workaroud(ab, mA); - - ab->vbus_draw = mA; - - atomic_notifier_call_chain(&ab->phy.notifier, - UX500_MUSB_VBUS, &ab->vbus_draw); - - return 0; -} - static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend) { /* TODO */ @@ -1392,7 +1360,6 @@ static int ab8500_usb_probe(struct platform_device *pdev) ab->phy.otg = otg; ab->phy.label = "ab8500"; ab->phy.set_suspend = ab8500_usb_set_suspend; - ab->phy.set_power = ab8500_usb_set_power; ab->phy.otg->state = OTG_STATE_UNDEFINED; otg->usb_phy = &ab->phy; diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 94eb2923afed..392ab422163c 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -642,17 +642,6 @@ static int fsl_otg_set_peripheral(struct usb_otg *otg, return 0; } -/* Set OTG port power, only for B-device */ -static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA) -{ - if (!fsl_otg_dev) - return -ENODEV; - if (phy->otg->state == OTG_STATE_B_PERIPHERAL) - pr_info("FSL OTG: Draw %d mA\n", mA); - - return 0; -} - /* * Delayed pin detect interrupt processing. * @@ -821,7 +810,6 @@ static int fsl_otg_conf(struct platform_device *pdev) /* initialize the otg structure */ fsl_otg_tc->phy.label = DRIVER_DESC; fsl_otg_tc->phy.dev = &pdev->dev; - fsl_otg_tc->phy.set_power = fsl_otg_set_power; fsl_otg_tc->phy.otg->usb_phy = &fsl_otg_tc->phy; fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host; diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 8a34759727bb..93d9aaad2994 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -842,23 +842,6 @@ static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA) motg->cur_power = mA; } -static int msm_otg_set_power(struct usb_phy *phy, unsigned mA) -{ - struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - - /* - * Gadget driver uses set_power method to notify about the - * available current based on suspend/configured states. - * - * IDEV_CHG can be drawn irrespective of suspend/un-configured - * states when CDP/ACA is connected. - */ - if (motg->chg_type == USB_SDP_CHARGER) - msm_otg_notify_charger(motg, mA); - - return 0; -} - static void msm_otg_start_host(struct usb_phy *phy, int on) { struct msm_otg *motg = container_of(phy, struct msm_otg, phy); @@ -1742,14 +1725,14 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) if (!IS_ERR(ext_vbus)) { motg->vbus.extcon = ext_vbus; motg->vbus.nb.notifier_call = msm_otg_vbus_notifier; - ret = extcon_register_notifier(ext_vbus, EXTCON_USB, - &motg->vbus.nb); + ret = devm_extcon_register_notifier(&pdev->dev, ext_vbus, + EXTCON_USB, &motg->vbus.nb); if (ret < 0) { dev_err(&pdev->dev, "register VBUS notifier failed\n"); return ret; } - ret = extcon_get_cable_state_(ext_vbus, EXTCON_USB); + ret = extcon_get_state(ext_vbus, EXTCON_USB); if (ret) set_bit(B_SESS_VLD, &motg->inputs); else @@ -1759,16 +1742,14 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) if (!IS_ERR(ext_id)) { motg->id.extcon = ext_id; motg->id.nb.notifier_call = msm_otg_id_notifier; - ret = extcon_register_notifier(ext_id, EXTCON_USB_HOST, - &motg->id.nb); + ret = devm_extcon_register_notifier(&pdev->dev, ext_id, + EXTCON_USB_HOST, &motg->id.nb); if (ret < 0) { dev_err(&pdev->dev, "register ID notifier failed\n"); - extcon_unregister_notifier(motg->vbus.extcon, - EXTCON_USB, &motg->vbus.nb); return ret; } - ret = extcon_get_cable_state_(ext_id, EXTCON_USB_HOST); + ret = extcon_get_state(ext_id, EXTCON_USB_HOST); if (ret) clear_bit(ID, &motg->inputs); else @@ -1883,10 +1864,9 @@ static int msm_otg_probe(struct platform_device *pdev) */ if (motg->phy_number) { phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4); - if (!phy_select) { - ret = -ENOMEM; - goto unregister_extcon; - } + if (!phy_select) + return -ENOMEM; + /* Enable second PHY with the OTG port */ writel(0x1, phy_select); } @@ -1897,7 +1877,7 @@ static int msm_otg_probe(struct platform_device *pdev) if (motg->irq < 0) { dev_err(&pdev->dev, "platform_get_irq failed\n"); ret = motg->irq; - goto unregister_extcon; + return motg->irq; } regs[0].supply = "vddcx"; @@ -1906,7 +1886,7 @@ static int msm_otg_probe(struct platform_device *pdev) ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs); if (ret) - goto unregister_extcon; + return ret; motg->vddcx = regs[0].consumer; motg->v3p3 = regs[1].consumer; @@ -1950,7 +1930,6 @@ static int msm_otg_probe(struct platform_device *pdev) } phy->init = msm_phy_init; - phy->set_power = msm_otg_set_power; phy->notify_disconnect = msm_phy_notify_disconnect; phy->type = USB_PHY_TYPE_USB2; @@ -2003,11 +1982,6 @@ disable_clks: clk_disable_unprepare(motg->clk); if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); -unregister_extcon: - extcon_unregister_notifier(motg->id.extcon, - EXTCON_USB_HOST, &motg->id.nb); - extcon_unregister_notifier(motg->vbus.extcon, - EXTCON_USB, &motg->vbus.nb); return ret; } @@ -2029,9 +2003,6 @@ static int msm_otg_remove(struct platform_device *pdev) */ gpiod_set_value_cansleep(motg->switch_gpio, 0); - extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb); - extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb); - msm_otg_debugfs_cleanup(); cancel_delayed_work_sync(&motg->chg_work); cancel_work_sync(&motg->sm_work); diff --git a/drivers/usb/phy/phy-omap-otg.c b/drivers/usb/phy/phy-omap-otg.c index 6523af4f8f93..800d1d90753d 100644 --- a/drivers/usb/phy/phy-omap-otg.c +++ b/drivers/usb/phy/phy-omap-otg.c @@ -118,19 +118,19 @@ static int omap_otg_probe(struct platform_device *pdev) otg_dev->id_nb.notifier_call = omap_otg_id_notifier; otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier; - ret = extcon_register_notifier(extcon, EXTCON_USB_HOST, &otg_dev->id_nb); + ret = devm_extcon_register_notifier(&pdev->dev, extcon, + EXTCON_USB_HOST, &otg_dev->id_nb); if (ret) return ret; - ret = extcon_register_notifier(extcon, EXTCON_USB, &otg_dev->vbus_nb); + ret = devm_extcon_register_notifier(&pdev->dev, extcon, + EXTCON_USB, &otg_dev->vbus_nb); if (ret) { - extcon_unregister_notifier(extcon, EXTCON_USB_HOST, - &otg_dev->id_nb); return ret; } - otg_dev->id = extcon_get_cable_state_(extcon, EXTCON_USB_HOST); - otg_dev->vbus = extcon_get_cable_state_(extcon, EXTCON_USB); + otg_dev->id = extcon_get_state(extcon, EXTCON_USB_HOST); + otg_dev->vbus = extcon_get_state(extcon, EXTCON_USB); omap_otg_set_mode(otg_dev); rev = readl(otg_dev->base); @@ -145,20 +145,8 @@ static int omap_otg_probe(struct platform_device *pdev) return 0; } -static int omap_otg_remove(struct platform_device *pdev) -{ - struct otg_device *otg_dev = platform_get_drvdata(pdev); - struct extcon_dev *edev = otg_dev->extcon; - - extcon_unregister_notifier(edev, EXTCON_USB_HOST, &otg_dev->id_nb); - extcon_unregister_notifier(edev, EXTCON_USB, &otg_dev->vbus_nb); - - return 0; -} - static struct platform_driver omap_otg_driver = { .probe = omap_otg_probe, - .remove = omap_otg_remove, .driver = { .name = "omap_otg", }, diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c index d8593adb3621..fdf686398772 100644 --- a/drivers/usb/phy/phy-qcom-8x16-usb.c +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -187,7 +187,7 @@ static int phy_8x16_init(struct usb_phy *phy) val = ULPI_PWR_OTG_COMP_DISABLE; usb_phy_io_write(phy, val, ULPI_SET(ULPI_PWR_CLK_MNG_REG)); - state = extcon_get_cable_state_(qphy->vbus_edev, EXTCON_USB); + state = extcon_get_state(qphy->vbus_edev, EXTCON_USB); if (state) phy_8x16_vbus_on(qphy); else @@ -316,23 +316,20 @@ static int phy_8x16_probe(struct platform_device *pdev) goto off_clks; qphy->vbus_notify.notifier_call = phy_8x16_vbus_notify; - ret = extcon_register_notifier(qphy->vbus_edev, EXTCON_USB, - &qphy->vbus_notify); + ret = devm_extcon_register_notifier(&pdev->dev, qphy->vbus_edev, + EXTCON_USB, &qphy->vbus_notify); if (ret < 0) goto off_power; ret = usb_add_phy_dev(&qphy->phy); if (ret) - goto off_extcon; + goto off_power; qphy->reboot_notify.notifier_call = phy_8x16_reboot_notify; register_reboot_notifier(&qphy->reboot_notify); return 0; -off_extcon: - extcon_unregister_notifier(qphy->vbus_edev, EXTCON_USB, - &qphy->vbus_notify); off_power: regulator_bulk_disable(ARRAY_SIZE(qphy->regulator), qphy->regulator); off_clks: @@ -347,8 +344,6 @@ static int phy_8x16_remove(struct platform_device *pdev) struct phy_8x16 *qphy = platform_get_drvdata(pdev); unregister_reboot_notifier(&qphy->reboot_notify); - extcon_unregister_notifier(qphy->vbus_edev, EXTCON_USB, - &qphy->vbus_notify); /* * Ensure that D+/D- lines are routed to uB connector, so diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index ab5d364f6e8c..a31c8682e998 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -121,7 +121,7 @@ static void check_vbus_state(struct tahvo_usb *tu) prev_state = tu->vbus_state; tu->vbus_state = reg & TAHVO_STAT_VBUS; if (prev_state != tu->vbus_state) { - extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state); + extcon_set_state_sync(tu->extcon, EXTCON_USB, tu->vbus_state); sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state"); } } @@ -130,7 +130,7 @@ static void tahvo_usb_become_host(struct tahvo_usb *tu) { struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); - extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, true); + extcon_set_state_sync(tu->extcon, EXTCON_USB_HOST, true); /* Power up the transceiver in USB host mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND | @@ -149,7 +149,7 @@ static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) { struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); - extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, false); + extcon_set_state_sync(tu->extcon, EXTCON_USB_HOST, false); /* Power up transceiver and set it in USB peripheral mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | @@ -379,9 +379,9 @@ static int tahvo_usb_probe(struct platform_device *pdev) } /* Set the initial cable state. */ - extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, + extcon_set_state_sync(tu->extcon, EXTCON_USB_HOST, tu->tahvo_mode == TAHVO_MODE_HOST); - extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state); + extcon_set_state_sync(tu->extcon, EXTCON_USB, tu->vbus_state); /* Create OTG interface */ tahvo_usb_power_off(tu); diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 012a37aa3e0d..623c51300393 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -389,7 +389,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv) if (enable && !mod) { if (priv->edev) { - cable = extcon_get_cable_state_(priv->edev, EXTCON_USB_HOST); + cable = extcon_get_state(priv->edev, EXTCON_USB_HOST); if ((cable > 0 && id != USBHS_HOST) || (!cable && id != USBHS_GADGET)) { dev_info(&pdev->dev, diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 165e81bfd93a..dfb346e9bd0c 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -577,7 +577,7 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, upphub = usbhsh_device_number(hpriv, parent); hubport = usbhsh_device_hubport(udev); - dev_dbg(dev, "%s connecte to Hub [%d:%d](%p)\n", __func__, + dev_dbg(dev, "%s connected to Hub [%d:%d](%p)\n", __func__, upphub, hubport, parent); } diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index d9bc8dafe000..a8d5f2e4878d 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -713,6 +713,15 @@ config USB_SERIAL_QT2 To compile this driver as a module, choose M here: the module will be called quatech-serial. +config USB_SERIAL_UPD78F0730 + tristate "USB Renesas uPD78F0730 Single Port Serial Driver" + help + Say Y here if you want to use the Renesas uPD78F0730 + serial driver. + + To compile this driver as a module, choose M here: the + module will be called upd78f0730. + config USB_SERIAL_DEBUG tristate "USB Debugging Device" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 9e43b7b002eb..5a21a82390e1 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o +obj-$(CONFIG_USB_SERIAL_UPD78F0730) += upd78f0730.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 1532cde8a437..2779e59c30f1 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -99,10 +99,17 @@ static int ark3116_read_reg(struct usb_serial *serial, usb_rcvctrlpipe(serial->dev, 0), 0xfe, 0xc0, 0, reg, buf, 1, ARK_TIMEOUT); - if (result < 0) + if (result < 1) { + dev_err(&serial->interface->dev, + "failed to read register %u: %d\n", + reg, result); + if (result >= 0) + result = -EIO; + return result; - else - return buf[0]; + } + + return buf[0]; } static inline int calc_divisor(int bps) @@ -118,17 +125,11 @@ static inline int calc_divisor(int bps) static int ark3116_attach(struct usb_serial *serial) { /* make sure we have our end-points */ - if ((serial->num_bulk_in == 0) || - (serial->num_bulk_out == 0) || - (serial->num_interrupt_in == 0)) { - dev_err(&serial->dev->dev, - "%s - missing endpoint - " - "bulk in: %d, bulk out: %d, int in %d\n", - KBUILD_MODNAME, - serial->num_bulk_in, - serial->num_bulk_out, - serial->num_interrupt_in); - return -EINVAL; + if (serial->num_bulk_in == 0 || + serial->num_bulk_out == 0 || + serial->num_interrupt_in == 0) { + dev_err(&serial->interface->dev, "missing endpoint\n"); + return -ENODEV; } return 0; @@ -186,10 +187,8 @@ static int ark3116_port_probe(struct usb_serial_port *port) if (priv->irda) ark3116_write_reg(serial, 0x9, 0); - dev_info(&serial->dev->dev, - "%s using %s mode\n", - KBUILD_MODNAME, - priv->irda ? "IrDA" : "RS232"); + dev_info(&port->dev, "using %s mode\n", priv->irda ? "IrDA" : "RS232"); + return 0; } @@ -325,9 +324,8 @@ static void ark3116_set_termios(struct tty_struct *tty, /* check for software flow control */ if (I_IXOFF(tty) || I_IXON(tty)) { - dev_warn(&serial->dev->dev, - "%s: don't know how to do software flow control\n", - KBUILD_MODNAME); + dev_warn(&port->dev, + "software flow control not implemented\n"); } /* Don't rewrite B0 */ @@ -346,8 +344,8 @@ static void ark3116_close(struct usb_serial_port *port) ark3116_write_reg(serial, UART_IER, 0); usb_serial_generic_close(port); - if (serial->num_interrupt_in) - usb_kill_urb(port->interrupt_in_urb); + + usb_kill_urb(port->interrupt_in_urb); } static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -366,23 +364,29 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) dev_dbg(&port->dev, "%s - usb_serial_generic_open failed: %d\n", __func__, result); - goto err_out; + goto err_free; } /* remove any data still left: also clears error state */ ark3116_read_reg(serial, UART_RX, buf); /* read modem status */ - priv->msr = ark3116_read_reg(serial, UART_MSR, buf); + result = ark3116_read_reg(serial, UART_MSR, buf); + if (result < 0) + goto err_close; + priv->msr = *buf; + /* read line status */ - priv->lsr = ark3116_read_reg(serial, UART_LSR, buf); + result = ark3116_read_reg(serial, UART_LSR, buf); + if (result < 0) + goto err_close; + priv->lsr = *buf; result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "submit irq_in urb failed %d\n", result); - ark3116_close(port); - goto err_out; + goto err_close; } /* activate interrupts */ @@ -395,8 +399,15 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ark3116_set_termios(tty, port, NULL); -err_out: kfree(buf); + + return 0; + +err_close: + usb_serial_generic_close(port); +err_free: + kfree(buf); + return result; } @@ -602,9 +613,8 @@ static void ark3116_read_int_callback(struct urb *urb) result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); + dev_err(&port->dev, "failed to resubmit interrupt urb: %d\n", + result); } diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 95aa5233726c..351745aec0e1 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -93,8 +93,8 @@ MODULE_DEVICE_TABLE(usb, id_table); struct ch341_private { spinlock_t lock; /* access lock */ unsigned baud_rate; /* set baud rate */ - u8 line_control; /* set line control value RTS/DTR */ - u8 line_status; /* active status of modem control inputs */ + u8 mcr; + u8 msr; u8 lcr; }; @@ -107,8 +107,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request, { int r; - dev_dbg(&dev->dev, "ch341_control_out(%02x,%02x,%04x,%04x)\n", - USB_DIR_OUT|0x40, (int)request, (int)value, (int)index); + dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x)\n", __func__, + request, value, index); r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, @@ -125,9 +125,8 @@ static int ch341_control_in(struct usb_device *dev, { int r; - dev_dbg(&dev->dev, "ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)\n", - USB_DIR_IN|0x40, (int)request, (int)value, (int)index, buf, - (int)bufsize); + dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x,%u)\n", __func__, + request, value, index, bufsize); r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, @@ -210,7 +209,7 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) goto out; spin_lock_irqsave(&priv->lock, flags); - priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; + priv->msr = (~(*buffer)) & CH341_BITS_MODEM_STAT; spin_unlock_irqrestore(&priv->lock, flags); out: kfree(buffer); @@ -239,30 +238,11 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) if (r < 0) goto out; - /* expect two bytes 0x56 0x00 */ - r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x2518, 0, buffer, size); - if (r < 0) - goto out; - - r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, 0x0050); - if (r < 0) - goto out; - - /* expect 0xff 0xee */ - r = ch341_get_status(dev, priv); - if (r < 0) - goto out; - r = ch341_set_baudrate_lcr(dev, priv, priv->lcr); if (r < 0) goto out; - r = ch341_set_handshake(dev, priv->line_control); - if (r < 0) - goto out; - - /* expect 0x9f 0xee */ - r = ch341_get_status(dev, priv); + r = ch341_set_handshake(dev, priv->mcr); out: kfree(buffer); return r; @@ -279,6 +259,11 @@ static int ch341_port_probe(struct usb_serial_port *port) spin_lock_init(&priv->lock); priv->baud_rate = DEFAULT_BAUD_RATE; + /* + * Some CH340 devices appear unable to change the initial LCR + * settings, so set a sane 8N1 default. + */ + priv->lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8; r = ch341_configure(port->serial->dev, priv); if (r < 0) @@ -304,7 +289,7 @@ static int ch341_port_remove(struct usb_serial_port *port) static int ch341_carrier_raised(struct usb_serial_port *port) { struct ch341_private *priv = usb_get_serial_port_data(port); - if (priv->line_status & CH341_BIT_DCD) + if (priv->msr & CH341_BIT_DCD) return 1; return 0; } @@ -317,11 +302,11 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) /* drop DTR and RTS */ spin_lock_irqsave(&priv->lock, flags); if (on) - priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR; + priv->mcr |= CH341_BIT_RTS | CH341_BIT_DTR; else - priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR); + priv->mcr &= ~(CH341_BIT_RTS | CH341_BIT_DTR); spin_unlock_irqrestore(&priv->lock, flags); - ch341_set_handshake(port->serial->dev, priv->line_control); + ch341_set_handshake(port->serial->dev, priv->mcr); } static void ch341_close(struct usb_serial_port *port) @@ -334,14 +319,9 @@ static void ch341_close(struct usb_serial_port *port) /* open this device, set default parameters */ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; struct ch341_private *priv = usb_get_serial_port_data(port); int r; - r = ch341_configure(serial->dev, priv); - if (r) - return r; - if (tty) ch341_set_termios(tty, port, NULL); @@ -353,6 +333,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) return r; } + r = ch341_get_status(port->serial->dev, priv); + if (r < 0) { + dev_err(&port->dev, "failed to read modem status: %d\n", r); + goto err_kill_interrupt_urb; + } + r = usb_serial_generic_open(tty, port); if (r) goto err_kill_interrupt_urb; @@ -374,7 +360,7 @@ static void ch341_set_termios(struct tty_struct *tty, struct ch341_private *priv = usb_get_serial_port_data(port); unsigned baud_rate; unsigned long flags; - unsigned char ctrl; + u8 lcr; int r; /* redundant changes may cause the chip to lose bytes */ @@ -383,54 +369,54 @@ static void ch341_set_termios(struct tty_struct *tty, baud_rate = tty_get_baud_rate(tty); - ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; + lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; switch (C_CSIZE(tty)) { case CS5: - ctrl |= CH341_LCR_CS5; + lcr |= CH341_LCR_CS5; break; case CS6: - ctrl |= CH341_LCR_CS6; + lcr |= CH341_LCR_CS6; break; case CS7: - ctrl |= CH341_LCR_CS7; + lcr |= CH341_LCR_CS7; break; case CS8: - ctrl |= CH341_LCR_CS8; + lcr |= CH341_LCR_CS8; break; } if (C_PARENB(tty)) { - ctrl |= CH341_LCR_ENABLE_PAR; + lcr |= CH341_LCR_ENABLE_PAR; if (C_PARODD(tty) == 0) - ctrl |= CH341_LCR_PAR_EVEN; + lcr |= CH341_LCR_PAR_EVEN; if (C_CMSPAR(tty)) - ctrl |= CH341_LCR_MARK_SPACE; + lcr |= CH341_LCR_MARK_SPACE; } if (C_CSTOPB(tty)) - ctrl |= CH341_LCR_STOP_BITS_2; + lcr |= CH341_LCR_STOP_BITS_2; if (baud_rate) { priv->baud_rate = baud_rate; - r = ch341_set_baudrate_lcr(port->serial->dev, priv, ctrl); + r = ch341_set_baudrate_lcr(port->serial->dev, priv, lcr); if (r < 0 && old_termios) { priv->baud_rate = tty_termios_baud_rate(old_termios); tty_termios_copy_hw(&tty->termios, old_termios); } else if (r == 0) { - priv->lcr = ctrl; + priv->lcr = lcr; } } spin_lock_irqsave(&priv->lock, flags); if (C_BAUD(tty) == B0) - priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS); + priv->mcr &= ~(CH341_BIT_DTR | CH341_BIT_RTS); else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) - priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS); + priv->mcr |= (CH341_BIT_DTR | CH341_BIT_RTS); spin_unlock_irqrestore(&priv->lock, flags); - ch341_set_handshake(port->serial->dev, priv->line_control); + ch341_set_handshake(port->serial->dev, priv->mcr); } static void ch341_break_ctl(struct tty_struct *tty, int break_state) @@ -486,20 +472,20 @@ static int ch341_tiocmset(struct tty_struct *tty, spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) - priv->line_control |= CH341_BIT_RTS; + priv->mcr |= CH341_BIT_RTS; if (set & TIOCM_DTR) - priv->line_control |= CH341_BIT_DTR; + priv->mcr |= CH341_BIT_DTR; if (clear & TIOCM_RTS) - priv->line_control &= ~CH341_BIT_RTS; + priv->mcr &= ~CH341_BIT_RTS; if (clear & TIOCM_DTR) - priv->line_control &= ~CH341_BIT_DTR; - control = priv->line_control; + priv->mcr &= ~CH341_BIT_DTR; + control = priv->mcr; spin_unlock_irqrestore(&priv->lock, flags); return ch341_set_handshake(port->serial->dev, control); } -static void ch341_update_line_status(struct usb_serial_port *port, +static void ch341_update_status(struct usb_serial_port *port, unsigned char *data, size_t len) { struct ch341_private *priv = usb_get_serial_port_data(port); @@ -514,8 +500,8 @@ static void ch341_update_line_status(struct usb_serial_port *port, status = ~data[2] & CH341_BITS_MODEM_STAT; spin_lock_irqsave(&priv->lock, flags); - delta = status ^ priv->line_status; - priv->line_status = status; + delta = status ^ priv->msr; + priv->msr = status; spin_unlock_irqrestore(&priv->lock, flags); if (data[1] & CH341_MULT_STAT) @@ -568,7 +554,7 @@ static void ch341_read_int_callback(struct urb *urb) } usb_serial_debug_data(&port->dev, __func__, len, data); - ch341_update_line_status(port, data, len); + ch341_update_status(port, data, len); exit: status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { @@ -587,8 +573,8 @@ static int ch341_tiocmget(struct tty_struct *tty) unsigned int result; spin_lock_irqsave(&priv->lock, flags); - mcr = priv->line_control; - status = priv->line_status; + mcr = priv->mcr; + status = priv->msr; spin_unlock_irqrestore(&priv->lock, flags); result = ((mcr & CH341_BIT_DTR) ? TIOCM_DTR : 0) @@ -619,6 +605,12 @@ static int ch341_reset_resume(struct usb_serial *serial) ret); return ret; } + + ret = ch341_get_status(port->serial->dev, priv); + if (ret < 0) { + dev_err(&port->dev, "failed to read modem status: %d\n", + ret); + } } return usb_serial_generic_resume(serial); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 8967715fe6fc..fdf89800ebc3 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -143,6 +143,7 @@ static int usb_console_setup(struct console *co, char *options) tty->driver = usb_serial_tty_driver; tty->index = co->index; init_ldsem(&tty->ldisc_sem); + spin_lock_init(&tty->files_lock); INIT_LIST_HEAD(&tty->tty_files); kref_get(&tty->driver->kref); __module_get(tty->driver->owner); @@ -264,8 +265,7 @@ static struct console usbcons = { void usb_serial_console_disconnect(struct usb_serial *serial) { - if (serial && serial->port && serial->port[0] - && serial->port[0] == usbcons_info.port) { + if (serial->port[0] == usbcons_info.port) { usb_serial_console_exit(); usb_serial_put(serial); } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 5d61d0871f2e..0c55e7f64269 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -178,6 +178,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */ { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */ { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */ + { USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */ + { USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */ { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index bbeeb2bd55a8..90110de715e0 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -1069,7 +1069,6 @@ static void cypress_read_int_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; unsigned long flags; char tty_flag = TTY_NORMAL; - int havedata = 0; int bytes = 0; int result; int i = 0; @@ -1118,16 +1117,12 @@ static void cypress_read_int_callback(struct urb *urb) priv->current_status = data[0] & 0xF8; bytes = data[1] + 2; i = 2; - if (bytes > 2) - havedata = 1; break; case packet_format_2: /* This is for the CY7C63743... */ priv->current_status = data[0] & 0xF8; bytes = (data[0] & 0x07) + 1; i = 1; - if (bytes > 1) - havedata = 1; break; } spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 6a1df9e824ca..eb433922598c 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1398,25 +1398,30 @@ static int digi_read_inb_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct digi_port *priv = usb_get_serial_port_data(port); - int opcode = ((unsigned char *)urb->transfer_buffer)[0]; - int len = ((unsigned char *)urb->transfer_buffer)[1]; - int port_status = ((unsigned char *)urb->transfer_buffer)[2]; - unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3; + unsigned char *buf = urb->transfer_buffer; + int opcode; + int len; + int port_status; + unsigned char *data; int flag, throttled; - int status = urb->status; - - /* do not process callbacks on closed ports */ - /* but do continue the read chain */ - if (urb->status == -ENOENT) - return 0; /* short/multiple packet check */ + if (urb->actual_length < 2) { + dev_warn(&port->dev, "short packet received\n"); + return -1; + } + + opcode = buf[0]; + len = buf[1]; + if (urb->actual_length != len + 2) { - dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, " - "status=%d, port=%d, opcode=%d, len=%d, " - "actual_length=%d, status=%d\n", __func__, status, - priv->dp_port_num, opcode, len, urb->actual_length, - port_status); + dev_err(&port->dev, "malformed packet received: port=%d, opcode=%d, len=%d, actual_length=%u\n", + priv->dp_port_num, opcode, len, urb->actual_length); + return -1; + } + + if (opcode == DIGI_CMD_RECEIVE_DATA && len < 1) { + dev_err(&port->dev, "malformed data packet received\n"); return -1; } @@ -1430,6 +1435,9 @@ static int digi_read_inb_callback(struct urb *urb) /* receive data */ if (opcode == DIGI_CMD_RECEIVE_DATA) { + port_status = buf[2]; + data = &buf[3]; + /* get flag from port_status */ flag = 0; @@ -1482,16 +1490,20 @@ static int digi_read_oob_callback(struct urb *urb) struct usb_serial *serial = port->serial; struct tty_struct *tty; struct digi_port *priv = usb_get_serial_port_data(port); + unsigned char *buf = urb->transfer_buffer; int opcode, line, status, val; int i; unsigned int rts; + if (urb->actual_length < 4) + return -1; + /* handle each oob command */ - for (i = 0; i < urb->actual_length - 3;) { - opcode = ((unsigned char *)urb->transfer_buffer)[i++]; - line = ((unsigned char *)urb->transfer_buffer)[i++]; - status = ((unsigned char *)urb->transfer_buffer)[i++]; - val = ((unsigned char *)urb->transfer_buffer)[i++]; + for (i = 0; i < urb->actual_length - 4; i += 4) { + opcode = buf[i]; + line = buf[i + 1]; + status = buf[i + 2]; + val = buf[i + 3]; dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n", opcode, line, status, val); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 23d14b98ae2a..c540de15aad2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1439,10 +1439,13 @@ static int read_latency_timer(struct usb_serial_port *port) FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0, priv->interface, buf, 1, WDR_TIMEOUT); - if (rv < 0) + if (rv < 1) { dev_err(&port->dev, "Unable to read latency timer: %i\n", rv); - else + if (rv >= 0) + rv = -EIO; + } else { priv->latency = buf[0]; + } kfree(buf); @@ -1531,7 +1534,7 @@ check_and_exit: } static int get_lsr_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) + unsigned int __user *retinfo) { struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned int result = 0; @@ -1802,8 +1805,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) mutex_init(&priv->cfg_lock); - priv->flags = ASYNC_LOW_LATENCY; - if (quirk && quirk->port_probe) quirk->port_probe(priv); @@ -2067,6 +2068,20 @@ static int ftdi_process_packet(struct usb_serial_port *port, priv->prev_status = status; } + /* save if the transmitter is empty or not */ + if (packet[1] & FTDI_RS_TEMT) + priv->transmit_empty = 1; + else + priv->transmit_empty = 0; + + len -= 2; + if (!len) + return 0; /* status only */ + + /* + * Break and error status must only be processed for packets with + * data payload to avoid over-reporting. + */ flag = TTY_NORMAL; if (packet[1] & FTDI_RS_ERR_MASK) { /* Break takes precedence over parity, which takes precedence @@ -2089,15 +2104,6 @@ static int ftdi_process_packet(struct usb_serial_port *port, } } - /* save if the transmitter is empty or not */ - if (packet[1] & FTDI_RS_TEMT) - priv->transmit_empty = 1; - else - priv->transmit_empty = 0; - - len -= 2; - if (!len) - return 0; /* status only */ port->icount.rx += len; ch = packet + 2; @@ -2428,8 +2434,12 @@ static int ftdi_get_modem_status(struct usb_serial_port *port, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, priv->interface, buf, len, WDR_TIMEOUT); - if (ret < 0) { + + /* NOTE: We allow short responses and handle that below. */ + if (ret < 1) { dev_err(&port->dev, "failed to get modem status: %d\n", ret); + if (ret >= 0) + ret = -EIO; ret = usb_translate_errors(ret); goto out; } @@ -2480,20 +2490,15 @@ static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; + void __user *argp = (void __user *)arg; - /* Based on code from acm.c and others */ switch (cmd) { - - case TIOCGSERIAL: /* gets serial port data */ - return get_serial_info(port, - (struct serial_struct __user *) arg); - - case TIOCSSERIAL: /* sets serial port data */ - return set_serial_info(tty, port, - (struct serial_struct __user *) arg); + case TIOCGSERIAL: + return get_serial_info(port, argp); + case TIOCSSERIAL: + return set_serial_info(tty, port, argp); case TIOCSERGETLSR: - return get_lsr_info(port, (struct serial_struct __user *)arg); - break; + return get_lsr_info(port, argp); default: break; } diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index d50e5773483f..bb7673e80a57 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -57,6 +57,88 @@ #define OPEN_TIMEOUT (5*HZ) /* 5 seconds */ +static const struct usb_device_id edgeport_2port_id_table[] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, + { } +}; + +static const struct usb_device_id edgeport_4port_id_table[] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, + { } +}; + +static const struct usb_device_id edgeport_8port_id_table[] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, + { } +}; + +static const struct usb_device_id Epic_port_id_table[] = { + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, + { } +}; + +/* Devices that this driver supports */ +static const struct usb_device_id id_table_combined[] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, id_table_combined); + + /* receive port state */ enum RXSTATE { EXPECT_HDR1 = 0, /* Expect header byte 1 */ @@ -217,8 +299,6 @@ static void edge_release(struct usb_serial *serial); static int edge_port_probe(struct usb_serial_port *port); static int edge_port_remove(struct usb_serial_port *port); -#include "io_tables.h" /* all of the devices that this driver supports */ - /* function prototypes for all of our local functions */ static void process_rcvd_data(struct edgeport_serial *edge_serial, @@ -492,20 +572,24 @@ static int get_epic_descriptor(struct edgeport_serial *ep) int result; struct usb_serial *serial = ep->serial; struct edgeport_product_info *product_info = &ep->product_info; - struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; + struct edge_compatibility_descriptor *epic; struct edge_compatibility_bits *bits; struct device *dev = &serial->dev->dev; ep->is_epic = 0; + + epic = kmalloc(sizeof(*epic), GFP_KERNEL); + if (!epic) + return -ENOMEM; + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_GET_EPIC_DESC, 0xC0, 0x00, 0x00, - &ep->epic_descriptor, - sizeof(struct edge_compatibility_descriptor), + epic, sizeof(*epic), 300); - - if (result > 0) { + if (result == sizeof(*epic)) { ep->is_epic = 1; + memcpy(&ep->epic_descriptor, epic, sizeof(*epic)); memset(product_info, 0, sizeof(struct edgeport_product_info)); product_info->NumPorts = epic->NumPorts; @@ -534,8 +618,16 @@ static int get_epic_descriptor(struct edgeport_serial *ep) dev_dbg(dev, " IOSPWriteLCR : %s\n", bits->IOSPWriteLCR ? "TRUE": "FALSE"); dev_dbg(dev, " IOSPSetBaudRate : %s\n", bits->IOSPSetBaudRate ? "TRUE": "FALSE"); dev_dbg(dev, " TrueEdgeport : %s\n", bits->TrueEdgeport ? "TRUE": "FALSE"); + + result = 0; + } else if (result >= 0) { + dev_warn(&serial->interface->dev, "short epic descriptor received: %d\n", + result); + result = -EIO; } + kfree(epic); + return result; } @@ -1560,7 +1652,6 @@ static int get_serial_info(struct edgeport_port *edge_port, tmp.line = edge_port->port->minor; tmp.port = edge_port->port->port_number; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = edge_port->maxTxCredits; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; @@ -2090,8 +2181,7 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, * rom_read * reads a number of bytes from the Edgeport device starting at the given * address. - * If successful returns the number of bytes read, otherwise it returns - * a negative error number of the problem. + * Returns zero on success or a negative error number. ****************************************************************************/ static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data) @@ -2116,12 +2206,17 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr, USB_REQUEST_ION_READ_ROM, 0xC0, addr, extAddr, transfer_buffer, current_length, 300); - if (result < 0) + if (result < current_length) { + if (result >= 0) + result = -EIO; break; + } memcpy(data, transfer_buffer, current_length); length -= current_length; addr += current_length; data += current_length; + + result = 0; } kfree(transfer_buffer); @@ -2575,9 +2670,10 @@ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) EDGE_MANUF_DESC_LEN, (__u8 *)(&edge_serial->manuf_descriptor)); - if (response < 1) - dev_err(dev, "error in getting manufacturer descriptor\n"); - else { + if (response < 0) { + dev_err(dev, "error in getting manufacturer descriptor: %d\n", + response); + } else { char string[30]; dev_dbg(dev, "**Manufacturer Descriptor\n"); dev_dbg(dev, " RomSize: %dK\n", @@ -2634,9 +2730,10 @@ static void get_boot_desc(struct edgeport_serial *edge_serial) EDGE_BOOT_DESC_LEN, (__u8 *)(&edge_serial->boot_descriptor)); - if (response < 1) - dev_err(dev, "error in getting boot descriptor\n"); - else { + if (response < 0) { + dev_err(dev, "error in getting boot descriptor: %d\n", + response); + } else { dev_dbg(dev, "**Boot Descriptor:\n"); dev_dbg(dev, " BootCodeLength: %d\n", le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength)); @@ -2779,7 +2876,7 @@ static int edge_startup(struct usb_serial *serial) dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); /* Read the epic descriptor */ - if (get_epic_descriptor(edge_serial) <= 0) { + if (get_epic_descriptor(edge_serial) < 0) { /* memcpy descriptor to Supports structures */ memcpy(&edge_serial->epic_descriptor.Supports, descriptor, sizeof(struct edge_compatibility_bits)); @@ -3015,6 +3112,139 @@ static int edge_port_remove(struct usb_serial_port *port) return 0; } +static struct usb_serial_driver edgeport_2port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_2", + }, + .description = "Edgeport 2 port adapter", + .id_table = edgeport_2port_id_table, + .num_ports = 2, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .disconnect = edge_disconnect, + .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + +static struct usb_serial_driver edgeport_4port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_4", + }, + .description = "Edgeport 4 port adapter", + .id_table = edgeport_4port_id_table, + .num_ports = 4, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .disconnect = edge_disconnect, + .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + +static struct usb_serial_driver edgeport_8port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_8", + }, + .description = "Edgeport 8 port adapter", + .id_table = edgeport_8port_id_table, + .num_ports = 8, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .disconnect = edge_disconnect, + .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + +static struct usb_serial_driver epic_device = { + .driver = { + .owner = THIS_MODULE, + .name = "epic", + }, + .description = "EPiC device", + .id_table = Epic_port_id_table, + .num_ports = 1, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .disconnect = edge_disconnect, + .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &edgeport_2port_device, &edgeport_4port_device, + &edgeport_8port_device, &epic_device, NULL +}; + module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h deleted file mode 100644 index ae5fac5656c9..000000000000 --- a/drivers/usb/serial/io_tables.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * IO Edgeport Driver tables - * - * Copyright (C) 2001 - * Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#ifndef IO_TABLES_H -#define IO_TABLES_H - -static const struct usb_device_id edgeport_2port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, - { } -}; - -static const struct usb_device_id edgeport_4port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, - { } -}; - -static const struct usb_device_id edgeport_8port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, - { } -}; - -static const struct usb_device_id Epic_port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, - { } -}; - -/* Devices that this driver supports */ -static const struct usb_device_id id_table_combined[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_serial_driver edgeport_2port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_2", - }, - .description = "Edgeport 2 port adapter", - .id_table = edgeport_2port_id_table, - .num_ports = 2, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_port_probe, - .port_remove = edge_port_remove, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver edgeport_4port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_4", - }, - .description = "Edgeport 4 port adapter", - .id_table = edgeport_4port_id_table, - .num_ports = 4, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_port_probe, - .port_remove = edge_port_remove, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver edgeport_8port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_8", - }, - .description = "Edgeport 8 port adapter", - .id_table = edgeport_8port_id_table, - .num_ports = 8, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_port_probe, - .port_remove = edge_port_remove, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver epic_device = { - .driver = { - .owner = THIS_MODULE, - .name = "epic", - }, - .description = "EPiC device", - .id_table = Epic_port_id_table, - .num_ports = 1, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_port_probe, - .port_remove = edge_port_remove, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &edgeport_2port_device, &edgeport_4port_device, - &edgeport_8port_device, &epic_device, NULL -}; - -#endif - diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 9a0db2965fbb..ceaeebaa6f90 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2468,7 +2468,6 @@ static int get_serial_info(struct edgeport_port *edge_port, tmp.line = edge_port->port->minor; tmp.port = edge_port->port->port_number; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = edge_port->port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index d57fb5199218..030390f37b0a 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -976,7 +976,6 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct device *dev = &port->dev; - u8 *buf; int result; int baud; u32 actual; @@ -991,20 +990,8 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); - buf = kmalloc(10, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - priv->poll = 0; - /* initialize writebuf */ -#define FISH(a, b, c, d) do { \ - result = usb_control_msg(port->serial->dev, \ - usb_rcvctrlpipe(port->serial->dev, 0), \ - b, a, c, d, buf, 1, 1000); \ - dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", a, b, c, d, result, \ - buf[0]); } while (0); - #define SOUP(a, b, c, d) do { \ result = usb_control_msg(port->serial->dev, \ usb_sndctrlpipe(port->serial->dev, 0), \ @@ -1017,7 +1004,7 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */ SOUP(0x03, 0x02, 0x02, 0x0); - kfree(buf); + iuu_led(port, 0xF000, 0xF000, 0, 0xFF); iuu_uart_on(port); if (boost < 100) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 1f9414bdd649..5662d324edd2 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -41,11 +41,508 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/usb/ezusb.h> -#include "keyspan.h" #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu" #define DRIVER_DESC "Keyspan USB to Serial Converter Driver" +/* Function prototypes for Keyspan serial converter */ +static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port); +static void keyspan_close(struct usb_serial_port *port); +static void keyspan_dtr_rts(struct usb_serial_port *port, int on); +static int keyspan_startup(struct usb_serial *serial); +static void keyspan_disconnect(struct usb_serial *serial); +static void keyspan_release(struct usb_serial *serial); +static int keyspan_port_probe(struct usb_serial_port *port); +static int keyspan_port_remove(struct usb_serial_port *port); +static int keyspan_write_room(struct tty_struct *tty); +static int keyspan_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); +static void keyspan_send_setup(struct usb_serial_port *port, int reset_port); +static void keyspan_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old); +static void keyspan_break_ctl(struct tty_struct *tty, int break_state); +static int keyspan_tiocmget(struct tty_struct *tty); +static int keyspan_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear); +static int keyspan_fake_startup(struct usb_serial *serial); + +static int keyspan_usa19_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, + u8 *prescaler, int portnum); +static int keyspan_usa19w_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, + u8 *prescaler, int portnum); +static int keyspan_usa28_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, + u8 *prescaler, int portnum); +static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, + u8 *prescaler, int portnum); + +static int keyspan_usa28_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); +static int keyspan_usa26_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); +static int keyspan_usa49_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); +static int keyspan_usa90_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); +static int keyspan_usa67_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); + +/* Values used for baud rate calculation - device specific */ +#define KEYSPAN_INVALID_BAUD_RATE (-1) +#define KEYSPAN_BAUD_RATE_OK (0) +#define KEYSPAN_USA18X_BAUDCLK (12000000L) /* a guess */ +#define KEYSPAN_USA19_BAUDCLK (12000000L) +#define KEYSPAN_USA19W_BAUDCLK (24000000L) +#define KEYSPAN_USA19HS_BAUDCLK (14769231L) +#define KEYSPAN_USA28_BAUDCLK (1843200L) +#define KEYSPAN_USA28X_BAUDCLK (12000000L) +#define KEYSPAN_USA49W_BAUDCLK (48000000L) + +/* Some constants used to characterise each device. */ +#define KEYSPAN_MAX_NUM_PORTS (4) +#define KEYSPAN_MAX_FLIPS (2) + +/* + * Device info for the Keyspan serial converter, used by the overall + * usb-serial probe function. + */ +#define KEYSPAN_VENDOR_ID (0x06cd) + +/* Product IDs for the products supported, pre-renumeration */ +#define keyspan_usa18x_pre_product_id 0x0105 +#define keyspan_usa19_pre_product_id 0x0103 +#define keyspan_usa19qi_pre_product_id 0x010b +#define keyspan_mpr_pre_product_id 0x011b +#define keyspan_usa19qw_pre_product_id 0x0118 +#define keyspan_usa19w_pre_product_id 0x0106 +#define keyspan_usa28_pre_product_id 0x0101 +#define keyspan_usa28x_pre_product_id 0x0102 +#define keyspan_usa28xa_pre_product_id 0x0114 +#define keyspan_usa28xb_pre_product_id 0x0113 +#define keyspan_usa49w_pre_product_id 0x0109 +#define keyspan_usa49wlc_pre_product_id 0x011a + +/* + * Product IDs post-renumeration. Note that the 28x and 28xb have the same + * id's post-renumeration but behave identically so it's not an issue. As + * such, the 28xb is not listed in any of the device tables. + */ +#define keyspan_usa18x_product_id 0x0112 +#define keyspan_usa19_product_id 0x0107 +#define keyspan_usa19qi_product_id 0x010c +#define keyspan_usa19hs_product_id 0x0121 +#define keyspan_mpr_product_id 0x011c +#define keyspan_usa19qw_product_id 0x0119 +#define keyspan_usa19w_product_id 0x0108 +#define keyspan_usa28_product_id 0x010f +#define keyspan_usa28x_product_id 0x0110 +#define keyspan_usa28xa_product_id 0x0115 +#define keyspan_usa28xb_product_id 0x0110 +#define keyspan_usa28xg_product_id 0x0135 +#define keyspan_usa49w_product_id 0x010a +#define keyspan_usa49wlc_product_id 0x012a +#define keyspan_usa49wg_product_id 0x0131 + +struct keyspan_device_details { + /* product ID value */ + int product_id; + + enum {msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format; + + /* Number of physical ports */ + int num_ports; + + /* 1 if endpoint flipping used on input, 0 if not */ + int indat_endp_flip; + + /* 1 if endpoint flipping used on output, 0 if not */ + int outdat_endp_flip; + + /* + * Table mapping input data endpoint IDs to physical port + * number and flip if used + */ + int indat_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Same for output endpoints */ + int outdat_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Input acknowledge endpoints */ + int inack_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Output control endpoints */ + int outcont_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Endpoint used for input status */ + int instat_endpoint; + + /* Endpoint used for input data 49WG only */ + int indat_endpoint; + + /* Endpoint used for global control functions */ + int glocont_endpoint; + + int (*calculate_baud_rate)(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, u8 *prescaler, + int portnum); + u32 baudclk; +}; + +/* + * Now for each device type we setup the device detail structure with the + * appropriate information (provided in Keyspan's documentation) + */ + +static const struct keyspan_device_details usa18x_device_details = { + .product_id = keyspan_usa18x_product_id, + .msg_format = msg_usa26, + .num_ports = 1, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x85}, + .outcont_endpoints = {0x05}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA18X_BAUDCLK, +}; + +static const struct keyspan_device_details usa19_device_details = { + .product_id = keyspan_usa19_product_id, + .msg_format = msg_usa28, + .num_ports = 1, + .indat_endp_flip = 1, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x83}, + .outcont_endpoints = {0x03}, + .instat_endpoint = 0x84, + .indat_endpoint = -1, + .glocont_endpoint = -1, + .calculate_baud_rate = keyspan_usa19_calc_baud, + .baudclk = KEYSPAN_USA19_BAUDCLK, +}; + +static const struct keyspan_device_details usa19qi_device_details = { + .product_id = keyspan_usa19qi_product_id, + .msg_format = msg_usa28, + .num_ports = 1, + .indat_endp_flip = 1, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x83}, + .outcont_endpoints = {0x03}, + .instat_endpoint = 0x84, + .indat_endpoint = -1, + .glocont_endpoint = -1, + .calculate_baud_rate = keyspan_usa28_calc_baud, + .baudclk = KEYSPAN_USA19_BAUDCLK, +}; + +static const struct keyspan_device_details mpr_device_details = { + .product_id = keyspan_mpr_product_id, + .msg_format = msg_usa28, + .num_ports = 1, + .indat_endp_flip = 1, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x83}, + .outcont_endpoints = {0x03}, + .instat_endpoint = 0x84, + .indat_endpoint = -1, + .glocont_endpoint = -1, + .calculate_baud_rate = keyspan_usa28_calc_baud, + .baudclk = KEYSPAN_USA19_BAUDCLK, +}; + +static const struct keyspan_device_details usa19qw_device_details = { + .product_id = keyspan_usa19qw_product_id, + .msg_format = msg_usa26, + .num_ports = 1, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x85}, + .outcont_endpoints = {0x05}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA19W_BAUDCLK, +}; + +static const struct keyspan_device_details usa19w_device_details = { + .product_id = keyspan_usa19w_product_id, + .msg_format = msg_usa26, + .num_ports = 1, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x85}, + .outcont_endpoints = {0x05}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA19W_BAUDCLK, +}; + +static const struct keyspan_device_details usa19hs_device_details = { + .product_id = keyspan_usa19hs_product_id, + .msg_format = msg_usa90, + .num_ports = 1, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {-1}, + .outcont_endpoints = {0x02}, + .instat_endpoint = 0x82, + .indat_endpoint = -1, + .glocont_endpoint = -1, + .calculate_baud_rate = keyspan_usa19hs_calc_baud, + .baudclk = KEYSPAN_USA19HS_BAUDCLK, +}; + +static const struct keyspan_device_details usa28_device_details = { + .product_id = keyspan_usa28_product_id, + .msg_format = msg_usa28, + .num_ports = 2, + .indat_endp_flip = 1, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81, 0x83}, + .outdat_endpoints = {0x01, 0x03}, + .inack_endpoints = {0x85, 0x86}, + .outcont_endpoints = {0x05, 0x06}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa28_calc_baud, + .baudclk = KEYSPAN_USA28_BAUDCLK, +}; + +static const struct keyspan_device_details usa28x_device_details = { + .product_id = keyspan_usa28x_product_id, + .msg_format = msg_usa26, + .num_ports = 2, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81, 0x83}, + .outdat_endpoints = {0x01, 0x03}, + .inack_endpoints = {0x85, 0x86}, + .outcont_endpoints = {0x05, 0x06}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA28X_BAUDCLK, +}; + +static const struct keyspan_device_details usa28xa_device_details = { + .product_id = keyspan_usa28xa_product_id, + .msg_format = msg_usa26, + .num_ports = 2, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81, 0x83}, + .outdat_endpoints = {0x01, 0x03}, + .inack_endpoints = {0x85, 0x86}, + .outcont_endpoints = {0x05, 0x06}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA28X_BAUDCLK, +}; + +static const struct keyspan_device_details usa28xg_device_details = { + .product_id = keyspan_usa28xg_product_id, + .msg_format = msg_usa67, + .num_ports = 2, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {0x84, 0x88}, + .outdat_endpoints = {0x02, 0x06}, + .inack_endpoints = {-1, -1}, + .outcont_endpoints = {-1, -1}, + .instat_endpoint = 0x81, + .indat_endpoint = -1, + .glocont_endpoint = 0x01, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA28X_BAUDCLK, +}; +/* + * We don't need a separate entry for the usa28xb as it appears as a 28x + * anyway. + */ + +static const struct keyspan_device_details usa49w_device_details = { + .product_id = keyspan_usa49w_product_id, + .msg_format = msg_usa49, + .num_ports = 4, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, + .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, + .inack_endpoints = {-1, -1, -1, -1}, + .outcont_endpoints = {-1, -1, -1, -1}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA49W_BAUDCLK, +}; + +static const struct keyspan_device_details usa49wlc_device_details = { + .product_id = keyspan_usa49wlc_product_id, + .msg_format = msg_usa49, + .num_ports = 4, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, + .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, + .inack_endpoints = {-1, -1, -1, -1}, + .outcont_endpoints = {-1, -1, -1, -1}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA19W_BAUDCLK, +}; + +static const struct keyspan_device_details usa49wg_device_details = { + .product_id = keyspan_usa49wg_product_id, + .msg_format = msg_usa49, + .num_ports = 4, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {-1, -1, -1, -1}, /* single 'global' data in EP */ + .outdat_endpoints = {0x01, 0x02, 0x04, 0x06}, + .inack_endpoints = {-1, -1, -1, -1}, + .outcont_endpoints = {-1, -1, -1, -1}, + .instat_endpoint = 0x81, + .indat_endpoint = 0x88, + .glocont_endpoint = 0x00, /* uses control EP */ + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA19W_BAUDCLK, +}; + +static const struct keyspan_device_details *keyspan_devices[] = { + &usa18x_device_details, + &usa19_device_details, + &usa19qi_device_details, + &mpr_device_details, + &usa19qw_device_details, + &usa19w_device_details, + &usa19hs_device_details, + &usa28_device_details, + &usa28x_device_details, + &usa28xa_device_details, + &usa28xg_device_details, + /* 28xb not required as it renumerates as a 28x */ + &usa49w_device_details, + &usa49wlc_device_details, + &usa49wg_device_details, + NULL, +}; + +static const struct usb_device_id keyspan_ids_combined[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); + +/* usb_device_id table for the pre-firmware download keyspan devices */ +static const struct usb_device_id keyspan_pre_ids[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, + { } /* Terminating entry */ +}; + +static const struct usb_device_id keyspan_1port_ids[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, + { } /* Terminating entry */ +}; + +static const struct usb_device_id keyspan_2port_ids[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, + { } /* Terminating entry */ +}; + +static const struct usb_device_id keyspan_4port_ids[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, + { } /* Terminating entry */ +}; + #define INSTAT_BUFLEN 32 #define GLOCONT_BUFLEN 64 #define INDAT49W_BUFLEN 512 @@ -126,8 +623,6 @@ struct keyspan_port_private { #include "keyspan_usa67msg.h" -module_usb_serial_driver(serial_drivers, keyspan_ids_combined); - static void keyspan_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; @@ -2523,6 +3018,97 @@ static int keyspan_port_remove(struct usb_serial_port *port) return 0; } +/* Structs for the devices, pre and post renumeration. */ +static struct usb_serial_driver keyspan_pre_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_no_firm", + }, + .description = "Keyspan - (without firmware)", + .id_table = keyspan_pre_ids, + .num_ports = 1, + .attach = keyspan_fake_startup, +}; + +static struct usb_serial_driver keyspan_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_1", + }, + .description = "Keyspan 1 port adapter", + .id_table = keyspan_1port_ids, + .num_ports = 1, + .open = keyspan_open, + .close = keyspan_close, + .dtr_rts = keyspan_dtr_rts, + .write = keyspan_write, + .write_room = keyspan_write_room, + .set_termios = keyspan_set_termios, + .break_ctl = keyspan_break_ctl, + .tiocmget = keyspan_tiocmget, + .tiocmset = keyspan_tiocmset, + .attach = keyspan_startup, + .disconnect = keyspan_disconnect, + .release = keyspan_release, + .port_probe = keyspan_port_probe, + .port_remove = keyspan_port_remove, +}; + +static struct usb_serial_driver keyspan_2port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_2", + }, + .description = "Keyspan 2 port adapter", + .id_table = keyspan_2port_ids, + .num_ports = 2, + .open = keyspan_open, + .close = keyspan_close, + .dtr_rts = keyspan_dtr_rts, + .write = keyspan_write, + .write_room = keyspan_write_room, + .set_termios = keyspan_set_termios, + .break_ctl = keyspan_break_ctl, + .tiocmget = keyspan_tiocmget, + .tiocmset = keyspan_tiocmset, + .attach = keyspan_startup, + .disconnect = keyspan_disconnect, + .release = keyspan_release, + .port_probe = keyspan_port_probe, + .port_remove = keyspan_port_remove, +}; + +static struct usb_serial_driver keyspan_4port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_4", + }, + .description = "Keyspan 4 port adapter", + .id_table = keyspan_4port_ids, + .num_ports = 4, + .open = keyspan_open, + .close = keyspan_close, + .dtr_rts = keyspan_dtr_rts, + .write = keyspan_write, + .write_room = keyspan_write_room, + .set_termios = keyspan_set_termios, + .break_ctl = keyspan_break_ctl, + .tiocmget = keyspan_tiocmget, + .tiocmset = keyspan_tiocmset, + .attach = keyspan_startup, + .disconnect = keyspan_disconnect, + .release = keyspan_release, + .port_probe = keyspan_port_probe, + .port_remove = keyspan_port_remove, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &keyspan_pre_device, &keyspan_1port_device, + &keyspan_2port_device, &keyspan_4port_device, NULL +}; + +module_usb_serial_driver(serial_drivers, keyspan_ids_combined); + MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h deleted file mode 100644 index 0273dda303a4..000000000000 --- a/drivers/usb/serial/keyspan.h +++ /dev/null @@ -1,629 +0,0 @@ -/* - Keyspan USB to Serial Converter driver - - (C) Copyright (C) 2000-2001 - Hugh Blemings <hugh@blemings.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - See http://blemings.org/hugh/keyspan.html for more information. - - Code in this driver inspired by and in a number of places taken - from Brian Warner's original Keyspan-PDA driver. - - This driver has been put together with the support of Innosys, Inc. - and Keyspan, Inc the manufacturers of the Keyspan USB-serial products. - Thanks Guys :) - - Thanks to Paulus for miscellaneous tidy ups, some largish chunks - of much nicer and/or completely new code and (perhaps most uniquely) - having the patience to sit down and explain why and where he'd changed - stuff. - - Tip 'o the hat to IBM (and previously Linuxcare :) for supporting - staff in their work on open source projects. - - See keyspan.c for update history. - -*/ - -#ifndef __LINUX_USB_SERIAL_KEYSPAN_H -#define __LINUX_USB_SERIAL_KEYSPAN_H - - -/* Function prototypes for Keyspan serial converter */ -static int keyspan_open (struct tty_struct *tty, - struct usb_serial_port *port); -static void keyspan_close (struct usb_serial_port *port); -static void keyspan_dtr_rts (struct usb_serial_port *port, int on); -static int keyspan_startup (struct usb_serial *serial); -static void keyspan_disconnect (struct usb_serial *serial); -static void keyspan_release (struct usb_serial *serial); -static int keyspan_port_probe(struct usb_serial_port *port); -static int keyspan_port_remove(struct usb_serial_port *port); -static int keyspan_write_room (struct tty_struct *tty); - -static int keyspan_write (struct tty_struct *tty, - struct usb_serial_port *port, - const unsigned char *buf, - int count); - -static void keyspan_send_setup (struct usb_serial_port *port, - int reset_port); - - -static void keyspan_set_termios (struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old); -static void keyspan_break_ctl (struct tty_struct *tty, - int break_state); -static int keyspan_tiocmget (struct tty_struct *tty); -static int keyspan_tiocmset (struct tty_struct *tty, - unsigned int set, - unsigned int clear); -static int keyspan_fake_startup (struct usb_serial *serial); - -static int keyspan_usa19_calc_baud (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa19w_calc_baud (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa28_calc_baud (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa19hs_calc_baud (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa28_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); -static int keyspan_usa26_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); -static int keyspan_usa49_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); - -static int keyspan_usa90_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); - -static int keyspan_usa67_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); - -/* Values used for baud rate calculation - device specific */ -#define KEYSPAN_INVALID_BAUD_RATE (-1) -#define KEYSPAN_BAUD_RATE_OK (0) -#define KEYSPAN_USA18X_BAUDCLK (12000000L) /* a guess */ -#define KEYSPAN_USA19_BAUDCLK (12000000L) -#define KEYSPAN_USA19W_BAUDCLK (24000000L) -#define KEYSPAN_USA19HS_BAUDCLK (14769231L) -#define KEYSPAN_USA28_BAUDCLK (1843200L) -#define KEYSPAN_USA28X_BAUDCLK (12000000L) -#define KEYSPAN_USA49W_BAUDCLK (48000000L) - -/* Some constants used to characterise each device. */ -#define KEYSPAN_MAX_NUM_PORTS (4) -#define KEYSPAN_MAX_FLIPS (2) - -/* Device info for the Keyspan serial converter, used - by the overall usb-serial probe function */ -#define KEYSPAN_VENDOR_ID (0x06cd) - -/* Product IDs for the products supported, pre-renumeration */ -#define keyspan_usa18x_pre_product_id 0x0105 -#define keyspan_usa19_pre_product_id 0x0103 -#define keyspan_usa19qi_pre_product_id 0x010b -#define keyspan_mpr_pre_product_id 0x011b -#define keyspan_usa19qw_pre_product_id 0x0118 -#define keyspan_usa19w_pre_product_id 0x0106 -#define keyspan_usa28_pre_product_id 0x0101 -#define keyspan_usa28x_pre_product_id 0x0102 -#define keyspan_usa28xa_pre_product_id 0x0114 -#define keyspan_usa28xb_pre_product_id 0x0113 -#define keyspan_usa49w_pre_product_id 0x0109 -#define keyspan_usa49wlc_pre_product_id 0x011a - -/* Product IDs post-renumeration. Note that the 28x and 28xb - have the same id's post-renumeration but behave identically - so it's not an issue. As such, the 28xb is not listed in any - of the device tables. */ -#define keyspan_usa18x_product_id 0x0112 -#define keyspan_usa19_product_id 0x0107 -#define keyspan_usa19qi_product_id 0x010c -#define keyspan_usa19hs_product_id 0x0121 -#define keyspan_mpr_product_id 0x011c -#define keyspan_usa19qw_product_id 0x0119 -#define keyspan_usa19w_product_id 0x0108 -#define keyspan_usa28_product_id 0x010f -#define keyspan_usa28x_product_id 0x0110 -#define keyspan_usa28xa_product_id 0x0115 -#define keyspan_usa28xb_product_id 0x0110 -#define keyspan_usa28xg_product_id 0x0135 -#define keyspan_usa49w_product_id 0x010a -#define keyspan_usa49wlc_product_id 0x012a -#define keyspan_usa49wg_product_id 0x0131 - -struct keyspan_device_details { - /* product ID value */ - int product_id; - - enum {msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format; - - /* Number of physical ports */ - int num_ports; - - /* 1 if endpoint flipping used on input, 0 if not */ - int indat_endp_flip; - - /* 1 if endpoint flipping used on output, 0 if not */ - int outdat_endp_flip; - - /* Table mapping input data endpoint IDs to physical - port number and flip if used */ - int indat_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Same for output endpoints */ - int outdat_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Input acknowledge endpoints */ - int inack_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Output control endpoints */ - int outcont_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Endpoint used for input status */ - int instat_endpoint; - - /* Endpoint used for input data 49WG only */ - int indat_endpoint; - - /* Endpoint used for global control functions */ - int glocont_endpoint; - - int (*calculate_baud_rate) (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); - u32 baudclk; -}; - -/* Now for each device type we setup the device detail - structure with the appropriate information (provided - in Keyspan's documentation) */ - -static const struct keyspan_device_details usa18x_device_details = { - .product_id = keyspan_usa18x_product_id, - .msg_format = msg_usa26, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x85}, - .outcont_endpoints = {0x05}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA18X_BAUDCLK, -}; - -static const struct keyspan_device_details usa19_device_details = { - .product_id = keyspan_usa19_product_id, - .msg_format = msg_usa28, - .num_ports = 1, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x83}, - .outcont_endpoints = {0x03}, - .instat_endpoint = 0x84, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa19_calc_baud, - .baudclk = KEYSPAN_USA19_BAUDCLK, -}; - -static const struct keyspan_device_details usa19qi_device_details = { - .product_id = keyspan_usa19qi_product_id, - .msg_format = msg_usa28, - .num_ports = 1, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x83}, - .outcont_endpoints = {0x03}, - .instat_endpoint = 0x84, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa28_calc_baud, - .baudclk = KEYSPAN_USA19_BAUDCLK, -}; - -static const struct keyspan_device_details mpr_device_details = { - .product_id = keyspan_mpr_product_id, - .msg_format = msg_usa28, - .num_ports = 1, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x83}, - .outcont_endpoints = {0x03}, - .instat_endpoint = 0x84, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa28_calc_baud, - .baudclk = KEYSPAN_USA19_BAUDCLK, -}; - -static const struct keyspan_device_details usa19qw_device_details = { - .product_id = keyspan_usa19qw_product_id, - .msg_format = msg_usa26, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x85}, - .outcont_endpoints = {0x05}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details usa19w_device_details = { - .product_id = keyspan_usa19w_product_id, - .msg_format = msg_usa26, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x85}, - .outcont_endpoints = {0x05}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details usa19hs_device_details = { - .product_id = keyspan_usa19hs_product_id, - .msg_format = msg_usa90, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {-1}, - .outcont_endpoints = {0x02}, - .instat_endpoint = 0x82, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa19hs_calc_baud, - .baudclk = KEYSPAN_USA19HS_BAUDCLK, -}; - -static const struct keyspan_device_details usa28_device_details = { - .product_id = keyspan_usa28_product_id, - .msg_format = msg_usa28, - .num_ports = 2, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81, 0x83}, - .outdat_endpoints = {0x01, 0x03}, - .inack_endpoints = {0x85, 0x86}, - .outcont_endpoints = {0x05, 0x06}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa28_calc_baud, - .baudclk = KEYSPAN_USA28_BAUDCLK, -}; - -static const struct keyspan_device_details usa28x_device_details = { - .product_id = keyspan_usa28x_product_id, - .msg_format = msg_usa26, - .num_ports = 2, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81, 0x83}, - .outdat_endpoints = {0x01, 0x03}, - .inack_endpoints = {0x85, 0x86}, - .outcont_endpoints = {0x05, 0x06}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA28X_BAUDCLK, -}; - -static const struct keyspan_device_details usa28xa_device_details = { - .product_id = keyspan_usa28xa_product_id, - .msg_format = msg_usa26, - .num_ports = 2, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81, 0x83}, - .outdat_endpoints = {0x01, 0x03}, - .inack_endpoints = {0x85, 0x86}, - .outcont_endpoints = {0x05, 0x06}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA28X_BAUDCLK, -}; - -static const struct keyspan_device_details usa28xg_device_details = { - .product_id = keyspan_usa28xg_product_id, - .msg_format = msg_usa67, - .num_ports = 2, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x84, 0x88}, - .outdat_endpoints = {0x02, 0x06}, - .inack_endpoints = {-1, -1}, - .outcont_endpoints = {-1, -1}, - .instat_endpoint = 0x81, - .indat_endpoint = -1, - .glocont_endpoint = 0x01, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA28X_BAUDCLK, -}; -/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */ - -static const struct keyspan_device_details usa49w_device_details = { - .product_id = keyspan_usa49w_product_id, - .msg_format = msg_usa49, - .num_ports = 4, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, - .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, - .inack_endpoints = {-1, -1, -1, -1}, - .outcont_endpoints = {-1, -1, -1, -1}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA49W_BAUDCLK, -}; - -static const struct keyspan_device_details usa49wlc_device_details = { - .product_id = keyspan_usa49wlc_product_id, - .msg_format = msg_usa49, - .num_ports = 4, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, - .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, - .inack_endpoints = {-1, -1, -1, -1}, - .outcont_endpoints = {-1, -1, -1, -1}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details usa49wg_device_details = { - .product_id = keyspan_usa49wg_product_id, - .msg_format = msg_usa49, - .num_ports = 4, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {-1, -1, -1, -1}, /* single 'global' data in EP */ - .outdat_endpoints = {0x01, 0x02, 0x04, 0x06}, - .inack_endpoints = {-1, -1, -1, -1}, - .outcont_endpoints = {-1, -1, -1, -1}, - .instat_endpoint = 0x81, - .indat_endpoint = 0x88, - .glocont_endpoint = 0x00, /* uses control EP */ - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details *keyspan_devices[] = { - &usa18x_device_details, - &usa19_device_details, - &usa19qi_device_details, - &mpr_device_details, - &usa19qw_device_details, - &usa19w_device_details, - &usa19hs_device_details, - &usa28_device_details, - &usa28x_device_details, - &usa28xa_device_details, - &usa28xg_device_details, - /* 28xb not required as it renumerates as a 28x */ - &usa49w_device_details, - &usa49wlc_device_details, - &usa49wg_device_details, - NULL, -}; - -static const struct usb_device_id keyspan_ids_combined[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); - -/* usb_device_id table for the pre-firmware download keyspan devices */ -static const struct usb_device_id keyspan_pre_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id keyspan_1port_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id keyspan_2port_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id keyspan_4port_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, - { } /* Terminating entry */ -}; - -/* Structs for the devices, pre and post renumeration. */ -static struct usb_serial_driver keyspan_pre_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_no_firm", - }, - .description = "Keyspan - (without firmware)", - .id_table = keyspan_pre_ids, - .num_ports = 1, - .attach = keyspan_fake_startup, -}; - -static struct usb_serial_driver keyspan_1port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_1", - }, - .description = "Keyspan 1 port adapter", - .id_table = keyspan_1port_ids, - .num_ports = 1, - .open = keyspan_open, - .close = keyspan_close, - .dtr_rts = keyspan_dtr_rts, - .write = keyspan_write, - .write_room = keyspan_write_room, - .set_termios = keyspan_set_termios, - .break_ctl = keyspan_break_ctl, - .tiocmget = keyspan_tiocmget, - .tiocmset = keyspan_tiocmset, - .attach = keyspan_startup, - .disconnect = keyspan_disconnect, - .release = keyspan_release, - .port_probe = keyspan_port_probe, - .port_remove = keyspan_port_remove, -}; - -static struct usb_serial_driver keyspan_2port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_2", - }, - .description = "Keyspan 2 port adapter", - .id_table = keyspan_2port_ids, - .num_ports = 2, - .open = keyspan_open, - .close = keyspan_close, - .dtr_rts = keyspan_dtr_rts, - .write = keyspan_write, - .write_room = keyspan_write_room, - .set_termios = keyspan_set_termios, - .break_ctl = keyspan_break_ctl, - .tiocmget = keyspan_tiocmget, - .tiocmset = keyspan_tiocmset, - .attach = keyspan_startup, - .disconnect = keyspan_disconnect, - .release = keyspan_release, - .port_probe = keyspan_port_probe, - .port_remove = keyspan_port_remove, -}; - -static struct usb_serial_driver keyspan_4port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_4", - }, - .description = "Keyspan 4 port adapter", - .id_table = keyspan_4port_ids, - .num_ports = 4, - .open = keyspan_open, - .close = keyspan_close, - .dtr_rts = keyspan_dtr_rts, - .write = keyspan_write, - .write_room = keyspan_write_room, - .set_termios = keyspan_set_termios, - .break_ctl = keyspan_break_ctl, - .tiocmget = keyspan_tiocmget, - .tiocmset = keyspan_tiocmset, - .attach = keyspan_startup, - .disconnect = keyspan_disconnect, - .release = keyspan_release, - .port_probe = keyspan_port_probe, - .port_remove = keyspan_port_remove, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &keyspan_pre_device, &keyspan_1port_device, - &keyspan_2port_device, &keyspan_4port_device, NULL -}; - -#endif diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 83523fcf6fb9..d2dab2a341b8 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -139,6 +139,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; + unsigned int len = urb->actual_length; int retval; int status = urb->status; struct keyspan_pda_private *priv; @@ -159,18 +160,26 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) goto exit; } + if (len < 1) { + dev_warn(&port->dev, "short message received\n"); + goto exit; + } + /* see if the message is data or a status interrupt */ switch (data[0]) { case 0: /* rest of message is rx data */ - if (urb->actual_length) { - tty_insert_flip_string(&port->port, data + 1, - urb->actual_length - 1); - tty_flip_buffer_push(&port->port); - } + if (len < 2) + break; + tty_insert_flip_string(&port->port, data + 1, len - 1); + tty_flip_buffer_push(&port->port); break; case 1: /* status interrupt */ + if (len < 3) { + dev_warn(&port->dev, "short interrupt message received\n"); + break; + } dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]); switch (data[1]) { case 1: /* modemline change */ diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 6cb45757818f..595415e59d5d 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -89,7 +89,6 @@ static struct usb_serial_driver kl5kusb105d_device = { .open = klsi_105_open, .close = klsi_105_close, .set_termios = klsi_105_set_termios, - /*.break_ctl = klsi_105_break_ctl,*/ .tiocmget = klsi_105_tiocmget, .port_probe = klsi_105_port_probe, .port_remove = klsi_105_port_remove, @@ -104,16 +103,15 @@ static struct usb_serial_driver * const serial_drivers[] = { }; struct klsi_105_port_settings { - __u8 pktlen; /* always 5, it seems */ - __u8 baudrate; - __u8 databits; - __u8 unknown1; - __u8 unknown2; -} __attribute__ ((packed)); + u8 pktlen; /* always 5, it seems */ + u8 baudrate; + u8 databits; + u8 unknown1; + u8 unknown2; +}; struct klsi_105_private { struct klsi_105_port_settings cfg; - struct ktermios termios; unsigned long line_state; /* modem line settings */ spinlock_t lock; }; @@ -143,10 +141,12 @@ static int klsi_105_chg_port_settings(struct usb_serial_port *port, if (rc < 0) dev_err(&port->dev, "Change port settings failed (error = %d)\n", rc); - dev_info(&port->serial->dev->dev, - "%d byte block, baudrate %x, databits %d, u1 %d, u2 %d\n", - settings->pktlen, settings->baudrate, settings->databits, - settings->unknown1, settings->unknown2); + + dev_dbg(&port->dev, + "pktlen %u, baudrate 0x%02x, databits %u, u1 %u, u2 %u\n", + settings->pktlen, settings->baudrate, settings->databits, + settings->unknown1, settings->unknown2); + return rc; } @@ -175,8 +175,6 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, u8 *status_buf; __u16 status; - dev_info(&port->serial->dev->dev, "sending SIO Poll request\n"); - status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL); if (!status_buf) return -ENOMEM; @@ -199,8 +197,8 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, } else { status = get_unaligned_le16(status_buf); - dev_info(&port->serial->dev->dev, "read status %x %x\n", - status_buf[0], status_buf[1]); + dev_dbg(&port->dev, "read status %02x %02x\n", + status_buf[0], status_buf[1]); *line_state_p = klsi_105_status2linestate(status); } @@ -233,8 +231,6 @@ static int klsi_105_port_probe(struct usb_serial_port *port) spin_lock_init(&priv->lock); - /* priv->termios is left uninitialized until port opening */ - usb_set_serial_port_data(port, priv); return 0; @@ -255,7 +251,6 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) struct klsi_105_private *priv = usb_get_serial_port_data(port); int retval = 0; int rc; - int i; unsigned long line_state; struct klsi_105_port_settings *cfg; unsigned long flags; @@ -278,14 +273,7 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) cfg->unknown2 = 1; klsi_105_chg_port_settings(port, cfg); - /* set up termios structure */ spin_lock_irqsave(&priv->lock, flags); - priv->termios.c_iflag = tty->termios.c_iflag; - priv->termios.c_oflag = tty->termios.c_oflag; - priv->termios.c_cflag = tty->termios.c_cflag; - priv->termios.c_lflag = tty->termios.c_lflag; - for (i = 0; i < NCCS; i++) - priv->termios.c_cc[i] = tty->termios.c_cc[i]; priv->cfg.pktlen = cfg->pktlen; priv->cfg.baudrate = cfg->baudrate; priv->cfg.databits = cfg->databits; @@ -438,19 +426,6 @@ static void klsi_105_set_termios(struct tty_struct *tty, */ baud = tty_get_baud_rate(tty); - if ((cflag & CBAUD) != (old_cflag & CBAUD)) { - /* reassert DTR and (maybe) RTS on transition from B0 */ - if ((old_cflag & CBAUD) == B0) { - dev_dbg(dev, "%s: baud was B0\n", __func__); -#if 0 - priv->control_state |= TIOCM_DTR; - /* don't set RTS if using hardware flow control */ - if (!(old_cflag & CRTSCTS)) - priv->control_state |= TIOCM_RTS; - mct_u232_set_modem_ctrl(serial, priv->control_state); -#endif - } - } switch (baud) { case 0: /* handled below */ break; @@ -484,17 +459,14 @@ static void klsi_105_set_termios(struct tty_struct *tty, baud = 9600; break; } - if ((cflag & CBAUD) == B0) { - dev_dbg(dev, "%s: baud is B0\n", __func__); - /* Drop RTS and DTR */ - /* maybe this should be simulated by sending read - * disable and read enable messages? - */ -#if 0 - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - mct_u232_set_modem_ctrl(serial, priv->control_state); -#endif - } + + /* + * FIXME: implement B0 handling + * + * Maybe this should be simulated by sending read disable and read + * enable messages? + */ + tty_encode_baud_rate(tty, baud, baud); if ((cflag & CSIZE) != (old_cflag & CSIZE)) { @@ -528,22 +500,6 @@ static void klsi_105_set_termios(struct tty_struct *tty, || (cflag & CSTOPB) != (old_cflag & CSTOPB)) { /* Not currently supported */ tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB); -#if 0 - priv->last_lcr = 0; - - /* set the parity */ - if (cflag & PARENB) - priv->last_lcr |= (cflag & PARODD) ? - MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN; - else - priv->last_lcr |= MCT_U232_PARITY_NONE; - - /* set the number of stop bits */ - priv->last_lcr |= (cflag & CSTOPB) ? - MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; - - mct_u232_set_line_ctrl(serial, priv->last_lcr); -#endif } /* * Set flow control: well, I do not really now how to handle DTR/RTS. @@ -554,14 +510,6 @@ static void klsi_105_set_termios(struct tty_struct *tty, || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { /* Not currently supported */ tty->termios.c_cflag &= ~CRTSCTS; - /* Drop DTR/RTS if no flow control otherwise assert */ -#if 0 - if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) - priv->control_state |= TIOCM_DTR | TIOCM_RTS; - else - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - mct_u232_set_modem_ctrl(serial, priv->control_state); -#endif } memcpy(cfg, &priv->cfg, sizeof(*cfg)); spin_unlock_irqrestore(&priv->lock, flags); @@ -572,25 +520,6 @@ err: kfree(cfg); } -#if 0 -static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct mct_u232_private *priv = - (struct mct_u232_private *)port->private; - unsigned char lcr = priv->last_lcr; - - dev_dbg(&port->dev, "%s - state=%d\n", __func__, break_state); - - /* LOCKING */ - if (break_state) - lcr |= MCT_U232_SET_BREAK; - - mct_u232_set_line_ctrl(serial, lcr); -} -#endif - static int klsi_105_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 885655315de1..edbc81f205c2 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -322,8 +322,12 @@ static int mct_u232_get_modem_stat(struct usb_serial_port *port, MCT_U232_GET_REQUEST_TYPE, 0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE, WDR_TIMEOUT); - if (rc < 0) { + if (rc < MCT_U232_GET_MODEM_STAT_SIZE) { dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n", rc); + + if (rc >= 0) + rc = -EIO; + *msr = 0; } else { *msr = buf[0]; diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 39e683096e94..cc84da8dbb84 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -135,23 +135,8 @@ static void metrousb_read_int_callback(struct urb *urb) throttled = metro_priv->throttled; spin_unlock_irqrestore(&metro_priv->lock, flags); - /* Continue trying to read if set. */ - if (!throttled) { - usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, - usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress), - port->interrupt_in_urb->transfer_buffer, - port->interrupt_in_urb->transfer_buffer_length, - metrousb_read_int_callback, port, 1); - - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - - if (result) - dev_err(&port->dev, - "%s - failed submitting interrupt in urb, error code=%d\n", - __func__, result); - } - return; - + if (throttled) + return; exit: /* Try to resubmit the urb. */ result = usb_submit_urb(urb, GFP_ATOMIC); @@ -161,19 +146,8 @@ exit: __func__, result); } -static void metrousb_write_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - - dev_warn(&port->dev, "%s not implemented yet.\n", - __func__); -} - static void metrousb_cleanup(struct usb_serial_port *port) { - dev_dbg(&port->dev, "%s\n", __func__); - - usb_unlink_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb); metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port); @@ -186,8 +160,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags = 0; int result = 0; - dev_dbg(&port->dev, "%s\n", __func__); - /* Make sure the urb is initialized. */ if (!port->interrupt_in_urb) { dev_err(&port->dev, "%s - interrupt urb not initialized\n", @@ -227,8 +199,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) __func__, result); goto exit; } - - dev_dbg(&port->dev, "%s - port open\n", __func__); exit: return result; } @@ -290,8 +260,6 @@ static void metrousb_throttle(struct tty_struct *tty) struct metrousb_private *metro_priv = usb_get_serial_port_data(port); unsigned long flags = 0; - dev_dbg(tty->dev, "%s\n", __func__); - /* Set the private information for the port to stop reading data. */ spin_lock_irqsave(&metro_priv->lock, flags); metro_priv->throttled = 1; @@ -305,8 +273,6 @@ static int metrousb_tiocmget(struct tty_struct *tty) struct metrousb_private *metro_priv = usb_get_serial_port_data(port); unsigned long flags = 0; - dev_dbg(tty->dev, "%s\n", __func__); - spin_lock_irqsave(&metro_priv->lock, flags); control_state = metro_priv->control_state; spin_unlock_irqrestore(&metro_priv->lock, flags); @@ -350,15 +316,12 @@ static void metrousb_unthrottle(struct tty_struct *tty) unsigned long flags = 0; int result = 0; - dev_dbg(tty->dev, "%s\n", __func__); - /* Set the private information for the port to resume reading data. */ spin_lock_irqsave(&metro_priv->lock, flags); metro_priv->throttled = 0; spin_unlock_irqrestore(&metro_priv->lock, flags); /* Submit the urb to read from the port. */ - port->interrupt_in_urb->dev = port->serial->dev; result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) dev_err(tty->dev, @@ -377,7 +340,6 @@ static struct usb_serial_driver metrousb_device = { .open = metrousb_open, .close = metrousb_cleanup, .read_int_callback = metrousb_read_int_callback, - .write_int_callback = metrousb_write_int_callback, .port_probe = metrousb_port_probe, .port_remove = metrousb_port_remove, .throttle = metrousb_throttle, diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 91bc170b408a..f075121c6e32 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -234,11 +234,16 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, status = usb_control_msg(usbdev, pipe, request, requesttype, value, index, buf, 1, MOS_WDR_TIMEOUT); - if (status == 1) + if (status == 1) { *data = *buf; - else if (status < 0) + } else { dev_err(&usbdev->dev, "mos7720: usb_control_msg() failed: %d\n", status); + if (status >= 0) + status = -EIO; + *data = 0; + } + kfree(buf); return status; @@ -1846,7 +1851,6 @@ static int get_serial_info(struct moschip_port *mos7720_port, tmp.line = mos7720_port->port->minor; tmp.port = mos7720_port->port->port_number; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index ea27fb23967a..3821c53fcee9 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -284,9 +284,15 @@ static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg, ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + if (ret < VENDOR_READ_LENGTH) { + if (ret >= 0) + ret = -EIO; + goto out; + } + *val = buf[0]; dev_dbg(&port->dev, "%s offset is %x, return val %x\n", __func__, reg, *val); - +out: kfree(buf); return ret; } @@ -352,8 +358,13 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + if (ret < VENDOR_READ_LENGTH) { + if (ret >= 0) + ret = -EIO; + goto out; + } *val = buf[0]; - +out: kfree(buf); return ret; } @@ -1023,6 +1034,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) * (can't set it up in mos7840_startup as the structures * * were not set up at that time.) */ if (port0->open_ports == 1) { + /* FIXME: Buffer never NULL, so URB is not submitted. */ if (serial->port[0]->interrupt_in_buffer == NULL) { /* set up interrupt urb */ usb_fill_int_urb(serial->port[0]->interrupt_in_urb, @@ -1479,10 +1491,10 @@ static int mos7840_tiocmget(struct tty_struct *tty) return -ENODEV; status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr); - if (status != 1) + if (status < 0) return -EIO; status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr); - if (status != 1) + if (status < 0) return -EIO; result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | ((mcr & MCR_RTS) ? TIOCM_RTS : 0) @@ -1952,7 +1964,6 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port, tmp.line = mos7840_port->port->minor; tmp.port = mos7840_port->port->port_number; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; tmp.baud_base = 9600; tmp.close_delay = 5 * HZ; @@ -2106,7 +2117,8 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) static int mos7840_attach(struct usb_serial *serial) { if (serial->num_bulk_in < serial->num_ports || - serial->num_bulk_out < serial->num_ports) { + serial->num_bulk_out < serial->num_ports || + serial->num_interrupt_in < 1) { dev_err(&serial->interface->dev, "missing endpoints\n"); return -ENODEV; } diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 5ded6f524d59..3937b9c3cc69 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -142,7 +142,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(port->serial->dev, port->read_urb->pipe); res = usb_serial_generic_open(tty, port); - if (!res) + if (res) return res; /* Request CTS line state, sometimes during opening the current @@ -343,7 +343,6 @@ static int get_serial_info(struct usb_serial_port *port, tmp.line = port->minor; tmp.port = 0; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = 1024; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 1db4b61bdf7b..ca69eb42071b 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -450,7 +450,7 @@ static int pl2303_get_line_request(struct usb_serial_port *port, if (ret != 7) { dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); - if (ret > 0) + if (ret >= 0) ret = -EIO; return ret; @@ -470,12 +470,8 @@ static int pl2303_set_line_request(struct usb_serial_port *port, ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); - if (ret != 7) { + if (ret < 0) { dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); - - if (ret > 0) - ret = -EIO; - return ret; } diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 5709cc93b083..fdbb904d153f 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -188,22 +188,22 @@ static inline int qt2_setdevice(struct usb_device *dev, u8 *data) } -static inline int qt2_getdevice(struct usb_device *dev, u8 *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_DEVICE, 0xc0, 0, 0, - data, 3, QT2_USB_TIMEOUT); -} - static inline int qt2_getregister(struct usb_device *dev, u8 uart, u8 reg, u8 *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_REGISTER, 0xc0, reg, - uart, data, sizeof(*data), QT2_USB_TIMEOUT); + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0xc0, reg, + uart, data, sizeof(*data), QT2_USB_TIMEOUT); + if (ret < sizeof(*data)) { + if (ret >= 0) + ret = -EIO; + } + return ret; } static inline int qt2_setregister(struct usb_device *dev, @@ -372,9 +372,11 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) 0xc0, 0, device_port, data, 2, QT2_USB_TIMEOUT); - if (status < 0) { + if (status < 2) { dev_err(&port->dev, "%s - open port failed %i\n", __func__, status); + if (status >= 0) + status = -EIO; kfree(data); return status; } @@ -463,7 +465,6 @@ static int get_serial_info(struct usb_serial_port *port, tmp.line = port->minor; tmp.port = 0; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index e1994e264cc0..465e851b2815 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -137,24 +137,9 @@ static int is_himemory(const u8 ifnum, return 0; } -static int sierra_calc_interface(struct usb_serial *serial) +static u8 sierra_interface_num(struct usb_serial *serial) { - int interface; - struct usb_interface *p_interface; - struct usb_host_interface *p_host_interface; - - /* Get the interface structure pointer from the serial struct */ - p_interface = serial->interface; - - /* Get a pointer to the host interface structure */ - p_host_interface = p_interface->cur_altsetting; - - /* read the interface descriptor for this active altsetting - * to find out the interface number we are on - */ - interface = p_host_interface->desc.bInterfaceNumber; - - return interface; + return serial->interface->cur_altsetting->desc.bInterfaceNumber; } static int sierra_probe(struct usb_serial *serial, @@ -165,7 +150,7 @@ static int sierra_probe(struct usb_serial *serial, u8 ifnum; udev = serial->dev; - ifnum = sierra_calc_interface(serial); + ifnum = sierra_interface_num(serial); /* * If this interface supports more than 1 alternate @@ -178,9 +163,6 @@ static int sierra_probe(struct usb_serial *serial, usb_set_interface(udev, ifnum, 1); } - /* ifnum could have changed - by calling usb_set_interface */ - ifnum = sierra_calc_interface(serial); - if (is_blacklisted(ifnum, (struct sierra_iface_info *)id->driver_info)) { dev_dbg(&serial->dev->dev, @@ -342,7 +324,7 @@ static int sierra_send_setup(struct usb_serial_port *port) /* If composite device then properly report interface */ if (serial->num_ports == 1) { - interface = sierra_calc_interface(serial); + interface = sierra_interface_num(serial); /* Control message is sent only to interfaces with * interrupt_in endpoints */ @@ -916,7 +898,7 @@ static int sierra_port_probe(struct usb_serial_port *port) /* Determine actual memory requirements */ if (serial->num_ports == 1) { /* Get interface number for composite device */ - ifnum = sierra_calc_interface(serial); + ifnum = sierra_interface_num(serial); himemoryp = &typeB_interface_list; } else { /* This is really the usb-serial port number of the interface diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 475e6c31b266..ddfd787c461c 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -232,11 +232,17 @@ static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status) ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_UART_STATUS, GET_UART_STATUS_TYPE, 0, GET_UART_STATUS_MSR, buf, 1, 100); - if (ret < 0) + if (ret < 1) { dev_err(&port->dev, "failed to get modem status: %d\n", ret); + if (ret >= 0) + ret = -EIO; + goto out; + } dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf); *status = *buf; + ret = 0; +out: kfree(buf); return ret; diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 2a156144c76c..5aa7bbbeba3d 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -80,9 +80,17 @@ static inline int ssu100_setdevice(struct usb_device *dev, u8 *data) static inline int ssu100_getdevice(struct usb_device *dev, u8 *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_DEVICE, 0xc0, 0, 0, - data, 3, 300); + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_DEVICE, 0xc0, 0, 0, + data, 3, 300); + if (ret < 3) { + if (ret >= 0) + ret = -EIO; + } + + return ret; } static inline int ssu100_getregister(struct usb_device *dev, @@ -90,10 +98,17 @@ static inline int ssu100_getregister(struct usb_device *dev, unsigned short reg, u8 *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_REGISTER, 0xc0, reg, - uart, data, sizeof(*data), 300); + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0xc0, reg, + uart, data, sizeof(*data), 300); + if (ret < sizeof(*data)) { + if (ret >= 0) + ret = -EIO; + } + return ret; } @@ -289,8 +304,10 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) QT_OPEN_CLOSE_CHANNEL, QT_TRANSFER_IN, 0x01, 0, data, 2, 300); - if (result < 0) { + if (result < 2) { dev_dbg(&port->dev, "%s - open failed %i\n", __func__, result); + if (result >= 0) + result = -EIO; kfree(data); return result; } @@ -322,7 +339,6 @@ static int get_serial_info(struct usb_serial_port *port, tmp.line = port->minor; tmp.port = 0; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 64b85b8dedf3..3107bf5d1c96 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1553,13 +1553,10 @@ static int ti_command_out_sync(struct ti_device *tdev, __u8 command, (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), value, moduleid, data, size, 1000); - if (status == size) - status = 0; - - if (status > 0) - status = -ECOMM; + if (status < 0) + return status; - return status; + return 0; } @@ -1575,8 +1572,7 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, if (status == size) status = 0; - - if (status > 0) + else if (status >= 0) status = -ECOMM; return status; diff --git a/drivers/usb/serial/upd78f0730.c b/drivers/usb/serial/upd78f0730.c new file mode 100644 index 000000000000..a028dd2310c9 --- /dev/null +++ b/drivers/usb/serial/upd78f0730.c @@ -0,0 +1,441 @@ +/* + * Renesas Electronics uPD78F0730 USB to serial converter driver + * + * Copyright (C) 2014,2016 Maksim Salau <maksim.salau@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Protocol of the adaptor is described in the application note U19660EJ1V0AN00 + * μPD78F0730 8-bit Single-Chip Microcontroller + * USB-to-Serial Conversion Software + * <https://www.renesas.com/en-eu/doc/DocumentServer/026/U19660EJ1V0AN00.pdf> + * + * The adaptor functionality is limited to the following: + * - data bits: 7 or 8 + * - stop bits: 1 or 2 + * - parity: even, odd or none + * - flow control: none + * - baud rates: 0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600 + * - signals: DTR, RTS and BREAK + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> + +#define DRIVER_DESC "Renesas uPD78F0730 USB to serial converter driver" + +#define DRIVER_AUTHOR "Maksim Salau <maksim.salau@gmail.com>" + +static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x0409, 0x0063) }, /* V850ESJX3-STICK */ + { USB_DEVICE(0x045B, 0x0212) }, /* YRPBRL78G13, YRPBRL78G14 */ + { USB_DEVICE(0x064B, 0x7825) }, /* Analog Devices EVAL-ADXL362Z-DB */ + {} +}; + +MODULE_DEVICE_TABLE(usb, id_table); + +/* + * Each adaptor is associated with a private structure, that holds the current + * state of control signals (DTR, RTS and BREAK). + */ +struct upd78f0730_port_private { + struct mutex lock; /* mutex to protect line_signals */ + u8 line_signals; +}; + +/* Op-codes of control commands */ +#define UPD78F0730_CMD_LINE_CONTROL 0x00 +#define UPD78F0730_CMD_SET_DTR_RTS 0x01 +#define UPD78F0730_CMD_SET_XON_XOFF_CHR 0x02 +#define UPD78F0730_CMD_OPEN_CLOSE 0x03 +#define UPD78F0730_CMD_SET_ERR_CHR 0x04 + +/* Data sizes in UPD78F0730_CMD_LINE_CONTROL command */ +#define UPD78F0730_DATA_SIZE_7_BITS 0x00 +#define UPD78F0730_DATA_SIZE_8_BITS 0x01 +#define UPD78F0730_DATA_SIZE_MASK 0x01 + +/* Stop-bit modes in UPD78F0730_CMD_LINE_CONTROL command */ +#define UPD78F0730_STOP_BIT_1_BIT 0x00 +#define UPD78F0730_STOP_BIT_2_BIT 0x02 +#define UPD78F0730_STOP_BIT_MASK 0x02 + +/* Parity modes in UPD78F0730_CMD_LINE_CONTROL command */ +#define UPD78F0730_PARITY_NONE 0x00 +#define UPD78F0730_PARITY_EVEN 0x04 +#define UPD78F0730_PARITY_ODD 0x08 +#define UPD78F0730_PARITY_MASK 0x0C + +/* Flow control modes in UPD78F0730_CMD_LINE_CONTROL command */ +#define UPD78F0730_FLOW_CONTROL_NONE 0x00 +#define UPD78F0730_FLOW_CONTROL_HW 0x10 +#define UPD78F0730_FLOW_CONTROL_SW 0x20 +#define UPD78F0730_FLOW_CONTROL_MASK 0x30 + +/* Control signal bits in UPD78F0730_CMD_SET_DTR_RTS command */ +#define UPD78F0730_RTS 0x01 +#define UPD78F0730_DTR 0x02 +#define UPD78F0730_BREAK 0x04 + +/* Port modes in UPD78F0730_CMD_OPEN_CLOSE command */ +#define UPD78F0730_PORT_CLOSE 0x00 +#define UPD78F0730_PORT_OPEN 0x01 + +/* Error character substitution modes in UPD78F0730_CMD_SET_ERR_CHR command */ +#define UPD78F0730_ERR_CHR_DISABLED 0x00 +#define UPD78F0730_ERR_CHR_ENABLED 0x01 + +/* + * Declaration of command structures + */ + +/* UPD78F0730_CMD_LINE_CONTROL command */ +struct upd78f0730_line_control { + u8 opcode; + __le32 baud_rate; + u8 params; +} __packed; + +/* UPD78F0730_CMD_SET_DTR_RTS command */ +struct upd78f0730_set_dtr_rts { + u8 opcode; + u8 params; +}; + +/* UPD78F0730_CMD_SET_XON_OFF_CHR command */ +struct upd78f0730_set_xon_xoff_chr { + u8 opcode; + u8 xon; + u8 xoff; +}; + +/* UPD78F0730_CMD_OPEN_CLOSE command */ +struct upd78f0730_open_close { + u8 opcode; + u8 state; +}; + +/* UPD78F0730_CMD_SET_ERR_CHR command */ +struct upd78f0730_set_err_chr { + u8 opcode; + u8 state; + u8 err_char; +}; + +static int upd78f0730_send_ctl(struct usb_serial_port *port, + const void *data, int size) +{ + struct usb_device *usbdev = port->serial->dev; + void *buf; + int res; + + if (size <= 0 || !data) + return -EINVAL; + + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + res = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x00, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x0000, 0x0000, buf, size, USB_CTRL_SET_TIMEOUT); + + kfree(buf); + + if (res != size) { + struct device *dev = &port->dev; + + dev_err(dev, "failed to send control request %02x: %d\n", + *(u8 *)data, res); + /* The maximum expected length of a transfer is 6 bytes */ + if (res >= 0) + res = -EIO; + + return res; + } + + return 0; +} + +static int upd78f0730_port_probe(struct usb_serial_port *port) +{ + struct upd78f0730_port_private *private; + + private = kzalloc(sizeof(*private), GFP_KERNEL); + if (!private) + return -ENOMEM; + + mutex_init(&private->lock); + usb_set_serial_port_data(port, private); + + return 0; +} + +static int upd78f0730_port_remove(struct usb_serial_port *port) +{ + struct upd78f0730_port_private *private; + + private = usb_get_serial_port_data(port); + mutex_destroy(&private->lock); + kfree(private); + + return 0; +} + +static int upd78f0730_tiocmget(struct tty_struct *tty) +{ + struct device *dev = tty->dev; + struct upd78f0730_port_private *private; + struct usb_serial_port *port = tty->driver_data; + int signals; + int res; + + private = usb_get_serial_port_data(port); + + mutex_lock(&private->lock); + signals = private->line_signals; + mutex_unlock(&private->lock); + + res = ((signals & UPD78F0730_DTR) ? TIOCM_DTR : 0) | + ((signals & UPD78F0730_RTS) ? TIOCM_RTS : 0); + + dev_dbg(dev, "%s - res = %x\n", __func__, res); + + return res; +} + +static int upd78f0730_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct device *dev = tty->dev; + struct usb_serial_port *port = tty->driver_data; + struct upd78f0730_port_private *private; + struct upd78f0730_set_dtr_rts request; + int res; + + private = usb_get_serial_port_data(port); + + mutex_lock(&private->lock); + if (set & TIOCM_DTR) { + private->line_signals |= UPD78F0730_DTR; + dev_dbg(dev, "%s - set DTR\n", __func__); + } + if (set & TIOCM_RTS) { + private->line_signals |= UPD78F0730_RTS; + dev_dbg(dev, "%s - set RTS\n", __func__); + } + if (clear & TIOCM_DTR) { + private->line_signals &= ~UPD78F0730_DTR; + dev_dbg(dev, "%s - clear DTR\n", __func__); + } + if (clear & TIOCM_RTS) { + private->line_signals &= ~UPD78F0730_RTS; + dev_dbg(dev, "%s - clear RTS\n", __func__); + } + request.opcode = UPD78F0730_CMD_SET_DTR_RTS; + request.params = private->line_signals; + + res = upd78f0730_send_ctl(port, &request, sizeof(request)); + mutex_unlock(&private->lock); + + return res; +} + +static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state) +{ + struct device *dev = tty->dev; + struct upd78f0730_port_private *private; + struct usb_serial_port *port = tty->driver_data; + struct upd78f0730_set_dtr_rts request; + + private = usb_get_serial_port_data(port); + + mutex_lock(&private->lock); + if (break_state) { + private->line_signals |= UPD78F0730_BREAK; + dev_dbg(dev, "%s - set BREAK\n", __func__); + } else { + private->line_signals &= ~UPD78F0730_BREAK; + dev_dbg(dev, "%s - clear BREAK\n", __func__); + } + request.opcode = UPD78F0730_CMD_SET_DTR_RTS; + request.params = private->line_signals; + + upd78f0730_send_ctl(port, &request, sizeof(request)); + mutex_unlock(&private->lock); +} + +static void upd78f0730_dtr_rts(struct usb_serial_port *port, int on) +{ + struct tty_struct *tty = port->port.tty; + unsigned int set = 0; + unsigned int clear = 0; + + if (on) + set = TIOCM_DTR | TIOCM_RTS; + else + clear = TIOCM_DTR | TIOCM_RTS; + + upd78f0730_tiocmset(tty, set, clear); +} + +static speed_t upd78f0730_get_baud_rate(struct tty_struct *tty) +{ + const speed_t baud_rate = tty_get_baud_rate(tty); + const speed_t supported[] = { + 0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600 + }; + int i; + + for (i = ARRAY_SIZE(supported) - 1; i >= 0; i--) { + if (baud_rate == supported[i]) + return baud_rate; + } + + /* If the baud rate is not supported, switch to the default one */ + tty_encode_baud_rate(tty, 9600, 9600); + + return tty_get_baud_rate(tty); +} + +static void upd78f0730_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct device *dev = &port->dev; + struct upd78f0730_line_control request; + speed_t baud_rate; + + if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) + return; + + if (C_BAUD(tty) == B0) + upd78f0730_dtr_rts(port, 0); + else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) + upd78f0730_dtr_rts(port, 1); + + baud_rate = upd78f0730_get_baud_rate(tty); + request.opcode = UPD78F0730_CMD_LINE_CONTROL; + request.baud_rate = cpu_to_le32(baud_rate); + request.params = 0; + dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud_rate); + + switch (C_CSIZE(tty)) { + case CS7: + request.params |= UPD78F0730_DATA_SIZE_7_BITS; + dev_dbg(dev, "%s - 7 data bits\n", __func__); + break; + default: + tty->termios.c_cflag &= ~CSIZE; + tty->termios.c_cflag |= CS8; + dev_warn(dev, "data size is not supported, using 8 bits\n"); + /* fall through */ + case CS8: + request.params |= UPD78F0730_DATA_SIZE_8_BITS; + dev_dbg(dev, "%s - 8 data bits\n", __func__); + break; + } + + if (C_PARENB(tty)) { + if (C_PARODD(tty)) { + request.params |= UPD78F0730_PARITY_ODD; + dev_dbg(dev, "%s - odd parity\n", __func__); + } else { + request.params |= UPD78F0730_PARITY_EVEN; + dev_dbg(dev, "%s - even parity\n", __func__); + } + + if (C_CMSPAR(tty)) { + tty->termios.c_cflag &= ~CMSPAR; + dev_warn(dev, "MARK/SPACE parity is not supported\n"); + } + } else { + request.params |= UPD78F0730_PARITY_NONE; + dev_dbg(dev, "%s - no parity\n", __func__); + } + + if (C_CSTOPB(tty)) { + request.params |= UPD78F0730_STOP_BIT_2_BIT; + dev_dbg(dev, "%s - 2 stop bits\n", __func__); + } else { + request.params |= UPD78F0730_STOP_BIT_1_BIT; + dev_dbg(dev, "%s - 1 stop bit\n", __func__); + } + + if (C_CRTSCTS(tty)) { + tty->termios.c_cflag &= ~CRTSCTS; + dev_warn(dev, "RTSCTS flow control is not supported\n"); + } + if (I_IXOFF(tty) || I_IXON(tty)) { + tty->termios.c_iflag &= ~(IXOFF | IXON); + dev_warn(dev, "XON/XOFF flow control is not supported\n"); + } + request.params |= UPD78F0730_FLOW_CONTROL_NONE; + dev_dbg(dev, "%s - no flow control\n", __func__); + + upd78f0730_send_ctl(port, &request, sizeof(request)); +} + +static int upd78f0730_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct upd78f0730_open_close request = { + .opcode = UPD78F0730_CMD_OPEN_CLOSE, + .state = UPD78F0730_PORT_OPEN + }; + int res; + + res = upd78f0730_send_ctl(port, &request, sizeof(request)); + if (res) + return res; + + if (tty) + upd78f0730_set_termios(tty, port, NULL); + + return usb_serial_generic_open(tty, port); +} + +static void upd78f0730_close(struct usb_serial_port *port) +{ + struct upd78f0730_open_close request = { + .opcode = UPD78F0730_CMD_OPEN_CLOSE, + .state = UPD78F0730_PORT_CLOSE + }; + + usb_serial_generic_close(port); + upd78f0730_send_ctl(port, &request, sizeof(request)); +} + +static struct usb_serial_driver upd78f0730_device = { + .driver = { + .owner = THIS_MODULE, + .name = "upd78f0730", + }, + .id_table = id_table, + .num_ports = 1, + .port_probe = upd78f0730_port_probe, + .port_remove = upd78f0730_port_remove, + .open = upd78f0730_open, + .close = upd78f0730_close, + .set_termios = upd78f0730_set_termios, + .tiocmget = upd78f0730_tiocmget, + .tiocmset = upd78f0730_tiocmset, + .dtr_rts = upd78f0730_dtr_rts, + .break_ctl = upd78f0730_break_ctl, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &upd78f0730_device, + NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index d3ea90bef84d..5ab65eb1dacc 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -487,7 +487,6 @@ static int whiteheat_ioctl(struct tty_struct *tty, serstruct.type = PORT_16654; serstruct.line = port->minor; serstruct.port = port->port_number; - serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo); serstruct.custom_divisor = 0; serstruct.baud_base = 460800; diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 02bdaa912164..369f3c24815a 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -1364,7 +1364,6 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock, static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk) { - u16 Newblk; u16 blk; struct ms_lib_type_extdat extdat; /* need check */ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; @@ -1377,7 +1376,6 @@ static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk) if ((blk & MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK) == 0) blk -= MS_PHYSICAL_BLOCKS_PER_SEGMENT; - Newblk = info->MS_Lib.Phy2LogMap[blk]; if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED_ERASED) { return blk; } else if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED) { diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 3aeaa536c44f..44f8ffccd031 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -870,13 +870,12 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, unsigned int pagelen; unsigned char *bptr, *cptr, *xptr; unsigned char ecc[3]; - int i, result, isnew; + int i, result; lbap = ((lba % 1000) << 1) | 0x1000; if (parity[MSB_of(lbap) ^ LSB_of(lbap)]) lbap ^= 1; pba = info->lba_to_pba[lba]; - isnew = 0; if (pba == UNDEF) { pba = sddr09_find_unused_pba(info, lba); @@ -887,7 +886,6 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, } info->pba_to_lba[pba] = lba; info->lba_to_pba[lba] = pba; - isnew = 1; } if (pba == 1) { diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index c4724fb3a691..e4cb9f0625e8 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -313,6 +313,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, default: break; } + break; default: usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n", wValue); |