diff options
123 files changed, 1928 insertions, 249 deletions
diff --git a/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml b/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml new file mode 100644 index 000000000000..2a9acf2b5a64 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/brcm,bcm7445-ehci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom STB USB EHCI Controller Device Tree Bindings + +allOf: + - $ref: "usb-hcd.yaml" + +maintainers: + - Al Cooper <alcooperx@gmail.com> + +properties: + compatible: + const: brcm,bcm7445-ehci + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + description: Clock specifier for the EHCI clock + + clock-names: + const: sw_usb + + phys: + maxItems: 1 + + phy-names: + const: usbphy + +required: + - compatible + - reg + - interrupts + - phys + - clocks + +additionalProperties: false + +examples: + - | + usb@f0b00300 { + compatible = "brcm,bcm7445-ehci"; + reg = <0xf0b00300 0xa8>; + interrupts = <0x0 0x5a 0x0>; + phys = <&usbphy_0 0x0>; + phy-names = "usbphy"; + clocks = <&usb20>; + clock-names = "sw_usb"; + }; + +... diff --git a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml new file mode 100644 index 000000000000..8eaf4b6c4735 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/usb/ti,tps6598x.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Texas Instruments 6598x Type-C Port Switch and Power Delivery controller DT bindings + +maintainers: + - Bryan O'Donoghue <bryan.odonoghue@linaro.org> + +description: | + Texas Instruments 6598x Type-C Port Switch and Power Delivery controller + +properties: + compatible: + enum: + - ti,tps6598x + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-names: + items: + - const: irq + +required: + - compatible + - reg + - interrupts + - interrupt-names + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + tps6598x: tps6598x@38 { + compatible = "ti,tps6598x"; + reg = <0x38>; + + interrupt-parent = <&msmgpio>; + interrupts = <107 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "irq"; + + pinctrl-names = "default"; + pinctrl-0 = <&typec_pins>; + + typec_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + port { + typec_ep: endpoint { + remote-endpoint = <&otg_ep>; + }; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index dc025f126d71..23e89d798b1b 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -24,6 +24,7 @@ Required properties: device - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 or RZ/G2 compatible device + - "brcm,bcm7445-xhci" for Broadcom STB SoCs with XHCI - "xhci-platform" (deprecated) When compatible with the generic version, nodes must list the diff --git a/Documentation/firmware-guide/acpi/intel-pmc-mux.rst b/Documentation/firmware-guide/acpi/intel-pmc-mux.rst new file mode 100644 index 000000000000..99b86710f02b --- /dev/null +++ b/Documentation/firmware-guide/acpi/intel-pmc-mux.rst @@ -0,0 +1,153 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================== +Intel North Mux-Agent +===================== + +Introduction +============ + +North Mux-Agent is a function of the Intel PMC firmware that is supported on +most Intel based platforms that have the PMC microcontroller. It's used for +configuring the various USB Multiplexer/DeMultiplexers on the system. The +platforms that allow the mux-agent to be configured from the operating system +have an ACPI device object (node) with HID "INTC105C" that represents it. + +The North Mux-Agent (aka. Intel PMC Mux Control, or just mux-agent) driver +communicates with the PMC microcontroller by using the PMC IPC method +(drivers/platform/x86/intel_scu_ipc.c). The driver registers with the USB Type-C +Mux Class which allows the USB Type-C Controller and Interface drivers to +configure the cable plug orientation and mode (with Alternate Modes). The driver +also registers with the USB Role Class in order to support both USB Host and +Device modes. The driver is located here: drivers/usb/typec/mux/intel_pmc_mux.c. + +Port nodes +========== + +General +------- + +For every USB Type-C connector under the mux-agent control on the system, there +is a separate child node under the PMC mux-agent device node. Those nodes do not +represent the actual connectors, but instead the "channels" in the mux-agent +that are associated with the connectors:: + + Scope (_SB.PCI0.PMC.MUX) + { + Device (CH0) + { + Name (_ADR, 0) + } + + Device (CH1) + { + Name (_ADR, 1) + } + } + +_PLD (Physical Location of Device) +---------------------------------- + +The optional _PLD object can be used with the port (the channel) nodes. If _PLD +is supplied, it should match the connector node _PLD:: + + Scope (_SB.PCI0.PMC.MUX) + { + Device (CH0) + { + Name (_ADR, 0) + Method (_PLD, 0, NotSerialized) + { + /* Consider this as pseudocode. */ + Return (\_SB.USBC.CON0._PLD()) + } + } + } + +Mux-agent specific _DSD Device Properties +----------------------------------------- + +Port Numbers +~~~~~~~~~~~~ + +In order to configure the muxes behind a USB Type-C connector, the PMC firmware +needs to know the USB2 port and the USB3 port that is associated with the +connector. The driver extracts the correct port numbers by reading specific _DSD +device properties named "usb2-port-number" and "usb3-port-number". These +properties have integer value that means the port index. The port index number +is 1's based, and value 0 is illegal. The driver uses the numbers extracted from +these device properties as-is when sending the mux-agent specific messages to +the PMC:: + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package() { + Package () {"usb2-port-number", 6}, + Package () {"usb3-port-number", 3}, + }, + }) + +Orientation +~~~~~~~~~~~ + +Depending on the platform, the data and SBU lines coming from the connector may +be "fixed" from the mux-agent's point of view, which means the mux-agent driver +should not configure them according to the cable plug orientation. This can +happen for example if a retimer on the platform handles the cable plug +orientation. The driver uses a specific device properties "sbu-orientation" +(SBU) and "hsl-orientation" (data) to know if those lines are "fixed", and to +which orientation. The value that these properties have is a string value, and +it can be one that is defined for the USB Type-C connector orientation: "normal" +or "reversed":: + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package() { + Package () {"sbu-orientation", "normal"}, + Package () {"hsl-orientation", "normal"}, + }, + }) + +Example ASL +=========== + +The following ASL is an example that shows the mux-agent node, and two +connectors under its control:: + + Scope (_SB.PCI0.PMC) + { + Device (MUX) + { + Name (_HID, "INTC105C") + + Device (CH0) + { + Name (_ADR, 0) + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package() { + Package () {"usb2-port-number", 6}, + Package () {"usb3-port-number", 3}, + Package () {"sbu-orientation", "normal"}, + Package () {"hsl-orientation", "normal"}, + }, + }) + } + + Device (CH1) + { + Name (_ADR, 1) + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package() { + Package () {"usb2-port-number", 5}, + Package () {"usb3-port-number", 2}, + Package () {"sbu-orientation", "normal"}, + Package () {"hsl-orientation", "normal"}, + }, + }) + } + } + } diff --git a/MAINTAINERS b/MAINTAINERS index ecc0749810b0..2d5ac1b89ed3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3481,6 +3481,14 @@ S: Supported F: Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml F: drivers/i2c/busses/i2c-brcmstb.c +BROADCOM BRCMSTB USB EHCI DRIVER +M: Al Cooper <alcooperx@gmail.com> +L: linux-usb@vger.kernel.org +L: bcm-kernel-feedback-list@broadcom.com +S: Maintained +F: Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml +F: drivers/usb/host/ehci-brcm.* + BROADCOM BRCMSTB USB2 and USB3 PHY DRIVER M: Al Cooper <alcooperx@gmail.com> L: linux-kernel@vger.kernel.org @@ -17583,6 +17591,13 @@ F: Documentation/driver-api/usb/typec.rst F: drivers/usb/typec/ F: include/linux/usb/typec.h +USB TYPEC INTEL PMC MUX DRIVER +M: Heikki Krogerus <heikki.krogerus@linux.intel.com> +L: linux-usb@vger.kernel.org +S: Maintained +F: Documentation/firmware-guide/acpi/intel-pmc-mux.rst +F: drivers/usb/typec/mux/intel_pmc_mux.c + USB TYPEC PI3USB30532 MUX DRIVER M: Hans de Goede <hdegoede@redhat.com> L: linux-usb@vger.kernel.org diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index ccc449df3792..20c2c428168e 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -460,6 +460,24 @@ static struct gpio_desc *of_find_arizona_gpio(struct device *dev, return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags); } +static struct gpio_desc *of_find_usb_gpio(struct device *dev, + const char *con_id, + enum of_gpio_flags *of_flags) +{ + /* + * Currently this USB quirk is only for the Fairchild FUSB302 host which is using + * an undocumented DT GPIO line named "fcs,int_n" without the compulsory "-gpios" + * suffix. + */ + if (!IS_ENABLED(CONFIG_TYPEC_FUSB302)) + return ERR_PTR(-ENOENT); + + if (!con_id || strcmp(con_id, "fcs,int_n")) + return ERR_PTR(-ENOENT); + + return of_get_named_gpiod_flags(dev->of_node, con_id, 0, of_flags); +} + struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, unsigned long *flags) { @@ -504,6 +522,9 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, if (PTR_ERR(desc) == -ENOENT) desc = of_find_arizona_gpio(dev, con_id, &of_flags); + if (PTR_ERR(desc) == -ENOENT) + desc = of_find_usb_gpio(dev, con_id, &of_flags); + if (IS_ERR(desc)) return desc; diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index 4aafba20f450..19bbb5b7e6b6 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -82,8 +82,6 @@ static void cdns3_exit_roles(struct cdns3 *cdns) cdns3_drd_exit(cdns); } -static enum usb_role cdsn3_hw_role_state_machine(struct cdns3 *cdns); - /** * cdns3_core_init_role - initialize role of operation * @cdns: Pointer to cdns3 structure @@ -193,12 +191,12 @@ err: } /** - * cdsn3_hw_role_state_machine - role switch state machine based on hw events. + * cdns3_hw_role_state_machine - role switch state machine based on hw events. * @cdns: Pointer to controller structure. * * Returns next role to be entered based on hw events. */ -static enum usb_role cdsn3_hw_role_state_machine(struct cdns3 *cdns) +static enum usb_role cdns3_hw_role_state_machine(struct cdns3 *cdns) { enum usb_role role; int id, vbus; @@ -291,14 +289,10 @@ int cdns3_hw_role_switch(struct cdns3 *cdns) enum usb_role real_role, current_role; int ret = 0; - /* Do nothing if role based on syfs. */ - if (cdns->role_override) - return 0; - pm_runtime_get_sync(cdns->dev); current_role = cdns->role; - real_role = cdsn3_hw_role_state_machine(cdns); + real_role = cdns3_hw_role_state_machine(cdns); /* Do nothing if nothing changed */ if (current_role == real_role) @@ -353,39 +347,6 @@ static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role) pm_runtime_get_sync(cdns->dev); - /* - * FIXME: switch role framework should be extended to meet - * requirements. Driver assumes that role can be controlled - * by SW or HW. Temporary workaround is to use USB_ROLE_NONE to - * switch from SW to HW control. - * - * For dr_mode == USB_DR_MODE_OTG: - * if user sets USB_ROLE_HOST or USB_ROLE_DEVICE then driver - * sets role_override flag and forces that role. - * if user sets USB_ROLE_NONE, driver clears role_override and lets - * HW state machine take over. - * - * For dr_mode != USB_DR_MODE_OTG: - * Assumptions: - * 1. Restricted user control between NONE and dr_mode. - * 2. Driver doesn't need to rely on role_override flag. - * 3. Driver needs to ensure that HW state machine is never called - * if dr_mode != USB_DR_MODE_OTG. - */ - if (role == USB_ROLE_NONE) - cdns->role_override = 0; - else - cdns->role_override = 1; - - /* - * HW state might have changed so driver need to trigger - * HW state machine if dr_mode == USB_DR_MODE_OTG. - */ - if (!cdns->role_override && cdns->dr_mode == USB_DR_MODE_OTG) { - cdns3_hw_role_switch(cdns); - goto pm_put; - } - if (cdns->role == role) goto pm_put; @@ -528,6 +489,8 @@ static int cdns3_probe(struct platform_device *pdev) sw_desc.get = cdns3_role_get; sw_desc.allow_userspace_control = true; sw_desc.driver_data = cdns; + if (device_property_read_bool(dev, "usb-role-switch")) + sw_desc.fwnode = dev->fwnode; cdns->role_sw = usb_role_switch_register(dev, &sw_desc); if (IS_ERR(cdns->role_sw)) { diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h index 969eb94de204..1ad1f1fe61e9 100644 --- a/drivers/usb/cdns3/core.h +++ b/drivers/usb/cdns3/core.h @@ -62,7 +62,6 @@ struct cdns3_role_driver { * This field based on firmware setting, kernel configuration * and hardware configuration. * @role_sw: pointer to role switch object. - * @role_override: set 1 if role rely on SW. */ struct cdns3 { struct device *dev; @@ -90,7 +89,6 @@ struct cdns3 { struct mutex mutex; enum usb_dr_mode dr_mode; struct usb_role_switch *role_sw; - int role_override; }; int cdns3_hw_role_switch(struct cdns3 *cdns); diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c index 16ad485f0b69..58089841ed52 100644 --- a/drivers/usb/cdns3/drd.c +++ b/drivers/usb/cdns3/drd.c @@ -329,7 +329,7 @@ int cdns3_drd_init(struct cdns3 *cdns) cdns->otg_v1_regs = NULL; cdns->otg_regs = regs; writel(1, &cdns->otg_v0_regs->simulate); - dev_info(cdns->dev, "DRD version v0 (%08x)\n", + dev_dbg(cdns->dev, "DRD version v0 (%08x)\n", readl(&cdns->otg_v0_regs->version)); } else { cdns->otg_v0_regs = NULL; @@ -337,7 +337,7 @@ int cdns3_drd_init(struct cdns3 *cdns) cdns->otg_regs = (void *)&cdns->otg_v1_regs->cmd; cdns->version = CDNS3_CONTROLLER_V1; writel(1, &cdns->otg_v1_regs->simulate); - dev_info(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n", + dev_dbg(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n", readl(&cdns->otg_v1_regs->did), readl(&cdns->otg_v1_regs->rid)); } diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 4d43f3b28309..559e5c01c2b0 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -2965,7 +2965,7 @@ static int cdns3_init_eps(struct cdns3_device *priv_dev) priv_ep->flags = 0; - dev_info(priv_dev->dev, "Initialized %s support: %s %s\n", + dev_dbg(priv_dev->dev, "Initialized %s support: %s %s\n", priv_ep->name, priv_ep->endpoint.caps.type_bulk ? "BULK, INT" : "", priv_ep->endpoint.caps.type_iso ? "ISO" : ""); diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 0d8e3f3804a3..084c48c5848f 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -468,7 +468,8 @@ static int usblp_release(struct inode *inode, struct file *file) usb_autopm_put_interface(usblp->intf); if (!usblp->present) /* finish cleanup from disconnect */ - usblp_cleanup(usblp); + usblp_cleanup(usblp); /* any URBs must be dead */ + mutex_unlock(&usblp_mutex); return 0; } @@ -1375,9 +1376,11 @@ static void usblp_disconnect(struct usb_interface *intf) usblp_unlink_urbs(usblp); mutex_unlock(&usblp->mut); + usb_poison_anchored_urbs(&usblp->urbs); if (!usblp->used) usblp_cleanup(usblp); + mutex_unlock(&usblp_mutex); } diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index f0a259937da8..1547aa6e5314 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -159,6 +159,7 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, * usb_hcd_pci_probe - initialize PCI-based HCDs * @dev: USB Host Controller being probed * @id: pci hotplug id connecting controller to HCD framework + * @driver: USB HC driver handle * Context: !in_interrupt() * * Allocates basic PCI resources for this USB host controller, and @@ -169,9 +170,9 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, * * Return: 0 if successful. */ -int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id, + const struct hc_driver *driver) { - struct hc_driver *driver; struct usb_hcd *hcd; int retval; int hcd_irq = 0; @@ -181,7 +182,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (!id) return -EINVAL; - driver = (struct hc_driver *)id->driver_data; + if (!driver) return -EINVAL; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index fc748c731832..b1e14beaac5f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -93,7 +93,7 @@ module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(old_scheme_first, "start with the old device initialization scheme"); -static bool use_both_schemes = 1; +static bool use_both_schemes = true; module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index a97dd1ba964e..73f4482d833a 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * usb hub driver head file * diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index 2ae90158ded7..fdd4897401e2 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * drivers/usb/core/otg_whitelist.h * diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 9f4320b9d7fc..a2ca38e25e0c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -1262,8 +1262,10 @@ void usb_create_sysfs_intf_files(struct usb_interface *intf) if (!alt->string && !(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) alt->string = usb_cache_string(udev, alt->desc.iInterface); - if (alt->string && device_create_file(&intf->dev, &dev_attr_interface)) - ; /* We don't actually care if the function fails. */ + if (alt->string && device_create_file(&intf->dev, &dev_attr_interface)) { + /* This is not a serious error */ + dev_dbg(&intf->dev, "interface string descriptor file not created\n"); + } intf->sysfs_files_created = 1; } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 64ed4023a8c8..19e4c550bc73 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Released under the GPLv2 only. */ diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 99b0bdfe0012..668d1ad646a4 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* * core.h - DesignWare HS OTG Controller common declarations * diff --git a/drivers/usb/dwc2/debug.h b/drivers/usb/dwc2/debug.h index a8c565b6bc34..47252c56d410 100644 --- a/drivers/usb/dwc2/debug.h +++ b/drivers/usb/dwc2/debug.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * debug.h - Designware USB2 DRD controller debug header * diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 1224fa9df604..ea02ee63ac6d 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* * hcd.h - DesignWare HS OTG Controller host-mode declarations * diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index c4027bbcedec..864b76a0b954 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* * hw.h - DesignWare HS OTG Controller hardware definitions * diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index 171280c80228..04ba11fff0ed 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -18,7 +18,6 @@ #include <asm/fixmap.h> #include <linux/bcd.h> #include <linux/export.h> -#include <linux/version.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/kthread.h> diff --git a/drivers/usb/early/xhci-dbc.h b/drivers/usb/early/xhci-dbc.h index 6e2b7266a695..8b4d71de45fc 100644 --- a/drivers/usb/early/xhci-dbc.h +++ b/drivers/usb/early/xhci-dbc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * xhci-dbc.h - xHCI debug capability early driver * diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index aaf975c809bf..7164ad9800f1 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -48,7 +48,6 @@ #define DRIVER_DESC "Aeroflex Gaisler GRUSBDC USB Peripheral Controller" static const char driver_name[] = DRIVER_NAME; -static const char driver_desc[] = DRIVER_DESC; #define gr_read32(x) (ioread32be((x))) #define gr_write32(x, v) (iowrite32be((v), (x))) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 55bdfdf11e4c..20137be083a8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -42,6 +42,15 @@ config USB_XHCI_PCI depends on USB_PCI default y +config USB_XHCI_PCI_RENESAS + tristate "Support for additional Renesas xHCI controller with firwmare" + depends on USB_XHCI_PCI + ---help--- + Say 'Y' to enable the support for the Renesas xHCI controller with + firwmare. Make sure you have the firwmare for the device and + installed on your system for this device to work. + If unsure, say 'N'. + config USB_XHCI_PLATFORM tristate "Generic xHCI driver for a platform device" select USB_XHCI_RCAR if ARCH_RENESAS @@ -97,6 +106,26 @@ config USB_XHCI_TEGRA endif # USB_XHCI_HCD +config USB_EHCI_BRCMSTB + tristate + +config USB_BRCMSTB + tristate "Broadcom STB USB support" + depends on (ARCH_BRCMSTB && PHY_BRCM_USB) || COMPILE_TEST + select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD + select USB_EHCI_BRCMSTB if USB_EHCI_HCD + select USB_XHCI_PLATFORM if USB_XHCI_HCD + help + Enables support for XHCI, EHCI and OHCI host controllers + found in Broadcom STB SoC's. + + To compile these drivers as modules, choose M here: the + modules will be called ohci-platform.ko, ehci-brcm.ko and + xhci-plat-hcd.ko + + Disabling this will keep the controllers and corresponding + PHYs powered down. + config USB_EHCI_HCD tristate "EHCI HCD (USB 2.0) support" depends on HAS_DMA && HAS_IOMEM diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index b191361257cc..bc731332fed9 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_USB_EHCI_HCD_STI) += ehci-st.o obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o +obj-$(CONFIG_USB_EHCI_BRCMSTB) += ehci-brcm.o obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o @@ -71,6 +72,7 @@ obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_FHCI_HCD) += fhci.o obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o +obj-$(CONFIG_USB_XHCI_PCI_RENESAS) += xhci-pci-renesas.o obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o obj-$(CONFIG_USB_XHCI_HISTB) += xhci-histb.o obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o diff --git a/drivers/usb/host/ehci-brcm.c b/drivers/usb/host/ehci-brcm.c new file mode 100644 index 000000000000..3e0ebe8cc649 --- /dev/null +++ b/drivers/usb/host/ehci-brcm.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2020, Broadcom */ + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/iopoll.h> + +#include "ehci.h" + +#define hcd_to_ehci_priv(h) ((struct brcm_priv *)hcd_to_ehci(h)->priv) + +struct brcm_priv { + struct clk *clk; +}; + +/* + * ehci_brcm_wait_for_sof + * Wait for start of next microframe, then wait extra delay microseconds + */ +static inline void ehci_brcm_wait_for_sof(struct ehci_hcd *ehci, u32 delay) +{ + u32 frame_idx = ehci_readl(ehci, &ehci->regs->frame_index); + u32 val; + int res; + + /* Wait for next microframe (every 125 usecs) */ + res = readl_relaxed_poll_timeout(&ehci->regs->frame_index, val, + val != frame_idx, 1, 130); + if (res) + ehci_err(ehci, "Error waiting for SOF\n"); + udelay(delay); +} + +/* + * ehci_brcm_hub_control + * The EHCI controller has a bug where it can violate the SOF + * interval between the first two SOF's transmitted after resume + * if the resume occurs near the end of the microframe. This causees + * the controller to detect babble on the suspended port and + * will eventually cause the controller to reset the port. + * The fix is to Intercept the echi-hcd request to complete RESUME and + * align it to the start of the next microframe. + * See SWLINUX-1909 for more details + */ +static int ehci_brcm_hub_control( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int ports = HCS_N_PORTS(ehci->hcs_params); + u32 __iomem *status_reg; + unsigned long flags; + int retval, irq_disabled = 0; + + status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; + + /* + * RESUME is cleared when GetPortStatus() is called 20ms after start + * of RESUME + */ + if ((typeReq == GetPortStatus) && + (wIndex && wIndex <= ports) && + ehci->reset_done[wIndex-1] && + time_after_eq(jiffies, ehci->reset_done[wIndex-1]) && + (ehci_readl(ehci, status_reg) & PORT_RESUME)) { + + /* + * to make sure we are not interrupted until RESUME bit + * is cleared, disable interrupts on current CPU + */ + ehci_dbg(ehci, "SOF alignment workaround\n"); + irq_disabled = 1; + local_irq_save(flags); + ehci_brcm_wait_for_sof(ehci, 5); + } + retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); + if (irq_disabled) + local_irq_restore(flags); + return retval; +} + +static int ehci_brcm_reset(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int len; + + ehci->big_endian_mmio = 1; + + ehci->caps = (void __iomem *)hcd->regs; + len = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); + ehci->regs = (void __iomem *)(hcd->regs + len); + + /* This fixes the lockup during reboot due to prior interrupts */ + ehci_writel(ehci, CMD_RESET, &ehci->regs->command); + mdelay(10); + + /* + * SWLINUX-1705: Avoid OUT packet underflows during high memory + * bus usage + * port_status[0x0f] = Broadcom-proprietary USB_EHCI_INSNREG00 @ 0x90 + */ + ehci_writel(ehci, 0x00800040, &ehci->regs->port_status[0x10]); + ehci_writel(ehci, 0x00000001, &ehci->regs->port_status[0x12]); + + return ehci_setup(hcd); +} + +static struct hc_driver __read_mostly ehci_brcm_hc_driver; + +static const struct ehci_driver_overrides brcm_overrides __initconst = { + .reset = ehci_brcm_reset, + .extra_priv_size = sizeof(struct brcm_priv), +}; + +static int ehci_brcm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res_mem; + struct brcm_priv *priv; + struct usb_hcd *hcd; + int irq; + int err; + + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (err) + return err; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return irq ? irq : -EINVAL; + + /* Hook the hub control routine to work around a bug */ + ehci_brcm_hc_driver.hub_control = ehci_brcm_hub_control; + + /* initialize hcd */ + hcd = usb_create_hcd(&ehci_brcm_hc_driver, dev, dev_name(dev)); + if (!hcd) + return -ENOMEM; + + platform_set_drvdata(pdev, hcd); + priv = hcd_to_ehci_priv(hcd); + + priv->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(priv->clk)) { + err = PTR_ERR(priv->clk); + goto err_hcd; + } + + err = clk_prepare_enable(priv->clk); + if (err) + goto err_hcd; + + hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res_mem); + if (IS_ERR(hcd->regs)) { + err = PTR_ERR(hcd->regs); + goto err_clk; + } + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = resource_size(res_mem); + err = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (err) + goto err_clk; + + device_wakeup_enable(hcd->self.controller); + device_enable_async_suspend(hcd->self.controller); + + return 0; + +err_clk: + clk_disable_unprepare(priv->clk); +err_hcd: + usb_put_hcd(hcd); + + return err; +} + +static int ehci_brcm_remove(struct platform_device *dev) +{ + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct brcm_priv *priv = hcd_to_ehci_priv(hcd); + + usb_remove_hcd(hcd); + clk_disable_unprepare(priv->clk); + usb_put_hcd(hcd); + return 0; +} + +static int __maybe_unused ehci_brcm_suspend(struct device *dev) +{ + int ret; + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct brcm_priv *priv = hcd_to_ehci_priv(hcd); + bool do_wakeup = device_may_wakeup(dev); + + ret = ehci_suspend(hcd, do_wakeup); + if (ret) + return ret; + clk_disable_unprepare(priv->clk); + return 0; +} + +static int __maybe_unused ehci_brcm_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct brcm_priv *priv = hcd_to_ehci_priv(hcd); + int err; + + err = clk_prepare_enable(priv->clk); + if (err) + return err; + /* + * SWLINUX-1705: Avoid OUT packet underflows during high memory + * bus usage + * port_status[0x0f] = Broadcom-proprietary USB_EHCI_INSNREG00 + * @ 0x90 + */ + ehci_writel(ehci, 0x00800040, &ehci->regs->port_status[0x10]); + ehci_writel(ehci, 0x00000001, &ehci->regs->port_status[0x12]); + + ehci_resume(hcd, false); + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(ehci_brcm_pm_ops, ehci_brcm_suspend, + ehci_brcm_resume); + +static const struct of_device_id brcm_ehci_of_match[] = { + { .compatible = "brcm,ehci-brcm-v2", }, + { .compatible = "brcm,bcm7445-ehci", }, + {} +}; + +static struct platform_driver ehci_brcm_driver = { + .probe = ehci_brcm_probe, + .remove = ehci_brcm_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "ehci-brcm", + .pm = &ehci_brcm_pm_ops, + .of_match_table = brcm_ehci_of_match, + } +}; + +static int __init ehci_brcm_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + ehci_init_driver(&ehci_brcm_hc_driver, &brcm_overrides); + return platform_driver_register(&ehci_brcm_driver); +} +module_init(ehci_brcm_init); + +static void __exit ehci_brcm_exit(void) +{ + platform_driver_unregister(&ehci_brcm_driver); +} +module_exit(ehci_brcm_exit); + +MODULE_ALIAS("platform:ehci-brcm"); +MODULE_DESCRIPTION("EHCI Broadcom STB driver"); +MODULE_AUTHOR("Al Cooper"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index 9d18c6e6ab27..c95341d472f4 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* Copyright (C) 2005-2010,2012 Freescale Semiconductor, Inc. * Copyright (c) 2005 MontaVista Software */ diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 1300c457d9ed..0d61f43c29dc 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -108,7 +108,7 @@ static int mv_ehci_probe(struct platform_device *pdev) struct ehci_hcd *ehci; struct ehci_hcd_mv *ehci_mv; struct resource *r; - int retval = -ENODEV; + int retval; u32 offset; u32 status; @@ -143,8 +143,6 @@ static int mv_ehci_probe(struct platform_device *pdev) goto err_put_hcd; } - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ehci_mv->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(ehci_mv->base)) { @@ -169,9 +167,8 @@ static int mv_ehci_probe(struct platform_device *pdev) hcd->regs = ehci_mv->op_regs; hcd->irq = platform_get_irq(pdev, 0); - if (!hcd->irq) { - dev_err(&pdev->dev, "Cannot get irq."); - retval = -ENODEV; + if (hcd->irq < 0) { + retval = hcd->irq; goto err_disable_clk; } diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index c9f91e6c72b6..09e01397f987 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -36,12 +36,12 @@ static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = { static int ehci_mxc_drv_probe(struct platform_device *pdev) { - struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct device *dev = &pdev->dev; + struct mxc_usbh_platform_data *pdata = dev_get_platdata(dev); struct usb_hcd *hcd; struct resource *res; int irq, ret; struct ehci_mxc_priv *priv; - struct device *dev = &pdev->dev; struct ehci_hcd *ehci; if (!pdata) { @@ -56,7 +56,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); + hcd->regs = devm_ioremap_resource(dev, res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto err_alloc; @@ -69,14 +69,14 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) priv = (struct ehci_mxc_priv *) ehci->priv; /* enable clocks */ - priv->usbclk = devm_clk_get(&pdev->dev, "ipg"); + priv->usbclk = devm_clk_get(dev, "ipg"); if (IS_ERR(priv->usbclk)) { ret = PTR_ERR(priv->usbclk); goto err_alloc; } clk_prepare_enable(priv->usbclk); - priv->ahbclk = devm_clk_get(&pdev->dev, "ahb"); + priv->ahbclk = devm_clk_get(dev, "ahb"); if (IS_ERR(priv->ahbclk)) { ret = PTR_ERR(priv->ahbclk); goto err_clk_ahb; @@ -84,13 +84,12 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) clk_prepare_enable(priv->ahbclk); /* "dr" device has its own clock on i.MX51 */ - priv->phyclk = devm_clk_get(&pdev->dev, "phy"); + priv->phyclk = devm_clk_get(dev, "phy"); if (IS_ERR(priv->phyclk)) priv->phyclk = NULL; if (priv->phyclk) clk_prepare_enable(priv->phyclk); - /* call platform specific init function */ if (pdata->init) { ret = pdata->init(pdev); diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 1a48ab1bd3b2..3c3820ad9092 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -360,23 +360,21 @@ static int ehci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { if (is_bypassed_id(pdev)) return -ENODEV; - return usb_hcd_pci_probe(pdev, id); + return usb_hcd_pci_probe(pdev, id, &ehci_pci_hc_driver); } static void ehci_pci_remove(struct pci_dev *pdev) { pci_clear_mwi(pdev); - usb_hcd_pci_remove(pdev); + usb_hcd_pci_remove(pdev); } /* PCI driver selection metadata; PCI hotplugging uses this */ static const struct pci_device_id pci_ids [] = { { /* handle any USB 2.0 EHCI controller */ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0), - .driver_data = (unsigned long) &ehci_pci_hc_driver, }, { PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_USB_HOST), - .driver_data = (unsigned long) &ehci_pci_hc_driver, }, { /* end: all zeroes */ } }; diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 10d51daa6a1b..e077b2ca53c5 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -480,7 +480,6 @@ static int tegra_ehci_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (!irq) { - dev_err(&pdev->dev, "Failed to get IRQ\n"); err = -ENODEV; goto cleanup_phy; } diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 229b3de319e6..eabf22a78eae 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (c) 2001-2002 by David Brownell */ diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h index 2ce5031d866d..81fbc019a9b3 100644 --- a/drivers/usb/host/fhci.h +++ b/drivers/usb/host/fhci.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Freescale QUICC Engine USB Host Controller Driver * diff --git a/drivers/usb/host/imx21-hcd.h b/drivers/usb/host/imx21-hcd.h index 7b9cf0a38d6e..96d16752a73e 100644 --- a/drivers/usb/host/imx21-hcd.h +++ b/drivers/usb/host/imx21-hcd.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Macros and prototypes for i.MX21 * diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 22117a6aeb4a..585222af24ff 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -277,21 +277,24 @@ static const struct ohci_driver_overrides pci_overrides __initconst = { static const struct pci_device_id pci_ids[] = { { /* handle any USB OHCI controller */ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0), - .driver_data = (unsigned long) &ohci_pci_hc_driver, }, { /* The device in the ConneXT I/O hub has no class reg */ PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_USB_OHCI), - .driver_data = (unsigned long) &ohci_pci_hc_driver, }, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE (pci, pci_ids); +static int ohci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return usb_hcd_pci_probe(dev, id, &ohci_pci_hc_driver); +} + /* pci driver glue; this is a "new style" PCI driver module */ static struct pci_driver ohci_pci_driver = { .name = hcd_name, .id_table = pci_ids, - .probe = usb_hcd_pci_probe, + .probe = ohci_pci_probe, .remove = usb_hcd_pci_remove, .shutdown = usb_hcd_pci_shutdown, diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index c158cda9e4b9..cff965240327 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -157,9 +157,10 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) * the call to usb_hcd_setup_local_mem() below does just that. */ - if (usb_hcd_setup_local_mem(hcd, mem->start, - mem->start - mem->parent->start, - resource_size(mem)) < 0) + retval = usb_hcd_setup_local_mem(hcd, mem->start, + mem->start - mem->parent->start, + resource_size(mem)); + if (retval < 0) goto err5; retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 27c26ca10bfd..b85a39588f9d 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-1.0+ +/* SPDX-License-Identifier: GPL-1.0+ */ /* * OHCI HCD (Host Controller Driver) for USB. * diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index beb2efa71341..92150ecdb036 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -205,7 +205,7 @@ static void usb_amd_find_chipset_info(void) { unsigned long flags; struct amd_chipset_info info; - info.need_pll_quirk = 0; + info.need_pll_quirk = false; spin_lock_irqsave(&amd_lock, flags); @@ -229,10 +229,10 @@ static void usb_amd_find_chipset_info(void) case AMD_CHIPSET_SB800: case AMD_CHIPSET_HUDSON2: case AMD_CHIPSET_BOLTON: - info.need_pll_quirk = 1; + info.need_pll_quirk = true; break; default: - info.need_pll_quirk = 0; + info.need_pll_quirk = false; break; } @@ -529,7 +529,7 @@ void usb_amd_dev_put(void) amd_chipset.nb_type = 0; memset(&amd_chipset.sb_type, 0, sizeof(amd_chipset.sb_type)); amd_chipset.isoc_reqs = 0; - amd_chipset.need_pll_quirk = 0; + amd_chipset.need_pll_quirk = false; spin_unlock_irqrestore(&amd_lock, flags); diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index 51973a923526..ab081475c113 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * R8A66597 HCD (Host Controller Driver) * diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index e9209e3e6248..995bc52d2d22 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -81,7 +81,6 @@ static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); static struct mutex u132_module_lock; static int u132_exiting; static int u132_instances; -static struct list_head u132_static_list; /* * end of the global variables protected by u132_module_lock */ @@ -177,7 +176,6 @@ struct u132_ring { }; struct u132 { struct kref kref; - struct list_head u132_list; struct mutex sw_lock; struct mutex scheduler_lock; struct u132_platform_data *board; @@ -254,7 +252,6 @@ static void u132_hcd_delete(struct kref *kref) struct usb_hcd *hcd = u132_to_hcd(u132); u132->going += 1; mutex_lock(&u132_module_lock); - list_del_init(&u132->u132_list); u132_instances -= 1; mutex_unlock(&u132_module_lock); dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13" @@ -3089,7 +3086,6 @@ static int u132_probe(struct platform_device *pdev) retval = 0; hcd->rsrc_start = 0; mutex_lock(&u132_module_lock); - list_add_tail(&u132->u132_list, &u132_static_list); u132->sequence_num = ++u132_instances; mutex_unlock(&u132_module_lock); u132_u132_init_kref(u132); @@ -3192,7 +3188,6 @@ static struct platform_driver u132_platform_driver = { static int __init u132_hcd_init(void) { int retval; - INIT_LIST_HEAD(&u132_static_list); u132_instances = 0; u132_exiting = 0; mutex_init(&u132_module_lock); @@ -3213,14 +3208,9 @@ static int __init u132_hcd_init(void) module_init(u132_hcd_init); static void __exit u132_hcd_exit(void) { - struct u132 *u132; - struct u132 *temp; mutex_lock(&u132_module_lock); u132_exiting += 1; mutex_unlock(&u132_module_lock); - list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) { - platform_device_unregister(u132->platform_dev); - } platform_driver_unregister(&u132_platform_driver); printk(KERN_INFO "u132-hcd driver deregistered\n"); wait_event(u132_hcd_wait, u132_instances == 0); diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index 957c87efc746..9b88745d247f 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -287,17 +287,21 @@ static const struct hc_driver uhci_driver = { static const struct pci_device_id uhci_pci_ids[] = { { /* handle any USB UHCI controller */ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0), - .driver_data = (unsigned long) &uhci_driver, }, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(pci, uhci_pci_ids); +static int uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return usb_hcd_pci_probe(dev, id, &uhci_driver); +} + static struct pci_driver uhci_pci_driver = { .name = hcd_name, .id_table = uhci_pci_ids, - .probe = usb_hcd_pci_probe, + .probe = uhci_pci_probe, .remove = usb_hcd_pci_remove, .shutdown = uhci_shutdown, diff --git a/drivers/usb/host/xhci-debugfs.h b/drivers/usb/host/xhci-debugfs.h index f7a4e2492b00..56db635fcd6e 100644 --- a/drivers/usb/host/xhci-debugfs.h +++ b/drivers/usb/host/xhci-debugfs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * xhci-debugfs.h - xHCI debugfs interface * diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index 268328c20681..fa59b242cd51 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * xHCI host controller driver * diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index acd56517215a..a93cfe817904 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2015 MediaTek Inc. * Author: diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h index ca0a3a5721dd..3be021793cc8 100644 --- a/drivers/usb/host/xhci-mvebu.h +++ b/drivers/usb/host/xhci-mvebu.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2014 Marvell * diff --git a/drivers/usb/host/xhci-pci-renesas.c b/drivers/usb/host/xhci-pci-renesas.c new file mode 100644 index 000000000000..f7d2445d30ec --- /dev/null +++ b/drivers/usb/host/xhci-pci-renesas.c @@ -0,0 +1,645 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2019-2020 Linaro Limited */ + +#include <linux/acpi.h> +#include <linux/firmware.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/unaligned/access_ok.h> + +#include "xhci.h" +#include "xhci-trace.h" +#include "xhci-pci.h" + +#define RENESAS_FW_VERSION 0x6C +#define RENESAS_ROM_CONFIG 0xF0 +#define RENESAS_FW_STATUS 0xF4 +#define RENESAS_FW_STATUS_MSB 0xF5 +#define RENESAS_ROM_STATUS 0xF6 +#define RENESAS_ROM_STATUS_MSB 0xF7 +#define RENESAS_DATA0 0xF8 +#define RENESAS_DATA1 0xFC + +#define RENESAS_FW_VERSION_FIELD GENMASK(23, 7) +#define RENESAS_FW_VERSION_OFFSET 8 + +#define RENESAS_FW_STATUS_DOWNLOAD_ENABLE BIT(0) +#define RENESAS_FW_STATUS_LOCK BIT(1) +#define RENESAS_FW_STATUS_RESULT GENMASK(6, 4) + #define RENESAS_FW_STATUS_INVALID 0 + #define RENESAS_FW_STATUS_SUCCESS BIT(4) + #define RENESAS_FW_STATUS_ERROR BIT(5) +#define RENESAS_FW_STATUS_SET_DATA0 BIT(8) +#define RENESAS_FW_STATUS_SET_DATA1 BIT(9) + +#define RENESAS_ROM_STATUS_ACCESS BIT(0) +#define RENESAS_ROM_STATUS_ERASE BIT(1) +#define RENESAS_ROM_STATUS_RELOAD BIT(2) +#define RENESAS_ROM_STATUS_RESULT GENMASK(6, 4) + #define RENESAS_ROM_STATUS_NO_RESULT 0 + #define RENESAS_ROM_STATUS_SUCCESS BIT(4) + #define RENESAS_ROM_STATUS_ERROR BIT(5) +#define RENESAS_ROM_STATUS_SET_DATA0 BIT(8) +#define RENESAS_ROM_STATUS_SET_DATA1 BIT(9) +#define RENESAS_ROM_STATUS_ROM_EXISTS BIT(15) + +#define RENESAS_ROM_ERASE_MAGIC 0x5A65726F +#define RENESAS_ROM_WRITE_MAGIC 0x53524F4D + +#define RENESAS_RETRY 10000 +#define RENESAS_DELAY 10 + +#define ROM_VALID_01 0x2013 +#define ROM_VALID_02 0x2026 + +static int renesas_verify_fw_version(struct pci_dev *pdev, u32 version) +{ + switch (version) { + case ROM_VALID_01: + case ROM_VALID_02: + return 0; + } + dev_err(&pdev->dev, "FW has invalid version :%d\n", version); + return -EINVAL; +} + +static int renesas_fw_download_image(struct pci_dev *dev, + const u32 *fw, size_t step, bool rom) +{ + size_t i; + int err; + u8 fw_status; + bool data0_or_data1; + u32 status_reg; + + if (rom) + status_reg = RENESAS_ROM_STATUS_MSB; + else + status_reg = RENESAS_FW_STATUS_MSB; + + /* + * The hardware does alternate between two 32-bit pages. + * (This is because each row of the firmware is 8 bytes). + * + * for even steps we use DATA0, for odd steps DATA1. + */ + data0_or_data1 = (step & 1) == 1; + + /* step+1. Read "Set DATAX" and confirm it is cleared. */ + for (i = 0; i < RENESAS_RETRY; i++) { + err = pci_read_config_byte(dev, status_reg, &fw_status); + if (err) { + dev_err(&dev->dev, "Read Status failed: %d\n", + pcibios_err_to_errno(err)); + return pcibios_err_to_errno(err); + } + if (!(fw_status & BIT(data0_or_data1))) + break; + + udelay(RENESAS_DELAY); + } + if (i == RENESAS_RETRY) { + dev_err(&dev->dev, "Timeout for Set DATAX step: %zd\n", step); + return -ETIMEDOUT; + } + + /* + * step+2. Write FW data to "DATAX". + * "LSB is left" => force little endian + */ + err = pci_write_config_dword(dev, data0_or_data1 ? + RENESAS_DATA1 : RENESAS_DATA0, + (__force u32)cpu_to_le32(fw[step])); + if (err) { + dev_err(&dev->dev, "Write to DATAX failed: %d\n", + pcibios_err_to_errno(err)); + return pcibios_err_to_errno(err); + } + + udelay(100); + + /* step+3. Set "Set DATAX". */ + err = pci_write_config_byte(dev, status_reg, BIT(data0_or_data1)); + if (err) { + dev_err(&dev->dev, "Write config for DATAX failed: %d\n", + pcibios_err_to_errno(err)); + return pcibios_err_to_errno(err); + } + + return 0; +} + +static int renesas_fw_verify(const void *fw_data, + size_t length) +{ + u16 fw_version_pointer; + u16 fw_version; + + /* + * The Firmware's Data Format is describe in + * "6.3 Data Format" R19UH0078EJ0500 Rev.5.00 page 124 + */ + + /* + * The bootrom chips of the big brother have sizes up to 64k, let's + * assume that's the biggest the firmware can get. + */ + if (length < 0x1000 || length >= 0x10000) { + pr_err("firmware is size %zd is not (4k - 64k).", + length); + return -EINVAL; + } + + /* The First 2 bytes are fixed value (55aa). "LSB on Left" */ + if (get_unaligned_le16(fw_data) != 0x55aa) { + pr_err("no valid firmware header found."); + return -EINVAL; + } + + /* verify the firmware version position and print it. */ + fw_version_pointer = get_unaligned_le16(fw_data + 4); + if (fw_version_pointer + 2 >= length) { + pr_err("fw ver pointer is outside of the firmware image"); + return -EINVAL; + } + + fw_version = get_unaligned_le16(fw_data + fw_version_pointer); + pr_err("got firmware version: %02x.", fw_version); + + return 0; +} + +static bool renesas_check_rom(struct pci_dev *pdev) +{ + u16 rom_status; + int retval; + + /* Check if external ROM exists */ + retval = pci_read_config_word(pdev, RENESAS_ROM_STATUS, &rom_status); + if (retval) + return false; + + rom_status &= RENESAS_ROM_STATUS_ROM_EXISTS; + if (rom_status) { + dev_dbg(&pdev->dev, "External ROM exists\n"); + return true; /* External ROM exists */ + } + + return false; +} + +static int renesas_check_rom_state(struct pci_dev *pdev) +{ + u16 rom_state; + u32 version; + int err; + + /* check FW version */ + err = pci_read_config_dword(pdev, RENESAS_FW_VERSION, &version); + if (err) + return pcibios_err_to_errno(err); + + version &= RENESAS_FW_VERSION_FIELD; + version = version >> RENESAS_FW_VERSION_OFFSET; + + err = renesas_verify_fw_version(pdev, version); + if (err) + return err; + + /* + * Test if ROM is present and loaded, if so we can skip everything + */ + err = pci_read_config_word(pdev, RENESAS_ROM_STATUS, &rom_state); + if (err) + return pcibios_err_to_errno(err); + + if (rom_state & BIT(15)) { + /* ROM exists */ + dev_dbg(&pdev->dev, "ROM exists\n"); + + /* Check the "Result Code" Bits (6:4) and act accordingly */ + switch (rom_state & RENESAS_ROM_STATUS_RESULT) { + case RENESAS_ROM_STATUS_SUCCESS: + return 0; + + case RENESAS_ROM_STATUS_NO_RESULT: /* No result yet */ + return 0; + + case RENESAS_ROM_STATUS_ERROR: /* Error State */ + default: /* All other states are marked as "Reserved states" */ + dev_err(&pdev->dev, "Invalid ROM.."); + break; + } + } + + return -EIO; +} + +static int renesas_fw_check_running(struct pci_dev *pdev) +{ + u8 fw_state; + int err; + + /* Check if device has ROM and loaded, if so skip everything */ + err = renesas_check_rom(pdev); + if (err) { /* we have rom */ + err = renesas_check_rom_state(pdev); + if (!err) + return err; + } + + /* + * Test if the device is actually needing the firmware. As most + * BIOSes will initialize the device for us. If the device is + * initialized. + */ + err = pci_read_config_byte(pdev, RENESAS_FW_STATUS, &fw_state); + if (err) + return pcibios_err_to_errno(err); + + /* + * Check if "FW Download Lock" is locked. If it is and the FW is + * ready we can simply continue. If the FW is not ready, we have + * to give up. + */ + if (fw_state & RENESAS_FW_STATUS_LOCK) { + dev_dbg(&pdev->dev, "FW Download Lock is engaged."); + + if (fw_state & RENESAS_FW_STATUS_SUCCESS) + return 0; + + dev_err(&pdev->dev, + "FW Download Lock is set and FW is not ready. Giving Up."); + return -EIO; + } + + /* + * Check if "FW Download Enable" is set. If someone (us?) tampered + * with it and it can't be reset, we have to give up too... and + * ask for a forgiveness and a reboot. + */ + if (fw_state & RENESAS_FW_STATUS_DOWNLOAD_ENABLE) { + dev_err(&pdev->dev, + "FW Download Enable is stale. Giving Up (poweroff/reboot needed)."); + return -EIO; + } + + /* Otherwise, Check the "Result Code" Bits (6:4) and act accordingly */ + switch (fw_state & RENESAS_FW_STATUS_RESULT) { + case 0: /* No result yet */ + dev_dbg(&pdev->dev, "FW is not ready/loaded yet."); + + /* tell the caller, that this device needs the firmware. */ + return 1; + + case RENESAS_FW_STATUS_SUCCESS: /* Success, device should be working. */ + dev_dbg(&pdev->dev, "FW is ready."); + return 0; + + case RENESAS_FW_STATUS_ERROR: /* Error State */ + dev_err(&pdev->dev, + "hardware is in an error state. Giving up (poweroff/reboot needed)."); + return -ENODEV; + + default: /* All other states are marked as "Reserved states" */ + dev_err(&pdev->dev, + "hardware is in an invalid state %lx. Giving up (poweroff/reboot needed).", + (fw_state & RENESAS_FW_STATUS_RESULT) >> 4); + return -EINVAL; + } +} + +static int renesas_fw_download(struct pci_dev *pdev, + const struct firmware *fw) +{ + const u32 *fw_data = (const u32 *)fw->data; + size_t i; + int err; + u8 fw_status; + + /* + * For more information and the big picture: please look at the + * "Firmware Download Sequence" in "7.1 FW Download Interface" + * of R19UH0078EJ0500 Rev.5.00 page 131 + */ + + /* + * 0. Set "FW Download Enable" bit in the + * "FW Download Control & Status Register" at 0xF4 + */ + err = pci_write_config_byte(pdev, RENESAS_FW_STATUS, + RENESAS_FW_STATUS_DOWNLOAD_ENABLE); + if (err) + return pcibios_err_to_errno(err); + + /* 1 - 10 follow one step after the other. */ + for (i = 0; i < fw->size / 4; i++) { + err = renesas_fw_download_image(pdev, fw_data, i, false); + if (err) { + dev_err(&pdev->dev, + "Firmware Download Step %zd failed at position %zd bytes with (%d).", + i, i * 4, err); + return err; + } + } + + /* + * This sequence continues until the last data is written to + * "DATA0" or "DATA1". Naturally, we wait until "SET DATA0/1" + * is cleared by the hardware beforehand. + */ + for (i = 0; i < RENESAS_RETRY; i++) { + err = pci_read_config_byte(pdev, RENESAS_FW_STATUS_MSB, + &fw_status); + if (err) + return pcibios_err_to_errno(err); + if (!(fw_status & (BIT(0) | BIT(1)))) + break; + + udelay(RENESAS_DELAY); + } + if (i == RENESAS_RETRY) + dev_warn(&pdev->dev, "Final Firmware Download step timed out."); + + /* + * 11. After finishing writing the last data of FW, the + * System Software must clear "FW Download Enable" + */ + err = pci_write_config_byte(pdev, RENESAS_FW_STATUS, 0); + if (err) + return pcibios_err_to_errno(err); + + /* 12. Read "Result Code" and confirm it is good. */ + for (i = 0; i < RENESAS_RETRY; i++) { + err = pci_read_config_byte(pdev, RENESAS_FW_STATUS, &fw_status); + if (err) + return pcibios_err_to_errno(err); + if (fw_status & RENESAS_FW_STATUS_SUCCESS) + break; + + udelay(RENESAS_DELAY); + } + if (i == RENESAS_RETRY) { + /* Timed out / Error - let's see if we can fix this */ + err = renesas_fw_check_running(pdev); + switch (err) { + case 0: /* + * we shouldn't end up here. + * maybe it took a little bit longer. + * But all should be well? + */ + break; + + case 1: /* (No result yet! */ + dev_err(&pdev->dev, "FW Load timedout"); + return -ETIMEDOUT; + + default: + return err; + } + } + + return 0; +} + +static void renesas_rom_erase(struct pci_dev *pdev) +{ + int retval, i; + u8 status; + + dev_dbg(&pdev->dev, "Performing ROM Erase...\n"); + retval = pci_write_config_dword(pdev, RENESAS_DATA0, + RENESAS_ROM_ERASE_MAGIC); + if (retval) { + dev_err(&pdev->dev, "ROM erase, magic word write failed: %d\n", + pcibios_err_to_errno(retval)); + return; + } + + retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); + if (retval) { + dev_err(&pdev->dev, "ROM status read failed: %d\n", + pcibios_err_to_errno(retval)); + return; + } + status |= RENESAS_ROM_STATUS_ERASE; + retval = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, status); + if (retval) { + dev_err(&pdev->dev, "ROM erase set word write failed\n"); + return; + } + + /* sleep a bit while ROM is erased */ + msleep(20); + + for (i = 0; i < RENESAS_RETRY; i++) { + retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, + &status); + status &= RENESAS_ROM_STATUS_ERASE; + if (!status) + break; + + mdelay(RENESAS_DELAY); + } + + if (i == RENESAS_RETRY) + dev_dbg(&pdev->dev, "Chip erase timedout: %x\n", status); + + dev_dbg(&pdev->dev, "ROM Erase... Done success\n"); +} + +static bool renesas_setup_rom(struct pci_dev *pdev, const struct firmware *fw) +{ + const u32 *fw_data = (const u32 *)fw->data; + int err, i; + u8 status; + + /* 2. Write magic word to Data0 */ + err = pci_write_config_dword(pdev, RENESAS_DATA0, + RENESAS_ROM_WRITE_MAGIC); + if (err) + return false; + + /* 3. Set External ROM access */ + err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, + RENESAS_ROM_STATUS_ACCESS); + if (err) + goto remove_bypass; + + /* 4. Check the result */ + err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); + if (err) + goto remove_bypass; + status &= GENMASK(6, 4); + if (status) { + dev_err(&pdev->dev, + "setting external rom failed: %x\n", status); + goto remove_bypass; + } + + /* 5 to 16 Write FW to DATA0/1 while checking SetData0/1 */ + for (i = 0; i < fw->size / 4; i++) { + err = renesas_fw_download_image(pdev, fw_data, i, true); + if (err) { + dev_err(&pdev->dev, + "ROM Download Step %d failed at position %d bytes with (%d)\n", + i, i * 4, err); + goto remove_bypass; + } + } + + /* + * wait till DATA0/1 is cleared + */ + for (i = 0; i < RENESAS_RETRY; i++) { + err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS_MSB, + &status); + if (err) + goto remove_bypass; + if (!(status & (BIT(0) | BIT(1)))) + break; + + udelay(RENESAS_DELAY); + } + if (i == RENESAS_RETRY) { + dev_err(&pdev->dev, "Final Firmware ROM Download step timed out\n"); + goto remove_bypass; + } + + /* 17. Remove bypass */ + err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 0); + if (err) + return false; + + udelay(10); + + /* 18. check result */ + for (i = 0; i < RENESAS_RETRY; i++) { + err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); + if (err) { + dev_err(&pdev->dev, "Read ROM status failed:%d\n", + pcibios_err_to_errno(err)); + return false; + } + status &= RENESAS_ROM_STATUS_RESULT; + if (status == RENESAS_ROM_STATUS_SUCCESS) { + dev_dbg(&pdev->dev, "Download ROM success\n"); + break; + } + udelay(RENESAS_DELAY); + } + if (i == RENESAS_RETRY) { /* Timed out */ + dev_err(&pdev->dev, + "Download to external ROM TO: %x\n", status); + return false; + } + + dev_dbg(&pdev->dev, "Download to external ROM succeeded\n"); + + /* Last step set Reload */ + err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, + RENESAS_ROM_STATUS_RELOAD); + if (err) { + dev_err(&pdev->dev, "Set ROM execute failed: %d\n", + pcibios_err_to_errno(err)); + return false; + } + + /* + * wait till Reload is cleared + */ + for (i = 0; i < RENESAS_RETRY; i++) { + err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); + if (err) + return false; + if (!(status & RENESAS_ROM_STATUS_RELOAD)) + break; + + udelay(RENESAS_DELAY); + } + if (i == RENESAS_RETRY) { + dev_err(&pdev->dev, "ROM Exec timed out: %x\n", status); + return false; + } + + return true; + +remove_bypass: + pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 0); + return false; +} + +static int renesas_load_fw(struct pci_dev *pdev, const struct firmware *fw) +{ + int err = 0; + bool rom; + + /* Check if the device has external ROM */ + rom = renesas_check_rom(pdev); + if (rom) { + /* perform chip erase first */ + renesas_rom_erase(pdev); + + /* lets try loading fw on ROM first */ + rom = renesas_setup_rom(pdev, fw); + if (!rom) { + dev_dbg(&pdev->dev, + "ROM load failed, falling back on FW load\n"); + } else { + dev_dbg(&pdev->dev, + "ROM load success\n"); + goto exit; + } + } + + err = renesas_fw_download(pdev, fw); + +exit: + if (err) + dev_err(&pdev->dev, "firmware failed to download (%d).", err); + return err; +} + +int renesas_xhci_check_request_fw(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct xhci_driver_data *driver_data = + (struct xhci_driver_data *)id->driver_data; + const char *fw_name = driver_data->firmware; + const struct firmware *fw; + int err; + + err = renesas_fw_check_running(pdev); + /* Continue ahead, if the firmware is already running. */ + if (err == 0) + return 0; + + if (err != 1) + return err; + + pci_dev_get(pdev); + err = request_firmware(&fw, fw_name, &pdev->dev); + pci_dev_put(pdev); + if (err) { + dev_err(&pdev->dev, "request_firmware failed: %d\n", err); + return err; + } + + err = renesas_fw_verify(fw->data, fw->size); + if (err) + goto exit; + + err = renesas_load_fw(pdev, fw); +exit: + release_firmware(fw); + return err; +} +EXPORT_SYMBOL_GPL(renesas_xhci_check_request_fw); + +void renesas_xhci_pci_exit(struct pci_dev *dev) +{ +} +EXPORT_SYMBOL_GPL(renesas_xhci_pci_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 766b74723e64..ef513c2fb843 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -15,6 +15,7 @@ #include "xhci.h" #include "xhci-trace.h" +#include "xhci-pci.h" #define SSIC_PORT_NUM 2 #define SSIC_PORT_CFG2 0x880c @@ -87,7 +88,16 @@ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) { - struct pci_dev *pdev = to_pci_dev(dev); + struct pci_dev *pdev = to_pci_dev(dev); + struct xhci_driver_data *driver_data; + const struct pci_device_id *id; + + id = pci_match_id(pdev->driver->id_table, pdev); + + if (id && id->driver_data) { + driver_data = (struct xhci_driver_data *)id->driver_data; + xhci->quirks |= driver_data->quirks; + } /* Look for vendor-specific quirks */ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && @@ -327,10 +337,15 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; struct xhci_hcd *xhci; - struct hc_driver *driver; struct usb_hcd *hcd; + struct xhci_driver_data *driver_data; - driver = (struct hc_driver *)id->driver_data; + driver_data = (struct xhci_driver_data *)id->driver_data; + if (driver_data && driver_data->quirks & XHCI_RENESAS_FW_QUIRK) { + retval = renesas_xhci_check_request_fw(dev, id); + if (retval) + return retval; + } /* Prevent runtime suspending between USB-2 and USB-3 initialization */ pm_runtime_get_noresume(&dev->dev); @@ -341,7 +356,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) * to say USB 2.0, but I'm not sure what the implications would be in * the other parts of the HCD code. */ - retval = usb_hcd_pci_probe(dev, id); + retval = usb_hcd_pci_probe(dev, id, &xhci_pci_hc_driver); if (retval) goto put_runtime_pm; @@ -349,8 +364,8 @@ 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->shared_hcd = usb_create_shared_hcd(driver, &dev->dev, - pci_name(dev), hcd); + xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev, + pci_name(dev), hcd); if (!xhci->shared_hcd) { retval = -ENOMEM; goto dealloc_usb2_hcd; @@ -392,6 +407,9 @@ static void xhci_pci_remove(struct pci_dev *dev) struct xhci_hcd *xhci; xhci = hcd_to_xhci(pci_get_drvdata(dev)); + if (xhci->quirks & XHCI_RENESAS_FW_QUIRK) + renesas_xhci_pci_exit(dev); + xhci->xhc_state |= XHCI_STATE_REMOVING; if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW) @@ -543,15 +561,26 @@ static void xhci_pci_shutdown(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ +static const struct xhci_driver_data reneses_data = { + .quirks = XHCI_RENESAS_FW_QUIRK, + .firmware = "renesas_usb_fw.mem", +}; + /* PCI driver selection metadata; PCI hotplugging uses this */ -static const struct pci_device_id pci_ids[] = { { +static const struct pci_device_id pci_ids[] = { + { PCI_DEVICE(0x1912, 0x0014), + .driver_data = (unsigned long)&reneses_data, + }, + { PCI_DEVICE(0x1912, 0x0015), + .driver_data = (unsigned long)&reneses_data, + }, /* handle any USB 3.0 xHCI controller */ - PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0), - .driver_data = (unsigned long) &xhci_pci_hc_driver, + { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0), }, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(pci, pci_ids); +MODULE_FIRMWARE("renesas_usb_fw.mem"); /* pci driver glue; this is a "new style" PCI driver module */ static struct pci_driver xhci_pci_driver = { diff --git a/drivers/usb/host/xhci-pci.h b/drivers/usb/host/xhci-pci.h new file mode 100644 index 000000000000..4d749556e350 --- /dev/null +++ b/drivers/usb/host/xhci-pci.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2019-2020 Linaro Limited */ + +#ifndef XHCI_PCI_H +#define XHCI_PCI_H + +#if IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS) +int renesas_xhci_check_request_fw(struct pci_dev *dev, + const struct pci_device_id *id); +void renesas_xhci_pci_exit(struct pci_dev *dev); + +#else +int renesas_xhci_check_request_fw(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return 0; +} + +void renesas_xhci_pci_exit(struct pci_dev *dev) { }; + +#endif + +struct xhci_driver_data { + u64 quirks; + const char *firmware; +}; + +#endif diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index ea460b9682d5..38ac6efb2cc2 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -112,6 +112,10 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V3) }; +static const struct xhci_plat_priv xhci_plat_brcm = { + .quirks = XHCI_RESET_ON_RESUME, +}; + static const struct of_device_id usb_xhci_of_match[] = { { .compatible = "generic-xhci", @@ -147,6 +151,12 @@ static const struct of_device_id usb_xhci_of_match[] = { }, { .compatible = "renesas,rcar-gen3-xhci", .data = &xhci_plat_renesas_rcar_gen3, + }, { + .compatible = "brcm,xhci-brcm-v2", + .data = &xhci_plat_brcm, + }, { + .compatible = "brcm,bcm7445-xhci", + .data = &xhci_plat_brcm, }, {}, }; diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h index 5681723fc9cd..b49f6447bd3a 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * xhci-plat.h - xHCI host controller driver platform Bus Glue. * diff --git a/drivers/usb/host/xhci-rcar.h b/drivers/usb/host/xhci-rcar.h index 012744a63a49..048ad3b8a6c7 100644 --- a/drivers/usb/host/xhci-rcar.h +++ b/drivers/usb/host/xhci-rcar.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * drivers/usb/host/xhci-rcar.h * diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index b19582b2a72c..627abd236dbe 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * xHCI host controller driver * diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 86cfefdd6632..2c6c4f8d1ee1 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * xHCI host controller driver @@ -1873,6 +1873,7 @@ struct xhci_hcd { #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) #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) unsigned int num_active_eps; unsigned int limit_active_eps; diff --git a/drivers/usb/isp1760/isp1760-core.h b/drivers/usb/isp1760/isp1760-core.h index 97cb4d7a3e1c..d9a0a4cc467c 100644 --- a/drivers/usb/isp1760/isp1760-core.h +++ b/drivers/usb/isp1760/isp1760-core.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Driver for the NXP ISP1760 chip * diff --git a/drivers/usb/isp1760/isp1760-regs.h b/drivers/usb/isp1760/isp1760-regs.h index 1f00c3850cf7..fedc4f5cded0 100644 --- a/drivers/usb/isp1760/isp1760-regs.h +++ b/drivers/usb/isp1760/isp1760-regs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Driver for the NXP ISP1760 chip * diff --git a/drivers/usb/isp1760/isp1760-udc.h b/drivers/usb/isp1760/isp1760-udc.h index 2d0b88747701..d2df650d54e9 100644 --- a/drivers/usb/isp1760/isp1760-udc.h +++ b/drivers/usb/isp1760/isp1760-udc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Driver for the NXP ISP1761 device controller * diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 8a5e6bb07d05..c0fb9e1c5361 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ /* * sisusb - usb kernel driver for Net2280/SiS315 based USB2VGA dongles * diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index ace09985dae4..aa33bc81ee52 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* $XFree86$ */ /* $XdotOrg$ */ /* diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index 706d77090e00..3df64d2a9d43 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* * General structure definitions for universal mode switching modules * diff --git a/drivers/usb/misc/usb_u132.h b/drivers/usb/misc/usb_u132.h index 4bf77736914f..1584efbbd704 100644 --- a/drivers/usb/misc/usb_u132.h +++ b/drivers/usb/misc/usb_u132.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Common Header File for the Elan Digital Systems U132 adapter * this file should be included by both the "ftdi-u132" and diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 6087be236a35..d49db92ab26c 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * mtu3.h - MediaTek USB3 DRD header * diff --git a/drivers/usb/mtu3/mtu3_debug.h b/drivers/usb/mtu3/mtu3_debug.h index e96a69234d05..fb6b28277c9b 100644 --- a/drivers/usb/mtu3/mtu3_debug.h +++ b/drivers/usb/mtu3/mtu3_debug.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * mtu3_debug.h - debug header * diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h index 5e58c4dbd54a..760fe7d69c6b 100644 --- a/drivers/usb/mtu3/mtu3_dr.h +++ b/drivers/usb/mtu3/mtu3_dr.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * mtu3_dr.h - dual role switch and host glue layer header * diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h index 8382d066749e..bf34f784f84b 100644 --- a/drivers/usb/mtu3/mtu3_hw_regs.h +++ b/drivers/usb/mtu3/mtu3_hw_regs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * mtu3_hw_regs.h - MediaTek USB3 DRD register and field definitions * diff --git a/drivers/usb/mtu3/mtu3_qmu.h b/drivers/usb/mtu3/mtu3_qmu.h index 9cfde201db63..66e1c0ab5a99 100644 --- a/drivers/usb/mtu3/mtu3_qmu.h +++ b/drivers/usb/mtu3/mtu3_qmu.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * mtu3_qmu.h - Queue Management Unit driver header * diff --git a/drivers/usb/mtu3/mtu3_trace.h b/drivers/usb/mtu3/mtu3_trace.h index 050e30f0fbd4..1b897636daf2 100644 --- a/drivers/usb/mtu3/mtu3_trace.h +++ b/drivers/usb/mtu3/mtu3_trace.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /** * mtu3_trace.h - trace support * diff --git a/drivers/usb/musb/davinci.h b/drivers/usb/musb/davinci.h index e021485c83ae..c8e67d15b510 100644 --- a/drivers/usb/musb/davinci.h +++ b/drivers/usb/musb/davinci.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2005-2006 by Texas Instruments */ diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 290a2bc46606..dbe5623db1e0 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * MUSB OTG driver defines * diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h index c444a80fe1da..e5b3506c7b3f 100644 --- a/drivers/usb/musb/musb_debug.h +++ b/drivers/usb/musb/musb_debug.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * MUSB OTG driver debug defines * diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 4b4d8dc5d3f2..7d67b69df0a0 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * MUSB OTG driver DMA controller abstraction * diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h index d02663660813..f49f25b3bf56 100644 --- a/drivers/usb/musb/musb_gadget.h +++ b/drivers/usb/musb/musb_gadget.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * MUSB OTG driver peripheral defines * diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 2999845632ce..32336571f05c 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * MUSB OTG driver host defines * diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h index f17aabd95a50..12874d3b2a64 100644 --- a/drivers/usb/musb/musb_io.h +++ b/drivers/usb/musb/musb_io.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * MUSB OTG driver register I/O * diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index 5cd7264fc2cb..5fa110978f1a 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * MUSB OTG driver register defines * diff --git a/drivers/usb/musb/musb_trace.h b/drivers/usb/musb/musb_trace.h index b193daf69685..380ebc77eab1 100644 --- a/drivers/usb/musb/musb_trace.h +++ b/drivers/usb/musb/musb_trace.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * musb_trace.h - MUSB Controller Trace Support * diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h index 859008fa0e3c..939a0361ae88 100644 --- a/drivers/usb/musb/omap2430.h +++ b/drivers/usb/musb/omap2430.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2005-2006 by Texas Instruments */ diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h index fd8025bbece7..8a253564fb18 100644 --- a/drivers/usb/musb/tusb6010.h +++ b/drivers/usb/musb/tusb6010.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Definitions for TUSB6010 USB 2.0 OTG Dual Role controller * diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h index 43d410f6641b..fbcc28ad9964 100644 --- a/drivers/usb/phy/phy-fsl-usb.h +++ b/drivers/usb/phy/phy-fsl-usb.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* Copyright (C) 2007,2008 Freescale Semiconductor, Inc. */ #include <linux/usb/otg-fsm.h> diff --git a/drivers/usb/phy/phy-jz4770.c b/drivers/usb/phy/phy-jz4770.c index 3ea1f5b9bcf8..8f62dc2a90ff 100644 --- a/drivers/usb/phy/phy-jz4770.c +++ b/drivers/usb/phy/phy-jz4770.c @@ -125,13 +125,13 @@ static int jz4770_phy_init(struct usb_phy *phy) err = regulator_enable(priv->vcc_supply); if (err) { - dev_err(priv->dev, "Unable to enable VCC: %d", err); + dev_err(priv->dev, "Unable to enable VCC: %d\n", err); return err; } err = clk_prepare_enable(priv->clk); if (err) { - dev_err(priv->dev, "Unable to start clock: %d", err); + dev_err(priv->dev, "Unable to start clock: %d\n", err); return err; } @@ -191,7 +191,7 @@ static int jz4770_phy_probe(struct platform_device *pdev) priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { - dev_err(dev, "Failed to map registers"); + dev_err(dev, "Failed to map registers\n"); return PTR_ERR(priv->base); } @@ -199,7 +199,7 @@ static int jz4770_phy_probe(struct platform_device *pdev) if (IS_ERR(priv->clk)) { err = PTR_ERR(priv->clk); if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get clock"); + dev_err(dev, "Failed to get clock\n"); return err; } @@ -207,14 +207,14 @@ static int jz4770_phy_probe(struct platform_device *pdev) if (IS_ERR(priv->vcc_supply)) { err = PTR_ERR(priv->vcc_supply); if (err != -EPROBE_DEFER) - dev_err(dev, "failed to get regulator"); + dev_err(dev, "Failed to get regulator\n"); return err; } err = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2); if (err) { if (err != -EPROBE_DEFER) - dev_err(dev, "Unable to register PHY"); + dev_err(dev, "Unable to register PHY\n"); return err; } diff --git a/drivers/usb/phy/phy-mv-usb.h b/drivers/usb/phy/phy-mv-usb.h index 96701a1229ad..5d5c0abb0c3a 100644 --- a/drivers/usb/phy/phy-mv-usb.h +++ b/drivers/usb/phy/phy-mv-usb.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2011 Marvell International Ltd. All rights reserved. */ diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index ef1735d014da..eb34d762a63d 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-1.0+ +/* SPDX-License-Identifier: GPL-1.0+ */ /* * Renesas USB driver * diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index c3d3cc35cee0..7d3700bf41d9 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-1.0+ +/* SPDX-License-Identifier: GPL-1.0+ */ /* * Renesas USB driver * diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h index 65dc19ca528e..56b7106d254d 100644 --- a/drivers/usb/renesas_usbhs/mod.h +++ b/drivers/usb/renesas_usbhs/mod.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-1.0+ +/* SPDX-License-Identifier: GPL-1.0+ */ /* * Renesas USB driver * diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 3b130529408b..a4ae9f97d9cd 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-1.0+ +/* SPDX-License-Identifier: GPL-1.0+ */ /* * Renesas USB driver * diff --git a/drivers/usb/renesas_usbhs/rcar2.h b/drivers/usb/renesas_usbhs/rcar2.h index 7d88732c5bff..046d07edb36f 100644 --- a/drivers/usb/renesas_usbhs/rcar2.h +++ b/drivers/usb/renesas_usbhs/rcar2.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ #include "common.h" extern const struct renesas_usbhs_platform_info usbhs_rcar_gen2_plat_info; diff --git a/drivers/usb/renesas_usbhs/rcar3.h b/drivers/usb/renesas_usbhs/rcar3.h index c7c5ec1e3af2..d13db30bd21b 100644 --- a/drivers/usb/renesas_usbhs/rcar3.h +++ b/drivers/usb/renesas_usbhs/rcar3.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ #include "common.h" extern const struct renesas_usbhs_platform_info usbhs_rcar_gen3_plat_info; diff --git a/drivers/usb/renesas_usbhs/rza.h b/drivers/usb/renesas_usbhs/rza.h index 1ca42a6fd480..a29b75fef057 100644 --- a/drivers/usb/renesas_usbhs/rza.h +++ b/drivers/usb/renesas_usbhs/rza.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ #include "common.h" extern const struct renesas_usbhs_platform_info usbhs_rza1_plat_info; diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 5b17709821df..27d92af29635 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -49,8 +49,10 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role) mutex_lock(&sw->lock); ret = sw->set(sw, role); - if (!ret) + if (!ret) { sw->role = role; + kobject_uevent(&sw->dev.kobj, KOBJ_CHANGE); + } mutex_unlock(&sw->lock); diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h index 16ce06039a4d..a6505ceb6693 100644 --- a/drivers/usb/storage/debug.h +++ b/drivers/usb/storage/debug.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for USB Mass Storage compliant devices * Debugging Functions Header File diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index 2dbf9c7d9749..dcd7b7e5eda8 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Header file for Special Initializers for certain USB Mass Storage devices * diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h index 072f1ffda2af..1d102463a66c 100644 --- a/drivers/usb/storage/protocol.h +++ b/drivers/usb/storage/protocol.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for USB Mass Storage compliant devices * Protocol Functions Header File diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h index 2bc5ea045bf7..2a79c3ed4d86 100644 --- a/drivers/usb/storage/scsiglue.h +++ b/drivers/usb/storage/scsiglue.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for USB Mass Storage compliant devices * SCSI Connecting Glue Header File diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index e605cbc3d8bf..b9f78ef3edc3 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -129,15 +129,11 @@ int sierra_ms_init(struct us_data *us) int result, retries; struct swoc_info *swocInfo; struct usb_device *udev; - struct Scsi_Host *sh; retries = 3; result = 0; udev = us->pusb_dev; - sh = us_to_host(us); - scsi_get_host_dev(sh); - /* Force Modem mode */ if (swi_tru_install == TRU_FORCE_MODEM) { usb_stor_dbg(us, "SWIMS: Forcing Modem Mode\n"); diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index fb3bb4ee4ccf..74ffd0d7e7b6 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for USB Mass Storage compliant devices * Transport Functions Header File diff --git a/drivers/usb/storage/unusual_alauda.h b/drivers/usb/storage/unusual_alauda.h index 0ec8c99a4976..13f61ec88cde 100644 --- a/drivers/usb/storage/unusual_alauda.h +++ b/drivers/usb/storage/unusual_alauda.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for the Alauda-based card readers */ diff --git a/drivers/usb/storage/unusual_cypress.h b/drivers/usb/storage/unusual_cypress.h index fb99e526cd48..0547daf116a2 100644 --- a/drivers/usb/storage/unusual_cypress.h +++ b/drivers/usb/storage/unusual_cypress.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for devices based on the Cypress USB/ATA bridge * with support for ATACB diff --git a/drivers/usb/storage/unusual_datafab.h b/drivers/usb/storage/unusual_datafab.h index fdab5e7d68ca..5335b5d2bd79 100644 --- a/drivers/usb/storage/unusual_datafab.h +++ b/drivers/usb/storage/unusual_datafab.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for the Datafab USB Compact Flash reader */ diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index f6c3681fa2e9..b6a9a7451620 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for USB Mass Storage compliant devices * Unusual Devices File diff --git a/drivers/usb/storage/unusual_ene_ub6250.h b/drivers/usb/storage/unusual_ene_ub6250.h index 9134b91fbd73..a3b32abc2b2f 100644 --- a/drivers/usb/storage/unusual_ene_ub6250.h +++ b/drivers/usb/storage/unusual_ene_ub6250.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ #if defined(CONFIG_USB_STORAGE_ENE_UB6250) || \ defined(CONFIG_USB_STORAGE_ENE_UB6250_MODULE) diff --git a/drivers/usb/storage/unusual_freecom.h b/drivers/usb/storage/unusual_freecom.h index 949231c7a36b..9ca686364a93 100644 --- a/drivers/usb/storage/unusual_freecom.h +++ b/drivers/usb/storage/unusual_freecom.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for the Freecom USB/IDE adaptor */ diff --git a/drivers/usb/storage/unusual_isd200.h b/drivers/usb/storage/unusual_isd200.h index d03a02cc904e..f248190bd666 100644 --- a/drivers/usb/storage/unusual_isd200.h +++ b/drivers/usb/storage/unusual_isd200.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for In-System Design, Inc. ISD200 ASIC */ diff --git a/drivers/usb/storage/unusual_jumpshot.h b/drivers/usb/storage/unusual_jumpshot.h index c323338881ef..44878f849c1c 100644 --- a/drivers/usb/storage/unusual_jumpshot.h +++ b/drivers/usb/storage/unusual_jumpshot.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for the Lexar "Jumpshot" Compact Flash reader */ diff --git a/drivers/usb/storage/unusual_karma.h b/drivers/usb/storage/unusual_karma.h index 8f1eebd71d2c..9fbed4cbc895 100644 --- a/drivers/usb/storage/unusual_karma.h +++ b/drivers/usb/storage/unusual_karma.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for the Rio Karma */ diff --git a/drivers/usb/storage/unusual_onetouch.h b/drivers/usb/storage/unusual_onetouch.h index c76d4e990f7b..cdfee8f6cf37 100644 --- a/drivers/usb/storage/unusual_onetouch.h +++ b/drivers/usb/storage/unusual_onetouch.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for the Maxtor OneTouch USB hard drive's button */ diff --git a/drivers/usb/storage/unusual_realtek.h b/drivers/usb/storage/unusual_realtek.h index 7e14c2d7cf73..945dcb19d31d 100644 --- a/drivers/usb/storage/unusual_realtek.h +++ b/drivers/usb/storage/unusual_realtek.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for Realtek RTS51xx USB card reader * diff --git a/drivers/usb/storage/unusual_sddr09.h b/drivers/usb/storage/unusual_sddr09.h index 650cf2862754..bfb650974129 100644 --- a/drivers/usb/storage/unusual_sddr09.h +++ b/drivers/usb/storage/unusual_sddr09.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for SanDisk SDDR-09 SmartMedia reader */ diff --git a/drivers/usb/storage/unusual_sddr55.h b/drivers/usb/storage/unusual_sddr55.h index e89df2cea7bd..6d6f76eb0630 100644 --- a/drivers/usb/storage/unusual_sddr55.h +++ b/drivers/usb/storage/unusual_sddr55.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for SanDisk SDDR-55 SmartMedia reader */ diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 37157ed9a881..162b09d69f62 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for USB Attached SCSI devices - Unusual Devices File * diff --git a/drivers/usb/storage/unusual_usbat.h b/drivers/usb/storage/unusual_usbat.h index 05abf6870b8f..f9d3e5efc39d 100644 --- a/drivers/usb/storage/unusual_usbat.h +++ b/drivers/usb/storage/unusual_usbat.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Unusual Devices File for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable */ diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 5850d624cac7..0451fac1adce 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Driver for USB Mass Storage compliant devices * Main Header File diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 8d894bdff77d..c9234748537a 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -917,6 +917,12 @@ EXPORT_SYMBOL_GPL(typec_unregister_cable); /* ------------------------------------------------------------------------- */ /* USB Type-C ports */ +static const char * const typec_orientations[] = { + [TYPEC_ORIENTATION_NONE] = "unknown", + [TYPEC_ORIENTATION_NORMAL] = "normal", + [TYPEC_ORIENTATION_REVERSE] = "reverse", +}; + static const char * const typec_roles[] = { [TYPEC_SINK] = "sink", [TYPEC_SOURCE] = "source", @@ -1248,18 +1254,9 @@ static ssize_t orientation_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct typec_port *p = to_typec_port(dev); - enum typec_orientation orientation = typec_get_orientation(p); - - switch (orientation) { - case TYPEC_ORIENTATION_NORMAL: - return sprintf(buf, "%s\n", "normal"); - case TYPEC_ORIENTATION_REVERSE: - return sprintf(buf, "%s\n", "reverse"); - case TYPEC_ORIENTATION_NONE: - default: - return sprintf(buf, "%s\n", "unknown"); - } + struct typec_port *port = to_typec_port(dev); + + return sprintf(buf, "%s\n", typec_orientations[port->orientation]); } static DEVICE_ATTR_RO(orientation); @@ -1452,6 +1449,21 @@ void typec_set_pwr_opmode(struct typec_port *port, EXPORT_SYMBOL_GPL(typec_set_pwr_opmode); /** + * typec_find_orientation - Convert orientation string to enum typec_orientation + * @name: Orientation string + * + * This routine is used to find the typec_orientation by its string name @name. + * + * Returns the orientation value on success, otherwise negative error code. + */ +int typec_find_orientation(const char *name) +{ + return match_string(typec_orientations, ARRAY_SIZE(typec_orientations), + name); +} +EXPORT_SYMBOL_GPL(typec_find_orientation); + +/** * typec_find_port_power_role - Get the typec port power capability * @name: port power capability string * diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c index c22e5c4bbf1a..c9d47ff21921 100644 --- a/drivers/usb/typec/mux/intel_pmc_mux.c +++ b/drivers/usb/typec/mux/intel_pmc_mux.c @@ -92,6 +92,9 @@ struct pmc_usb_port { u8 usb2_port; u8 usb3_port; + + enum typec_orientation sbu_orientation; + enum typec_orientation hsl_orientation; }; struct pmc_usb { @@ -100,6 +103,22 @@ struct pmc_usb { struct pmc_usb_port *port; }; +static int sbu_orientation(struct pmc_usb_port *port) +{ + if (port->sbu_orientation) + return port->sbu_orientation - 1; + + return port->orientation - 1; +} + +static int hsl_orientation(struct pmc_usb_port *port) +{ + if (port->hsl_orientation) + return port->hsl_orientation - 1; + + return port->orientation - 1; +} + static int pmc_usb_command(struct pmc_usb_port *port, u8 *msg, u32 len) { u8 response[4]; @@ -152,8 +171,9 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state) req.mode_data = (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT; req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT; - req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_AUX_SHIFT; - req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_HSL_SHIFT; + + req.mode_data |= sbu_orientation(port) << PMC_USB_ALTMODE_ORI_AUX_SHIFT; + req.mode_data |= hsl_orientation(port) << PMC_USB_ALTMODE_ORI_HSL_SHIFT; req.mode_data |= (state->mode - TYPEC_STATE_MODAL) << PMC_USB_ALTMODE_DP_MODE_SHIFT; @@ -177,8 +197,9 @@ pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state) req.mode_data = (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT; req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT; - req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_AUX_SHIFT; - req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_HSL_SHIFT; + + req.mode_data |= sbu_orientation(port) << PMC_USB_ALTMODE_ORI_AUX_SHIFT; + req.mode_data |= hsl_orientation(port) << PMC_USB_ALTMODE_ORI_HSL_SHIFT; if (TBT_ADAPTER(data->device_mode) == TBT_ADAPTER_TBT3) req.mode_data |= PMC_USB_ALTMODE_TBT_TYPE; @@ -215,8 +236,8 @@ static int pmc_usb_connect(struct pmc_usb_port *port) msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT; - msg[1] |= (port->orientation - 1) << PMC_USB_MSG_ORI_HSL_SHIFT; - msg[1] |= (port->orientation - 1) << PMC_USB_MSG_ORI_AUX_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)); } @@ -300,6 +321,7 @@ static int pmc_usb_register_port(struct pmc_usb *pmc, int index, struct usb_role_switch_desc desc = { }; struct typec_switch_desc sw_desc = { }; struct typec_mux_desc mux_desc = { }; + const char *str; int ret; ret = fwnode_property_read_u8(fwnode, "usb2-port-number", &port->usb2_port); @@ -310,6 +332,14 @@ static int pmc_usb_register_port(struct pmc_usb *pmc, int index, if (ret) return ret; + ret = fwnode_property_read_string(fwnode, "sbu-orientation", &str); + if (!ret) + port->sbu_orientation = typec_find_orientation(str); + + ret = fwnode_property_read_string(fwnode, "hsl-orientation", &str); + if (!ret) + port->hsl_orientation = typec_find_orientation(str); + port->num = index; port->pmc = pmc; diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index b498960ff72b..b28facece43c 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -9,14 +9,13 @@ #include <linux/delay.h> #include <linux/errno.h> #include <linux/extcon.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/proc_fs.h> #include <linux/regulator/consumer.h> @@ -83,7 +82,7 @@ struct fusb302_chip { struct work_struct irq_work; bool irq_suspended; bool irq_while_suspended; - int gpio_int_n; + struct gpio_desc *gpio_int_n; int gpio_int_n_irq; struct extcon_dev *extcon; @@ -1618,30 +1617,17 @@ done: static int init_gpio(struct fusb302_chip *chip) { - struct device_node *node; + struct device *dev = chip->dev; int ret = 0; - node = chip->dev->of_node; - chip->gpio_int_n = of_get_named_gpio(node, "fcs,int_n", 0); - if (!gpio_is_valid(chip->gpio_int_n)) { - ret = chip->gpio_int_n; - dev_err(chip->dev, "cannot get named GPIO Int_N, ret=%d", ret); - return ret; - } - ret = devm_gpio_request(chip->dev, chip->gpio_int_n, "fcs,int_n"); - if (ret < 0) { - dev_err(chip->dev, "cannot request GPIO Int_N, ret=%d", ret); - return ret; - } - ret = gpio_direction_input(chip->gpio_int_n); - if (ret < 0) { - dev_err(chip->dev, - "cannot set GPIO Int_N to input, ret=%d", ret); - return ret; + chip->gpio_int_n = devm_gpiod_get(dev, "fcs,int_n", GPIOD_IN); + if (IS_ERR(chip->gpio_int_n)) { + dev_err(dev, "failed to request gpio_int_n\n"); + return PTR_ERR(chip->gpio_int_n); } - ret = gpio_to_irq(chip->gpio_int_n); + ret = gpiod_to_irq(chip->gpio_int_n); if (ret < 0) { - dev_err(chip->dev, + dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret); return ret; } diff --git a/drivers/usb/typec/tcpm/fusb302_reg.h b/drivers/usb/typec/tcpm/fusb302_reg.h index 00b39d365478..edc0e4b0f1e6 100644 --- a/drivers/usb/typec/tcpm/fusb302_reg.h +++ b/drivers/usb/typec/tcpm/fusb302_reg.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright 2016-2017 Google, Inc * diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c index 0698addd1185..b7c9fe5caabe 100644 --- a/drivers/usb/typec/tps6598x.c +++ b/drivers/usb/typec/tps6598x.c @@ -12,6 +12,7 @@ #include <linux/regmap.h> #include <linux/interrupt.h> #include <linux/usb/typec.h> +#include <linux/usb/role.h> /* Register offsets */ #define TPS_REG_VID 0x00 @@ -94,6 +95,7 @@ struct tps6598x { struct typec_port *port; struct typec_partner *partner; struct usb_pd_identity partner_identity; + struct usb_role_switch *role_sw; }; /* @@ -190,6 +192,23 @@ static int tps6598x_read_partner_identity(struct tps6598x *tps) return 0; } +static void tps6598x_set_data_role(struct tps6598x *tps, + enum typec_data_role role, bool connected) +{ + enum usb_role role_val; + + if (role == TYPEC_HOST) + role_val = USB_ROLE_HOST; + else + role_val = USB_ROLE_DEVICE; + + if (!connected) + role_val = USB_ROLE_NONE; + + usb_role_switch_set_role(tps->role_sw, role_val); + typec_set_data_role(tps->port, role); +} + static int tps6598x_connect(struct tps6598x *tps, u32 status) { struct typec_partner_desc desc; @@ -220,7 +239,7 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status) typec_set_pwr_opmode(tps->port, mode); typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status)); typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status)); - typec_set_data_role(tps->port, TPS_STATUS_DATAROLE(status)); + tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), true); tps->partner = typec_register_partner(tps->port, &desc); if (IS_ERR(tps->partner)) @@ -240,7 +259,7 @@ static void tps6598x_disconnect(struct tps6598x *tps, u32 status) typec_set_pwr_opmode(tps->port, TYPEC_PWR_MODE_USB); typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status)); typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status)); - typec_set_data_role(tps->port, TPS_STATUS_DATAROLE(status)); + tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), false); } static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, @@ -328,7 +347,7 @@ static int tps6598x_dr_set(struct typec_port *port, enum typec_data_role role) goto out_unlock; } - typec_set_data_role(tps->port, role); + tps6598x_set_data_role(tps, role, true); out_unlock: mutex_unlock(&tps->lock); @@ -452,6 +471,7 @@ static int tps6598x_probe(struct i2c_client *client) { struct typec_capability typec_cap = { }; struct tps6598x *tps; + struct fwnode_handle *fwnode; u32 status; u32 conf; u32 vid; @@ -495,11 +515,22 @@ static int tps6598x_probe(struct i2c_client *client) if (ret < 0) return ret; + fwnode = device_get_named_child_node(&client->dev, "connector"); + if (IS_ERR(fwnode)) + return PTR_ERR(fwnode); + + tps->role_sw = fwnode_usb_role_switch_get(fwnode); + if (IS_ERR(tps->role_sw)) { + ret = PTR_ERR(tps->role_sw); + goto err_fwnode_put; + } + typec_cap.revision = USB_TYPEC_REV_1_2; typec_cap.pd_revision = 0x200; typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; typec_cap.driver_data = tps; typec_cap.ops = &tps6598x_ops; + typec_cap.fwnode = fwnode; switch (TPS_SYSCONF_PORTINFO(conf)) { case TPS_PORTINFO_SINK_ACCESSORY: @@ -525,12 +556,16 @@ static int tps6598x_probe(struct i2c_client *client) typec_cap.data = TYPEC_PORT_DFP; break; default: - return -ENODEV; + ret = -ENODEV; + goto err_role_put; } tps->port = typec_register_port(&client->dev, &typec_cap); - if (IS_ERR(tps->port)) - return PTR_ERR(tps->port); + if (IS_ERR(tps->port)) { + ret = PTR_ERR(tps->port); + goto err_role_put; + } + fwnode_handle_put(fwnode); if (status & TPS_STATUS_PLUG_PRESENT) { ret = tps6598x_connect(tps, status); @@ -545,12 +580,19 @@ static int tps6598x_probe(struct i2c_client *client) if (ret) { tps6598x_disconnect(tps, 0); typec_unregister_port(tps->port); - return ret; + goto err_role_put; } i2c_set_clientdata(client, tps); return 0; + +err_role_put: + usb_role_switch_put(tps->role_sw); +err_fwnode_put: + fwnode_handle_put(fwnode); + + return ret; } static int tps6598x_remove(struct i2c_client *client) @@ -559,10 +601,17 @@ static int tps6598x_remove(struct i2c_client *client) tps6598x_disconnect(tps, 0); typec_unregister_port(tps->port); + usb_role_switch_put(tps->role_sw); return 0; } +static const struct of_device_id tps6598x_of_match[] = { + { .compatible = "ti,tps6598x", }, + {} +}; +MODULE_DEVICE_TABLE(of, tps6598x_of_match); + static const struct i2c_device_id tps6598x_id[] = { { "tps6598x" }, { } @@ -572,6 +621,7 @@ MODULE_DEVICE_TABLE(i2c, tps6598x_id); static struct i2c_driver tps6598x_i2c_driver = { .driver = { .name = "tps6598x", + .of_match_table = tps6598x_of_match, }, .probe_new = tps6598x_probe, .remove = tps6598x_remove, diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile index b35e15a1f02c..8a8eb5cb8e0f 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -7,6 +7,10 @@ typec_ucsi-y := ucsi.o typec_ucsi-$(CONFIG_TRACING) += trace.o +ifneq ($(CONFIG_POWER_SUPPLY),) + typec_ucsi-y += psy.o +endif + ifneq ($(CONFIG_TYPEC_DP_ALTMODE),) typec_ucsi-y += displayport.o endif diff --git a/drivers/usb/typec/ucsi/psy.c b/drivers/usb/typec/ucsi/psy.c new file mode 100644 index 000000000000..26ed0b520749 --- /dev/null +++ b/drivers/usb/typec/ucsi/psy.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Power Supply for UCSI + * + * Copyright (C) 2020, Intel Corporation + * Author: K V, Abhilash <abhilash.k.v@intel.com> + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> + */ + +#include <linux/property.h> +#include <linux/usb/pd.h> + +#include "ucsi.h" + +/* Power Supply access to expose source power information */ +enum ucsi_psy_online_states { + UCSI_PSY_OFFLINE = 0, + UCSI_PSY_FIXED_ONLINE, + UCSI_PSY_PROG_ONLINE, +}; + +static enum power_supply_property ucsi_psy_props[] = { + POWER_SUPPLY_PROP_USB_TYPE, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_MIN, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_CURRENT_NOW, +}; + +static int ucsi_psy_get_online(struct ucsi_connector *con, + union power_supply_propval *val) +{ + val->intval = UCSI_PSY_OFFLINE; + if (con->status.flags & UCSI_CONSTAT_CONNECTED && + (con->status.flags & UCSI_CONSTAT_PWR_DIR) == TYPEC_SINK) + val->intval = UCSI_PSY_FIXED_ONLINE; + return 0; +} + +static int ucsi_psy_get_voltage_min(struct ucsi_connector *con, + union power_supply_propval *val) +{ + u32 pdo; + + switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { + case UCSI_CONSTAT_PWR_OPMODE_PD: + pdo = con->src_pdos[0]; + val->intval = pdo_fixed_voltage(pdo) * 1000; + break; + case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: + case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: + case UCSI_CONSTAT_PWR_OPMODE_BC: + case UCSI_CONSTAT_PWR_OPMODE_DEFAULT: + val->intval = UCSI_TYPEC_VSAFE5V * 1000; + break; + default: + val->intval = 0; + break; + } + return 0; +} + +static int ucsi_psy_get_voltage_max(struct ucsi_connector *con, + union power_supply_propval *val) +{ + u32 pdo; + + switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { + case UCSI_CONSTAT_PWR_OPMODE_PD: + if (con->num_pdos > 0) { + pdo = con->src_pdos[con->num_pdos - 1]; + val->intval = pdo_fixed_voltage(pdo) * 1000; + } else { + val->intval = 0; + } + break; + case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: + case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: + case UCSI_CONSTAT_PWR_OPMODE_BC: + case UCSI_CONSTAT_PWR_OPMODE_DEFAULT: + val->intval = UCSI_TYPEC_VSAFE5V * 1000; + break; + default: + val->intval = 0; + break; + } + return 0; +} + +static int ucsi_psy_get_voltage_now(struct ucsi_connector *con, + union power_supply_propval *val) +{ + int index; + u32 pdo; + + switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { + case UCSI_CONSTAT_PWR_OPMODE_PD: + index = rdo_index(con->rdo); + if (index > 0) { + pdo = con->src_pdos[index - 1]; + val->intval = pdo_fixed_voltage(pdo) * 1000; + } else { + val->intval = 0; + } + break; + case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: + case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: + case UCSI_CONSTAT_PWR_OPMODE_BC: + case UCSI_CONSTAT_PWR_OPMODE_DEFAULT: + val->intval = UCSI_TYPEC_VSAFE5V * 1000; + break; + default: + val->intval = 0; + break; + } + return 0; +} + +static int ucsi_psy_get_current_max(struct ucsi_connector *con, + union power_supply_propval *val) +{ + u32 pdo; + + switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { + case UCSI_CONSTAT_PWR_OPMODE_PD: + if (con->num_pdos > 0) { + pdo = con->src_pdos[con->num_pdos - 1]; + val->intval = pdo_max_current(pdo) * 1000; + } else { + val->intval = 0; + } + break; + case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: + val->intval = UCSI_TYPEC_1_5_CURRENT * 1000; + break; + case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: + val->intval = UCSI_TYPEC_3_0_CURRENT * 1000; + break; + case UCSI_CONSTAT_PWR_OPMODE_BC: + case UCSI_CONSTAT_PWR_OPMODE_DEFAULT: + /* UCSI can't tell b/w DCP/CDP or USB2/3x1/3x2 SDP chargers */ + default: + val->intval = 0; + break; + } + return 0; +} + +static int ucsi_psy_get_current_now(struct ucsi_connector *con, + union power_supply_propval *val) +{ + u16 flags = con->status.flags; + + if (UCSI_CONSTAT_PWR_OPMODE(flags) == UCSI_CONSTAT_PWR_OPMODE_PD) + val->intval = rdo_op_current(con->rdo) * 1000; + else + val->intval = 0; + return 0; +} + +static int ucsi_psy_get_usb_type(struct ucsi_connector *con, + union power_supply_propval *val) +{ + u16 flags = con->status.flags; + + val->intval = POWER_SUPPLY_USB_TYPE_C; + if (flags & UCSI_CONSTAT_CONNECTED && + UCSI_CONSTAT_PWR_OPMODE(flags) == UCSI_CONSTAT_PWR_OPMODE_PD) + val->intval = POWER_SUPPLY_USB_TYPE_PD; + + return 0; +} + +static int ucsi_psy_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct ucsi_connector *con = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_USB_TYPE: + return ucsi_psy_get_usb_type(con, val); + case POWER_SUPPLY_PROP_ONLINE: + return ucsi_psy_get_online(con, val); + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + return ucsi_psy_get_voltage_min(con, val); + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + return ucsi_psy_get_voltage_max(con, val); + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + return ucsi_psy_get_voltage_now(con, val); + case POWER_SUPPLY_PROP_CURRENT_MAX: + return ucsi_psy_get_current_max(con, val); + case POWER_SUPPLY_PROP_CURRENT_NOW: + return ucsi_psy_get_current_now(con, val); + default: + return -EINVAL; + } +} + +static enum power_supply_usb_type ucsi_psy_usb_types[] = { + POWER_SUPPLY_USB_TYPE_C, + POWER_SUPPLY_USB_TYPE_PD, + POWER_SUPPLY_USB_TYPE_PD_PPS, +}; + +int ucsi_register_port_psy(struct ucsi_connector *con) +{ + struct power_supply_config psy_cfg = {}; + struct device *dev = con->ucsi->dev; + char *psy_name; + + psy_cfg.drv_data = con; + psy_cfg.fwnode = dev_fwnode(dev); + + psy_name = devm_kasprintf(dev, GFP_KERNEL, "ucsi-source-psy-%s%d", + dev_name(dev), con->num); + if (!psy_name) + return -ENOMEM; + + con->psy_desc.name = psy_name; + con->psy_desc.type = POWER_SUPPLY_TYPE_USB, + con->psy_desc.usb_types = ucsi_psy_usb_types; + con->psy_desc.num_usb_types = ARRAY_SIZE(ucsi_psy_usb_types); + con->psy_desc.properties = ucsi_psy_props, + con->psy_desc.num_properties = ARRAY_SIZE(ucsi_psy_props), + con->psy_desc.get_property = ucsi_psy_get_prop; + + con->psy = power_supply_register(dev, &con->psy_desc, &psy_cfg); + + return PTR_ERR_OR_ZERO(con->psy); +} + +void ucsi_unregister_port_psy(struct ucsi_connector *con) +{ + if (IS_ERR_OR_NULL(con->psy)) + return; + + power_supply_unregister(con->psy); +} diff --git a/drivers/usb/typec/ucsi/trace.c b/drivers/usb/typec/ucsi/trace.c index 48ad1dc1b1b2..cb62ad835761 100644 --- a/drivers/usb/typec/ucsi/trace.c +++ b/drivers/usb/typec/ucsi/trace.c @@ -35,16 +35,16 @@ const char *ucsi_cmd_str(u64 raw_cmd) const char *ucsi_cci_str(u32 cci) { - if (cci & GENMASK(7, 0)) { - if (cci & BIT(29)) + if (UCSI_CCI_CONNECTOR(cci)) { + if (cci & UCSI_CCI_ACK_COMPLETE) return "Event pending (ACK completed)"; - if (cci & BIT(31)) + if (cci & UCSI_CCI_COMMAND_COMPLETE) return "Event pending (command completed)"; return "Connector Change"; } - if (cci & BIT(29)) + if (cci & UCSI_CCI_ACK_COMPLETE) return "ACK completed"; - if (cci & BIT(31)) + if (cci & UCSI_CCI_COMMAND_COMPLETE) return "Command completed"; return ""; diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index ddf2ad3752de..d0c63afaf345 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -492,19 +492,45 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient) } } +static void ucsi_get_pdos(struct ucsi_connector *con, int is_partner) +{ + struct ucsi *ucsi = con->ucsi; + u64 command; + int ret; + + command = UCSI_COMMAND(UCSI_GET_PDOS) | UCSI_CONNECTOR_NUMBER(con->num); + command |= UCSI_GET_PDOS_PARTNER_PDO(is_partner); + command |= UCSI_GET_PDOS_NUM_PDOS(UCSI_MAX_PDOS - 1); + command |= UCSI_GET_PDOS_SRC_PDOS; + ret = ucsi_run_command(ucsi, command, con->src_pdos, + sizeof(con->src_pdos)); + if (ret < 0) { + dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret); + return; + } + con->num_pdos = ret / sizeof(u32); /* number of bytes to 32-bit PDOs */ + if (ret == 0) + dev_warn(ucsi->dev, "UCSI_GET_PDOS returned 0 bytes\n"); +} + static void ucsi_pwr_opmode_change(struct ucsi_connector *con) { switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { case UCSI_CONSTAT_PWR_OPMODE_PD: + con->rdo = con->status.request_data_obj; typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_PD); + ucsi_get_pdos(con, 1); break; case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: + con->rdo = 0; typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_1_5A); break; case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: + con->rdo = 0; typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_3_0A); break; default: + con->rdo = 0; typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_USB); break; } @@ -566,6 +592,8 @@ static void ucsi_partner_change(struct ucsi_connector *con) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: + case UCSI_CONSTAT_PARTNER_TYPE_CABLE: + case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: @@ -611,7 +639,8 @@ static void ucsi_handle_connector_change(struct work_struct *work) role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); - if (con->status.change & UCSI_CONSTAT_POWER_OPMODE_CHANGE) + if (con->status.change & UCSI_CONSTAT_POWER_OPMODE_CHANGE || + con->status.change & UCSI_CONSTAT_POWER_LEVEL_CHANGE) ucsi_pwr_opmode_change(con); if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) { @@ -627,6 +656,8 @@ static void ucsi_handle_connector_change(struct work_struct *work) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: + case UCSI_CONSTAT_PARTNER_TYPE_CABLE: + case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: @@ -905,6 +936,10 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) cap->driver_data = con; cap->ops = &ucsi_ops; + ret = ucsi_register_port_psy(con); + if (ret) + return ret; + /* Register the connector */ con->port = typec_register_port(ucsi->dev, cap); if (IS_ERR(con->port)) @@ -927,6 +962,8 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: + case UCSI_CONSTAT_PARTNER_TYPE_CABLE: + case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: typec_set_data_role(con->port, TYPEC_HOST); break; case UCSI_CONSTAT_PARTNER_TYPE_DFP: @@ -1029,6 +1066,7 @@ err_unregister: for (con = ucsi->connector; con->port; con++) { ucsi_unregister_partner(con); ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON); + ucsi_unregister_port_psy(con); typec_unregister_port(con->port); con->port = NULL; } @@ -1152,6 +1190,7 @@ void ucsi_unregister(struct ucsi *ucsi) ucsi_unregister_partner(&ucsi->connector[i]); ucsi_unregister_altmodes(&ucsi->connector[i], UCSI_RECIPIENT_CON); + ucsi_unregister_port_psy(&ucsi->connector[i]); typec_unregister_port(ucsi->connector[i].port); } diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 8e831108f481..cba6f77bea61 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -5,6 +5,7 @@ #include <linux/bitops.h> #include <linux/device.h> +#include <linux/power_supply.h> #include <linux/types.h> #include <linux/usb/typec.h> @@ -21,7 +22,7 @@ struct ucsi_altmode; #define UCSI_MESSAGE_OUT 32 /* Command Status and Connector Change Indication (CCI) bits */ -#define UCSI_CCI_CONNECTOR(_c_) (((_c_) & GENMASK(7, 0)) >> 1) +#define UCSI_CCI_CONNECTOR(_c_) (((_c_) & GENMASK(7, 1)) >> 1) #define UCSI_CCI_LENGTH(_c_) (((_c_) & GENMASK(15, 8)) >> 8) #define UCSI_CCI_NOT_SUPPORTED BIT(25) #define UCSI_CCI_CANCEL_COMPLETE BIT(26) @@ -130,6 +131,11 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); #define UCSI_GET_ALTMODE_OFFSET(_r_) ((u64)(_r_) << 32) #define UCSI_GET_ALTMODE_NUM_ALTMODES(_r_) ((u64)(_r_) << 40) +/* GET_PDOS command bits */ +#define UCSI_GET_PDOS_PARTNER_PDO(_r_) ((u64)(_r_) << 23) +#define UCSI_GET_PDOS_NUM_PDOS(_r_) ((u64)(_r_) << 32) +#define UCSI_GET_PDOS_SRC_PDOS ((u64)1 << 34) + /* -------------------------------------------------------------------------- */ /* Error information returned by PPM in response to GET_ERROR_STATUS command. */ @@ -294,6 +300,11 @@ struct ucsi { #define UCSI_MAX_SVID 5 #define UCSI_MAX_ALTMODES (UCSI_MAX_SVID * 6) +#define UCSI_MAX_PDOS (4) + +#define UCSI_TYPEC_VSAFE5V 5000 +#define UCSI_TYPEC_1_5_CURRENT 1500 +#define UCSI_TYPEC_3_0_CURRENT 3000 struct ucsi_connector { int num; @@ -313,6 +324,11 @@ struct ucsi_connector { struct ucsi_connector_status status; struct ucsi_connector_capability cap; + struct power_supply *psy; + struct power_supply_desc psy_desc; + u32 rdo; + u32 src_pdos[UCSI_MAX_PDOS]; + int num_pdos; }; int ucsi_send_command(struct ucsi *ucsi, u64 command, @@ -321,6 +337,14 @@ int ucsi_send_command(struct ucsi *ucsi, u64 command, void ucsi_altmode_update_active(struct ucsi_connector *con); int ucsi_resume(struct ucsi *ucsi); +#if IS_ENABLED(CONFIG_POWER_SUPPLY) +int ucsi_register_port_psy(struct ucsi_connector *con); +void ucsi_unregister_port_psy(struct ucsi_connector *con); +#else +static inline int ucsi_register_port_psy(struct ucsi_connector *con) { return 0; } +static inline void ucsi_unregister_port_psy(struct ucsi_connector *con) { } +#endif /* CONFIG_POWER_SUPPLY */ + #if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE) struct typec_altmode * ucsi_register_displayport(struct ucsi_connector *con, diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index e12105ed3834..3dbb42c637c1 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -479,7 +479,8 @@ extern void usb_hcd_platform_shutdown(struct platform_device *dev); struct pci_dev; struct pci_device_id; extern int usb_hcd_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id); + const struct pci_device_id *id, + const struct hc_driver *driver); extern void usb_hcd_pci_remove(struct pci_dev *dev); extern void usb_hcd_pci_shutdown(struct pci_dev *dev); diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index b00a2642a9cd..5daa1c49761c 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -254,6 +254,7 @@ int typec_set_mode(struct typec_port *port, int mode); void *typec_get_drvdata(struct typec_port *port); +int typec_find_orientation(const char *name); int typec_find_port_power_role(const char *name); int typec_find_power_role(const char *name); int typec_find_port_data_role(const char *name); |