diff options
81 files changed, 1622 insertions, 760 deletions
diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml index 17e4f20c8d39..c78499a41c72 100644 --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml @@ -48,6 +48,22 @@ properties: - compatible - "#clock-cells" + reset: + type: object + + properties: + compatible: + const: raspberrypi,firmware-reset + + "#reset-cells": + const: 1 + description: > + The argument is the ID of the firmware reset line to affect. + + required: + - compatible + - "#reset-cells" + additionalProperties: false required: @@ -64,5 +80,10 @@ examples: compatible = "raspberrypi,firmware-clocks"; #clock-cells = <1>; }; + + reset: reset { + compatible = "raspberrypi,firmware-reset"; + #reset-cells = <1>; + }; }; ... diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml new file mode 100644 index 000000000000..1e8e1c22180e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Mediatek MT6360 Type-C Port Switch and Power Delivery controller DT bindings + +maintainers: + - ChiYuan Huang <cy_huang@richtek.com> + +description: | + Mediatek MT6360 is a multi-functional device. It integrates charger, ADC, flash, RGB indicators, + regulators (BUCKs/LDOs), and TypeC Port Switch with Power Delivery controller. + This document only describes MT6360 Type-C Port Switch and Power Delivery controller. + +properties: + compatible: + enum: + - mediatek,mt6360-tcpc + + interrupts: + maxItems: 1 + + interrupt-names: + items: + - const: PD_IRQB + + connector: + type: object + $ref: ../connector/usb-connector.yaml# + description: + Properties for usb c connector. + +additionalProperties: false + +required: + - compatible + - interrupts + - interrupt-names + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/usb/pd.h> + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + mt6360@34 { + compatible = "mediatek,mt6360"; + reg = <0x34>; + tcpc { + compatible = "mediatek,mt6360-tcpc"; + interrupts-extended = <&gpio26 3 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "PD_IRQB"; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = <PDO_FIXED(5000, 1000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>; + sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>; + op-sink-microwatt = <10000000>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&usb_hs>; + }; + }; + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&usb_ss>; + }; + }; + port@2 { + reg = <2>; + endpoint { + remote-endpoint = <&dp_aux>; + }; + }; + }; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/usb/renesas,usb-xhci.yaml b/Documentation/devicetree/bindings/usb/renesas,usb-xhci.yaml index add9f7b66da0..0f078bd0a3e5 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usb-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usb-xhci.yaml @@ -30,6 +30,7 @@ properties: - renesas,xhci-r8a774a1 # RZ/G2M - renesas,xhci-r8a774b1 # RZ/G2N - renesas,xhci-r8a774c0 # RZ/G2E + - renesas,xhci-r8a774e1 # RZ/G2H - renesas,xhci-r8a7795 # R-Car H3 - renesas,xhci-r8a7796 # R-Car M3-W - renesas,xhci-r8a77961 # R-Car M3-W+ diff --git a/MAINTAINERS b/MAINTAINERS index d746519253c3..b1c3d0f975ef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11049,7 +11049,7 @@ F: net/dsa/tag_mtk.c MEDIATEK USB3 DRD IP DRIVER M: Chunfeng Yun <chunfeng.yun@mediatek.com> -L: linux-usb@vger.kernel.org (moderated for non-subscribers) +L: linux-usb@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts index 222d7825e1ab..e94244a215af 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts @@ -4,6 +4,8 @@ #include "bcm2835-rpi.dtsi" #include "bcm283x-rpi-usb-peripheral.dtsi" +#include <dt-bindings/reset/raspberrypi,firmware-reset.h> + / { compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; model = "Raspberry Pi 4 Model B"; @@ -88,6 +90,11 @@ ""; status = "okay"; }; + + reset: reset { + compatible = "raspberrypi,firmware-reset"; + #reset-cells = <1>; + }; }; &gpio { @@ -207,6 +214,21 @@ }; }; +&pcie0 { + pci@1,0 { + #address-cells = <3>; + #size-cells = <2>; + ranges; + + reg = <0 0 0 0 0>; + + usb@1,0 { + reg = <0x10000 0 0 0 0>; + resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>; + }; + }; +}; + /* uart0 communicates with the BT module */ &uart0 { pinctrl-names = "default"; diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 4ce270513695..1472cccfd0b3 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -212,19 +212,16 @@ static int ath3k_load_firmware(struct usb_device *udev, BT_DBG("udev %p", udev); - pipe = usb_sndctrlpipe(udev, 0); - send_buf = kmalloc(BULK_SIZE, GFP_KERNEL); if (!send_buf) { BT_ERR("Can't allocate memory chunk for firmware"); return -ENOMEM; } - memcpy(send_buf, firmware->data, FW_HDR_SIZE); - err = usb_control_msg(udev, pipe, USB_REQ_DFU_DNLOAD, USB_TYPE_VENDOR, - 0, 0, send_buf, FW_HDR_SIZE, - USB_CTRL_SET_TIMEOUT); - if (err < 0) { + err = usb_control_msg_send(udev, 0, USB_REQ_DFU_DNLOAD, USB_TYPE_VENDOR, + 0, 0, firmware->data, FW_HDR_SIZE, + USB_CTRL_SET_TIMEOUT); + if (err) { BT_ERR("Can't change to loading configuration err"); goto error; } @@ -259,44 +256,17 @@ error: static int ath3k_get_state(struct usb_device *udev, unsigned char *state) { - int ret, pipe = 0; - char *buf; - - buf = kmalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - pipe = usb_rcvctrlpipe(udev, 0); - ret = usb_control_msg(udev, pipe, ATH3K_GETSTATE, - USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - buf, sizeof(*buf), USB_CTRL_SET_TIMEOUT); - - *state = *buf; - kfree(buf); - - return ret; + return usb_control_msg_recv(udev, 0, ATH3K_GETSTATE, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + state, 1, USB_CTRL_SET_TIMEOUT); } static int ath3k_get_version(struct usb_device *udev, struct ath3k_version *version) { - int ret, pipe = 0; - struct ath3k_version *buf; - const int size = sizeof(*buf); - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - pipe = usb_rcvctrlpipe(udev, 0); - ret = usb_control_msg(udev, pipe, ATH3K_GETVERSION, - USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - buf, size, USB_CTRL_SET_TIMEOUT); - - memcpy(version, buf, size); - kfree(buf); - - return ret; + return usb_control_msg_recv(udev, 0, ATH3K_GETVERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + version, sizeof(*version), USB_CTRL_SET_TIMEOUT); } static int ath3k_load_fwfile(struct usb_device *udev, @@ -316,13 +286,10 @@ static int ath3k_load_fwfile(struct usb_device *udev, } size = min_t(uint, count, FW_HDR_SIZE); - memcpy(send_buf, firmware->data, size); - pipe = usb_sndctrlpipe(udev, 0); - ret = usb_control_msg(udev, pipe, ATH3K_DNLOAD, - USB_TYPE_VENDOR, 0, 0, send_buf, - size, USB_CTRL_SET_TIMEOUT); - if (ret < 0) { + ret = usb_control_msg_send(udev, 0, ATH3K_DNLOAD, USB_TYPE_VENDOR, 0, 0, + firmware->data, size, USB_CTRL_SET_TIMEOUT); + if (ret) { BT_ERR("Can't change to loading configuration err"); kfree(send_buf); return ret; @@ -355,23 +322,19 @@ static int ath3k_load_fwfile(struct usb_device *udev, return 0; } -static int ath3k_switch_pid(struct usb_device *udev) +static void ath3k_switch_pid(struct usb_device *udev) { - int pipe = 0; - - pipe = usb_sndctrlpipe(udev, 0); - return usb_control_msg(udev, pipe, USB_REG_SWITCH_VID_PID, - USB_TYPE_VENDOR, 0, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); + usb_control_msg_send(udev, 0, USB_REG_SWITCH_VID_PID, USB_TYPE_VENDOR, + 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); } static int ath3k_set_normal_mode(struct usb_device *udev) { unsigned char fw_state; - int pipe = 0, ret; + int ret; ret = ath3k_get_state(udev, &fw_state); - if (ret < 0) { + if (ret) { BT_ERR("Can't get state to change to normal mode err"); return ret; } @@ -381,10 +344,9 @@ static int ath3k_set_normal_mode(struct usb_device *udev) return 0; } - pipe = usb_sndctrlpipe(udev, 0); - return usb_control_msg(udev, pipe, ATH3K_SET_NORMAL_MODE, - USB_TYPE_VENDOR, 0, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); + return usb_control_msg_send(udev, 0, ATH3K_SET_NORMAL_MODE, + USB_TYPE_VENDOR, 0, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); } static int ath3k_load_patch(struct usb_device *udev) @@ -397,7 +359,7 @@ static int ath3k_load_patch(struct usb_device *udev) int ret; ret = ath3k_get_state(udev, &fw_state); - if (ret < 0) { + if (ret) { BT_ERR("Can't get state to change to load ram patch err"); return ret; } @@ -408,7 +370,7 @@ static int ath3k_load_patch(struct usb_device *udev) } ret = ath3k_get_version(udev, &fw_version); - if (ret < 0) { + if (ret) { BT_ERR("Can't get version to change to load ram patch err"); return ret; } @@ -449,13 +411,13 @@ static int ath3k_load_syscfg(struct usb_device *udev) int clk_value, ret; ret = ath3k_get_state(udev, &fw_state); - if (ret < 0) { + if (ret) { BT_ERR("Can't get state to change to load configuration err"); return -EBUSY; } ret = ath3k_get_version(udev, &fw_version); - if (ret < 0) { + if (ret) { BT_ERR("Can't get version to change to load ram patch err"); return ret; } @@ -529,7 +491,7 @@ static int ath3k_probe(struct usb_interface *intf, return ret; } ret = ath3k_set_normal_mode(udev); - if (ret < 0) { + if (ret) { BT_ERR("Set normal mode failed"); return ret; } diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index fbd785dd0513..4843e94713a4 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -178,9 +178,8 @@ config ISCSI_IBFT Otherwise, say N. config RASPBERRYPI_FIRMWARE - bool "Raspberry Pi Firmware Driver" + tristate "Raspberry Pi Firmware Driver" depends on BCM2835_MBOX - default USB_PCI help This option enables support for communicating with the firmware on the Raspberry Pi. diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 8f2fb4c562da..2371d08bdd17 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -12,8 +12,6 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/pci.h> -#include <linux/delay.h> #include <soc/bcm2835/raspberrypi-firmware.h> #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) @@ -21,8 +19,6 @@ #define MBOX_DATA28(msg) ((msg) & ~0xf) #define MBOX_CHAN_PROPERTY 8 -#define VL805_PCI_CONFIG_VERSION_OFFSET 0x50 - static struct platform_device *rpi_hwmon; static struct platform_device *rpi_clk; @@ -301,63 +297,6 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) } EXPORT_SYMBOL_GPL(rpi_firmware_get); -/* - * The Raspberry Pi 4 gets its USB functionality from VL805, a PCIe chip that - * implements xHCI. After a PCI reset, VL805's firmware may either be loaded - * directly from an EEPROM or, if not present, by the SoC's co-processor, - * VideoCore. RPi4's VideoCore OS contains both the non public firmware load - * logic and the VL805 firmware blob. This function triggers the aforementioned - * process. - */ -int rpi_firmware_init_vl805(struct pci_dev *pdev) -{ - struct device_node *fw_np; - struct rpi_firmware *fw; - u32 dev_addr, version; - int ret; - - fw_np = of_find_compatible_node(NULL, NULL, - "raspberrypi,bcm2835-firmware"); - if (!fw_np) - return 0; - - fw = rpi_firmware_get(fw_np); - of_node_put(fw_np); - if (!fw) - return -ENODEV; - - /* - * Make sure we don't trigger a firmware load unnecessarily. - * - * If something went wrong with PCI, this whole exercise would be - * futile as VideoCore expects from us a configured PCI bus. Just take - * the faulty version (likely ~0) and let xHCI's registration fail - * further down the line. - */ - pci_read_config_dword(pdev, VL805_PCI_CONFIG_VERSION_OFFSET, &version); - if (version) - goto exit; - - dev_addr = pdev->bus->number << 20 | PCI_SLOT(pdev->devfn) << 15 | - PCI_FUNC(pdev->devfn) << 12; - - ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET, - &dev_addr, sizeof(dev_addr)); - if (ret) - return ret; - - /* Wait for vl805 to startup */ - usleep_range(200, 1000); - - pci_read_config_dword(pdev, VL805_PCI_CONFIG_VERSION_OFFSET, - &version); -exit: - pci_info(pdev, "VL805 firmware version %08x\n", version); - - return 0; -} -EXPORT_SYMBOL_GPL(rpi_firmware_init_vl805); - static const struct of_device_id rpi_firmware_of_match[] = { { .compatible = "raspberrypi,bcm2835-firmware", }, {}, diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 85fa7d54f11f..bac63d04297f 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -28,8 +28,6 @@ #include <linux/string.h> #include <linux/types.h> -#include <soc/bcm2835/raspberrypi-firmware.h> - #include "../pci.h" /* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */ @@ -931,24 +929,9 @@ static int brcm_pcie_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node, *msi_np; struct pci_host_bridge *bridge; - struct device_node *fw_np; struct brcm_pcie *pcie; int ret; - /* - * We have to wait for Raspberry Pi's firmware interface to be up as a - * PCI fixup, rpi_firmware_init_vl805(), depends on it. This driver's - * probe can race with the firmware interface's (see - * drivers/firmware/raspberrypi.c) and potentially break the PCI fixup. - */ - fw_np = of_find_compatible_node(NULL, NULL, - "raspberrypi,bcm2835-firmware"); - if (fw_np && !rpi_firmware_get(fw_np)) { - of_node_put(fw_np); - return -EPROBE_DEFER; - } - of_node_put(fw_np); - bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie)); if (!bridge) return -ENOMEM; diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index d9efbfd29646..97e848740e13 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -140,6 +140,17 @@ config RESET_QCOM_PDC to control reset signals provided by PDC for Modem, Compute, Display, GPU, Debug, AOP, Sensors, Audio, SP and APPS. +config RESET_RASPBERRYPI + tristate "Raspberry Pi 4 Firmware Reset Driver" + depends on RASPBERRYPI_FIRMWARE || (RASPBERRYPI_FIRMWARE=n && COMPILE_TEST) + default USB_XHCI_PCI + help + Raspberry Pi 4's co-processor controls some of the board's HW + initialization process, but it's up to Linux to trigger it when + relevant. This driver provides a reset controller capable of + interfacing with RPi4's co-processor and model these firmware + initialization routines as reset lines. + config RESET_SCMI tristate "Reset driver controlled via ARM SCMI interface" depends on ARM_SCMI_PROTOCOL || COMPILE_TEST diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 249ed357c997..16947610cc3b 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o +obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o obj-$(CONFIG_RESET_SCMI) += reset-scmi.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o diff --git a/drivers/reset/reset-raspberrypi.c b/drivers/reset/reset-raspberrypi.c new file mode 100644 index 000000000000..02f59c06f69b --- /dev/null +++ b/drivers/reset/reset-raspberrypi.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Raspberry Pi 4 firmware reset driver + * + * Copyright (C) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de> + */ +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <soc/bcm2835/raspberrypi-firmware.h> +#include <dt-bindings/reset/raspberrypi,firmware-reset.h> + +struct rpi_reset { + struct reset_controller_dev rcdev; + struct rpi_firmware *fw; +}; + +static inline struct rpi_reset *to_rpi(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct rpi_reset, rcdev); +} + +static int rpi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct rpi_reset *priv = to_rpi(rcdev); + u32 dev_addr; + int ret; + + switch (id) { + case RASPBERRYPI_FIRMWARE_RESET_ID_USB: + /* + * The Raspberry Pi 4 gets its USB functionality from VL805, a + * PCIe chip that implements xHCI. After a PCI reset, VL805's + * firmware may either be loaded directly from an EEPROM or, if + * not present, by the SoC's co-processor, VideoCore. rpi's + * VideoCore OS contains both the non public firmware load + * logic and the VL805 firmware blob. This triggers the + * aforementioned process. + * + * The pci device address is expected is expected by the + * firmware encoded like this: + * + * PCI_BUS << 20 | PCI_SLOT << 15 | PCI_FUNC << 12 + * + * But since rpi's PCIe is hardwired, we know the address in + * advance. + */ + dev_addr = 0x100000; + ret = rpi_firmware_property(priv->fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET, + &dev_addr, sizeof(dev_addr)); + if (ret) + return ret; + + /* Wait for vl805 to startup */ + usleep_range(200, 1000); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static const struct reset_control_ops rpi_reset_ops = { + .reset = rpi_reset_reset, +}; + +static int rpi_reset_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rpi_firmware *fw; + struct device_node *np; + struct rpi_reset *priv; + + np = of_get_parent(dev->of_node); + if (!np) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + fw = rpi_firmware_get(np); + of_node_put(np); + if (!fw) + return -EPROBE_DEFER; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + priv->fw = fw; + priv->rcdev.owner = THIS_MODULE; + priv->rcdev.nr_resets = RASPBERRYPI_FIRMWARE_RESET_NUM_IDS; + priv->rcdev.ops = &rpi_reset_ops; + priv->rcdev.of_node = dev->of_node; + + return devm_reset_controller_register(dev, &priv->rcdev); +} + +static const struct of_device_id rpi_reset_of_match[] = { + { .compatible = "raspberrypi,firmware-reset" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rpi_reset_of_match); + +static struct platform_driver rpi_reset_driver = { + .probe = rpi_reset_probe, + .driver = { + .name = "raspberrypi-reset", + .of_match_table = rpi_reset_of_match, + }, +}; +module_platform_driver(rpi_reset_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>"); +MODULE_DESCRIPTION("Raspberry Pi 4 firmware reset driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index ea66f8f385ba..e62a770a5d3b 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -230,12 +230,12 @@ CXACRU__ATTR_INIT(_name) static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf) { - return snprintf(buf, PAGE_SIZE, "%u\n", value); + return sprintf(buf, "%u\n", value); } static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", value); + return sprintf(buf, "%d\n", value); } static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf) @@ -255,8 +255,8 @@ static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf) static char *str[] = { "no", "yes" }; if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf) @@ -264,8 +264,8 @@ static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf) static char *str[] = { NULL, "not connected", "connected", "lost" }; if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL)) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf) @@ -275,8 +275,8 @@ static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf) "waiting", "initialising" }; if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf) @@ -288,8 +288,8 @@ static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf) "ITU-T G.992.2 (G.LITE)" }; if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } /* @@ -309,8 +309,7 @@ static ssize_t mac_address_show(struct device *dev, if (instance == NULL || instance->usbatm->atm_dev == NULL) return -ENODEV; - return snprintf(buf, PAGE_SIZE, "%pM\n", - instance->usbatm->atm_dev->esi); + return sprintf(buf, "%pM\n", instance->usbatm->atm_dev->esi); } static ssize_t adsl_state_show(struct device *dev, @@ -326,8 +325,8 @@ static ssize_t adsl_state_show(struct device *dev, value = instance->card_info[CXINF_LINE_STARTABLE]; if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } static ssize_t adsl_state_store(struct device *dev, diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 4e12a32ca392..56fe30d247da 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -511,9 +511,10 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance, ** receive ** **************/ -static void usbatm_rx_process(unsigned long data) +static void usbatm_rx_process(struct tasklet_struct *t) { - struct usbatm_data *instance = (struct usbatm_data *)data; + struct usbatm_data *instance = from_tasklet(instance, t, + rx_channel.tasklet); struct urb *urb; while ((urb = usbatm_pop_urb(&instance->rx_channel))) { @@ -564,9 +565,10 @@ static void usbatm_rx_process(unsigned long data) ** send ** ***********/ -static void usbatm_tx_process(unsigned long data) +static void usbatm_tx_process(struct tasklet_struct *t) { - struct usbatm_data *instance = (struct usbatm_data *)data; + struct usbatm_data *instance = from_tasklet(instance, t, + tx_channel.tasklet); struct sk_buff *skb = instance->current_skb; struct urb *urb = NULL; const unsigned int buf_size = instance->tx_channel.buf_size; @@ -1069,8 +1071,8 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, usbatm_init_channel(&instance->rx_channel); usbatm_init_channel(&instance->tx_channel); - tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance); - tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance); + tasklet_setup(&instance->rx_channel.tasklet, usbatm_rx_process); + tasklet_setup(&instance->tx_channel.tasklet, usbatm_tx_process); instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding; instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding; instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance; diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c index 60f4711717d2..e65f1a0ae80b 100644 --- a/drivers/usb/c67x00/c67x00-sched.c +++ b/drivers/usb/c67x00/c67x00-sched.c @@ -1123,9 +1123,9 @@ static void c67x00_do_work(struct c67x00_hcd *c67x00) /* -------------------------------------------------------------------------- */ -static void c67x00_sched_tasklet(unsigned long __c67x00) +static void c67x00_sched_tasklet(struct tasklet_struct *t) { - struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00; + struct c67x00_hcd *c67x00 = from_tasklet(c67x00, t, tasklet); c67x00_do_work(c67x00); } @@ -1136,8 +1136,7 @@ void c67x00_sched_kick(struct c67x00_hcd *c67x00) int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00) { - tasklet_init(&c67x00->tasklet, c67x00_sched_tasklet, - (unsigned long)c67x00); + tasklet_setup(&c67x00->tasklet, c67x00_sched_tasklet); return 0; } diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7f6f3ab5b8a6..f3803fa7c007 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -173,7 +173,7 @@ static int acm_wb_alloc(struct acm *acm) for (;;) { wb = &acm->wb[wbn]; if (!wb->use) { - wb->use = 1; + wb->use = true; wb->len = 0; return wbn; } @@ -191,7 +191,8 @@ static int acm_wb_is_avail(struct acm *acm) n = ACM_NW; spin_lock_irqsave(&acm->write_lock, flags); for (i = 0; i < ACM_NW; i++) - n -= acm->wb[i].use; + if(acm->wb[i].use) + n--; spin_unlock_irqrestore(&acm->write_lock, flags); return n; } @@ -201,7 +202,7 @@ static int acm_wb_is_avail(struct acm *acm) */ static void acm_write_done(struct acm *acm, struct acm_wb *wb) { - wb->use = 0; + wb->use = false; acm->transmitting--; usb_autopm_put_interface_async(acm->control); } @@ -741,7 +742,7 @@ static void acm_port_shutdown(struct tty_port *port) if (!urb) break; wb = urb->context; - wb->use = 0; + wb->use = false; usb_autopm_put_interface_async(acm->control); } @@ -792,7 +793,7 @@ static int acm_tty_write(struct tty_struct *tty, wb = &acm->wb[wbn]; if (!acm->dev) { - wb->use = 0; + wb->use = false; spin_unlock_irqrestore(&acm->write_lock, flags); return -ENODEV; } @@ -804,7 +805,7 @@ static int acm_tty_write(struct tty_struct *tty, stat = usb_autopm_get_interface_async(acm->control); if (stat) { - wb->use = 0; + wb->use = false; spin_unlock_irqrestore(&acm->write_lock, flags); return stat; } diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index cd5e9d8ab237..a50ea3911042 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -64,12 +64,12 @@ #define ACM_NR 16 struct acm_wb { - unsigned char *buf; + u8 *buf; dma_addr_t dmah; - int len; - int use; + unsigned int len; struct urb *urb; struct acm *instance; + bool use; }; struct acm_rb { diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c index 7b3a21360d7c..6c4e3a19f42c 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -91,14 +91,14 @@ static void usb_conn_detect_cable(struct work_struct *work) return; } - if (info->last_role == USB_ROLE_HOST) + if (info->last_role == USB_ROLE_HOST && info->vbus) regulator_disable(info->vbus); ret = usb_role_switch_set_role(info->role_sw, role); if (ret) dev_err(info->dev, "failed to set role: %d\n", ret); - if (role == USB_ROLE_HOST) { + if (role == USB_ROLE_HOST && info->vbus) { ret = regulator_enable(info->vbus); if (ret) dev_err(info->dev, "enable vbus regulator failed\n"); @@ -106,8 +106,9 @@ static void usb_conn_detect_cable(struct work_struct *work) info->last_role = role; - dev_dbg(info->dev, "vbus regulator is %s\n", - regulator_is_enabled(info->vbus) ? "enabled" : "disabled"); + if (info->vbus) + dev_dbg(info->dev, "vbus regulator is %s\n", + regulator_is_enabled(info->vbus) ? "enabled" : "disabled"); power_supply_changed(info->charger); } @@ -156,6 +157,7 @@ static int usb_conn_probe(struct platform_device *pdev) struct power_supply_config cfg = { .of_node = dev->of_node, }; + bool need_vbus = true; int ret = 0; info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); @@ -185,10 +187,26 @@ static int usb_conn_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&info->dw_det, usb_conn_detect_cable); - info->vbus = devm_regulator_get(dev, "vbus"); + /* + * If the USB connector is a child of a USB port and that port already provides the VBUS + * supply, there's no need for the USB connector to provide it again. + */ + if (dev->parent && dev->parent->of_node) { + if (of_find_property(dev->parent->of_node, "vbus-supply", NULL)) + need_vbus = false; + } + + if (!need_vbus) { + info->vbus = devm_regulator_get_optional(dev, "vbus"); + if (PTR_ERR(info->vbus) == -ENODEV) + info->vbus = NULL; + } else { + info->vbus = devm_regulator_get(dev, "vbus"); + } + if (IS_ERR(info->vbus)) { if (PTR_ERR(info->vbus) != -EPROBE_DEFER) - dev_err(dev, "failed to get vbus\n"); + dev_err(dev, "failed to get vbus: %ld\n", PTR_ERR(info->vbus)); return PTR_ERR(info->vbus); } @@ -266,7 +284,7 @@ static int usb_conn_remove(struct platform_device *pdev) cancel_delayed_work_sync(&info->dw_det); - if (info->last_role == USB_ROLE_HOST) + if (info->last_role == USB_ROLE_HOST && info->vbus) regulator_disable(info->vbus); usb_role_switch_put(info->role_sw); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 7e73e989645b..c976ea9f9582 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -973,8 +973,7 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver, bus_for_each_dev(&usb_bus_type, NULL, new_udriver, __usb_bus_reprobe_drivers); } else { - printk(KERN_ERR "%s: error %d registering device " - " driver %s\n", + pr_err("%s: error %d registering device driver %s\n", usbcore_name, retval, new_udriver->name); } @@ -1050,9 +1049,8 @@ out: out_newid: driver_unregister(&new_driver->drvwrap.driver); - printk(KERN_ERR "%s: error %d registering interface " - " driver %s\n", - usbcore_name, retval, new_driver->name); + pr_err("%s: error %d registering interface driver %s\n", + usbcore_name, retval, new_driver->name); goto out; } EXPORT_SYMBOL_GPL(usb_register_driver); diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 2b2f1ab6e36a..22c887f5c497 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -195,7 +195,7 @@ int usb_choose_configuration(struct usb_device *udev) } EXPORT_SYMBOL_GPL(usb_choose_configuration); -static int __check_usb_generic(struct device_driver *drv, void *data) +static int __check_for_non_generic_match(struct device_driver *drv, void *data) { struct usb_device *udev = data; struct usb_device_driver *udrv; @@ -219,7 +219,7 @@ static bool usb_generic_driver_match(struct usb_device *udev) * If any other driver wants the device, leave the device to this other * driver. */ - if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_usb_generic)) + if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_for_non_generic_match)) return false; return true; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a33b849e8beb..2c6b9578a7d3 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1657,9 +1657,9 @@ static void __usb_hcd_giveback_urb(struct urb *urb) usb_put_urb(urb); } -static void usb_giveback_urb_bh(unsigned long param) +static void usb_giveback_urb_bh(struct tasklet_struct *t) { - struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param; + struct giveback_urb_bh *bh = from_tasklet(bh, t, bh); struct list_head local_list; spin_lock_irq(&bh->lock); @@ -2403,7 +2403,7 @@ static void init_giveback_urb_bh(struct giveback_urb_bh *bh) spin_lock_init(&bh->lock); INIT_LIST_HEAD(&bh->head); - tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh); + tasklet_setup(&bh->bh, usb_giveback_urb_bh); } struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5b768b80d1ee..5742ddeb0455 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -410,8 +410,8 @@ static int get_hub_descriptor(struct usb_device *hdev, */ static int clear_hub_feature(struct usb_device *hdev, int feature) { - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, 1000); + return usb_control_msg_send(hdev, 0, USB_REQ_CLEAR_FEATURE, USB_RT_HUB, + feature, 0, NULL, 0, 1000); } /* @@ -419,9 +419,8 @@ static int clear_hub_feature(struct usb_device *hdev, int feature) */ int usb_clear_port_feature(struct usb_device *hdev, int port1, int feature) { - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, - NULL, 0, 1000); + return usb_control_msg_send(hdev, 0, USB_REQ_CLEAR_FEATURE, USB_RT_PORT, + feature, port1, NULL, 0, 1000); } /* @@ -429,9 +428,8 @@ int usb_clear_port_feature(struct usb_device *hdev, int port1, int feature) */ static int set_port_feature(struct usb_device *hdev, int port1, int feature) { - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, - NULL, 0, 1000); + return usb_control_msg_send(hdev, 0, USB_REQ_SET_FEATURE, USB_RT_PORT, + feature, port1, NULL, 0, 1000); } static char *to_led_name(int selector) @@ -755,15 +753,14 @@ hub_clear_tt_buffer(struct usb_device *hdev, u16 devinfo, u16 tt) /* Need to clear both directions for control ep */ if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL) { - int status = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - HUB_CLEAR_TT_BUFFER, USB_RT_PORT, - devinfo ^ 0x8000, tt, NULL, 0, 1000); + int status = usb_control_msg_send(hdev, 0, + HUB_CLEAR_TT_BUFFER, USB_RT_PORT, + devinfo ^ 0x8000, tt, NULL, 0, 1000); if (status) return status; } - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo, - tt, NULL, 0, 1000); + return usb_control_msg_send(hdev, 0, HUB_CLEAR_TT_BUFFER, USB_RT_PORT, + devinfo, tt, NULL, 0, 1000); } /* @@ -1049,11 +1046,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) */ if (type != HUB_RESUME) { if (hdev->parent && hub_is_superspeed(hdev)) { - ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - HUB_SET_DEPTH, USB_RT_HUB, - hdev->level - 1, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); - if (ret < 0) + ret = usb_control_msg_send(hdev, 0, HUB_SET_DEPTH, USB_RT_HUB, + hdev->level - 1, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (ret) dev_err(hub->intfdev, "set hub depth failed\n"); } @@ -2329,13 +2325,10 @@ static int usb_enumerate_device_otg(struct usb_device *udev) /* enable HNP before suspend, it's simpler */ if (port1 == bus->otg_port) { bus->b_hnp_enable = 1; - err = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, 0, - USB_DEVICE_B_HNP_ENABLE, - 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); - if (err < 0) { + err = usb_control_msg_send(udev, 0, USB_REQ_SET_FEATURE, 0, + USB_DEVICE_B_HNP_ENABLE, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (err) { /* * OTG MESSAGE: report errors here, * customize to match your product. @@ -2347,13 +2340,10 @@ static int usb_enumerate_device_otg(struct usb_device *udev) } else if (desc->bLength == sizeof (struct usb_otg_descriptor)) { /* Set a_alt_hnp_support for legacy otg device */ - err = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, 0, - USB_DEVICE_A_ALT_HNP_SUPPORT, - 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); - if (err < 0) + err = usb_control_msg_send(udev, 0, USB_REQ_SET_FEATURE, 0, + USB_DEVICE_A_ALT_HNP_SUPPORT, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (err) dev_err(&udev->dev, "set a_alt_hnp_support failed: %d\n", err); @@ -3121,10 +3111,8 @@ int usb_disable_ltm(struct usb_device *udev) if (!udev->actconfig) return 0; - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_LTM_ENABLE, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); + return usb_control_msg_send(udev, 0, USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_LTM_ENABLE, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); } EXPORT_SYMBOL_GPL(usb_disable_ltm); @@ -3143,10 +3131,8 @@ void usb_enable_ltm(struct usb_device *udev) if (!udev->actconfig) return; - usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_LTM_ENABLE, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); + usb_control_msg_send(udev, 0, USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_LTM_ENABLE, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); } EXPORT_SYMBOL_GPL(usb_enable_ltm); @@ -3163,17 +3149,14 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm); static int usb_enable_remote_wakeup(struct usb_device *udev) { if (udev->speed < USB_SPEED_SUPER) - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); + return usb_control_msg_send(udev, 0, USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); else - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE, - USB_INTRF_FUNC_SUSPEND, - USB_INTRF_FUNC_SUSPEND_RW | - USB_INTRF_FUNC_SUSPEND_LP, - NULL, 0, USB_CTRL_SET_TIMEOUT); + return usb_control_msg_send(udev, 0, USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE, + USB_INTRF_FUNC_SUSPEND, + USB_INTRF_FUNC_SUSPEND_RW | USB_INTRF_FUNC_SUSPEND_LP, + NULL, 0, USB_CTRL_SET_TIMEOUT); } /* @@ -3189,15 +3172,13 @@ static int usb_enable_remote_wakeup(struct usb_device *udev) static int usb_disable_remote_wakeup(struct usb_device *udev) { if (udev->speed < USB_SPEED_SUPER) - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); + return usb_control_msg_send(udev, 0, USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); else - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE, - USB_INTRF_FUNC_SUSPEND, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); + return usb_control_msg_send(udev, 0, USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE, + USB_INTRF_FUNC_SUSPEND, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); } /* Count of wakeup-enabled devices at or below udev */ diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index ae1de9cc4b09..1580694e3b95 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -163,6 +163,139 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, EXPORT_SYMBOL_GPL(usb_control_msg); /** + * usb_control_msg_send - Builds a control "send" message, sends it off and waits for completion + * @dev: pointer to the usb device to send the message to + * @endpoint: endpoint to send the message to + * @request: USB message request value + * @requesttype: USB message request type value + * @value: USB message value + * @index: USB message index value + * @driver_data: pointer to the data to send + * @size: length in bytes of the data to send + * @timeout: time in msecs to wait for the message to complete before timing + * out (if 0 the wait is forever) + * + * Context: !in_interrupt () + * + * This function sends a control message to a specified endpoint that is not + * expected to fill in a response (i.e. a "send message") and waits for the + * message to complete, or timeout. + * + * Do not 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. + * + * The data pointer can be made to a reference on the stack, or anywhere else, + * as it will not be modified at all. This does not have the restriction that + * usb_control_msg() has where the data pointer must be to dynamically allocated + * memory (i.e. memory that can be successfully DMAed to a device). + * + * Return: If successful, 0 is returned, Otherwise, a negative error number. + */ +int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request, + __u8 requesttype, __u16 value, __u16 index, + const void *driver_data, __u16 size, int timeout) +{ + unsigned int pipe = usb_sndctrlpipe(dev, endpoint); + int ret; + u8 *data = NULL; + + if (usb_pipe_type_check(dev, pipe)) + return -EINVAL; + + if (size) { + data = kmemdup(driver_data, size, GFP_KERNEL); + if (!data) + return -ENOMEM; + } + + ret = usb_control_msg(dev, pipe, request, requesttype, value, index, + data, size, timeout); + kfree(data); + + if (ret < 0) + return ret; + if (ret == size) + return 0; + return -EINVAL; +} +EXPORT_SYMBOL_GPL(usb_control_msg_send); + +/** + * usb_control_msg_recv - Builds a control "receive" message, sends it off and waits for completion + * @dev: pointer to the usb device to send the message to + * @endpoint: endpoint to send the message to + * @request: USB message request value + * @requesttype: USB message request type value + * @value: USB message value + * @index: USB message index value + * @driver_data: pointer to the data to be filled in by the message + * @size: length in bytes of the data to be received + * @timeout: time in msecs to wait for the message to complete before timing + * out (if 0 the wait is forever) + * + * Context: !in_interrupt () + * + * This function sends a control message to a specified endpoint that is + * expected to fill in a response (i.e. a "receive message") and waits for the + * message to complete, or timeout. + * + * Do not 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. + * + * The data pointer can be made to a reference on the stack, or anywhere else + * that can be successfully written to. This function does not have the + * restriction that usb_control_msg() has where the data pointer must be to + * dynamically allocated memory (i.e. memory that can be successfully DMAed to a + * device). + * + * The "whole" message must be properly received from the device in order for + * this function to be successful. If a device returns less than the expected + * amount of data, then the function will fail. Do not use this for messages + * where a variable amount of data might be returned. + * + * Return: If successful, 0 is returned, Otherwise, a negative error number. + */ +int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request, + __u8 requesttype, __u16 value, __u16 index, + void *driver_data, __u16 size, int timeout) +{ + unsigned int pipe = usb_rcvctrlpipe(dev, endpoint); + int ret; + u8 *data; + + if (!size || !driver_data || usb_pipe_type_check(dev, pipe)) + return -EINVAL; + + data = kmalloc(size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = usb_control_msg(dev, pipe, request, requesttype, value, index, + data, size, timeout); + + if (ret < 0) + goto exit; + + if (ret == size) { + memcpy(driver_data, data, size); + ret = 0; + } else { + ret = -EINVAL; + } + +exit: + kfree(data); + return ret; +} +EXPORT_SYMBOL_GPL(usb_control_msg_recv); + +/** * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion * @usb_dev: pointer to the usb device to send the message to * @pipe: endpoint "pipe" to send the message to @@ -948,7 +1081,7 @@ int usb_set_isoch_delay(struct usb_device *dev) if (dev->speed < USB_SPEED_SUPER) return 0; - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + return usb_control_msg_send(dev, 0, USB_REQ_SET_ISOCH_DELAY, USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, dev->hub_delay, 0, NULL, 0, @@ -1070,13 +1203,13 @@ int usb_clear_halt(struct usb_device *dev, int pipe) * (like some ibmcam model 1 units) seem to expect hosts to make * this request for iso endpoints, which can't halt! */ - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, - USB_ENDPOINT_HALT, endp, NULL, 0, - USB_CTRL_SET_TIMEOUT); + result = usb_control_msg_send(dev, 0, + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, endp, NULL, 0, + USB_CTRL_SET_TIMEOUT); /* don't un-halt or force to DATA0 except on success */ - if (result < 0) + if (result) return result; /* NOTE: seems like Microsoft and Apple don't bother verifying @@ -1438,9 +1571,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) if (dev->quirks & USB_QUIRK_NO_SET_INTF) ret = -EPIPE; else - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, - alternate, interface, NULL, 0, 5000); + ret = usb_control_msg_send(dev, 0, + USB_REQ_SET_INTERFACE, + USB_RECIP_INTERFACE, alternate, + interface, NULL, 0, 5000); /* 9.4.10 says devices don't need this and are free to STALL the * request if the interface only has one alternate setting. @@ -1450,7 +1584,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) "manual set_interface for iface %d, alt %d\n", interface, alternate); manual = 1; - } else if (ret < 0) { + } else if (ret) { /* Re-instate the old alt setting */ usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting); usb_enable_lpm(dev); @@ -1574,11 +1708,10 @@ int usb_reset_configuration(struct usb_device *dev) mutex_unlock(hcd->bandwidth_mutex); return retval; } - retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, - config->desc.bConfigurationValue, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); - if (retval < 0) { + retval = usb_control_msg_send(dev, 0, USB_REQ_SET_CONFIGURATION, 0, + config->desc.bConfigurationValue, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (retval) { usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); @@ -1963,10 +2096,10 @@ free_interfaces: } kfree(new_interfaces); - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, configuration, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); - if (ret < 0 && cp) { + ret = usb_control_msg_send(dev, 0, USB_REQ_SET_CONFIGURATION, 0, + configuration, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (ret && cp) { /* * All the old state is gone, so what else can we do? * The device is probably useless now anyway. diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 7bc23469f4e4..357b149b20d3 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -192,24 +192,39 @@ static const int pipetypes[4] = { }; /** - * usb_urb_ep_type_check - sanity check of endpoint in the given urb - * @urb: urb to be checked + * usb_pipe_type_check - sanity check of a specific pipe for a usb device + * @dev: struct usb_device to be checked + * @pipe: pipe to check * * This performs a light-weight sanity check for the endpoint in the - * given urb. It returns 0 if the urb contains a valid endpoint, otherwise - * a negative error code. + * given usb device. It returns 0 if the pipe is valid for the specific usb + * device, otherwise a negative error code. */ -int usb_urb_ep_type_check(const struct urb *urb) +int usb_pipe_type_check(struct usb_device *dev, unsigned int pipe) { const struct usb_host_endpoint *ep; - ep = usb_pipe_endpoint(urb->dev, urb->pipe); + ep = usb_pipe_endpoint(dev, pipe); if (!ep) return -EINVAL; - if (usb_pipetype(urb->pipe) != pipetypes[usb_endpoint_type(&ep->desc)]) + if (usb_pipetype(pipe) != pipetypes[usb_endpoint_type(&ep->desc)]) return -EINVAL; return 0; } +EXPORT_SYMBOL_GPL(usb_pipe_type_check); + +/** + * usb_urb_ep_type_check - sanity check of endpoint in the given urb + * @urb: urb to be checked + * + * This performs a light-weight sanity check for the endpoint in the + * given urb. It returns 0 if the urb contains a valid endpoint, otherwise + * a negative error code. + */ +int usb_urb_ep_type_check(const struct urb *urb) +{ + return usb_pipe_type_check(urb->dev, urb->pipe); +} EXPORT_SYMBOL_GPL(usb_urb_ep_type_check); /** @@ -474,7 +489,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) */ /* Check that the pipe's type matches the endpoint's type */ - if (usb_urb_ep_type_check(urb)) + if (usb_pipe_type_check(urb->dev, urb->pipe)) dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", usb_pipetype(urb->pipe), pipetypes[xfertype]); @@ -772,11 +787,12 @@ void usb_block_urb(struct urb *urb) EXPORT_SYMBOL_GPL(usb_block_urb); /** - * usb_kill_anchored_urbs - cancel transfer requests en masse + * usb_kill_anchored_urbs - kill all URBs associated with an anchor * @anchor: anchor the requests are bound to * - * this allows all outstanding URBs to be killed starting - * from the back of the queue + * This kills all outstanding URBs starting from the back of the queue, + * with guarantee that no completer callbacks will take place from the + * anchor after this function returns. * * This routine should not be called by a driver after its disconnect * method has returned. @@ -784,20 +800,26 @@ EXPORT_SYMBOL_GPL(usb_block_urb); void usb_kill_anchored_urbs(struct usb_anchor *anchor) { struct urb *victim; + int surely_empty; - spin_lock_irq(&anchor->lock); - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - /* we must make sure the URB isn't freed before we kill it*/ - usb_get_urb(victim); - spin_unlock_irq(&anchor->lock); - /* this will unanchor the URB */ - usb_kill_urb(victim); - usb_put_urb(victim); + do { spin_lock_irq(&anchor->lock); - } - spin_unlock_irq(&anchor->lock); + while (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.prev, + struct urb, anchor_list); + /* make sure the URB isn't freed before we kill it */ + usb_get_urb(victim); + spin_unlock_irq(&anchor->lock); + /* this will unanchor the URB */ + usb_kill_urb(victim); + usb_put_urb(victim); + spin_lock_irq(&anchor->lock); + } + surely_empty = usb_anchor_check_wakeup(anchor); + + spin_unlock_irq(&anchor->lock); + cpu_relax(); + } while (!surely_empty); } EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs); @@ -816,21 +838,27 @@ EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs); void usb_poison_anchored_urbs(struct usb_anchor *anchor) { struct urb *victim; + int surely_empty; - spin_lock_irq(&anchor->lock); - anchor->poisoned = 1; - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - /* we must make sure the URB isn't freed before we kill it*/ - usb_get_urb(victim); - spin_unlock_irq(&anchor->lock); - /* this will unanchor the URB */ - usb_poison_urb(victim); - usb_put_urb(victim); + do { spin_lock_irq(&anchor->lock); - } - spin_unlock_irq(&anchor->lock); + anchor->poisoned = 1; + while (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.prev, + struct urb, anchor_list); + /* make sure the URB isn't freed before we kill it */ + usb_get_urb(victim); + spin_unlock_irq(&anchor->lock); + /* this will unanchor the URB */ + usb_poison_urb(victim); + usb_put_urb(victim); + spin_lock_irq(&anchor->lock); + } + surely_empty = usb_anchor_check_wakeup(anchor); + + spin_unlock_irq(&anchor->lock); + cpu_relax(); + } while (!surely_empty); } EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs); @@ -970,14 +998,20 @@ void usb_scuttle_anchored_urbs(struct usb_anchor *anchor) { struct urb *victim; unsigned long flags; + int surely_empty; + + do { + spin_lock_irqsave(&anchor->lock, flags); + while (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.prev, + struct urb, anchor_list); + __usb_unanchor_urb(victim, anchor); + } + surely_empty = usb_anchor_check_wakeup(anchor); - spin_lock_irqsave(&anchor->lock, flags); - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - __usb_unanchor_urb(victim, anchor); - } - spin_unlock_irqrestore(&anchor->lock, flags); + spin_unlock_irqrestore(&anchor->lock, flags); + cpu_relax(); + } while (!surely_empty); } EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs); diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index db9fd4bd1a38..44b78f1c5e1a 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -121,6 +121,13 @@ static int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg) return 0; } +static void __dwc2_disable_regulators(void *data) +{ + struct dwc2_hsotg *hsotg = data; + + regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); +} + static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) { struct platform_device *pdev = to_platform_device(hsotg->dev); @@ -131,6 +138,11 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) if (ret) return ret; + ret = devm_add_action_or_reset(&pdev->dev, + __dwc2_disable_regulators, hsotg); + if (ret) + return ret; + if (hsotg->clk) { ret = clk_prepare_enable(hsotg->clk); if (ret) @@ -186,10 +198,7 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) if (hsotg->clk) clk_disable_unprepare(hsotg->clk); - ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), - hsotg->supplies); - - return ret; + return 0; } /** diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 46af0aa07e2e..85cb15734aa8 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -698,9 +698,9 @@ drop_out: f_midi_drop_out_substreams(midi); } -static void f_midi_in_tasklet(unsigned long data) +static void f_midi_in_tasklet(struct tasklet_struct *t) { - struct f_midi *midi = (struct f_midi *) data; + struct f_midi *midi = from_tasklet(midi, t, tasklet); f_midi_transmit(midi); } @@ -875,7 +875,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0; midi->gadget = cdev->gadget; - tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); + tasklet_setup(&midi->tasklet, f_midi_in_tasklet); status = f_midi_register_card(midi); if (status < 0) goto fail_register; diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 2707be628298..fa66449b3907 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -923,9 +923,9 @@ static int qe_ep_rxframe_handle(struct qe_ep *ep) return 0; } -static void ep_rx_tasklet(unsigned long data) +static void ep_rx_tasklet(struct tasklet_struct *t) { - struct qe_udc *udc = (struct qe_udc *)data; + struct qe_udc *udc = from_tasklet(udc, t, rx_tasklet); struct qe_ep *ep; struct qe_frame *pframe; struct qe_bd __iomem *bd; @@ -2553,8 +2553,7 @@ static int qe_udc_probe(struct platform_device *ofdev) DMA_TO_DEVICE); } - tasklet_init(&udc->rx_tasklet, ep_rx_tasklet, - (unsigned long)udc); + tasklet_setup(&udc->rx_tasklet, ep_rx_tasklet); /* request irq and disable DR */ udc->usb_irq = irq_of_parse_and_map(np, 0); if (!udc->usb_irq) { diff --git a/drivers/usb/host/ehci-npcm7xx.c b/drivers/usb/host/ehci-npcm7xx.c index adaf8fb4b459..6b5a7a873e01 100644 --- a/drivers/usb/host/ehci-npcm7xx.c +++ b/drivers/usb/host/ehci-npcm7xx.c @@ -37,8 +37,7 @@ static const char hcd_name[] = "npcm7xx-ehci"; static struct hc_driver __read_mostly ehci_npcm7xx_hc_driver; -#ifdef CONFIG_PM_SLEEP -static int ehci_npcm7xx_drv_suspend(struct device *dev) +static int __maybe_unused ehci_npcm7xx_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); bool do_wakeup = device_may_wakeup(dev); @@ -46,14 +45,13 @@ static int ehci_npcm7xx_drv_suspend(struct device *dev) return ehci_suspend(hcd, do_wakeup); } -static int ehci_npcm7xx_drv_resume(struct device *dev) +static int __maybe_unused ehci_npcm7xx_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); ehci_resume(hcd, false); return 0; } -#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(ehci_npcm7xx_pm_ops, ehci_npcm7xx_drv_suspend, ehci_npcm7xx_drv_resume); @@ -183,7 +181,7 @@ static struct platform_driver npcm7xx_ehci_hcd_driver = { .driver = { .name = "npcm7xx-ehci", .bus = &platform_bus_type, - .pm = &ehci_npcm7xx_pm_ops, + .pm = pm_ptr(&ehci_npcm7xx_pm_ops), .of_match_table = npcm7xx_ehci_id_table, } }; diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 006c4f6188a5..a48dd3fac153 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -42,6 +42,9 @@ #define EHCI_MAX_CLKS 4 #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv) +#define BCM_USB_FIFO_THRESHOLD 0x00800040 +#define bcm_iproc_insnreg01 hostpc[0] + struct ehci_platform_priv { struct clk *clks[EHCI_MAX_CLKS]; struct reset_control *rsts; @@ -75,6 +78,11 @@ static int ehci_platform_reset(struct usb_hcd *hcd) if (pdata->no_io_watchdog) ehci->need_io_watchdog = 0; + + if (of_device_is_compatible(pdev->dev.of_node, "brcm,xgs-iproc-ehci")) + ehci_writel(ehci, BCM_USB_FIFO_THRESHOLD, + &ehci->regs->bcm_iproc_insnreg01); + return 0; } @@ -410,8 +418,7 @@ static int ehci_platform_remove(struct platform_device *dev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int ehci_platform_suspend(struct device *dev) +static int __maybe_unused ehci_platform_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct usb_ehci_pdata *pdata = dev_get_platdata(dev); @@ -433,7 +440,7 @@ static int ehci_platform_suspend(struct device *dev) return ret; } -static int ehci_platform_resume(struct device *dev) +static int __maybe_unused ehci_platform_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct usb_ehci_pdata *pdata = dev_get_platdata(dev); @@ -464,7 +471,6 @@ static int ehci_platform_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ static const struct of_device_id vt8500_ehci_ids[] = { { .compatible = "via,vt8500-ehci", }, @@ -499,7 +505,7 @@ static struct platform_driver ehci_platform_driver = { .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ehci-platform", - .pm = &ehci_platform_pm_ops, + .pm = pm_ptr(&ehci_platform_pm_ops), .of_match_table = vt8500_ehci_ids, .acpi_match_table = ACPI_PTR(ehci_acpi_match), } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 847979f265b1..6dfb242f9a4b 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -307,26 +307,6 @@ static int __maybe_unused same_tt(struct usb_device *dev1, #ifdef CONFIG_USB_EHCI_TT_NEWSCHED -/* Which uframe does the low/fullspeed transfer start in? - * - * The parameter is the mask of ssplits in "H-frame" terms - * and this returns the transfer start uframe in "B-frame" terms, - * which allows both to match, e.g. a ssplit in "H-frame" uframe 0 - * will cause a transfer in "B-frame" uframe 0. "B-frames" lag - * "H-frames" by 1 uframe. See the EHCI spec sec 4.5 and figure 4.7. - */ -static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask) -{ - unsigned char smask = hc32_to_cpu(ehci, mask) & QH_SMASK; - - if (!smask) { - ehci_err(ehci, "invalid empty smask!\n"); - /* uframe 7 can't have bw so this will indicate failure */ - return 7; - } - return ffs(smask) - 1; -} - static const unsigned char max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index add796c78561..3694e450a11a 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -34,8 +34,7 @@ struct spear_ehci { static struct hc_driver __read_mostly ehci_spear_hc_driver; -#ifdef CONFIG_PM_SLEEP -static int ehci_spear_drv_suspend(struct device *dev) +static int __maybe_unused ehci_spear_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); bool do_wakeup = device_may_wakeup(dev); @@ -43,14 +42,13 @@ static int ehci_spear_drv_suspend(struct device *dev) return ehci_suspend(hcd, do_wakeup); } -static int ehci_spear_drv_resume(struct device *dev) +static int __maybe_unused ehci_spear_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); ehci_resume(hcd, false); return 0; } -#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend, ehci_spear_drv_resume); @@ -155,7 +153,7 @@ static struct platform_driver spear_ehci_hcd_driver = { .driver = { .name = "spear-ehci", .bus = &platform_bus_type, - .pm = &ehci_spear_pm_ops, + .pm = pm_ptr(&ehci_spear_pm_ops), .of_match_table = spear_ehci_id_table, } }; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index dd37e77dae00..73e13e7c2b46 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -102,7 +102,7 @@ static void io_watchdog_func(struct timer_list *t); /* Some boards misreport power switching/overcurrent */ -static bool distrust_firmware = true; +static bool distrust_firmware; module_param (distrust_firmware, bool, 0); MODULE_PARM_DESC (distrust_firmware, "true to distrust firmware power/overcurrent setup"); @@ -673,20 +673,24 @@ retry: /* handle root hub init quirks ... */ val = roothub_a (ohci); - val &= ~(RH_A_PSM | RH_A_OCPM); + /* Configure for per-port over-current protection by default */ + val &= ~RH_A_NOCP; + val |= RH_A_OCPM; if (ohci->flags & OHCI_QUIRK_SUPERIO) { - /* NSC 87560 and maybe others */ + /* NSC 87560 and maybe others. + * Ganged power switching, no over-current protection. + */ val |= RH_A_NOCP; - val &= ~(RH_A_POTPGT | RH_A_NPS); - ohci_writel (ohci, val, &ohci->regs->roothub.a); + val &= ~(RH_A_POTPGT | RH_A_NPS | RH_A_PSM | RH_A_OCPM); } else if ((ohci->flags & OHCI_QUIRK_AMD756) || (ohci->flags & OHCI_QUIRK_HUB_POWER)) { /* hub power always on; required for AMD-756 and some - * Mac platforms. ganged overcurrent reporting, if any. + * Mac platforms. */ val |= RH_A_NPS; - ohci_writel (ohci, val, &ohci->regs->roothub.a); } + ohci_writel(ohci, val, &ohci->regs->roothub.a); + ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status); ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM, &ohci->regs->roothub.b); diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 8c1bbac6d136..c32b544c043a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -16,8 +16,7 @@ #include <linux/export.h> #include <linux/acpi.h> #include <linux/dmi.h> - -#include <soc/bcm2835/raspberrypi-firmware.h> +#include <linux/of.h> #include "pci-quirks.h" #include "xhci-ext-caps.h" @@ -1247,7 +1246,8 @@ iounmap: static void quirk_usb_early_handoff(struct pci_dev *pdev) { - int ret; + struct device_node *parent; + bool is_rpi; /* Skip Netlogic mips SoC's internal PCI USB controller. * This device does not need/support EHCI/OHCI handoff @@ -1255,14 +1255,16 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev) if (pdev->vendor == 0x184e) /* vendor Netlogic */ return; + /* + * Bypass the Raspberry Pi 4 controller xHCI controller, things are + * taken care of by the board's co-processor. + */ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) { - ret = rpi_firmware_init_vl805(pdev); - if (ret) { - /* Firmware might be outdated, or something failed */ - dev_warn(&pdev->dev, - "Failed to load VL805's firmware: %d. Will continue to attempt to work, but bad things might happen. You should fix this...\n", - ret); - } + parent = of_get_parent(pdev->bus->dev.of_node); + is_rpi = of_device_is_compatible(parent, "brcm,bcm2711-pcie"); + of_node_put(parent); + if (is_rpi) + return; } if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI && diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index b8918f73a432..ae4e4ab638b5 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -288,14 +288,14 @@ static const struct tty_operations dbc_tty_ops = { .unthrottle = dbc_tty_unthrottle, }; -static void dbc_rx_push(unsigned long _port) +static void dbc_rx_push(struct tasklet_struct *t) { struct dbc_request *req; struct tty_struct *tty; unsigned long flags; bool do_push = false; bool disconnect = false; - struct dbc_port *port = (void *)_port; + struct dbc_port *port = from_tasklet(port, t, push); struct list_head *queue = &port->read_queue; spin_lock_irqsave(&port->port_lock, flags); @@ -382,7 +382,7 @@ xhci_dbc_tty_init_port(struct xhci_dbc *dbc, struct dbc_port *port) { tty_port_init(&port->port); spin_lock_init(&port->port_lock); - tasklet_init(&port->push, dbc_rx_push, (unsigned long)port); + tasklet_setup(&port->push, dbc_rx_push); INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queue); INIT_LIST_HEAD(&port->write_pool); diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index c88bffd68742..2c0fda57869e 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -451,9 +451,11 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci, if (!epriv) return; + epriv->show_ring = dev->eps[ep_index].ring; + snprintf(epriv->name, sizeof(epriv->name), "ep%02d", ep_index); epriv->root = xhci_debugfs_create_ring_dir(xhci, - &dev->eps[ep_index].ring, + &epriv->show_ring, epriv->name, spriv->root); spriv->eps[ep_index] = epriv; @@ -475,6 +477,111 @@ void xhci_debugfs_remove_endpoint(struct xhci_hcd *xhci, kfree(epriv); } +static int xhci_stream_id_show(struct seq_file *s, void *unused) +{ + struct xhci_ep_priv *epriv = s->private; + + if (!epriv->stream_info) + return -EPERM; + + seq_printf(s, "Show stream ID %d trb ring, supported [1 - %d]\n", + epriv->stream_id, epriv->stream_info->num_streams - 1); + + return 0; +} + +static int xhci_stream_id_open(struct inode *inode, struct file *file) +{ + return single_open(file, xhci_stream_id_show, inode->i_private); +} + +static ssize_t xhci_stream_id_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct xhci_ep_priv *epriv = s->private; + int ret; + u16 stream_id; /* MaxPStreams + 1 <= 16 */ + + if (!epriv->stream_info) + return -EPERM; + + /* Decimal number */ + ret = kstrtou16_from_user(ubuf, count, 10, &stream_id); + if (ret) + return ret; + + if (stream_id == 0 || stream_id >= epriv->stream_info->num_streams) + return -EINVAL; + + epriv->stream_id = stream_id; + epriv->show_ring = epriv->stream_info->stream_rings[stream_id]; + + return count; +} + +static const struct file_operations stream_id_fops = { + .open = xhci_stream_id_open, + .write = xhci_stream_id_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int xhci_stream_context_array_show(struct seq_file *s, void *unused) +{ + struct xhci_ep_priv *epriv = s->private; + struct xhci_stream_ctx *stream_ctx; + dma_addr_t dma; + int id; + + if (!epriv->stream_info) + return -EPERM; + + seq_printf(s, "Allocated %d streams and %d stream context array entries\n", + epriv->stream_info->num_streams, + epriv->stream_info->num_stream_ctxs); + + for (id = 0; id < epriv->stream_info->num_stream_ctxs; id++) { + stream_ctx = epriv->stream_info->stream_ctx_array + id; + dma = epriv->stream_info->ctx_array_dma + id * 16; + if (id < epriv->stream_info->num_streams) + seq_printf(s, "%pad stream id %d deq %016llx\n", &dma, + id, le64_to_cpu(stream_ctx->stream_ring)); + else + seq_printf(s, "%pad stream context entry not used deq %016llx\n", + &dma, le64_to_cpu(stream_ctx->stream_ring)); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(xhci_stream_context_array); + +void xhci_debugfs_create_stream_files(struct xhci_hcd *xhci, + struct xhci_virt_device *dev, + int ep_index) +{ + struct xhci_slot_priv *spriv = dev->debugfs_private; + struct xhci_ep_priv *epriv; + + if (!spriv || !spriv->eps[ep_index] || + !dev->eps[ep_index].stream_info) + return; + + epriv = spriv->eps[ep_index]; + epriv->stream_info = dev->eps[ep_index].stream_info; + + /* Show trb ring of stream ID 1 by default */ + epriv->stream_id = 1; + epriv->show_ring = epriv->stream_info->stream_rings[1]; + debugfs_create_file("stream_id", 0644, + epriv->root, epriv, + &stream_id_fops); + debugfs_create_file("stream_context_array", 0444, + epriv->root, epriv, + &xhci_stream_context_array_fops); +} + void xhci_debugfs_create_slot(struct xhci_hcd *xhci, int slot_id) { struct xhci_slot_priv *priv; diff --git a/drivers/usb/host/xhci-debugfs.h b/drivers/usb/host/xhci-debugfs.h index 56db635fcd6e..7c074b4be819 100644 --- a/drivers/usb/host/xhci-debugfs.h +++ b/drivers/usb/host/xhci-debugfs.h @@ -91,6 +91,9 @@ struct xhci_file_map { struct xhci_ep_priv { char name[DEBUGFS_NAMELEN]; struct dentry *root; + struct xhci_stream_info *stream_info; + struct xhci_ring *show_ring; + unsigned int stream_id; }; struct xhci_slot_priv { @@ -113,6 +116,9 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci, void xhci_debugfs_remove_endpoint(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, int ep_index); +void xhci_debugfs_create_stream_files(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, + int ep_index); #else static inline void xhci_debugfs_init(struct xhci_hcd *xhci) { } static inline void xhci_debugfs_exit(struct xhci_hcd *xhci) { } @@ -128,6 +134,10 @@ static inline void xhci_debugfs_remove_endpoint(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, int ep_index) { } +static inline void +xhci_debugfs_create_stream_files(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, + int ep_index) { } #endif /* CONFIG_DEBUG_FS */ #endif /* __LINUX_XHCI_DEBUGFS_H */ diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 4311d4c9b68d..8f321f39ab96 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -77,7 +77,7 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) { struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs; u32 value, check_val; - int u3_ports_disabed = 0; + int u3_ports_disabled = 0; int ret; int i; @@ -92,7 +92,7 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) /* power on and enable u3 ports except skipped ones */ for (i = 0; i < mtk->num_u3_ports; i++) { if ((0x1 << i) & mtk->u3p_dis_msk) { - u3_ports_disabed++; + u3_ports_disabled++; continue; } @@ -117,7 +117,7 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) check_val = STS1_SYSPLL_STABLE | STS1_REF_RST | STS1_SYS125_RST | STS1_XHCI_RST; - if (mtk->num_u3_ports > u3_ports_disabed) + if (mtk->num_u3_ports > u3_ports_disabled) check_val |= STS1_U3_MAC_RST; ret = readl_poll_timeout(&ippc->ip_pw_sts1, value, diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 3feaafebfe58..c26c06e5c88c 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/acpi.h> +#include <linux/reset.h> #include "xhci.h" #include "xhci-trace.h" @@ -346,6 +347,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) struct xhci_hcd *xhci; struct usb_hcd *hcd; struct xhci_driver_data *driver_data; + struct reset_control *reset; driver_data = (struct xhci_driver_data *)id->driver_data; if (driver_data && driver_data->quirks & XHCI_RENESAS_FW_QUIRK) { @@ -354,6 +356,11 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return retval; } + reset = devm_reset_control_get_optional_exclusive(&dev->dev, NULL); + if (IS_ERR(reset)) + return PTR_ERR(reset); + reset_control_reset(reset); + /* Prevent runtime suspending between USB-2 and USB-3 initialization */ pm_runtime_get_noresume(&dev->dev); @@ -371,6 +378,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* USB 2.0 roothub is stored in the PCI device now. */ hcd = dev_get_drvdata(&dev->dev); xhci = hcd_to_xhci(hcd); + xhci->reset = reset; xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev, pci_name(dev), hcd); if (!xhci->shared_hcd) { @@ -522,6 +530,8 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int retval = 0; + reset_control_reset(xhci->reset); + /* The BIOS on systems with the Intel Panther Point chipset may or may * not support xHCI natively. That means that during system resume, it * may switch the ports back to EHCI so that users can use their diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 3057cfc76d6a..aa2d35f98200 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -54,6 +54,16 @@ static int xhci_priv_init_quirk(struct usb_hcd *hcd) return priv->init_quirk(hcd); } +static int xhci_priv_suspend_quirk(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (!priv->suspend_quirk) + return 0; + + return priv->suspend_quirk(hcd); +} + static int xhci_priv_resume_quirk(struct usb_hcd *hcd) { struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); @@ -173,6 +183,8 @@ static int xhci_plat_probe(struct platform_device *pdev) struct usb_hcd *hcd; int ret; int irq; + struct xhci_plat_priv *priv = NULL; + if (usb_disabled()) return -ENODEV; @@ -264,16 +276,18 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) goto disable_reg_clk; - priv_match = of_device_get_match_data(&pdev->dev); - if (priv_match) { - struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + if (pdev->dev.of_node) + priv_match = of_device_get_match_data(&pdev->dev); + else + priv_match = dev_get_platdata(&pdev->dev); + if (priv_match) { + priv = hcd_to_xhci_priv(hcd); /* Just copy data for now */ - if (priv_match) - *priv = *priv_match; + *priv = *priv_match; } - device_wakeup_enable(hcd->self.controller); + device_set_wakeup_capable(&pdev->dev, true); xhci->main_hcd = hcd; xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, @@ -316,6 +330,9 @@ static int xhci_plat_probe(struct platform_device *pdev) hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); xhci->shared_hcd->tpl_support = hcd->tpl_support; + if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)) + hcd->skip_phy_initialization = 1; + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto disable_usb_phy; @@ -397,14 +414,14 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + ret = xhci_priv_suspend_quirk(hcd); + if (ret) + return ret; /* * xhci_suspend() needs `do_wakeup` to know whether host is allowed - * to do wakeup during suspend. Since xhci_plat_suspend is currently - * only designed for system suspend, device_may_wakeup() is enough - * to dertermine whether host is allowed to do wakeup. Need to - * reconsider this when xhci_plat_suspend enlarges its scope, e.g., - * also applies to runtime suspend. + * to do wakeup during suspend. */ return xhci_suspend(xhci, device_may_wakeup(dev)); } @@ -434,6 +451,11 @@ static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ret; + + ret = xhci_priv_suspend_quirk(hcd); + if (ret) + return ret; return xhci_suspend(xhci, true); } diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h index b49f6447bd3a..1fb149d1fbce 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -15,6 +15,7 @@ struct xhci_plat_priv { unsigned long long quirks; void (*plat_start)(struct usb_hcd *); int (*init_quirk)(struct usb_hcd *); + int (*suspend_quirk)(struct usb_hcd *); int (*resume_quirk)(struct usb_hcd *); }; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a741a38a4c69..167dae117f73 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3736,6 +3736,24 @@ static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci, return start_frame; } +/* Check if we should generate event interrupt for a TD in an isoc URB */ +static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i) +{ + if (xhci->hci_version < 0x100) + return false; + /* always generate an event interrupt for the last TD */ + if (i == num_tds - 1) + return false; + /* + * If AVOID_BEI is set the host handles full event rings poorly, + * generate an event at least every 8th TD to clear the event ring + */ + if (i && xhci->quirks & XHCI_AVOID_BEI) + return !!(i % 8); + + return true; +} + /* This is for isoc transfer */ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) @@ -3843,10 +3861,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, more_trbs_coming = false; td->last_trb = ep_ring->enqueue; field |= TRB_IOC; - /* set BEI, except for the last TD */ - if (xhci->hci_version >= 0x100 && - !(xhci->quirks & XHCI_AVOID_BEI) && - i < num_tds - 1) + if (trb_block_event_intr(xhci, num_tds, i)) field |= TRB_BEI; } /* Calculate TRB length */ diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 190923d8b246..934be1686352 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1866,7 +1866,6 @@ static const struct tegra_xusb_phy_type tegra124_phy_types[] = { static const unsigned int tegra124_xusb_context_ipfs[] = { IPFS_XUSB_HOST_MSI_BAR_SZ_0, - IPFS_XUSB_HOST_MSI_BAR_SZ_0, IPFS_XUSB_HOST_MSI_AXI_BAR_ST_0, IPFS_XUSB_HOST_MSI_FPCI_BAR_ST_0, IPFS_XUSB_HOST_MSI_VEC0_0, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f4cedcaee14b..482fe8c5e3b4 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -982,12 +982,15 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) xhci->shared_hcd->state != HC_STATE_SUSPENDED) return -EINVAL; - xhci_dbc_suspend(xhci); - /* Clear root port wake on bits if wakeup not allowed. */ if (!do_wakeup) xhci_disable_port_wake_on_bits(xhci); + if (!HCD_HW_ACCESSIBLE(hcd)) + return 0; + + xhci_dbc_suspend(xhci); + /* Don't poll the roothubs on bus suspend. */ xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); @@ -1915,8 +1918,6 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); trace_xhci_add_endpoint(ep_ctx); - xhci_debugfs_create_endpoint(xhci, virt_dev, ep_index); - xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n", (unsigned int) ep->desc.bEndpointAddress, udev->slot_id, @@ -2949,6 +2950,7 @@ static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) xhci_check_bw_drop_ep_streams(xhci, virt_dev, i); virt_dev->eps[i].ring = virt_dev->eps[i].new_ring; virt_dev->eps[i].new_ring = NULL; + xhci_debugfs_create_endpoint(xhci, virt_dev, i); } command_cleanup: kfree(command->completion); @@ -3531,6 +3533,7 @@ static int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, xhci_dbg(xhci, "Slot %u ep ctx %u now has streams.\n", udev->slot_id, ep_index); vdev->eps[ep_index].ep_state |= EP_HAS_STREAMS; + xhci_debugfs_create_stream_files(xhci, vdev, ep_index); } xhci_free_command(xhci, config_cmd); spin_unlock_irqrestore(&xhci->lock, flags); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ea1754f185a2..8be88379c0fb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1770,6 +1770,8 @@ struct xhci_hcd { /* optional clocks */ struct clk *clk; struct clk *reg_clk; + /* optional reset controller */ + struct reset_control *reset; /* data structures */ struct xhci_device_context_array *dcbaa; struct xhci_ring *cmd_ring; @@ -1874,6 +1876,7 @@ struct xhci_hcd { #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35) #define XHCI_RENESAS_FW_QUIRK BIT_ULL(36) +#define XHCI_SKIP_PHY_INIT BIT_ULL(37) unsigned int num_active_eps; unsigned int limit_active_eps; diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 360416680e82..59b02a539963 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -389,7 +389,7 @@ void mts_int_submit_urb (struct urb* transfer, res = usb_submit_urb( transfer, GFP_ATOMIC ); if ( unlikely(res) ) { MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res ); - context->srb->result = DID_ERROR << 16; + set_host_byte(context->srb, DID_ERROR); mts_transfer_cleanup(transfer); } } @@ -438,7 +438,7 @@ static void mts_data_done( struct urb* transfer ) scsi_set_resid(context->srb, context->data_length - transfer->actual_length); } else if ( unlikely(status) ) { - context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; + set_host_byte(context->srb, (status == -ENOENT ? DID_ABORT : DID_ERROR)); } mts_get_status(transfer); @@ -455,12 +455,12 @@ static void mts_command_done( struct urb *transfer ) if (status == -ENOENT) { /* We are being killed */ MTS_DEBUG_GOT_HERE(); - context->srb->result = DID_ABORT<<16; + set_host_byte(context->srb, DID_ABORT); } else { /* A genuine error has occurred */ MTS_DEBUG_GOT_HERE(); - context->srb->result = DID_ERROR<<16; + set_host_byte(context->srb, DID_ERROR); } mts_transfer_cleanup(transfer); @@ -495,7 +495,7 @@ static void mts_do_sg (struct urb* transfer) scsi_sg_count(context->srb)); if (unlikely(status)) { - context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; + set_host_byte(context->srb, (status == -ENOENT ? DID_ABORT : DID_ERROR)); mts_transfer_cleanup(transfer); } @@ -578,7 +578,7 @@ mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback MTS_DEBUG("this device doesn't exist\n"); - srb->result = DID_BAD_TARGET << 16; + set_host_byte(srb, DID_BAD_TARGET); if(likely(callback != NULL)) callback(srb); @@ -605,7 +605,7 @@ mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback if(unlikely(res)){ MTS_ERROR("error %d submitting URB\n",(int)res); - srb->result = DID_ERROR << 16; + set_host_byte(srb, DID_ERROR); if(likely(callback != NULL)) callback(srb); diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index a7eefe11f31a..45a387979935 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -209,6 +209,7 @@ static void adu_interrupt_out_callback(struct urb *urb) if (status != 0) { if ((status != -ENOENT) && + (status != -ESHUTDOWN) && (status != -ECONNRESET)) { dev_dbg(&dev->udev->dev, "%s :nonzero status received: %d\n", __func__, diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index f922544056de..c3583df4c324 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -308,15 +308,9 @@ static int tower_open(struct inode *inode, struct file *file) int subminor; int retval = 0; struct usb_interface *interface; - struct tower_reset_reply *reset_reply; + struct tower_reset_reply reset_reply; int result; - reset_reply = kmalloc(sizeof(*reset_reply), GFP_KERNEL); - if (!reset_reply) { - retval = -ENOMEM; - goto exit; - } - nonseekable_open(inode, file); subminor = iminor(inode); @@ -347,15 +341,11 @@ static int tower_open(struct inode *inode, struct file *file) } /* reset the tower */ - result = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - LEGO_USB_TOWER_REQUEST_RESET, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - reset_reply, - sizeof(*reset_reply), - 1000); + result = usb_control_msg_recv(dev->udev, 0, + LEGO_USB_TOWER_REQUEST_RESET, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, 0, + &reset_reply, sizeof(reset_reply), 1000); if (result < 0) { dev_err(&dev->udev->dev, "LEGO USB Tower reset control request failed\n"); @@ -394,7 +384,6 @@ unlock_exit: mutex_unlock(&dev->lock); exit: - kfree(reset_reply); return retval; } @@ -753,7 +742,7 @@ static int tower_probe(struct usb_interface *interface, const struct usb_device_ struct device *idev = &interface->dev; struct usb_device *udev = interface_to_usbdev(interface); struct lego_usb_tower *dev; - struct tower_get_version_reply *get_version_reply = NULL; + struct tower_get_version_reply get_version_reply; int retval = -ENOMEM; int result; @@ -798,34 +787,25 @@ static int tower_probe(struct usb_interface *interface, const struct usb_device_ dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; - get_version_reply = kmalloc(sizeof(*get_version_reply), GFP_KERNEL); - if (!get_version_reply) { - retval = -ENOMEM; - goto error; - } - /* get the firmware version and log it */ - result = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - LEGO_USB_TOWER_REQUEST_GET_VERSION, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - get_version_reply, - sizeof(*get_version_reply), - 1000); - if (result != sizeof(*get_version_reply)) { - if (result >= 0) - result = -EIO; + result = usb_control_msg_recv(udev, 0, + LEGO_USB_TOWER_REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + &get_version_reply, + sizeof(get_version_reply), + 1000); + if (!result) { dev_err(idev, "get version request failed: %d\n", result); retval = result; goto error; } dev_info(&interface->dev, "LEGO USB Tower firmware version is %d.%d build %d\n", - get_version_reply->major, - get_version_reply->minor, - le16_to_cpu(get_version_reply->build_no)); + get_version_reply.major, + get_version_reply.minor, + le16_to_cpu(get_version_reply.build_no)); /* we can register the device now, as it is ready */ usb_set_intfdata(interface, dev); @@ -844,11 +824,9 @@ static int tower_probe(struct usb_interface *interface, const struct usb_device_ USB_MAJOR, dev->minor); exit: - kfree(get_version_reply); return retval; error: - kfree(get_version_reply); tower_delete(dev); return retval; } diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index 116bd789e568..48099c6bf04c 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -322,8 +322,7 @@ static int usb3503_platform_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int usb3503_suspend(struct usb3503 *hub) +static int __maybe_unused usb3503_suspend(struct usb3503 *hub) { usb3503_switch_mode(hub, USB3503_MODE_STANDBY); clk_disable_unprepare(hub->clk); @@ -331,7 +330,7 @@ static int usb3503_suspend(struct usb3503 *hub) return 0; } -static int usb3503_resume(struct usb3503 *hub) +static int __maybe_unused usb3503_resume(struct usb3503 *hub) { clk_prepare_enable(hub->clk); usb3503_switch_mode(hub, hub->mode); @@ -339,30 +338,29 @@ static int usb3503_resume(struct usb3503 *hub) return 0; } -static int usb3503_i2c_suspend(struct device *dev) +static int __maybe_unused usb3503_i2c_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); return usb3503_suspend(i2c_get_clientdata(client)); } -static int usb3503_i2c_resume(struct device *dev) +static int __maybe_unused usb3503_i2c_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); return usb3503_resume(i2c_get_clientdata(client)); } -static int usb3503_platform_suspend(struct device *dev) +static int __maybe_unused usb3503_platform_suspend(struct device *dev) { return usb3503_suspend(dev_get_drvdata(dev)); } -static int usb3503_platform_resume(struct device *dev) +static int __maybe_unused usb3503_platform_resume(struct device *dev) { return usb3503_resume(dev_get_drvdata(dev)); } -#endif static SIMPLE_DEV_PM_OPS(usb3503_i2c_pm_ops, usb3503_i2c_suspend, usb3503_i2c_resume); @@ -388,7 +386,7 @@ MODULE_DEVICE_TABLE(of, usb3503_of_match); static struct i2c_driver usb3503_i2c_driver = { .driver = { .name = USB3503_I2C_NAME, - .pm = &usb3503_i2c_pm_ops, + .pm = pm_ptr(&usb3503_i2c_pm_ops), .of_match_table = of_match_ptr(usb3503_of_match), }, .probe = usb3503_i2c_probe, @@ -400,7 +398,7 @@ static struct platform_driver usb3503_platform_driver = { .driver = { .name = USB3503_I2C_NAME, .of_match_table = of_match_ptr(usb3503_of_match), - .pm = &usb3503_platform_pm_ops, + .pm = pm_ptr(&usb3503_platform_pm_ops), }, .probe = usb3503_platform_probe, .remove = usb3503_platform_remove, diff --git a/drivers/usb/misc/usb4604.c b/drivers/usb/misc/usb4604.c index 1b4de651e697..2142af9bbdec 100644 --- a/drivers/usb/misc/usb4604.c +++ b/drivers/usb/misc/usb4604.c @@ -112,8 +112,7 @@ static int usb4604_i2c_probe(struct i2c_client *i2c, return usb4604_probe(hub); } -#ifdef CONFIG_PM_SLEEP -static int usb4604_i2c_suspend(struct device *dev) +static int __maybe_unused usb4604_i2c_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct usb4604 *hub = i2c_get_clientdata(client); @@ -123,7 +122,7 @@ static int usb4604_i2c_suspend(struct device *dev) return 0; } -static int usb4604_i2c_resume(struct device *dev) +static int __maybe_unused usb4604_i2c_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct usb4604 *hub = i2c_get_clientdata(client); @@ -132,7 +131,6 @@ static int usb4604_i2c_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(usb4604_i2c_pm_ops, usb4604_i2c_suspend, usb4604_i2c_resume); @@ -154,7 +152,7 @@ MODULE_DEVICE_TABLE(of, usb4604_of_match); static struct i2c_driver usb4604_i2c_driver = { .driver = { .name = "usb4604", - .pm = &usb4604_i2c_pm_ops, + .pm = pm_ptr(&usb4604_i2c_pm_ops), .of_match_table = of_match_ptr(usb4604_of_match), }, .probe = usb4604_i2c_probe, diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 61e9e987fe4a..bb546f624a45 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -187,7 +187,6 @@ static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; default: return -ENOTTY; - break; } return 0; diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index b2e09883c7e2..e3165d79b5f6 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -96,15 +96,13 @@ static void yurex_delete(struct kref *kref) if (dev->cntl_urb) { usb_kill_urb(dev->cntl_urb); kfree(dev->cntl_req); - if (dev->cntl_buffer) - usb_free_coherent(dev->udev, YUREX_BUF_SIZE, + usb_free_coherent(dev->udev, YUREX_BUF_SIZE, dev->cntl_buffer, dev->cntl_urb->transfer_dma); usb_free_urb(dev->cntl_urb); } if (dev->urb) { usb_kill_urb(dev->urb); - if (dev->int_buffer) - usb_free_coherent(dev->udev, YUREX_BUF_SIZE, + usb_free_coherent(dev->udev, YUREX_BUF_SIZE, dev->int_buffer, dev->urb->transfer_dma); usb_free_urb(dev->urb); } diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 71f4f02c05c6..aef0a0bba25a 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -370,12 +370,6 @@ static inline struct mtu3 *gadget_to_mtu3(struct usb_gadget *g) return container_of(g, struct mtu3, g); } -static inline int is_first_entry(const struct list_head *list, - const struct list_head *head) -{ - return list_is_last(head, list); -} - static inline struct mtu3_request *to_mtu3_request(struct usb_request *req) { return req ? container_of(req, struct mtu3_request, request) : NULL; diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index aa4a3140394b..4c52ba96f17e 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -518,7 +518,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab, * 3. Enable AB regulators * 4. Enable USB phy * 5. Reset the musb controller - * 6. Switch the ULPI GPIO pins to fucntion mode + * 6. Switch the ULPI GPIO pins to function mode * 7. Enable the musb Peripheral5 clock * 8. Restore MUSB context */ diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 2ec4eeacebc7..5eed1078fac8 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -282,11 +282,12 @@ static void destroy_urbtracker(struct kref *kref) * port callback had to be deferred because the disconnect mutex could not be * obtained at the time. */ -static void send_deferred_urbs(unsigned long _mos_parport) +static void send_deferred_urbs(struct tasklet_struct *t) { int ret_val; unsigned long flags; - struct mos7715_parport *mos_parport = (void *)_mos_parport; + struct mos7715_parport *mos_parport = from_tasklet(mos_parport, t, + urb_tasklet); struct urbtracker *urbtrack, *tmp; struct list_head *cursor, *next; struct device *dev; @@ -716,8 +717,7 @@ static int mos7715_parport_init(struct usb_serial *serial) INIT_LIST_HEAD(&mos_parport->deferred_urbs); usb_set_serial_data(serial, mos_parport); /* hijack private pointer */ mos_parport->serial = serial; - tasklet_init(&mos_parport->urb_tasklet, send_deferred_urbs, - (unsigned long) mos_parport); + tasklet_setup(&mos_parport->urb_tasklet, send_deferred_urbs); init_completion(&mos_parport->syncmsg_compl); /* cycle parallel port reset bit */ diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 89f5e33a6e6d..3c76336e43bb 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -1383,7 +1383,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; isd200_srb_set_bufflen(srb, 0); } else { - usb_stor_dbg(us, " Not removeable media, just report okay\n"); + usb_stor_dbg(us, " Not removable media, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = 0; } diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index e5a971b83e3f..560efd1479ba 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -92,7 +92,7 @@ static int slave_alloc (struct scsi_device *sdev) static int slave_configure(struct scsi_device *sdev) { struct us_data *us = host_to_us(sdev->host); - struct device *dev = us->pusb_dev->bus->sysdev; + struct device *dev = sdev->host->dma_dev; /* * Many devices have trouble transferring more than 32KB at a time, diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 8183504e3abb..c8a577309e8f 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -279,17 +279,17 @@ static bool uas_evaluate_response_iu(struct response_iu *riu, struct scsi_cmnd * switch (response_code) { case RC_INCORRECT_LUN: - cmnd->result = DID_BAD_TARGET << 16; + set_host_byte(cmnd, DID_BAD_TARGET); break; case RC_TMF_SUCCEEDED: - cmnd->result = DID_OK << 16; + set_host_byte(cmnd, DID_OK); break; case RC_TMF_NOT_SUPPORTED: - cmnd->result = DID_TARGET_FAILURE << 16; + set_host_byte(cmnd, DID_TARGET_FAILURE); break; default: uas_log_cmd_state(cmnd, "response iu", response_code); - cmnd->result = DID_ERROR << 16; + set_host_byte(cmnd, DID_ERROR); break; } @@ -660,7 +660,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, spin_lock_irqsave(&devinfo->lock, flags); if (devinfo->resetting) { - cmnd->result = DID_ERROR << 16; + set_host_byte(cmnd, DID_ERROR); cmnd->scsi_done(cmnd); goto zombie; } @@ -704,7 +704,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, * of queueing, no matter how fatal the error */ if (err == -ENODEV) { - cmnd->result = DID_ERROR << 16; + set_host_byte(cmnd, DID_ERROR); cmnd->scsi_done(cmnd); goto zombie; } @@ -837,17 +837,24 @@ static int uas_slave_alloc(struct scsi_device *sdev) */ blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); - if (devinfo->flags & US_FL_MAX_SECTORS_64) - blk_queue_max_hw_sectors(sdev->request_queue, 64); - else if (devinfo->flags & US_FL_MAX_SECTORS_240) - blk_queue_max_hw_sectors(sdev->request_queue, 240); - return 0; } static int uas_slave_configure(struct scsi_device *sdev) { struct uas_dev_info *devinfo = sdev->hostdata; + struct device *dev = sdev->host->dma_dev; + + if (devinfo->flags & US_FL_MAX_SECTORS_64) + blk_queue_max_hw_sectors(sdev->request_queue, 64); + else if (devinfo->flags & US_FL_MAX_SECTORS_240) + blk_queue_max_hw_sectors(sdev->request_queue, 240); + else if (devinfo->udev->speed >= USB_SPEED_SUPER) + blk_queue_max_hw_sectors(sdev->request_queue, 2048); + + blk_queue_max_hw_sectors(sdev->request_queue, + min_t(size_t, queue_max_hw_sectors(sdev->request_queue), + dma_max_mapping_size(dev) >> SECTOR_SHIFT)); if (devinfo->flags & US_FL_NO_REPORT_OPCODES) sdev->no_report_opcodes = 1; @@ -1033,7 +1040,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) shost->can_queue = devinfo->qdepth - 2; usb_set_intfdata(intf, shost); - result = scsi_add_host(shost, &intf->dev); + result = scsi_add_host_with_dma(shost, &intf->dev, udev->bus->sysdev); if (result) goto free_streams; diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 94a64729dc27..c2ef367cf257 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1049,8 +1049,9 @@ int usb_stor_probe2(struct us_data *us) goto BadDevice; usb_autopm_get_interface_no_resume(us->pusb_intf); snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s", - dev_name(&us->pusb_intf->dev)); - result = scsi_add_host(us_to_host(us), dev); + dev_name(dev)); + result = scsi_add_host_with_dma(us_to_host(us), dev, + us->pusb_dev->bus->sysdev); if (result) { dev_warn(dev, "Unable to add the scsi host\n"); diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index a4dbd11f8ee2..edead555835e 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -11,6 +11,7 @@ config TYPEC_MUX_PI3USB30532 config TYPEC_MUX_INTEL_PMC tristate "Intel PMC mux control" + depends on ACPI depends on INTEL_SCU_IPC select USB_ROLE_SWITCH help diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c index 676b525c2a66..d7f63b74c6b1 100644 --- a/drivers/usb/typec/mux/intel_pmc_mux.c +++ b/drivers/usb/typec/mux/intel_pmc_mux.c @@ -80,10 +80,48 @@ enum { #define PMC_USB_DP_HPD_LVL BIT(4) #define PMC_USB_DP_HPD_IRQ BIT(5) +/* + * Input Output Manager (IOM) PORT STATUS + */ +#define IOM_PORT_STATUS_OFFSET 0x560 + +#define IOM_PORT_STATUS_ACTIVITY_TYPE_MASK GENMASK(9, 6) +#define IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT 6 +#define IOM_PORT_STATUS_ACTIVITY_TYPE_USB 0x03 +/* activity type: Safe Mode */ +#define IOM_PORT_STATUS_ACTIVITY_TYPE_SAFE_MODE 0x04 +/* activity type: Display Port */ +#define IOM_PORT_STATUS_ACTIVITY_TYPE_DP 0x05 +/* activity type: Display Port Multi Function Device */ +#define IOM_PORT_STATUS_ACTIVITY_TYPE_DP_MFD 0x06 +/* activity type: Thunderbolt */ +#define IOM_PORT_STATUS_ACTIVITY_TYPE_TBT 0x07 +#define IOM_PORT_STATUS_ACTIVITY_TYPE_ALT_MODE_USB 0x0c +#define IOM_PORT_STATUS_ACTIVITY_TYPE_ALT_MODE_TBT_USB 0x0d +/* Upstream Facing Port Information */ +#define IOM_PORT_STATUS_UFP BIT(10) +/* Display Port Hot Plug Detect status */ +#define IOM_PORT_STATUS_DHPD_HPD_STATUS_MASK GENMASK(13, 12) +#define IOM_PORT_STATUS_DHPD_HPD_STATUS_SHIFT 12 +#define IOM_PORT_STATUS_DHPD_HPD_STATUS_ASSERT 0x01 +#define IOM_PORT_STATUS_DHPD_HPD_SOURCE_TBT BIT(14) +#define IOM_PORT_STATUS_CONNECTED BIT(31) + +#define IOM_PORT_ACTIVITY_IS(_status_, _type_) \ + ((((_status_) & IOM_PORT_STATUS_ACTIVITY_TYPE_MASK) >> \ + IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT) == \ + (IOM_PORT_STATUS_ACTIVITY_TYPE_##_type_)) + +#define IOM_PORT_HPD_ASSERTED(_status_) \ + ((((_status_) & IOM_PORT_STATUS_DHPD_HPD_STATUS_MASK) >> \ + IOM_PORT_STATUS_DHPD_HPD_STATUS_SHIFT) & \ + IOM_PORT_STATUS_DHPD_HPD_STATUS_ASSERT) + struct pmc_usb; struct pmc_usb_port { int num; + u32 iom_status; struct pmc_usb *pmc; struct typec_mux *typec_mux; struct typec_switch *typec_sw; @@ -104,8 +142,21 @@ struct pmc_usb { struct device *dev; struct intel_scu_ipc_dev *ipc; struct pmc_usb_port *port; + struct acpi_device *iom_adev; + void __iomem *iom_base; }; +static void update_port_status(struct pmc_usb_port *port) +{ + u8 port_num; + + /* SoC expects the USB Type-C port numbers to start with 0 */ + port_num = port->usb3_port - 1; + + port->iom_status = readl(port->pmc->iom_base + IOM_PORT_STATUS_OFFSET + + port_num * sizeof(u32)); +} + static int sbu_orientation(struct pmc_usb_port *port) { if (port->sbu_orientation) @@ -148,18 +199,17 @@ static int pmc_usb_command(struct pmc_usb_port *port, u8 *msg, u32 len) } static int -pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_mux_state *state) +pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_displayport_data *dp) { - struct typec_displayport_data *data = state->data; u8 msg[2] = { }; msg[0] = PMC_USB_DP_HPD; msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; - if (data->status & DP_STATUS_IRQ_HPD) + if (dp->status & DP_STATUS_IRQ_HPD) msg[1] = PMC_USB_DP_HPD_IRQ; - if (data->status & DP_STATUS_HPD_STATE) + if (dp->status & DP_STATUS_HPD_STATE) msg[1] |= PMC_USB_DP_HPD_LVL; return pmc_usb_command(port, msg, sizeof(msg)); @@ -172,8 +222,15 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state) struct altmode_req req = { }; int ret; - if (data->status & DP_STATUS_IRQ_HPD) - return pmc_usb_mux_dp_hpd(port, state); + if (IOM_PORT_ACTIVITY_IS(port->iom_status, DP) || + IOM_PORT_ACTIVITY_IS(port->iom_status, DP_MFD)) { + if (IOM_PORT_HPD_ASSERTED(port->iom_status) && + (!(data->status & DP_STATUS_IRQ_HPD) && + data->status & DP_STATUS_HPD_STATE)) + return 0; + + return pmc_usb_mux_dp_hpd(port, state->data); + } req.usage = PMC_USB_ALT_MODE; req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; @@ -189,8 +246,8 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state) if (ret) return ret; - if (data->status & DP_STATUS_HPD_STATE) - return pmc_usb_mux_dp_hpd(port, state); + if (data->status & (DP_STATUS_IRQ_HPD | DP_STATUS_HPD_STATE)) + return pmc_usb_mux_dp_hpd(port, state->data); return 0; } @@ -202,6 +259,10 @@ pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state) u8 cable_speed = TBT_CABLE_SPEED(data->cable_mode); struct altmode_req req = { }; + if (IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) || + IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB)) + return 0; + req.usage = PMC_USB_ALT_MODE; req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; req.mode_type = PMC_USB_MODE_TYPE_TBT << PMC_USB_MODE_TYPE_SHIFT; @@ -233,6 +294,10 @@ pmc_usb_mux_usb4(struct pmc_usb_port *port, struct typec_mux_state *state) struct altmode_req req = { }; u8 cable_speed; + if (IOM_PORT_ACTIVITY_IS(port->iom_status, TBT) || + IOM_PORT_ACTIVITY_IS(port->iom_status, ALT_MODE_TBT_USB)) + return 0; + req.usage = PMC_USB_ALT_MODE; req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; req.mode_type = PMC_USB_MODE_TYPE_TBT << PMC_USB_MODE_TYPE_SHIFT; @@ -267,34 +332,61 @@ static int pmc_usb_mux_safe_state(struct pmc_usb_port *port) { u8 msg; + if (IOM_PORT_ACTIVITY_IS(port->iom_status, SAFE_MODE)) + return 0; + msg = PMC_USB_SAFE_MODE; msg |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; return pmc_usb_command(port, &msg, sizeof(msg)); } -static int pmc_usb_connect(struct pmc_usb_port *port) +static int pmc_usb_disconnect(struct pmc_usb_port *port) { + struct typec_displayport_data data = { }; u8 msg[2]; - msg[0] = PMC_USB_CONNECT; + if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED)) + return 0; + + /* Clear DisplayPort HPD if it's still asserted. */ + if (IOM_PORT_HPD_ASSERTED(port->iom_status)) + pmc_usb_mux_dp_hpd(port, &data); + + msg[0] = PMC_USB_DISCONNECT; msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT; - msg[1] |= hsl_orientation(port) << PMC_USB_MSG_ORI_HSL_SHIFT; - msg[1] |= sbu_orientation(port) << PMC_USB_MSG_ORI_AUX_SHIFT; return pmc_usb_command(port, msg, sizeof(msg)); } -static int pmc_usb_disconnect(struct pmc_usb_port *port) +static int pmc_usb_connect(struct pmc_usb_port *port, enum usb_role role) { + u8 ufp = role == USB_ROLE_DEVICE ? 1 : 0; u8 msg[2]; + int ret; - msg[0] = PMC_USB_DISCONNECT; + if (port->orientation == TYPEC_ORIENTATION_NONE) + return -EINVAL; + + if (port->iom_status & IOM_PORT_STATUS_CONNECTED) { + if (port->role == role || port->role == USB_ROLE_NONE) + return 0; + + /* Role swap */ + ret = pmc_usb_disconnect(port); + if (ret) + return ret; + } + + msg[0] = PMC_USB_CONNECT; msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT; + msg[1] |= ufp << PMC_USB_MSG_UFP_SHIFT; + msg[1] |= hsl_orientation(port) << PMC_USB_MSG_ORI_HSL_SHIFT; + msg[1] |= sbu_orientation(port) << PMC_USB_MSG_ORI_AUX_SHIFT; return pmc_usb_command(port, msg, sizeof(msg)); } @@ -304,13 +396,15 @@ pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state) { struct pmc_usb_port *port = typec_mux_get_drvdata(mux); + update_port_status(port); + if (port->orientation == TYPEC_ORIENTATION_NONE || port->role == USB_ROLE_NONE) return 0; if (state->mode == TYPEC_STATE_SAFE) return pmc_usb_mux_safe_state(port); if (state->mode == TYPEC_STATE_USB) - return pmc_usb_connect(port); + return pmc_usb_connect(port, port->role); if (state->alt) { switch (state->alt->svid) { @@ -325,7 +419,7 @@ pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state) /* REVISIT: Try with usb3_port set to 0? */ break; case TYPEC_MODE_USB3: - return pmc_usb_connect(port); + return pmc_usb_connect(port, port->role); case TYPEC_MODE_USB4: return pmc_usb_mux_usb4(port, state); } @@ -339,38 +433,28 @@ static int pmc_usb_set_orientation(struct typec_switch *sw, { struct pmc_usb_port *port = typec_switch_get_drvdata(sw); - if (port->orientation == orientation) - return 0; + update_port_status(port); port->orientation = orientation; - if (port->role) { - if (orientation == TYPEC_ORIENTATION_NONE) - return pmc_usb_disconnect(port); - else - return pmc_usb_connect(port); - } - return 0; } static int pmc_usb_set_role(struct usb_role_switch *sw, enum usb_role role) { struct pmc_usb_port *port = usb_role_switch_get_drvdata(sw); + int ret; - if (port->role == role) - return 0; + update_port_status(port); - port->role = role; + if (role == USB_ROLE_NONE) + ret = pmc_usb_disconnect(port); + else + ret = pmc_usb_connect(port, role); - if (port->orientation) { - if (role == USB_ROLE_NONE) - return pmc_usb_disconnect(port); - else - return pmc_usb_connect(port); - } + port->role = role; - return 0; + return ret; } static int pmc_usb_register_port(struct pmc_usb *pmc, int index, @@ -444,6 +528,45 @@ err_unregister_switch: return ret; } +static int is_memory(struct acpi_resource *res, void *data) +{ + struct resource r; + + return !acpi_dev_resource_memory(res, &r); +} + +static int pmc_usb_probe_iom(struct pmc_usb *pmc) +{ + struct list_head resource_list; + struct resource_entry *rentry; + struct acpi_device *adev; + int ret; + + adev = acpi_dev_get_first_match_dev("INTC1072", NULL, -1); + if (!adev) + return -ENODEV; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, is_memory, NULL); + if (ret < 0) + return ret; + + rentry = list_first_entry_or_null(&resource_list, struct resource_entry, node); + if (rentry) + pmc->iom_base = devm_ioremap_resource(pmc->dev, rentry->res); + + acpi_dev_free_resource_list(&resource_list); + + if (!pmc->iom_base) { + put_device(&adev->dev); + return -ENOMEM; + } + + pmc->iom_adev = adev; + + return 0; +} + static int pmc_usb_probe(struct platform_device *pdev) { struct fwnode_handle *fwnode = NULL; @@ -458,6 +581,12 @@ static int pmc_usb_probe(struct platform_device *pdev) device_for_each_child_node(&pdev->dev, fwnode) pmc->num_ports++; + /* The IOM microcontroller has a limitation of max 4 ports. */ + if (pmc->num_ports > 4) { + dev_err(&pdev->dev, "driver limited to 4 ports\n"); + return -ERANGE; + } + pmc->port = devm_kcalloc(&pdev->dev, pmc->num_ports, sizeof(struct pmc_usb_port), GFP_KERNEL); if (!pmc->port) @@ -469,6 +598,10 @@ static int pmc_usb_probe(struct platform_device *pdev) pmc->dev = &pdev->dev; + ret = pmc_usb_probe_iom(pmc); + if (ret) + return ret; + /* * For every physical USB connector (USB2 and USB3 combo) there is a * child ACPI device node under the PMC mux ACPI device object. @@ -494,6 +627,8 @@ err_remove_ports: usb_role_switch_unregister(pmc->port[i].usb_sw); } + put_device(&pmc->iom_adev->dev); + return ret; } @@ -508,6 +643,8 @@ static int pmc_usb_remove(struct platform_device *pdev) usb_role_switch_unregister(pmc->port[i].usb_sw); } + put_device(&pmc->iom_adev->dev); + return 0; } diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index fa3f39336246..58a64e1bf627 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -27,6 +27,14 @@ config TYPEC_RT1711H Type-C Port Controller Manager to provide USB PD and USB Type-C functionalities. +config TYPEC_MT6360 + tristate "Mediatek MT6360 Type-C driver" + depends on MFD_MT6360 + help + Mediatek MT6360 is a multi-functional IC that includes + USB Type-C. It works with Type-C Port Controller Manager + to provide USB PD and USB Type-C functionalities. + endif # TYPEC_TCPCI config TYPEC_FUSB302 diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile index a5ff6c8eb892..7592ccb8c526 100644 --- a/drivers/usb/typec/tcpm/Makefile +++ b/drivers/usb/typec/tcpm/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o typec_wcove-y := wcove.o obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o +obj-$(CONFIG_TYPEC_MT6360) += tcpci_mt6360.o diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index bd80e03b2b6f..7d9491ba62fb 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -191,12 +191,47 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc, struct tcpci *tcpci = tcpc_to_tcpci(tcpc); unsigned int reg; int ret; + enum typec_cc_status cc1, cc2; - /* Keep the disconnect cc line open */ + /* Obtain Rp setting from role control */ ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, ®); if (ret < 0) return ret; + ret = tcpci_get_cc(tcpc, &cc1, &cc2); + if (ret < 0) + return ret; + + /* + * When port has drp toggling enabled, ROLE_CONTROL would only have the initial + * terminations for the toggling and does not indicate the final cc + * terminations when ConnectionResult is 0 i.e. drp toggling stops and + * the connection is resolbed. Infer port role from TCPC_CC_STATUS based on the + * terminations seen. The port role is then used to set the cc terminations. + */ + if (reg & TCPC_ROLE_CTRL_DRP) { + /* Disable DRP for the OPEN setting to take effect */ + reg = reg & ~TCPC_ROLE_CTRL_DRP; + + if (polarity == TYPEC_POLARITY_CC2) { + reg &= ~(TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT); + /* Local port is source */ + if (cc2 == TYPEC_CC_RD) + /* Role control would have the Rp setting when DRP was enabled */ + reg |= TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT; + else + reg |= TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT; + } else { + reg &= ~(TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT); + /* Local port is source */ + if (cc1 == TYPEC_CC_RD) + /* Role control would have the Rp setting when DRP was enabled */ + reg |= TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT; + else + reg |= TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT; + } + } + if (polarity == TYPEC_POLARITY_CC2) reg |= TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT; else @@ -330,23 +365,47 @@ static int tcpci_pd_transmit(struct tcpc_dev *tcpc, int ret; cnt = msg ? pd_header_cnt(header) * 4 : 0; - ret = regmap_write(tcpci->regmap, TCPC_TX_BYTE_CNT, cnt + 2); - if (ret < 0) - return ret; + /** + * TCPCI spec forbids direct access of TCPC_TX_DATA. + * But, since some of the chipsets offer this capability, + * it's fair to support both. + */ + if (tcpci->data->TX_BUF_BYTE_x_hidden) { + u8 buf[TCPC_TRANSMIT_BUFFER_MAX_LEN] = {0,}; + u8 pos = 0; - ret = tcpci_write16(tcpci, TCPC_TX_HDR, header); - if (ret < 0) - return ret; + /* Payload + header + TCPC_TX_BYTE_CNT */ + buf[pos++] = cnt + 2; + + if (msg) + memcpy(&buf[pos], &msg->header, sizeof(msg->header)); + + pos += sizeof(header); + + if (cnt > 0) + memcpy(&buf[pos], msg->payload, cnt); + + pos += cnt; + ret = regmap_raw_write(tcpci->regmap, TCPC_TX_BYTE_CNT, buf, pos); + if (ret < 0) + return ret; + } else { + ret = regmap_write(tcpci->regmap, TCPC_TX_BYTE_CNT, cnt + 2); + if (ret < 0) + return ret; - if (cnt > 0) { - ret = regmap_raw_write(tcpci->regmap, TCPC_TX_DATA, - &msg->payload, cnt); + ret = tcpci_write16(tcpci, TCPC_TX_HDR, header); if (ret < 0) return ret; + + if (cnt > 0) { + ret = regmap_raw_write(tcpci->regmap, TCPC_TX_DATA, &msg->payload, cnt); + if (ret < 0) + return ret; + } } - reg = (PD_RETRY_COUNT << TCPC_TRANSMIT_RETRY_SHIFT) | - (type << TCPC_TRANSMIT_TYPE_SHIFT); + reg = (PD_RETRY_COUNT << TCPC_TRANSMIT_RETRY_SHIFT) | (type << TCPC_TRANSMIT_TYPE_SHIFT); ret = regmap_write(tcpci->regmap, TCPC_TRANSMIT, reg); if (ret < 0) return ret; diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h index 11c36d086c86..cf9d8b63adcb 100644 --- a/drivers/usb/typec/tcpm/tcpci.h +++ b/drivers/usb/typec/tcpm/tcpci.h @@ -16,6 +16,7 @@ #define TCPC_PD_INT_REV 0xa #define TCPC_ALERT 0x10 +#define TCPC_ALERT_EXTENDED_STATUS BIT(13) #define TCPC_ALERT_VBUS_DISCNCT BIT(11) #define TCPC_ALERT_RX_BUF_OVF BIT(10) #define TCPC_ALERT_FAULT BIT(9) @@ -32,6 +33,10 @@ #define TCPC_ALERT_MASK 0x12 #define TCPC_POWER_STATUS_MASK 0x14 #define TCPC_FAULT_STATUS_MASK 0x15 + +#define TCPC_EXTENDED_STATUS_MASK 0x16 +#define TCPC_EXTENDED_STATUS_MASK_VSAFE0V BIT(0) + #define TCPC_CONFIG_STD_OUTPUT 0x18 #define TCPC_TCPC_CTRL 0x19 @@ -123,9 +128,17 @@ #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76 #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78 +/* I2C_WRITE_BYTE_COUNT + 1 when TX_BUF_BYTE_x is only accessible I2C_WRITE_BYTE_COUNT */ +#define TCPC_TRANSMIT_BUFFER_MAX_LEN 31 + +/* + * @TX_BUF_BYTE_x_hidden + * optional; Set when TX_BUF_BYTE_x can only be accessed through I2C_WRITE_BYTE_COUNT. + */ struct tcpci; struct tcpci_data { struct regmap *regmap; + unsigned char TX_BUF_BYTE_x_hidden:1; int (*init)(struct tcpci *tcpci, struct tcpci_data *data); int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data, bool enable); diff --git a/drivers/usb/typec/tcpm/tcpci_mt6360.c b/drivers/usb/typec/tcpm/tcpci_mt6360.c new file mode 100644 index 000000000000..f1bd9e09bc87 --- /dev/null +++ b/drivers/usb/typec/tcpm/tcpci_mt6360.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 MediaTek Inc. + * + * Author: ChiYuan Huang <cy_huang@richtek.com> + */ + +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/usb/tcpm.h> + +#include "tcpci.h" + +#define MT6360_REG_VCONNCTRL1 0x8C +#define MT6360_REG_MODECTRL2 0x8F +#define MT6360_REG_SWRESET 0xA0 +#define MT6360_REG_DEBCTRL1 0xA1 +#define MT6360_REG_DRPCTRL1 0xA2 +#define MT6360_REG_DRPCTRL2 0xA3 +#define MT6360_REG_I2CTORST 0xBF +#define MT6360_REG_RXCTRL2 0xCF +#define MT6360_REG_CTDCTRL2 0xEC + +/* MT6360_REG_VCONNCTRL1 */ +#define MT6360_VCONNCL_ENABLE BIT(0) +/* MT6360_REG_RXCTRL2 */ +#define MT6360_OPEN40M_ENABLE BIT(7) +/* MT6360_REG_CTDCTRL2 */ +#define MT6360_RPONESHOT_ENABLE BIT(6) + +struct mt6360_tcpc_info { + struct tcpci_data tdata; + struct tcpci *tcpci; + struct device *dev; + int irq; +}; + +static inline int mt6360_tcpc_read16(struct regmap *regmap, + unsigned int reg, u16 *val) +{ + return regmap_raw_read(regmap, reg, val, sizeof(u16)); +} + +static inline int mt6360_tcpc_write16(struct regmap *regmap, + unsigned int reg, u16 val) +{ + return regmap_raw_write(regmap, reg, &val, sizeof(u16)); +} + +static int mt6360_tcpc_init(struct tcpci *tcpci, struct tcpci_data *tdata) +{ + struct regmap *regmap = tdata->regmap; + int ret; + + ret = regmap_write(regmap, MT6360_REG_SWRESET, 0x01); + if (ret) + return ret; + + /* after reset command, wait 1~2ms to wait IC action */ + usleep_range(1000, 2000); + + /* write all alert to masked */ + ret = mt6360_tcpc_write16(regmap, TCPC_ALERT_MASK, 0); + if (ret) + return ret; + + /* config I2C timeout reset enable , and timeout to 200ms */ + ret = regmap_write(regmap, MT6360_REG_I2CTORST, 0x8F); + if (ret) + return ret; + + /* config CC Detect Debounce : 26.7*val us */ + ret = regmap_write(regmap, MT6360_REG_DEBCTRL1, 0x10); + if (ret) + return ret; + + /* DRP Toggle Cycle : 51.2 + 6.4*val ms */ + ret = regmap_write(regmap, MT6360_REG_DRPCTRL1, 4); + if (ret) + return ret; + + /* DRP Duyt Ctrl : dcSRC: /1024 */ + ret = mt6360_tcpc_write16(regmap, MT6360_REG_DRPCTRL2, 330); + if (ret) + return ret; + + /* Enable VCONN Current Limit function */ + ret = regmap_update_bits(regmap, MT6360_REG_VCONNCTRL1, MT6360_VCONNCL_ENABLE, + MT6360_VCONNCL_ENABLE); + if (ret) + return ret; + + /* Enable cc open 40ms when pmic send vsysuv signal */ + ret = regmap_update_bits(regmap, MT6360_REG_RXCTRL2, MT6360_OPEN40M_ENABLE, + MT6360_OPEN40M_ENABLE); + if (ret) + return ret; + + /* Enable Rpdet oneshot detection */ + ret = regmap_update_bits(regmap, MT6360_REG_CTDCTRL2, MT6360_RPONESHOT_ENABLE, + MT6360_RPONESHOT_ENABLE); + if (ret) + return ret; + + /* Set shipping mode off, AUTOIDLE on */ + return regmap_write(regmap, MT6360_REG_MODECTRL2, 0x7A); +} + +static irqreturn_t mt6360_irq(int irq, void *dev_id) +{ + struct mt6360_tcpc_info *mti = dev_id; + + return tcpci_irq(mti->tcpci); +} + +static int mt6360_tcpc_probe(struct platform_device *pdev) +{ + struct mt6360_tcpc_info *mti; + int ret; + + mti = devm_kzalloc(&pdev->dev, sizeof(*mti), GFP_KERNEL); + if (!mti) + return -ENOMEM; + + mti->dev = &pdev->dev; + + mti->tdata.regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!mti->tdata.regmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + mti->irq = platform_get_irq_byname(pdev, "PD_IRQB"); + if (mti->irq < 0) + return mti->irq; + + mti->tdata.init = mt6360_tcpc_init; + mti->tcpci = tcpci_register_port(&pdev->dev, &mti->tdata); + if (IS_ERR(mti->tcpci)) { + dev_err(&pdev->dev, "Failed to register tcpci port\n"); + return PTR_ERR(mti->tcpci); + } + + ret = devm_request_threaded_irq(mti->dev, mti->irq, NULL, mt6360_irq, IRQF_ONESHOT, + dev_name(&pdev->dev), mti); + if (ret) { + dev_err(mti->dev, "Failed to register irq\n"); + tcpci_unregister_port(mti->tcpci); + return ret; + } + + device_init_wakeup(&pdev->dev, true); + platform_set_drvdata(pdev, mti); + + return 0; +} + +static int mt6360_tcpc_remove(struct platform_device *pdev) +{ + struct mt6360_tcpc_info *mti = platform_get_drvdata(pdev); + + disable_irq(mti->irq); + tcpci_unregister_port(mti->tcpci); + return 0; +} + +static int __maybe_unused mt6360_tcpc_suspend(struct device *dev) +{ + struct mt6360_tcpc_info *mti = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(mti->irq); + + return 0; +} + +static int __maybe_unused mt6360_tcpc_resume(struct device *dev) +{ + struct mt6360_tcpc_info *mti = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(mti->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(mt6360_tcpc_pm_ops, mt6360_tcpc_suspend, mt6360_tcpc_resume); + +static const struct of_device_id __maybe_unused mt6360_tcpc_of_id[] = { + { .compatible = "mediatek,mt6360-tcpc", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt6360_tcpc_of_id); + +static struct platform_driver mt6360_tcpc_driver = { + .driver = { + .name = "mt6360-tcpc", + .pm = &mt6360_tcpc_pm_ops, + .of_match_table = mt6360_tcpc_of_id, + }, + .probe = mt6360_tcpc_probe, + .remove = mt6360_tcpc_remove, +}; +module_platform_driver(mt6360_tcpc_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("MT6360 USB Type-C Port Controller Interface Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index a48e3f90d196..92806547f485 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -8,8 +8,10 @@ #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/device.h> +#include <linux/hrtimer.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kthread.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/power_supply.h> @@ -28,7 +30,8 @@ #include <linux/usb/role.h> #include <linux/usb/tcpm.h> #include <linux/usb/typec_altmode.h> -#include <linux/workqueue.h> + +#include <uapi/linux/sched/types.h> #define FOREACH_STATE(S) \ S(INVALID_STATE), \ @@ -203,7 +206,7 @@ struct tcpm_port { struct device *dev; struct mutex lock; /* tcpm state machine lock */ - struct workqueue_struct *wq; + struct kthread_worker *wq; struct typec_capability typec_caps; struct typec_port *typec_port; @@ -247,15 +250,17 @@ struct tcpm_port { enum tcpm_state prev_state; enum tcpm_state state; enum tcpm_state delayed_state; - unsigned long delayed_runtime; + ktime_t delayed_runtime; unsigned long delay_ms; spinlock_t pd_event_lock; u32 pd_events; - struct work_struct event_work; - struct delayed_work state_machine; - struct delayed_work vdm_state_machine; + struct kthread_work event_work; + struct hrtimer state_machine_timer; + struct kthread_work state_machine; + struct hrtimer vdm_state_machine_timer; + struct kthread_work vdm_state_machine; bool state_machine_running; struct completion tx_complete; @@ -340,7 +345,7 @@ struct tcpm_port { }; struct pd_rx_event { - struct work_struct work; + struct kthread_work work; struct tcpm_port *port; struct pd_message msg; }; @@ -914,6 +919,27 @@ static int tcpm_pd_send_sink_caps(struct tcpm_port *port) return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg); } +static void mod_tcpm_delayed_work(struct tcpm_port *port, unsigned int delay_ms) +{ + if (delay_ms) { + hrtimer_start(&port->state_machine_timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL); + } else { + hrtimer_cancel(&port->state_machine_timer); + kthread_queue_work(port->wq, &port->state_machine); + } +} + +static void mod_vdm_delayed_work(struct tcpm_port *port, unsigned int delay_ms) +{ + if (delay_ms) { + hrtimer_start(&port->vdm_state_machine_timer, ms_to_ktime(delay_ms), + HRTIMER_MODE_REL); + } else { + hrtimer_cancel(&port->vdm_state_machine_timer); + kthread_queue_work(port->wq, &port->vdm_state_machine); + } +} + static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state, unsigned int delay_ms) { @@ -922,9 +948,8 @@ static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state, tcpm_states[port->state], tcpm_states[state], delay_ms); port->delayed_state = state; - mod_delayed_work(port->wq, &port->state_machine, - msecs_to_jiffies(delay_ms)); - port->delayed_runtime = jiffies + msecs_to_jiffies(delay_ms); + mod_tcpm_delayed_work(port, delay_ms); + port->delayed_runtime = ktime_add(ktime_get(), ms_to_ktime(delay_ms)); port->delay_ms = delay_ms; } else { tcpm_log(port, "state change %s -> %s", @@ -939,7 +964,7 @@ static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state, * machine. */ if (!port->state_machine_running) - mod_delayed_work(port->wq, &port->state_machine, 0); + mod_tcpm_delayed_work(port, 0); } } @@ -960,7 +985,7 @@ static void tcpm_queue_message(struct tcpm_port *port, enum pd_msg_request message) { port->queued_message = message; - mod_delayed_work(port->wq, &port->state_machine, 0); + mod_tcpm_delayed_work(port, 0); } /* @@ -981,7 +1006,7 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header, port->vdm_retries = 0; port->vdm_state = VDM_STATE_READY; - mod_delayed_work(port->wq, &port->vdm_state_machine, 0); + mod_vdm_delayed_work(port, 0); } static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header, @@ -1244,8 +1269,7 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, port->vdm_state = VDM_STATE_WAIT_RSP_BUSY; port->vdo_retry = (p[0] & ~VDO_CMDT_MASK) | CMDT_INIT; - mod_delayed_work(port->wq, &port->vdm_state_machine, - msecs_to_jiffies(PD_T_VDM_BUSY)); + mod_vdm_delayed_work(port, PD_T_VDM_BUSY); return; } port->vdm_state = VDM_STATE_DONE; @@ -1390,8 +1414,7 @@ static void vdm_run_state_machine(struct tcpm_port *port) port->vdm_retries = 0; port->vdm_state = VDM_STATE_BUSY; timeout = vdm_ready_timeout(port->vdo_data[0]); - mod_delayed_work(port->wq, &port->vdm_state_machine, - timeout); + mod_vdm_delayed_work(port, timeout); } break; case VDM_STATE_WAIT_RSP_BUSY: @@ -1420,10 +1443,9 @@ static void vdm_run_state_machine(struct tcpm_port *port) } } -static void vdm_state_machine_work(struct work_struct *work) +static void vdm_state_machine_work(struct kthread_work *work) { - struct tcpm_port *port = container_of(work, struct tcpm_port, - vdm_state_machine.work); + struct tcpm_port *port = container_of(work, struct tcpm_port, vdm_state_machine); enum vdm_states prev_state; mutex_lock(&port->lock); @@ -1591,6 +1613,7 @@ static int tcpm_altmode_vdm(struct typec_altmode *altmode, struct tcpm_port *port = typec_altmode_get_drvdata(altmode); tcpm_queue_vdm_unlocked(port, header, data, count - 1); + return 0; } @@ -2005,7 +2028,7 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port, } } -static void tcpm_pd_rx_handler(struct work_struct *work) +static void tcpm_pd_rx_handler(struct kthread_work *work) { struct pd_rx_event *event = container_of(work, struct pd_rx_event, work); @@ -2067,10 +2090,10 @@ void tcpm_pd_receive(struct tcpm_port *port, const struct pd_message *msg) if (!event) return; - INIT_WORK(&event->work, tcpm_pd_rx_handler); + kthread_init_work(&event->work, tcpm_pd_rx_handler); event->port = port; memcpy(&event->msg, msg, sizeof(*msg)); - queue_work(port->wq, &event->work); + kthread_queue_work(port->wq, &event->work); } EXPORT_SYMBOL_GPL(tcpm_pd_receive); @@ -2123,9 +2146,9 @@ static bool tcpm_send_queued_message(struct tcpm_port *port) } while (port->queued_message != PD_MSG_NONE); if (port->delayed_state != INVALID_STATE) { - if (time_is_after_jiffies(port->delayed_runtime)) { - mod_delayed_work(port->wq, &port->state_machine, - port->delayed_runtime - jiffies); + if (ktime_after(port->delayed_runtime, ktime_get())) { + mod_tcpm_delayed_work(port, ktime_to_ms(ktime_sub(port->delayed_runtime, + ktime_get()))); return true; } port->delayed_state = INVALID_STATE; @@ -3258,10 +3281,9 @@ static void run_state_machine(struct tcpm_port *port) case SNK_DISCOVERY_DEBOUNCE_DONE: if (!tcpm_port_is_disconnected(port) && tcpm_port_is_sink(port) && - time_is_after_jiffies(port->delayed_runtime)) { + ktime_after(port->delayed_runtime, ktime_get())) { tcpm_set_state(port, SNK_DISCOVERY, - jiffies_to_msecs(port->delayed_runtime - - jiffies)); + ktime_to_ms(ktime_sub(port->delayed_runtime, ktime_get()))); break; } tcpm_set_state(port, unattached_state(port), 0); @@ -3573,7 +3595,7 @@ static void run_state_machine(struct tcpm_port *port) */ tcpm_set_pwr_role(port, TYPEC_SOURCE); tcpm_pd_send_control(port, PD_CTRL_PS_RDY); - tcpm_set_state(port, SRC_STARTUP, 0); + tcpm_set_state(port, SRC_STARTUP, PD_T_SWAP_SRC_START); break; case VCONN_SWAP_ACCEPT: @@ -3674,10 +3696,9 @@ static void run_state_machine(struct tcpm_port *port) } } -static void tcpm_state_machine_work(struct work_struct *work) +static void tcpm_state_machine_work(struct kthread_work *work) { - struct tcpm_port *port = container_of(work, struct tcpm_port, - state_machine.work); + struct tcpm_port *port = container_of(work, struct tcpm_port, state_machine); enum tcpm_state prev_state; mutex_lock(&port->lock); @@ -4041,7 +4062,7 @@ static void _tcpm_pd_hard_reset(struct tcpm_port *port) 0); } -static void tcpm_pd_event_handler(struct work_struct *work) +static void tcpm_pd_event_handler(struct kthread_work *work) { struct tcpm_port *port = container_of(work, struct tcpm_port, event_work); @@ -4082,7 +4103,7 @@ void tcpm_cc_change(struct tcpm_port *port) spin_lock(&port->pd_event_lock); port->pd_events |= TCPM_CC_EVENT; spin_unlock(&port->pd_event_lock); - queue_work(port->wq, &port->event_work); + kthread_queue_work(port->wq, &port->event_work); } EXPORT_SYMBOL_GPL(tcpm_cc_change); @@ -4091,7 +4112,7 @@ void tcpm_vbus_change(struct tcpm_port *port) spin_lock(&port->pd_event_lock); port->pd_events |= TCPM_VBUS_EVENT; spin_unlock(&port->pd_event_lock); - queue_work(port->wq, &port->event_work); + kthread_queue_work(port->wq, &port->event_work); } EXPORT_SYMBOL_GPL(tcpm_vbus_change); @@ -4100,7 +4121,7 @@ void tcpm_pd_hard_reset(struct tcpm_port *port) spin_lock(&port->pd_event_lock); port->pd_events = TCPM_RESET_EVENT; spin_unlock(&port->pd_event_lock); - queue_work(port->wq, &port->event_work); + kthread_queue_work(port->wq, &port->event_work); } EXPORT_SYMBOL_GPL(tcpm_pd_hard_reset); @@ -4808,6 +4829,22 @@ static int devm_tcpm_psy_register(struct tcpm_port *port) return PTR_ERR_OR_ZERO(port->psy); } +static enum hrtimer_restart state_machine_timer_handler(struct hrtimer *timer) +{ + struct tcpm_port *port = container_of(timer, struct tcpm_port, state_machine_timer); + + kthread_queue_work(port->wq, &port->state_machine); + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart vdm_state_machine_timer_handler(struct hrtimer *timer) +{ + struct tcpm_port *port = container_of(timer, struct tcpm_port, vdm_state_machine_timer); + + kthread_queue_work(port->wq, &port->vdm_state_machine); + return HRTIMER_NORESTART; +} + struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) { struct tcpm_port *port; @@ -4829,12 +4866,18 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) mutex_init(&port->lock); mutex_init(&port->swap_lock); - port->wq = create_singlethread_workqueue(dev_name(dev)); - if (!port->wq) - return ERR_PTR(-ENOMEM); - INIT_DELAYED_WORK(&port->state_machine, tcpm_state_machine_work); - INIT_DELAYED_WORK(&port->vdm_state_machine, vdm_state_machine_work); - INIT_WORK(&port->event_work, tcpm_pd_event_handler); + port->wq = kthread_create_worker(0, dev_name(dev)); + if (IS_ERR(port->wq)) + return ERR_CAST(port->wq); + sched_set_fifo(port->wq->task); + + kthread_init_work(&port->state_machine, tcpm_state_machine_work); + kthread_init_work(&port->vdm_state_machine, vdm_state_machine_work); + kthread_init_work(&port->event_work, tcpm_pd_event_handler); + hrtimer_init(&port->state_machine_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + port->state_machine_timer.function = state_machine_timer_handler; + hrtimer_init(&port->vdm_state_machine_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + port->vdm_state_machine_timer.function = vdm_state_machine_timer_handler; spin_lock_init(&port->pd_event_lock); @@ -4886,7 +4929,7 @@ out_role_sw_put: usb_role_switch_put(port->role_sw); out_destroy_wq: tcpm_debugfs_exit(port); - destroy_workqueue(port->wq); + kthread_destroy_worker(port->wq); return ERR_PTR(err); } EXPORT_SYMBOL_GPL(tcpm_register_port); @@ -4901,7 +4944,7 @@ void tcpm_unregister_port(struct tcpm_port *port) typec_unregister_port(port->typec_port); usb_role_switch_put(port->role_sw); tcpm_debugfs_exit(port); - destroy_workqueue(port->wq); + kthread_destroy_worker(port->wq); } EXPORT_SYMBOL_GPL(tcpm_unregister_port); diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c index e4b96674c405..4ce6c6a45eb1 100644 --- a/drivers/usb/usbip/usbip_common.c +++ b/drivers/usb/usbip/usbip_common.c @@ -755,13 +755,7 @@ EXPORT_SYMBOL_GPL(usbip_recv_xbuff); static int __init usbip_core_init(void) { - int ret; - - ret = usbip_init_eh(); - if (ret) - return ret; - - return 0; + return usbip_init_eh(); } static void __exit usbip_core_exit(void) diff --git a/include/dt-bindings/reset/raspberrypi,firmware-reset.h b/include/dt-bindings/reset/raspberrypi,firmware-reset.h new file mode 100644 index 000000000000..1a4f4c792723 --- /dev/null +++ b/include/dt-bindings/reset/raspberrypi,firmware-reset.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Nicolas Saenz Julienne + * Author: Nicolas Saenz Julienne <nsaenzjulienne@suse.com> + */ + +#ifndef _DT_BINDINGS_RASPBERRYPI_FIRMWARE_RESET_H +#define _DT_BINDINGS_RASPBERRYPI_FIRMWARE_RESET_H + +#define RASPBERRYPI_FIRMWARE_RESET_ID_USB 0 +#define RASPBERRYPI_FIRMWARE_RESET_NUM_IDS 1 + +#endif diff --git a/include/linux/usb.h b/include/linux/usb.h index 20c555db4621..a5460f08126e 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1764,6 +1764,7 @@ static inline int usb_urb_dir_out(struct urb *urb) return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT; } +int usb_pipe_type_check(struct usb_device *dev, unsigned int pipe); int usb_urb_ep_type_check(const struct urb *urb); void *usb_alloc_coherent(struct usb_device *dev, size_t size, @@ -1801,6 +1802,12 @@ extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, int timeout); /* wrappers around usb_control_msg() for the most common standard requests */ +int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request, + __u8 requesttype, __u16 value, __u16 index, + const void *data, __u16 size, int timeout); +int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request, + __u8 requesttype, __u16 value, __u16 index, + void *data, __u16 size, int timeout); extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned char descindex, void *buf, int size); extern int usb_get_status(struct usb_device *dev, diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h index b6c233e79bd4..f842e4589bd2 100644 --- a/include/linux/usb/pd.h +++ b/include/linux/usb/pd.h @@ -471,8 +471,10 @@ static inline unsigned int rdo_max_power(u32 rdo) #define PD_T_VCONN_SOURCE_ON 100 #define PD_T_SINK_REQUEST 100 /* 100 ms minimum */ #define PD_T_ERROR_RECOVERY 100 /* minimum 25 is insufficient */ -#define PD_T_SRCSWAPSTDBY 625 /* Maximum of 650ms */ -#define PD_T_NEWSRC 250 /* Maximum of 275ms */ +#define PD_T_SRCSWAPSTDBY 625 /* Maximum of 650ms */ +#define PD_T_NEWSRC 250 /* Maximum of 275ms */ +#define PD_T_SWAP_SRC_START 20 /* Minimum of 20ms */ +#define PD_T_BIST_CONT_MODE 50 /* 30 - 60 ms */ #define PD_T_DRP_TRY 100 /* 75 - 150 ms */ #define PD_T_DRP_TRYWAIT 600 /* 400 - 800 ms */ @@ -483,5 +485,4 @@ static inline unsigned int rdo_max_power(u32 rdo) #define PD_N_CAPS_COUNT (PD_T_NO_RESPONSE / PD_T_SEND_SOURCE_CAP) #define PD_N_HARD_RESET_COUNT 2 -#define PD_T_BIST_CONT_MODE 50 /* 30 - 60 ms */ #endif /* __LINUX_USB_PD_H */ diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index 3025aca3c358..cc9cdbc66403 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -10,7 +10,6 @@ #include <linux/of_device.h> struct rpi_firmware; -struct pci_dev; enum rpi_firmware_property_status { RPI_FIRMWARE_STATUS_REQUEST = 0, @@ -142,7 +141,6 @@ int rpi_firmware_property(struct rpi_firmware *fw, int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); -int rpi_firmware_init_vl805(struct pci_dev *pdev); #else static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len) @@ -160,11 +158,6 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware { return NULL; } - -static inline int rpi_firmware_init_vl805(struct pci_dev *pdev) -{ - return 0; -} #endif #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 69137c14d0dc..5b8994070c96 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -158,29 +158,17 @@ static int usb6fire_fw_ihex_init(const struct firmware *fw, static int usb6fire_fw_ezusb_write(struct usb_device *device, int type, int value, char *data, int len) { - int ret; - - ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), type, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, 0, data, len, HZ); - if (ret < 0) - return ret; - else if (ret != len) - return -EIO; - return 0; + return usb_control_msg_send(device, 0, type, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, 0, data, len, HZ); } static int usb6fire_fw_ezusb_read(struct usb_device *device, int type, int value, char *data, int len) { - int ret = usb_control_msg(device, usb_rcvctrlpipe(device, 0), type, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, - 0, data, len, HZ); - if (ret < 0) - return ret; - else if (ret != len) - return -EIO; - return 0; + return usb_control_msg_recv(device, 0, type, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, 0, data, len, HZ); } static int usb6fire_fw_fpga_write(struct usb_device *device, @@ -230,7 +218,7 @@ static int usb6fire_fw_ezusb_upload( /* upload firmware image */ data = 0x01; /* stop ezusb cpu */ ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1); - if (ret < 0) { + if (ret) { kfree(rec); release_firmware(fw); dev_err(&intf->dev, @@ -242,7 +230,7 @@ static int usb6fire_fw_ezusb_upload( while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */ ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address, rec->data, rec->len); - if (ret < 0) { + if (ret) { kfree(rec); release_firmware(fw); dev_err(&intf->dev, @@ -257,7 +245,7 @@ static int usb6fire_fw_ezusb_upload( if (postdata) { /* write data after firmware has been uploaded */ ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr, postdata, postlen); - if (ret < 0) { + if (ret) { dev_err(&intf->dev, "unable to upload ezusb firmware %s: post urb.\n", fwname); @@ -267,7 +255,7 @@ static int usb6fire_fw_ezusb_upload( data = 0x00; /* resume ezusb cpu */ ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1); - if (ret < 0) { + if (ret) { dev_err(&intf->dev, "unable to upload ezusb firmware %s: end message.\n", fwname); @@ -302,7 +290,7 @@ static int usb6fire_fw_fpga_upload( end = fw->data + fw->size; ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0); - if (ret < 0) { + if (ret) { kfree(buffer); release_firmware(fw); dev_err(&intf->dev, @@ -327,7 +315,7 @@ static int usb6fire_fw_fpga_upload( kfree(buffer); ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0); - if (ret < 0) { + if (ret) { dev_err(&intf->dev, "unable to upload fpga firmware: end urb.\n"); return ret; @@ -363,7 +351,7 @@ int usb6fire_fw_init(struct usb_interface *intf) u8 buffer[12]; ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8); - if (ret < 0) { + if (ret) { dev_err(&intf->dev, "unable to receive device firmware state.\n"); return ret; diff --git a/sound/usb/helper.c b/sound/usb/helper.c index 4c12cc5b53fd..cf92d7110773 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c @@ -63,20 +63,6 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype return NULL; } -/* check the validity of pipe and EP types */ -int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe) -{ - static const int pipetypes[4] = { - PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT - }; - struct usb_host_endpoint *ep; - - ep = usb_pipe_endpoint(dev, pipe); - if (!ep || usb_pipetype(pipe) != pipetypes[usb_endpoint_type(&ep->desc)]) - return -EINVAL; - return 0; -} - /* * Wrapper for usb_control_msg(). * Allocates a temp buffer to prevent dmaing from/to the stack. @@ -89,7 +75,7 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, void *buf = NULL; int timeout; - if (snd_usb_pipe_sanity_check(dev, pipe)) + if (usb_pipe_type_check(dev, pipe)) return -EINVAL; if (size > 0) { diff --git a/sound/usb/helper.h b/sound/usb/helper.h index 5e8a18b4e7b9..f5b4c6647e4d 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h @@ -7,7 +7,6 @@ unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size); void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype); void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype); -int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe); int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size); diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index a148caa5f48e..f9c924e3964e 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -156,16 +156,14 @@ static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate) * This control message doesn't have any ack from the * other side */ - ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), - HIFACE_SET_RATE_REQUEST, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - rate_value, 0, NULL, 0, 100); - if (ret < 0) { + ret = usb_control_msg_send(device, 0, + HIFACE_SET_RATE_REQUEST, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + rate_value, 0, NULL, 0, 100); + if (ret) dev_err(&device->dev, "Error setting samplerate %d.\n", rate); - return ret; - } - return 0; + return ret; } static struct pcm_substream *hiface_pcm_get_substream(struct snd_pcm_substream diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 60674ce4879b..601292c51491 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -337,23 +337,18 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, { struct usb_device *usbdev = line6->usbdev; int ret; - unsigned char *len; + u8 len; unsigned count; if (address > 0xffff || datalen > 0xff) return -EINVAL; - len = kmalloc(1, GFP_KERNEL); - if (!len) - return -ENOMEM; - /* query the serial number: */ - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - (datalen << 8) | 0x21, address, - NULL, 0, LINE6_TIMEOUT * HZ); - - if (ret < 0) { + ret = usb_control_msg_send(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + (datalen << 8) | 0x21, address, NULL, 0, + LINE6_TIMEOUT * HZ); + if (ret) { dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); goto exit; } @@ -362,45 +357,41 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { mdelay(LINE6_READ_WRITE_STATUS_DELAY); - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - 0x0012, 0x0000, len, 1, - LINE6_TIMEOUT * HZ); - if (ret < 0) { + ret = usb_control_msg_recv(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0012, 0x0000, &len, 1, + LINE6_TIMEOUT * HZ); + if (ret) { dev_err(line6->ifcdev, "receive length failed (error %d)\n", ret); goto exit; } - if (*len != 0xff) + if (len != 0xff) break; } ret = -EIO; - if (*len == 0xff) { + if (len == 0xff) { dev_err(line6->ifcdev, "read failed after %d retries\n", count); goto exit; - } else if (*len != datalen) { + } else if (len != datalen) { /* should be equal or something went wrong */ dev_err(line6->ifcdev, "length mismatch (expected %d, got %d)\n", - (int)datalen, (int)*len); + (int)datalen, len); goto exit; } /* receive the result: */ - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x0013, 0x0000, data, datalen, - LINE6_TIMEOUT * HZ); - - if (ret < 0) + ret = usb_control_msg_recv(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0013, 0x0000, data, datalen, LINE6_TIMEOUT * HZ); + if (ret) dev_err(line6->ifcdev, "read failed (error %d)\n", ret); exit: - kfree(len); return ret; } EXPORT_SYMBOL_GPL(line6_read_data); @@ -423,12 +414,10 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, if (!status) return -ENOMEM; - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - 0x0022, address, data, datalen, - LINE6_TIMEOUT * HZ); - - if (ret < 0) { + ret = usb_control_msg_send(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x0022, address, data, datalen, LINE6_TIMEOUT * HZ); + if (ret) { dev_err(line6->ifcdev, "write request failed (error %d)\n", ret); goto exit; @@ -437,14 +426,10 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { mdelay(LINE6_READ_WRITE_STATUS_DELAY); - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), - 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - 0x0012, 0x0000, - status, 1, LINE6_TIMEOUT * HZ); - - if (ret < 0) { + ret = usb_control_msg_recv(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0012, 0x0000, status, 1, LINE6_TIMEOUT * HZ); + if (ret) { dev_err(line6->ifcdev, "receiving status failed (error %d)\n", ret); goto exit; diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index eef45f7fef0d..a1261f55d62b 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -183,29 +183,25 @@ static const struct attribute_group podhd_dev_attr_group = { static int podhd_dev_start(struct usb_line6_podhd *pod) { int ret; - u8 *init_bytes; + u8 init_bytes[8]; int i; struct usb_device *usbdev = pod->line6.usbdev; - init_bytes = kmalloc(8, GFP_KERNEL); - if (!init_bytes) - return -ENOMEM; - - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), + ret = usb_control_msg_send(usbdev, 0, 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 0x11, 0, NULL, 0, LINE6_TIMEOUT * HZ); - if (ret < 0) { + if (ret) { dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret); goto exit; } /* NOTE: looks like some kind of ping message */ - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, + ret = usb_control_msg_recv(usbdev, 0, 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x11, 0x0, init_bytes, 3, LINE6_TIMEOUT * HZ); - if (ret < 0) { + if (ret) { dev_err(pod->line6.ifcdev, "receive length failed (error %d)\n", ret); goto exit; @@ -220,13 +216,12 @@ static int podhd_dev_start(struct usb_line6_podhd *pod) goto exit; } - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), + ret = usb_control_msg_send(usbdev, 0, USB_REQ_SET_FEATURE, USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT, 1, 0, NULL, 0, LINE6_TIMEOUT * HZ); exit: - kfree(init_bytes); return ret; } diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 94dd5e7ab2e6..a9b56085b76a 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -126,11 +126,11 @@ static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) { int ret; - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); + ret = usb_control_msg_send(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); - if (ret < 0) { + if (ret) { dev_err(&usbdev->dev, "send failed (error %d)\n", ret); return ret; } diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 0ffff7640892..9609c6d9655c 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -1978,7 +1978,7 @@ static int scarlett2_mixer_status_create(struct usb_mixer_interface *mixer) return 0; } - if (snd_usb_pipe_sanity_check(dev, pipe)) + if (usb_pipe_type_check(dev, pipe)) return -EINVAL; mixer->urb = usb_alloc_urb(0, GFP_KERNEL); diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 75bbdc691243..395d1ea6f03f 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -856,7 +856,7 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev) static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 }; void *buf; - if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x05))) + if (usb_pipe_type_check(dev, usb_sndintpipe(dev, 0x05))) return -EINVAL; buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL); if (!buf) @@ -885,8 +885,6 @@ static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev) { int ret; - if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0))) - return -EINVAL; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, 0, NULL, 0, 1000); @@ -994,8 +992,6 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev) dev_dbg(&dev->dev, "Waiting for Axe-Fx III to boot up...\n"); - if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0))) - return -EINVAL; /* If the Axe-Fx III has not fully booted, it will timeout when trying * to enable the audio streaming interface. A more generous timeout is * used here to detect when the Axe-Fx III has finished booting as the @@ -1028,7 +1024,7 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf, { int err, actual_length; - if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x01))) + if (usb_pipe_type_check(dev, usb_sndintpipe(dev, 0x01))) return -EINVAL; err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x01), buf, *length, &actual_length, 1000); @@ -1040,7 +1036,7 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf, memset(buf, 0, buf_size); - if (snd_usb_pipe_sanity_check(dev, usb_rcvintpipe(dev, 0x82))) + if (usb_pipe_type_check(dev, usb_rcvintpipe(dev, 0x82))) return -EINVAL; err = usb_interrupt_msg(dev, usb_rcvintpipe(dev, 0x82), buf, buf_size, &actual_length, 1000); @@ -1127,8 +1123,6 @@ static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev) { int ret; - if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0))) - return -EINVAL; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 1, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0, 0, NULL, 0, 1000); diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index f86f7a61fb36..6d35303b0948 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -82,40 +82,13 @@ static int us144_create_usbmidi(struct snd_card *card) &US122L(card)->midi_list, &quirk); } -/* - * Wrapper for usb_control_msg(). - * Allocates a temp buffer to prevent dmaing from/to the stack. - */ -static int us122l_ctl_msg(struct usb_device *dev, unsigned int pipe, - __u8 request, __u8 requesttype, - __u16 value, __u16 index, void *data, - __u16 size, int timeout) -{ - int err; - void *buf = NULL; - - if (size > 0) { - buf = kmemdup(data, size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - } - err = usb_control_msg(dev, pipe, request, requesttype, - value, index, buf, size, timeout); - if (size > 0) { - memcpy(data, buf, size); - kfree(buf); - } - return err; -} - static void pt_info_set(struct usb_device *dev, u8 v) { int ret; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 'I', - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - v, 0, NULL, 0, 1000); + ret = usb_control_msg_send(dev, 0, 'I', + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + v, 0, NULL, 0, 1000); snd_printdd(KERN_DEBUG "%i\n", ret); } @@ -305,10 +278,11 @@ static int us122l_set_sample_rate(struct usb_device *dev, int rate) data[0] = rate; data[1] = rate >> 8; data[2] = rate >> 16; - err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, - USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000); - if (err < 0) + err = usb_control_msg_send(dev, 0, UAC_SET_CUR, + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, + UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, + 1000); + if (err) snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n", dev->devnum, rate, ep); return err; |