diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-07-29 10:17:10 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-07-29 10:17:10 -0700 |
commit | 4eee1520ea845a6d6d82e85498d9412419560871 (patch) | |
tree | afdf2e9891a35c3223000e957d560683c4192f09 | |
parent | 91e60731dd605c5d6bab8b9ccac886da1780d5ca (diff) | |
parent | 51d4b0a44c82e5eff056ef76acd2c3c605a8eb74 (diff) |
Merge tag 'usb-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB / Thunderbolt updates from Greg KH:
"Here is the big set of USB and Thunderbolt driver changes for
6.17-rc1.
Lots of little things in here, mostly all small cleanups and updates,
no major new features this development cycle. Stuff included in here
is:
- xhci minor tweaks for error handling
- typec minor updates and a driver update
- gadget driver api cleanups
- unused function removals
- unbind memory leak fixes
- a few new device ids added
- a few new devices supported for some drivers
- other minor cleanups and changes
All of these have been in linux-next with no reported issues, with the
leak fixes being in the shortest amount of time, but they are
'obviously correct' :)"
* tag 'usb-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (100 commits)
usb: musb: omap2430: clean up probe error handling
usb: musb: omap2430: fix device leak at unbind
usb: gadget: udc: renesas_usb3: fix device leak at unbind
usb: dwc3: meson-g12a: fix device leaks at unbind
usb: dwc3: imx8mp: fix device leak at unbind
usb: musb: omap2430: enable compile testing
usb: gadget: udc: renesas_usb3: drop unused module alias
usb: xhci: print xhci->xhc_state when queue_command failed
usb: atm: cxacru: Merge cxacru_upload_firmware() into cxacru_heavy_init()
USB: serial: option: add Foxconn T99W709
usb: core: add urb->sgt parameter description
thunderbolt: Fix copy+paste error in match_service_id()
usb: typec: ucsi: Update power_supply on power role change
usb: typec: ucsi: psy: Set current max to 100mA for BC 1.2 and Default
usb: typec: fusb302: cache PD RX state
usb: typec: ucsi: yoga-c630: add DRM dependency
usb: gadget : fix use-after-free in composite_dev_cleanup()
usb: chipidea: imx: Add a missing blank line
usb: gadget: f_uac1: replace scnprintf() with sysfs_emit()
usb: usblp: clean up assignment inside if conditions
...
93 files changed, 983 insertions, 650 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-typec-displayport b/Documentation/ABI/testing/sysfs-driver-typec-displayport index 256c87c5219a..314acd54e13e 100644 --- a/Documentation/ABI/testing/sysfs-driver-typec-displayport +++ b/Documentation/ABI/testing/sysfs-driver-typec-displayport @@ -62,3 +62,13 @@ Description: by VESA DisplayPort Alt Mode on USB Type-C Standard. - 0 when HPD’s logical state is low (HPD_Low) as defined by VESA DisplayPort Alt Mode on USB Type-C Standard. + +What: /sys/bus/typec/devices/.../displayport/irq_hpd +Date: June 2025 +Contact: RD Babiera <rdbabiera@google.com> +Description: + IRQ_HPD events are sent over the USB PD protocol in Status Update and + Attention messages. IRQ_HPD can only be asserted when HPD is high, + and is asserted when an IRQ_HPD has been issued since the last Status + Update. This is a read only node that returns the number of IRQ events + raised in the driver's lifetime. diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml index cc5787a8cfa3..691d6cf02c27 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml @@ -23,6 +23,7 @@ properties: - nvidia,tegra30-udc - nvidia,tegra114-udc - nvidia,tegra124-udc + - nxp,s32g2-usb - qcom,ci-hdrc - items: - enum: @@ -37,6 +38,10 @@ properties: - enum: - nuvoton,npcm845-udc - const: nuvoton,npcm750-udc + - items: + - enum: + - nxp,s32g3-usb + - const: nxp,s32g2-usb clocks: minItems: 1 diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml index e83d30a91b88..6c3a10991b8b 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.yaml +++ b/Documentation/devicetree/bindings/usb/dwc2.yaml @@ -59,7 +59,7 @@ properties: - const: amcc,dwc-otg - const: apm,apm82181-dwc-otg - const: snps,dwc2 - - const: sophgo,cv1800-usb + - const: sophgo,cv1800b-usb - const: st,stm32f4x9-fsotg - const: st,stm32f4x9-hsotg - const: st,stm32f7-hsotg diff --git a/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml index 019435540df0..ca677d1a8274 100644 --- a/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml +++ b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml @@ -21,6 +21,8 @@ properties: - fsl,imx53-usbmisc - fsl,imx6q-usbmisc - fsl,vf610-usbmisc + - nxp,s32g2-usbmisc + - nxp,s32g3-usbmisc - items: - enum: - fsl,imx6ul-usbmisc diff --git a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml index 6fe2d356dcbd..9a94b2a74a1e 100644 --- a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml +++ b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml @@ -26,19 +26,26 @@ properties: description: The regulator that provides 3.3V or 5.0V core power to the hub. - peer-hub: - $ref: /schemas/types.yaml#/definitions/phandle - description: - For onboard hub controllers that support USB 3.x and USB 2.0 hubs - with shared resets and power supplies, this property is used to identify - the hubs with which these are shared. + peer-hub: true + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + patternProperties: + '^port@': + $ref: /schemas/graph.yaml#/properties/port + + properties: + reg: + minimum: 1 + maximum: 4 required: - compatible - reg allOf: - - $ref: usb-device.yaml# + - $ref: usb-hub.yaml# - if: properties: compatible: @@ -62,13 +69,6 @@ allOf: peer-hub: true vdd-supply: true -patternProperties: - "^.*@[0-9a-f]{1,2}$": - description: The hard wired USB devices - type: object - $ref: /schemas/usb/usb-device.yaml - additionalProperties: true - unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt b/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt deleted file mode 100644 index 29f12a533f66..000000000000 --- a/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt +++ /dev/null @@ -1,28 +0,0 @@ -* NXP LPC32xx SoC USB Device Controller (UDC) - -Required properties: -- compatible: Must be "nxp,lpc3220-udc" -- reg: Physical base address of the controller and length of memory mapped - region. -- interrupts: The USB interrupts: - * USB Device Low Priority Interrupt - * USB Device High Priority Interrupt - * USB Device DMA Interrupt - * External USB Transceiver Interrupt (OTG ATX) -- transceiver: phandle of the associated ISP1301 device - this is necessary for - the UDC controller for connecting to the USB physical layer - -Example: - - isp1301: usb-transceiver@2c { - compatible = "nxp,isp1301"; - reg = <0x2c>; - }; - - usbd@31020000 { - compatible = "nxp,lpc3220-udc"; - reg = <0x31020000 0x300>; - interrupt-parent = <&mic>; - interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>; - transceiver = <&isp1301>; - }; diff --git a/Documentation/devicetree/bindings/usb/nxp,lpc3220-udc.yaml b/Documentation/devicetree/bindings/usb/nxp,lpc3220-udc.yaml new file mode 100644 index 000000000000..be0457a06861 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/nxp,lpc3220-udc.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/nxp,lpc3220-udc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP LPC32xx SoC USB Device Controller (UDC) + +maintainers: + - Frank Li <Frank.Li@nxp.com> + +properties: + compatible: + const: nxp,lpc3220-udc + + reg: + maxItems: 1 + + interrupts: + items: + - description: USB Device Low Priority Interrupt + - description: USB Device High Priority Interrupt + - description: USB Device DMA Interrupt + - description: External USB Transceiver Interrupt (OTG ATX) + + clocks: + maxItems: 1 + + transceiver: + description: + phandle of the associated ISP1301 device - this is necessary for + the UDC controller for connecting to the USB physical layer + +required: + - compatible + - reg + - interrupts + - transceiver + +additionalProperties: false + +examples: + - | + usbd@31020000 { + compatible = "nxp,lpc3220-udc"; + reg = <0x31020000 0x300>; + interrupt-parent = <&mic>; + interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>; + transceiver = <&isp1301>; + }; diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml index 6f4d41ba6ca7..a19816bbb1fd 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml @@ -27,6 +27,7 @@ properties: - renesas,usbhs-r9a07g044 # RZ/G2{L,LC} - renesas,usbhs-r9a07g054 # RZ/V2L - renesas,usbhs-r9a08g045 # RZ/G3S + - renesas,usbhs-r9a09g056 # RZ/V2N - renesas,usbhs-r9a09g057 # RZ/V2H(P) - const: renesas,rzg2l-usbhs diff --git a/Documentation/driver-api/usb/anchors.rst b/Documentation/driver-api/usb/anchors.rst index 4b248e691bd6..5a93d171e76c 100644 --- a/Documentation/driver-api/usb/anchors.rst +++ b/Documentation/driver-api/usb/anchors.rst @@ -45,17 +45,6 @@ This function kills all URBs associated with an anchor. The URBs are called in the reverse temporal order they were submitted. This way no data can be reordered. -:c:func:`usb_unlink_anchored_urbs` ----------------------------------- - - -This function unlinks all URBs associated with an anchor. The URBs -are processed in the reverse temporal order they were submitted. -This is similar to :c:func:`usb_kill_anchored_urbs`, but it will not sleep. -Therefore no guarantee is made that the URBs have been unlinked when -the call returns. They may be unlinked later but will be unlinked in -finite time. - :c:func:`usb_scuttle_anchored_urbs` ----------------------------------- diff --git a/Documentation/usb/gadget_configfs.rst b/Documentation/usb/gadget_configfs.rst index 868e118a2644..ada57c0e34aa 100644 --- a/Documentation/usb/gadget_configfs.rst +++ b/Documentation/usb/gadget_configfs.rst @@ -92,7 +92,7 @@ Then the strings can be specified:: Further custom string descriptors can be created as directories within the language's directory, with the string text being written to the "s" attribute -within the string's directory: +within the string's directory:: $ mkdir strings/0x409/xu.0 $ echo <string text> > strings/0x409/xu.0/s @@ -104,9 +104,9 @@ string descriptors to associate those strings with class descriptors. ------------------------------ Each gadget will consist of a number of configurations, their corresponding -directories must be created: +directories must be created:: -$ mkdir configs/<name>.<number> + $ mkdir configs/<name>.<number> where <name> can be any string which is legal in a filesystem and the <number> is the configuration's number, e.g.:: @@ -246,7 +246,7 @@ a symlink to a function being removed from the configuration, e.g.:: ... ... -Remove strings directories in configurations: +Remove strings directories in configurations:: $ rmdir configs/<config name>.<number>/strings/<lang> @@ -270,7 +270,7 @@ e.g.:: ... ... -Remove functions (function modules are not unloaded, though): +Remove functions (function modules are not unloaded, though):: $ rmdir functions/<name>.<instance name> @@ -369,18 +369,18 @@ For more information on configfs please see The concepts described above translate to USB gadgets like this: 1. A gadget has its config group, which has some attributes (idVendor, -idProduct etc) and default sub-groups (configs, functions, strings). -Writing to the attributes causes the information to be stored in -appropriate locations. In the configs, functions and strings sub-groups -a user can create their sub-groups to represent configurations, functions, -and groups of strings in a given language. + idProduct etc) and default sub-groups (configs, functions, strings). + Writing to the attributes causes the information to be stored in appropriate + locations. In the configs, functions and strings sub-groups a user can + create their sub-groups to represent configurations, functions, and groups + of strings in a given language. 2. The user creates configurations and functions, in the configurations -creates symbolic links to functions. This information is used when the -gadget's UDC attribute is written to, which means binding the gadget -to the UDC. The code in drivers/usb/gadget/configfs.c iterates over -all configurations, and in each configuration it iterates over all -functions and binds them. This way the whole gadget is bound. + creates symbolic links to functions. This information is used when the + gadget's UDC attribute is written to, which means binding the gadget to the + UDC. The code in drivers/usb/gadget/configfs.c iterates over all + configurations, and in each configuration it iterates over all functions and + binds them. This way the whole gadget is bound. 3. The file drivers/usb/gadget/configfs.c contains code for @@ -388,13 +388,12 @@ functions and binds them. This way the whole gadget is bound. - gadget's default groups (configs, functions, strings) - associating functions with configurations (symlinks) -4. Each USB function naturally has its own view of what it wants -configured, so config_groups for particular functions are defined -in the functions implementation files drivers/usb/gadget/f_*.c. +4. Each USB function naturally has its own view of what it wants configured, so + config_groups for particular functions are defined in the functions + implementation files drivers/usb/gadget/f_*.c. 5. Function's code is written in such a way that it uses - -usb_get_function_instance(), which, in turn, calls request_module. -So, provided that modprobe works, modules for particular functions -are loaded automatically. Please note that the converse is not true: -after a gadget is disabled and torn down, the modules remain loaded. + usb_get_function_instance(), which, in turn, calls request_module. So, + provided that modprobe works, modules for particular functions are loaded + automatically. Please note that the converse is not true: after a gadget is + disabled and torn down, the modules remain loaded. diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi index ea1456d361a3..4be6534ed01d 100644 --- a/arch/arm64/boot/dts/freescale/s32g2.dtsi +++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi @@ -376,6 +376,29 @@ status = "disabled"; }; + usbmisc: usbmisc@44064200 { + #index-cells = <1>; + compatible = "nxp,s32g2-usbmisc"; + reg = <0x44064200 0x200>; + }; + + usbotg: usb@44064000 { + compatible = "nxp,s32g2-usb"; + reg = <0x44064000 0x200>; + interrupt-parent = <&gic>; + interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>, /* OTG Core */ + <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>; /* OTG Wakeup */ + clocks = <&clks 94>, <&clks 95>; + fsl,usbmisc = <&usbmisc 0>; + ahb-burst-config = <0x3>; + tx-burst-size-dword = <0x10>; + rx-burst-size-dword = <0x10>; + phy_type = "ulpi"; + dr_mode = "host"; + maximum-speed = "high-speed"; + status = "disabled"; + }; + i2c0: i2c@401e4000 { compatible = "nxp,s32g2-i2c"; reg = <0x401e4000 0x1000>; diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi index 991dbfbfa203..191d2dab4254 100644 --- a/arch/arm64/boot/dts/freescale/s32g3.dtsi +++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi @@ -435,6 +435,29 @@ status = "disabled"; }; + usbmisc: usbmisc@44064200 { + #index-cells = <1>; + compatible = "nxp,s32g3-usbmisc"; + reg = <0x44064200 0x200>; + }; + + usbotg: usb@44064000 { + compatible = "nxp,s32g3-usb", "nxp,s32g2-usb"; + reg = <0x44064000 0x200>; + interrupt-parent = <&gic>; + interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>, /* OTG Core */ + <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>; /* OTG Wakeup */ + clocks = <&clks 94>, <&clks 95>; + fsl,usbmisc = <&usbmisc 0>; + ahb-burst-config = <0x3>; + tx-burst-size-dword = <0x10>; + rx-burst-size-dword = <0x10>; + phy_type = "ulpi"; + dr_mode = "host"; + maximum-speed = "high-speed"; + status = "disabled"; + }; + i2c0: i2c@401e4000 { compatible = "nxp,s32g3-i2c", "nxp,s32g2-i2c"; diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 5ba3d9c4b3fb..715ce1dcb304 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -232,10 +232,6 @@ static int stk1160_start_streaming(struct stk1160 *dev) /* submit urbs and enables IRQ */ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - struct stk1160_urb *stk_urb = &dev->isoc_ctl.urb_ctl[i]; - - dma_sync_sgtable_for_device(stk1160_get_dmadev(dev), stk_urb->sgt, - DMA_FROM_DEVICE); rc = usb_submit_urb(dev->isoc_ctl.urb_ctl[i].urb, GFP_KERNEL); if (rc) { stk1160_err("cannot submit urb[%d] (%d)\n", i, rc); diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 9cbd957ecc90..416cb74377eb 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -298,9 +298,7 @@ static void stk1160_process_isoc(struct stk1160 *dev, struct urb *urb) static void stk1160_isoc_irq(struct urb *urb) { int i, rc; - struct stk1160_urb *stk_urb = urb->context; - struct stk1160 *dev = stk_urb->dev; - struct device *dma_dev = stk1160_get_dmadev(dev); + struct stk1160 *dev = urb->context; switch (urb->status) { case 0: @@ -315,10 +313,6 @@ static void stk1160_isoc_irq(struct urb *urb) return; } - invalidate_kernel_vmap_range(stk_urb->transfer_buffer, - urb->transfer_buffer_length); - dma_sync_sgtable_for_cpu(dma_dev, stk_urb->sgt, DMA_FROM_DEVICE); - stk1160_process_isoc(dev, urb); /* Reset urb buffers */ @@ -327,7 +321,6 @@ static void stk1160_isoc_irq(struct urb *urb) urb->iso_frame_desc[i].actual_length = 0; } - dma_sync_sgtable_for_device(dma_dev, stk_urb->sgt, DMA_FROM_DEVICE); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc) stk1160_err("urb re-submit failed (%d)\n", rc); @@ -365,11 +358,9 @@ void stk1160_cancel_isoc(struct stk1160 *dev) static void stk_free_urb(struct stk1160 *dev, struct stk1160_urb *stk_urb) { - struct device *dma_dev = stk1160_get_dmadev(dev); - - dma_vunmap_noncontiguous(dma_dev, stk_urb->transfer_buffer); - dma_free_noncontiguous(dma_dev, stk_urb->urb->transfer_buffer_length, - stk_urb->sgt, DMA_FROM_DEVICE); + usb_free_noncoherent(dev->udev, stk_urb->urb->transfer_buffer_length, + stk_urb->transfer_buffer, DMA_FROM_DEVICE, + stk_urb->sgt); usb_free_urb(stk_urb->urb); stk_urb->transfer_buffer = NULL; @@ -410,32 +401,19 @@ void stk1160_uninit_isoc(struct stk1160 *dev) static int stk1160_fill_urb(struct stk1160 *dev, struct stk1160_urb *stk_urb, int sb_size, int max_packets) { - struct device *dma_dev = stk1160_get_dmadev(dev); - stk_urb->urb = usb_alloc_urb(max_packets, GFP_KERNEL); if (!stk_urb->urb) return -ENOMEM; - stk_urb->sgt = dma_alloc_noncontiguous(dma_dev, sb_size, - DMA_FROM_DEVICE, GFP_KERNEL, 0); - - /* - * If the buffer allocation failed, we exit but return 0 since - * we allow the driver working with less buffers - */ - if (!stk_urb->sgt) - goto free_urb; - stk_urb->transfer_buffer = dma_vmap_noncontiguous(dma_dev, sb_size, - stk_urb->sgt); + stk_urb->transfer_buffer = usb_alloc_noncoherent(dev->udev, sb_size, + GFP_KERNEL, &stk_urb->dma, + DMA_FROM_DEVICE, &stk_urb->sgt); if (!stk_urb->transfer_buffer) - goto free_sgt; + goto free_urb; - stk_urb->dma = stk_urb->sgt->sgl->dma_address; stk_urb->dev = dev; return 0; -free_sgt: - dma_free_noncontiguous(dma_dev, sb_size, stk_urb->sgt, DMA_FROM_DEVICE); - stk_urb->sgt = NULL; + free_urb: usb_free_urb(stk_urb->urb); stk_urb->urb = NULL; @@ -494,12 +472,13 @@ int stk1160_alloc_isoc(struct stk1160 *dev) urb->transfer_buffer = dev->isoc_ctl.urb_ctl[i].transfer_buffer; urb->transfer_buffer_length = sb_size; urb->complete = stk1160_isoc_irq; - urb->context = &dev->isoc_ctl.urb_ctl[i]; + urb->context = dev; urb->interval = 1; urb->start_frame = 0; urb->number_of_packets = max_packets; urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = dev->isoc_ctl.urb_ctl[i].dma; + urb->sgt = dev->isoc_ctl.urb_ctl[i].sgt; k = 0; for (j = 0; j < max_packets; j++) { diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 7b498d14ed7a..4cbcb0a03bab 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -16,8 +16,6 @@ #include <media/videobuf2-v4l2.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> #define STK1160_VERSION "0.9.5" #define STK1160_VERSION_NUM 0x000905 @@ -195,8 +193,3 @@ void stk1160_select_input(struct stk1160 *dev); /* Provided by stk1160-ac97.c */ void stk1160_ac97_setup(struct stk1160 *dev); - -static inline struct device *stk1160_get_dmadev(struct stk1160 *dev) -{ - return bus_to_hcd(dev->udev->bus)->self.sysdev; -} diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index e3567aeb0007..a75af314e46b 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1275,20 +1275,6 @@ static inline enum dma_data_direction uvc_stream_dir( return DMA_TO_DEVICE; } -static inline struct device *uvc_stream_to_dmadev(struct uvc_streaming *stream) -{ - return bus_to_hcd(stream->dev->udev->bus)->self.sysdev; -} - -static int uvc_submit_urb(struct uvc_urb *uvc_urb, gfp_t mem_flags) -{ - /* Sync DMA. */ - dma_sync_sgtable_for_device(uvc_stream_to_dmadev(uvc_urb->stream), - uvc_urb->sgt, - uvc_stream_dir(uvc_urb->stream)); - return usb_submit_urb(uvc_urb->urb, mem_flags); -} - /* * uvc_video_decode_data_work: Asynchronous memcpy processing * @@ -1310,7 +1296,7 @@ static void uvc_video_copy_data_work(struct work_struct *work) uvc_queue_buffer_release(op->buf); } - ret = uvc_submit_urb(uvc_urb, GFP_KERNEL); + ret = usb_submit_urb(uvc_urb->urb, GFP_KERNEL); if (ret < 0) dev_err(&uvc_urb->stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1736,12 +1722,6 @@ static void uvc_video_complete(struct urb *urb) /* Re-initialise the URB async work. */ uvc_urb->async_operations = 0; - /* Sync DMA and invalidate vmap range. */ - dma_sync_sgtable_for_cpu(uvc_stream_to_dmadev(uvc_urb->stream), - uvc_urb->sgt, uvc_stream_dir(stream)); - invalidate_kernel_vmap_range(uvc_urb->buffer, - uvc_urb->stream->urb_size); - /* * Process the URB headers, and optionally queue expensive memcpy tasks * to be deferred to a work queue. @@ -1750,7 +1730,7 @@ static void uvc_video_complete(struct urb *urb) /* If no async work is needed, resubmit the URB immediately. */ if (!uvc_urb->async_operations) { - ret = uvc_submit_urb(uvc_urb, GFP_ATOMIC); + ret = usb_submit_urb(uvc_urb->urb, GFP_ATOMIC); if (ret < 0) dev_err(&stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1765,17 +1745,15 @@ static void uvc_video_complete(struct urb *urb) */ static void uvc_free_urb_buffers(struct uvc_streaming *stream) { - struct device *dma_dev = uvc_stream_to_dmadev(stream); + struct usb_device *udev = stream->dev->udev; struct uvc_urb *uvc_urb; for_each_uvc_urb(uvc_urb, stream) { if (!uvc_urb->buffer) continue; - dma_vunmap_noncontiguous(dma_dev, uvc_urb->buffer); - dma_free_noncontiguous(dma_dev, stream->urb_size, uvc_urb->sgt, - uvc_stream_dir(stream)); - + usb_free_noncoherent(udev, stream->urb_size, uvc_urb->buffer, + uvc_stream_dir(stream), uvc_urb->sgt); uvc_urb->buffer = NULL; uvc_urb->sgt = NULL; } @@ -1786,26 +1764,13 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream) static bool uvc_alloc_urb_buffer(struct uvc_streaming *stream, struct uvc_urb *uvc_urb, gfp_t gfp_flags) { - struct device *dma_dev = uvc_stream_to_dmadev(stream); - - uvc_urb->sgt = dma_alloc_noncontiguous(dma_dev, stream->urb_size, - uvc_stream_dir(stream), - gfp_flags, 0); - if (!uvc_urb->sgt) - return false; - uvc_urb->dma = uvc_urb->sgt->sgl->dma_address; - - uvc_urb->buffer = dma_vmap_noncontiguous(dma_dev, stream->urb_size, - uvc_urb->sgt); - if (!uvc_urb->buffer) { - dma_free_noncontiguous(dma_dev, stream->urb_size, - uvc_urb->sgt, - uvc_stream_dir(stream)); - uvc_urb->sgt = NULL; - return false; - } + struct usb_device *udev = stream->dev->udev; - return true; + uvc_urb->buffer = usb_alloc_noncoherent(udev, stream->urb_size, + gfp_flags, &uvc_urb->dma, + uvc_stream_dir(stream), + &uvc_urb->sgt); + return !!uvc_urb->buffer; } /* @@ -1953,6 +1918,7 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, urb->complete = uvc_video_complete; urb->number_of_packets = npackets; urb->transfer_buffer_length = size; + urb->sgt = uvc_urb->sgt; for (i = 0; i < npackets; ++i) { urb->iso_frame_desc[i].offset = i * psize; @@ -2009,6 +1975,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, size, uvc_video_complete, uvc_urb); urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = uvc_urb->dma; + urb->sgt = uvc_urb->sgt; uvc_urb->urb = urb; } @@ -2120,7 +2087,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, /* Submit the URBs. */ for_each_uvc_urb(uvc_urb, stream) { - ret = uvc_submit_urb(uvc_urb, gfp_flags); + ret = usb_submit_urb(uvc_urb->urb, gfp_flags); if (ret < 0) { dev_err(&stream->intf->dev, "Failed to submit URB %u (%d).\n", diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index a3a7c8059eee..45239703745e 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -36,7 +36,7 @@ static bool match_service_id(const struct tb_service_id *id, return false; } - if (id->match_flags & TBSVC_MATCH_PROTOCOL_VERSION) { + if (id->match_flags & TBSVC_MATCH_PROTOCOL_REVISION) { if (id->protocol_revision != svc->prtcrevs) return false; } diff --git a/drivers/thunderbolt/nvm.c b/drivers/thunderbolt/nvm.c index 8901db2de327..da11c8112e29 100644 --- a/drivers/thunderbolt/nvm.c +++ b/drivers/thunderbolt/nvm.c @@ -588,7 +588,7 @@ int tb_nvm_read_data(unsigned int address, void *buf, size_t size, * @size: Size of the buffer in bytes * @retries: Number of retries if the block write fails * @write_block: Function that writes block to the flash - * @write_block_data: Data passwd to @write_block + * @write_block_data: Data passed to @write_block * * This is generic function that writes data to NVM or NVM like device. * diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index b6c58a7e7b6a..e9f4186f20f4 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -3069,7 +3069,7 @@ static int tb_switch_asym_disable(struct tb_switch *sw) * @width: The new link width * * Set device router link width to @width from router upstream port - * perspective. Supports also asymmetric links if the routers boths side + * perspective. Supports also asymmetric links if the routers both side * of the link supports it. * * Does nothing for host router. diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index a12ab90b3db7..68a8e9de8b4f 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -980,25 +980,60 @@ cleanup: return ret; } -static void cxacru_upload_firmware(struct cxacru_data *instance, - const struct firmware *fw, - const struct firmware *bp) + +static int cxacru_find_firmware(struct cxacru_data *instance, + char *phase, const struct firmware **fw_p) { - int ret; + struct usbatm_data *usbatm = instance->usbatm; + struct device *dev = &usbatm->usb_intf->dev; + char buf[16]; + + sprintf(buf, "cxacru-%s.bin", phase); + usb_dbg(usbatm, "cxacru_find_firmware: looking for %s\n", buf); + + if (request_firmware(fw_p, buf, dev)) { + usb_dbg(usbatm, "no stage %s firmware found\n", phase); + return -ENOENT; + } + + usb_info(usbatm, "found firmware %s\n", buf); + + return 0; +} + +static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, + struct usb_interface *usb_intf) +{ + const struct firmware *fw, *bp; + struct cxacru_data *instance = usbatm_instance->driver_data; struct usbatm_data *usbatm = instance->usbatm; struct usb_device *usb_dev = usbatm->usb_dev; __le16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct }; __le32 val; + int ret; - usb_dbg(usbatm, "%s\n", __func__); + ret = cxacru_find_firmware(instance, "fw", &fw); + if (ret) { + usb_warn(usbatm_instance, "firmware (cxacru-fw.bin) unavailable (system misconfigured?)\n"); + return ret; + } + + if (instance->modem_type->boot_rom_patch) { + ret = cxacru_find_firmware(instance, "bp", &bp); + if (ret) { + usb_warn(usbatm_instance, "boot ROM patch (cxacru-bp.bin) unavailable (system misconfigured?)\n"); + release_firmware(fw); + return ret; + } + } /* FirmwarePllFClkValue */ val = cpu_to_le32(instance->modem_type->pll_f_clk); ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4); if (ret) { usb_err(usbatm, "FirmwarePllFClkValue failed: %d\n", ret); - return; + goto done; } /* FirmwarePllBClkValue */ @@ -1006,7 +1041,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4); if (ret) { usb_err(usbatm, "FirmwarePllBClkValue failed: %d\n", ret); - return; + goto done; } /* Enable SDRAM */ @@ -1014,7 +1049,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4); if (ret) { usb_err(usbatm, "Enable SDRAM failed: %d\n", ret); - return; + goto done; } /* Firmware */ @@ -1022,7 +1057,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size); if (ret) { usb_err(usbatm, "Firmware upload failed: %d\n", ret); - return; + goto done; } /* Boot ROM patch */ @@ -1031,7 +1066,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size); if (ret) { usb_err(usbatm, "Boot ROM patching failed: %d\n", ret); - return; + goto done; } } @@ -1039,7 +1074,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4); if (ret) { usb_err(usbatm, "Signature storing failed: %d\n", ret); - return; + goto done; } usb_info(usbatm, "starting device\n"); @@ -1051,7 +1086,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, } if (ret) { usb_err(usbatm, "Passing control to firmware failed: %d\n", ret); - return; + goto done; } /* Delay to allow firmware to start up. */ @@ -1065,53 +1100,10 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); if (ret < 0) { usb_err(usbatm, "modem failed to initialize: %d\n", ret); - return; - } -} - -static int cxacru_find_firmware(struct cxacru_data *instance, - char *phase, const struct firmware **fw_p) -{ - struct usbatm_data *usbatm = instance->usbatm; - struct device *dev = &usbatm->usb_intf->dev; - char buf[16]; - - sprintf(buf, "cxacru-%s.bin", phase); - usb_dbg(usbatm, "cxacru_find_firmware: looking for %s\n", buf); - - if (request_firmware(fw_p, buf, dev)) { - usb_dbg(usbatm, "no stage %s firmware found\n", phase); - return -ENOENT; - } - - usb_info(usbatm, "found firmware %s\n", buf); - - return 0; -} - -static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, - struct usb_interface *usb_intf) -{ - const struct firmware *fw, *bp; - struct cxacru_data *instance = usbatm_instance->driver_data; - int ret = cxacru_find_firmware(instance, "fw", &fw); - - if (ret) { - usb_warn(usbatm_instance, "firmware (cxacru-fw.bin) unavailable (system misconfigured?)\n"); - return ret; + goto done; } - if (instance->modem_type->boot_rom_patch) { - ret = cxacru_find_firmware(instance, "bp", &bp); - if (ret) { - usb_warn(usbatm_instance, "boot ROM patch (cxacru-bp.bin) unavailable (system misconfigured?)\n"); - release_firmware(fw); - return ret; - } - } - - cxacru_upload_firmware(instance, fw, bp); - +done: if (instance->modem_type->boot_rom_patch) release_firmware(bp); release_firmware(fw); diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 780f4d151345..e1ec9b38f5b9 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2025 NXP * Copyright (C) 2012 Marek Vasut <marex@denx.de> * on behalf of DENX Software Engineering GmbH */ @@ -78,6 +79,10 @@ static const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = { CI_HDRC_HAS_PORTSC_PEC_MISSED, }; +static const struct ci_hdrc_imx_platform_flag s32g_usb_data = { + .flags = CI_HDRC_DISABLE_HOST_STREAMING, +}; + static const struct of_device_id ci_hdrc_imx_dt_ids[] = { { .compatible = "fsl,imx23-usb", .data = &imx23_usb_data}, { .compatible = "fsl,imx28-usb", .data = &imx28_usb_data}, @@ -89,6 +94,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = { { .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data}, { .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data}, { .compatible = "fsl,imx8ulp-usb", .data = &imx8ulp_usb_data}, + { .compatible = "nxp,s32g2-usb", .data = &s32g_usb_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); @@ -331,6 +337,11 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) if (ci->usb_phy) schedule_work(&ci->usb_phy->chg_work); break; + case CI_HDRC_CONTROLLER_PULLUP_EVENT: + if (ci->role == CI_ROLE_GADGET) + imx_usbmisc_pullup(data->usbmisc_data, + ci->gadget.connected); + break; default: break; } diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 88b8da79d518..cb95c84d0322 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -37,5 +37,6 @@ int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data); int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect); int imx_usbmisc_suspend(struct imx_usbmisc_data *data, bool wakeup); int imx_usbmisc_resume(struct imx_usbmisc_data *data, bool wakeup); +int imx_usbmisc_pullup(struct imx_usbmisc_data *data, bool on); #endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */ diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 1a48e6440e6c..64a421ae0f05 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1970,6 +1970,11 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on) hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); else hw_write(ci, OP_USBCMD, USBCMD_RS, 0); + + if (ci->platdata->notify_event) { + _gadget->connected = is_on; + ci->platdata->notify_event(ci, CI_HDRC_CONTROLLER_PULLUP_EVENT); + } pm_runtime_put_sync(ci->dev); return 0; diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 118b9a68496b..3d20c5e76c6a 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2025 NXP */ #include <linux/module.h> @@ -155,6 +156,18 @@ BLKCTL_OTG_VBUS_WAKEUP_EN | \ BLKCTL_OTG_DPDM_WAKEUP_EN) +#define S32G_WAKEUP_IE BIT(0) +#define S32G_CORE_IE BIT(1) +#define S32G_PWRFLTEN BIT(7) +#define S32G_WAKEUPCTRL BIT(10) +#define S32G_WAKEUPEN BIT(11) + +/* Workaround errata ERR050474 (handle packages that aren't 4 byte aligned) */ +#define S32G_UCMALLBE BIT(15) + +#define S32G_WAKEUP_BITS (S32G_WAKEUP_IE | S32G_CORE_IE | S32G_WAKEUPEN | \ + S32G_WAKEUPCTRL) + struct usbmisc_ops { /* It's called once when probe a usb device */ int (*init)(struct imx_usbmisc_data *data); @@ -170,6 +183,9 @@ struct usbmisc_ops { int (*charger_detection)(struct imx_usbmisc_data *data); /* It's called when system resume from usb power lost */ int (*power_lost_check)(struct imx_usbmisc_data *data); + /* It's called when device controller changed pullup status */ + void (*pullup)(struct imx_usbmisc_data *data, bool on); + /* It's called during suspend/resume to save power */ void (*vbus_comparator_on)(struct imx_usbmisc_data *data, bool on); }; @@ -614,6 +630,57 @@ static int usbmisc_vf610_init(struct imx_usbmisc_data *data) return 0; } +static int usbmisc_s32g_set_wakeup(struct imx_usbmisc_data *data, bool enabled) +{ + struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&usbmisc->lock, flags); + + reg = readl(usbmisc->base); + if (enabled) + reg |= S32G_WAKEUP_BITS; + else + reg &= ~S32G_WAKEUP_BITS; + + writel(reg, usbmisc->base); + spin_unlock_irqrestore(&usbmisc->lock, flags); + + return 0; +} + +static int usbmisc_s32g_init(struct imx_usbmisc_data *data, u32 extra_flags) +{ + struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&usbmisc->lock, flags); + + reg = readl(usbmisc->base); + + reg |= S32G_PWRFLTEN; + reg |= extra_flags; + + writel(reg, usbmisc->base); + + spin_unlock_irqrestore(&usbmisc->lock, flags); + usbmisc_s32g_set_wakeup(data, false); + + return 0; +} + +static int usbmisc_s32g2_init(struct imx_usbmisc_data *data) +{ + return usbmisc_s32g_init(data, S32G_UCMALLBE); +} + +static int usbmisc_s32g3_init(struct imx_usbmisc_data *data) +{ + return usbmisc_s32g_init(data, 0); +} + static int usbmisc_imx7d_set_wakeup (struct imx_usbmisc_data *data, bool enabled) { @@ -995,6 +1062,25 @@ static int usbmisc_imx7ulp_init(struct imx_usbmisc_data *data) return 0; } +static void usbmisc_imx7d_pullup(struct imx_usbmisc_data *data, bool on) +{ + struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&usbmisc->lock, flags); + val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); + if (!on) { + val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK; + val |= MX7D_USBNC_USB_CTRL2_OPMODE(1); + val |= MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN; + } else { + val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN; + } + writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2); + spin_unlock_irqrestore(&usbmisc->lock, flags); +} + static int usbmisc_imx7d_power_lost_check(struct imx_usbmisc_data *data) { struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); @@ -1033,6 +1119,11 @@ static int usbmisc_imx6sx_power_lost_check(struct imx_usbmisc_data *data) return 0; } +static int usbmisc_s32g_power_lost_check(struct imx_usbmisc_data *data) +{ + return 1; +} + static u32 usbmisc_blkctl_wakeup_setting(struct imx_usbmisc_data *data) { u32 wakeup_setting = BLKCTL_WAKEUP_SOURCE; @@ -1112,6 +1203,7 @@ static const struct usbmisc_ops imx7d_usbmisc_ops = { .set_wakeup = usbmisc_imx7d_set_wakeup, .charger_detection = imx7d_charger_detection, .power_lost_check = usbmisc_imx7d_power_lost_check, + .pullup = usbmisc_imx7d_pullup, .vbus_comparator_on = usbmisc_imx7d_vbus_comparator_on, }; @@ -1128,9 +1220,22 @@ static const struct usbmisc_ops imx95_usbmisc_ops = { .set_wakeup = usbmisc_imx95_set_wakeup, .charger_detection = imx7d_charger_detection, .power_lost_check = usbmisc_imx7d_power_lost_check, + .pullup = usbmisc_imx7d_pullup, .vbus_comparator_on = usbmisc_imx7d_vbus_comparator_on, }; +static const struct usbmisc_ops s32g2_usbmisc_ops = { + .init = usbmisc_s32g2_init, + .set_wakeup = usbmisc_s32g_set_wakeup, + .power_lost_check = usbmisc_s32g_power_lost_check, +}; + +static const struct usbmisc_ops s32g3_usbmisc_ops = { + .init = usbmisc_s32g3_init, + .set_wakeup = usbmisc_s32g_set_wakeup, + .power_lost_check = usbmisc_s32g_power_lost_check, +}; + static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data) { struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); @@ -1225,6 +1330,21 @@ int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect) } EXPORT_SYMBOL_GPL(imx_usbmisc_charger_detection); +int imx_usbmisc_pullup(struct imx_usbmisc_data *data, bool on) +{ + struct imx_usbmisc *usbmisc; + + if (!data) + return 0; + + usbmisc = dev_get_drvdata(data->dev); + if (usbmisc->ops->pullup) + usbmisc->ops->pullup(data, on); + + return 0; +} +EXPORT_SYMBOL_GPL(imx_usbmisc_pullup); + int imx_usbmisc_suspend(struct imx_usbmisc_data *data, bool wakeup) { struct imx_usbmisc *usbmisc; @@ -1356,6 +1476,14 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = { .compatible = "fsl,imx95-usbmisc", .data = &imx95_usbmisc_ops, }, + { + .compatible = "nxp,s32g2-usbmisc", + .data = &s32g2_usbmisc_ops, + }, + { + .compatible = "nxp,s32g3-usbmisc", + .data = &s32g3_usbmisc_ops, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index f9171fbedf5c..73f9476774ae 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1520,6 +1520,12 @@ skip_countries: goto err_remove_files; } + if (quirks & CLEAR_HALT_CONDITIONS) { + /* errors intentionally ignored */ + usb_clear_halt(usb_dev, acm->in); + usb_clear_halt(usb_dev, acm->out); + } + tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor, &control_interface->dev); if (IS_ERR(tty_dev)) { @@ -1527,11 +1533,6 @@ skip_countries: goto err_release_data_interface; } - if (quirks & CLEAR_HALT_CONDITIONS) { - usb_clear_halt(usb_dev, acm->in); - usb_clear_halt(usb_dev, acm->out); - } - dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); return 0; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index e2527faa6592..acbefccbdb2a 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -366,7 +366,8 @@ static int usblp_check_status(struct usblp *usblp, int err) int error; mutex_lock(&usblp->mut); - if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { + error = usblp_read_status(usblp, usblp->statusbuf); + if (error < 0) { mutex_unlock(&usblp->mut); printk_ratelimited(KERN_ERR "usblp%d: error %d reading printer status\n", @@ -751,14 +752,16 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t rv = -EINTR; goto raise_biglock; } - if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0) + rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK)); + if (rv < 0) goto raise_wait; while (writecount < count) { /* * Step 1: Submit next block. */ - if ((transfer_length = count - writecount) > USBLP_BUF_SIZE) + transfer_length = count - writecount; + if (transfer_length > USBLP_BUF_SIZE) transfer_length = USBLP_BUF_SIZE; rv = -ENOMEM; @@ -776,7 +779,9 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t spin_lock_irq(&usblp->lock); usblp->wcomplete = 0; spin_unlock_irq(&usblp->lock); - if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { + + rv = usb_submit_urb(writeurb, GFP_KERNEL); + if (rv < 0) { usblp->wstatus = 0; spin_lock_irq(&usblp->lock); usblp->no_paper = 0; @@ -857,9 +862,10 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo goto done; } - if ((avail = usblp->rstatus) < 0) { + avail = usblp->rstatus; + if (avail < 0) { printk(KERN_ERR "usblp%d: error %d reading from printer\n", - usblp->minor, (int)avail); + usblp->minor, (int)avail); usblp_submit_read(usblp); count = -EIO; goto done; @@ -872,7 +878,8 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo goto done; } - if ((usblp->readcount += count) == avail) { + usblp->readcount += count; + if (usblp->readcount == avail) { if (usblp_submit_read(usblp) < 0) { /* We don't want to leak USB return codes into errno. */ if (count == 0) @@ -973,7 +980,8 @@ static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock) break; } set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_rtest(usblp, nonblock)) < 0) { + rc = usblp_rtest(usblp, nonblock); + if (rc < 0) { mutex_unlock(&usblp->mut); break; } @@ -1031,7 +1039,8 @@ static int usblp_submit_read(struct usblp *usblp) usblp->readcount = 0; /* XXX Why here? */ usblp->rcomplete = 0; spin_unlock_irqrestore(&usblp->lock, flags); - if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) { + rc = usb_submit_urb(urb, GFP_KERNEL); + if (rc < 0) { dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc); spin_lock_irqsave(&usblp->lock, flags); usblp->rstatus = rc; @@ -1150,7 +1159,8 @@ static int usblp_probe(struct usb_interface *intf, /* Malloc device ID string buffer to the largest expected length, * since we can re-query it on an ioctl and a dynamic string * could change in length. */ - if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) { + usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL); + if (!usblp->device_id_string) { retval = -ENOMEM; goto abort; } @@ -1160,7 +1170,8 @@ static int usblp_probe(struct usb_interface *intf, * malloc both regardless of bidirectionality, because the * alternate setting can be changed later via an ioctl. */ - if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) { + usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL); + if (!usblp->readbuf) { retval = -ENOMEM; goto abort; } diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index fc0cfd94cbab..42468bbeffd2 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -107,8 +107,14 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, */ desc = (struct usb_ss_ep_comp_descriptor *) buffer; - if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP || - size < USB_DT_SS_EP_COMP_SIZE) { + if (size < USB_DT_SS_EP_COMP_SIZE) { + dev_notice(ddev, + "invalid SuperSpeed endpoint companion descriptor " + "of length %d, skipping\n", size); + return; + } + + if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) { dev_notice(ddev, "No SuperSpeed endpoint companion for config %d " " interface %d altsetting %d ep %d: " "using minimum values\n", diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 460d4dde5994..c3177034b779 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -119,11 +119,11 @@ ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf) guard(mutex)(&usb_dynids_lock); list_for_each_entry(dynid, &dynids->list, node) if (dynid->id.bInterfaceClass != 0) - count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x %02x\n", + count += sysfs_emit_at(&buf[count], count, "%04x %04x %02x\n", dynid->id.idVendor, dynid->id.idProduct, dynid->id.bInterfaceClass); else - count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x\n", + count += sysfs_emit_at(&buf[count], count, "%04x %04x\n", dynid->id.idVendor, dynid->id.idProduct); return count; } diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 56b534f59907..cd223475917e 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -210,7 +210,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct hc_driver *driver) hcd->amd_resume_bug = usb_hcd_amd_resume_bug(dev, driver); if (driver->flags & HCD_MEMORY) { - /* EHCI, OHCI */ + /* XHCI, EHCI, OHCI */ hcd->rsrc_start = pci_resource_start(dev, 0); hcd->rsrc_len = pci_resource_len(dev, 0); if (!devm_request_mem_region(&dev->dev, hcd->rsrc_start, diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index c22de97432a0..03771bbc6c01 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1342,29 +1342,35 @@ void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; if (IS_ENABLED(CONFIG_HAS_DMA) && - (urb->transfer_flags & URB_DMA_MAP_SG)) + (urb->transfer_flags & URB_DMA_MAP_SG)) { dma_unmap_sg(hcd->self.sysdev, urb->sg, urb->num_sgs, dir); - else if (IS_ENABLED(CONFIG_HAS_DMA) && - (urb->transfer_flags & URB_DMA_MAP_PAGE)) + } else if (IS_ENABLED(CONFIG_HAS_DMA) && + (urb->transfer_flags & URB_DMA_MAP_PAGE)) { dma_unmap_page(hcd->self.sysdev, urb->transfer_dma, urb->transfer_buffer_length, dir); - else if (IS_ENABLED(CONFIG_HAS_DMA) && - (urb->transfer_flags & URB_DMA_MAP_SINGLE)) + } else if (IS_ENABLED(CONFIG_HAS_DMA) && + (urb->transfer_flags & URB_DMA_MAP_SINGLE)) { dma_unmap_single(hcd->self.sysdev, urb->transfer_dma, urb->transfer_buffer_length, dir); - else if (urb->transfer_flags & URB_MAP_LOCAL) + } else if (urb->transfer_flags & URB_MAP_LOCAL) { hcd_free_coherent(urb->dev->bus, &urb->transfer_dma, &urb->transfer_buffer, urb->transfer_buffer_length, dir); + } else if ((urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) && urb->sgt) { + dma_sync_sgtable_for_cpu(hcd->self.sysdev, urb->sgt, dir); + if (dir == DMA_FROM_DEVICE) + invalidate_kernel_vmap_range(urb->transfer_buffer, + urb->transfer_buffer_length); + } /* Make it safe to call this routine more than once */ urb->transfer_flags &= ~(URB_DMA_MAP_SG | URB_DMA_MAP_PAGE | @@ -1425,8 +1431,15 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, } dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { + if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) { + if (!urb->sgt) + return 0; + + if (dir == DMA_TO_DEVICE) + flush_kernel_vmap_range(urb->transfer_buffer, + urb->transfer_buffer_length); + dma_sync_sgtable_for_device(hcd->self.sysdev, urb->sgt, dir); + } else if (urb->transfer_buffer_length != 0) { if (hcd->localmem_pool) { ret = hcd_alloc_coherent( urb->dev->bus, mem_flags, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 0cf94c7a2c9c..ff0ff95d5cca 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -736,7 +736,7 @@ void usb_detect_quirks(struct usb_device *udev) udev->quirks ^= usb_detect_dynamic_quirks(udev); if (udev->quirks) - dev_dbg(&udev->dev, "USB quirks for this device: %x\n", + dev_dbg(&udev->dev, "USB quirks for this device: 0x%x\n", udev->quirks); #ifdef CONFIG_USB_DEFAULT_PERSIST diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 5e52a35486af..7a76d5a62db1 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -500,7 +500,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* Check that the pipe's type matches the endpoint's type */ if (usb_pipe_type_check(urb->dev, urb->pipe)) - dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", + dev_warn_once(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", usb_pipetype(urb->pipe), pipetypes[xfertype]); /* Check against a simple/standard policy */ @@ -597,10 +597,9 @@ EXPORT_SYMBOL_GPL(usb_submit_urb); * code). * * Drivers should not call this routine or related routines, such as - * usb_kill_urb() or usb_unlink_anchored_urbs(), after their disconnect - * method has returned. The disconnect function should synchronize with - * a driver's I/O routines to insure that all URB-related activity has - * completed before it returns. + * usb_kill_urb(), after their disconnect method has returned. The + * disconnect function should synchronize with a driver's I/O routines + * to insure that all URB-related activity has completed before it returns. * * This request is asynchronous, however the HCD might call the ->complete() * callback during unlink. Therefore when drivers call usb_unlink_urb(), they @@ -890,28 +889,6 @@ void usb_unpoison_anchored_urbs(struct usb_anchor *anchor) spin_unlock_irqrestore(&anchor->lock, flags); } EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs); -/** - * usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse - * @anchor: anchor the requests are bound to - * - * this allows all outstanding URBs to be unlinked starting - * from the back of the queue. This function is asynchronous. - * The unlinking is just triggered. It may happen after this - * function has returned. - * - * This routine should not be called by a driver after its disconnect - * method has returned. - */ -void usb_unlink_anchored_urbs(struct usb_anchor *anchor) -{ - struct urb *victim; - - while ((victim = usb_get_from_anchor(anchor)) != NULL) { - usb_unlink_urb(victim); - usb_put_urb(victim); - } -} -EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); /** * usb_anchor_suspend_wakeups diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 118fa4c93a79..fca7735fc660 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1030,6 +1030,86 @@ void usb_free_coherent(struct usb_device *dev, size_t size, void *addr, } EXPORT_SYMBOL_GPL(usb_free_coherent); +/** + * usb_alloc_noncoherent - allocate dma-noncoherent buffer for URB_NO_xxx_DMA_MAP + * @dev: device the buffer will be used with + * @size: requested buffer size + * @mem_flags: affect whether allocation may block + * @dma: used to return DMA address of buffer + * @dir: DMA transfer direction + * @table: used to return sg_table of allocated memory + * + * To explicit manage the memory ownership for the kernel vs the device by + * USB core, the user needs save sg_table to urb->sgt. Then USB core will + * do DMA sync for CPU and device properly. + * + * When the buffer is no longer used, free it with usb_free_noncoherent(). + * + * Return: Either null (indicating no buffer could be allocated), or the + * cpu-space pointer to a buffer that may be used to perform DMA to the + * specified device. Such cpu-space buffers are returned along with the DMA + * address (through the pointer provided). + */ +void *usb_alloc_noncoherent(struct usb_device *dev, size_t size, + gfp_t mem_flags, dma_addr_t *dma, + enum dma_data_direction dir, + struct sg_table **table) +{ + struct device *dmadev; + struct sg_table *sgt; + void *buffer; + + if (!dev || !dev->bus) + return NULL; + + dmadev = bus_to_hcd(dev->bus)->self.sysdev; + + sgt = dma_alloc_noncontiguous(dmadev, size, dir, mem_flags, 0); + if (!sgt) + return NULL; + + buffer = dma_vmap_noncontiguous(dmadev, size, sgt); + if (!buffer) { + dma_free_noncontiguous(dmadev, size, sgt, dir); + return NULL; + } + + *table = sgt; + *dma = sg_dma_address(sgt->sgl); + + return buffer; +} +EXPORT_SYMBOL_GPL(usb_alloc_noncoherent); + +/** + * usb_free_noncoherent - free memory allocated with usb_alloc_noncoherent() + * @dev: device the buffer was used with + * @size: requested buffer size + * @addr: CPU address of buffer + * @dir: DMA transfer direction + * @table: describe the allocated and DMA mapped memory, + * + * This reclaims an I/O buffer, letting it be reused. The memory must have + * been allocated using usb_alloc_noncoherent(), and the parameters must match + * those provided in that allocation request. + */ +void usb_free_noncoherent(struct usb_device *dev, size_t size, + void *addr, enum dma_data_direction dir, + struct sg_table *table) +{ + struct device *dmadev; + + if (!dev || !dev->bus) + return; + if (!addr) + return; + + dmadev = bus_to_hcd(dev->bus)->self.sysdev; + dma_vunmap_noncontiguous(dmadev, addr); + dma_free_noncontiguous(dmadev, size, table, dir); +} +EXPORT_SYMBOL_GPL(usb_free_noncoherent); + /* * Notifications of device and interface registration */ diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 4d73fae80b12..ea6bd537e337 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -334,7 +334,7 @@ const struct of_device_id dwc2_of_match_table[] = { .data = dwc2_set_amlogic_a1_params }, { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params }, { .compatible = "apm,apm82181-dwc-otg", .data = dwc2_set_amcc_params }, - { .compatible = "sophgo,cv1800-usb", + { .compatible = "sophgo,cv1800b-usb", .data = dwc2_set_cv1800_params }, { .compatible = "st,stm32f4x9-fsotg", .data = dwc2_set_stm32f4x9_fsotg_params }, diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 12b4dc07d08a..3f83ecc9fc23 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -371,6 +371,9 @@ static void dwc2_driver_shutdown(struct platform_device *dev) dwc2_disable_global_interrupts(hsotg); synchronize_irq(hsotg->irq); + + if (hsotg->ll_hw_enabled) + dwc2_lowlevel_hw_disable(hsotg); } /** diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c index 3edc5aca76f9..bce6af82f54c 100644 --- a/drivers/usb/dwc3/dwc3-imx8mp.c +++ b/drivers/usb/dwc3/dwc3-imx8mp.c @@ -244,7 +244,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) IRQF_ONESHOT, dev_name(dev), dwc3_imx); if (err) { dev_err(dev, "failed to request IRQ #%d --> %d\n", irq, err); - goto depopulate; + goto put_dwc3; } device_set_wakeup_capable(dev, true); @@ -252,6 +252,8 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) return 0; +put_dwc3: + put_device(&dwc3_imx->dwc3->dev); depopulate: of_platform_depopulate(dev); remove_swnode: @@ -265,8 +267,11 @@ disable_rpm: static void dwc3_imx8mp_remove(struct platform_device *pdev) { + struct dwc3_imx8mp *dwc3_imx = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; + put_device(&dwc3_imx->dwc3->dev); + pm_runtime_get_sync(dev); of_platform_depopulate(dev); device_remove_software_node(dev); diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 7d80bf7b18b0..55e144ba8cfc 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -837,6 +837,9 @@ static void dwc3_meson_g12a_remove(struct platform_device *pdev) usb_role_switch_unregister(priv->role_switch); + put_device(priv->switch_desc.udc); + put_device(priv->switch_desc.usb2_port); + of_platform_depopulate(dev); for (i = 0 ; i < PHY_COUNT ; ++i) { diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c index 4ca7f6240d07..1e28d6f50ed0 100644 --- a/drivers/usb/dwc3/dwc3-xilinx.c +++ b/drivers/usb/dwc3/dwc3-xilinx.c @@ -32,6 +32,9 @@ #define XLNX_USB_TRAFFIC_ROUTE_CONFIG 0x005C #define XLNX_USB_TRAFFIC_ROUTE_FPD 0x1 +/* USB 2.0 IP Register */ +#define XLNX_USB2_TRAFFIC_ROUTE_CONFIG 0x0044 + #define XLNX_USB_FPD_PIPE_CLK 0x7c #define PIPE_CLK_DESELECT 1 #define PIPE_CLK_SELECT 0 @@ -66,6 +69,23 @@ static void dwc3_xlnx_mask_phy_rst(struct dwc3_xlnx *priv_data, bool mask) writel(reg, priv_data->regs + XLNX_USB_PHY_RST_EN); } +static void dwc3_xlnx_set_coherency(struct dwc3_xlnx *priv_data, u32 coherency_offset) +{ + struct device *dev = priv_data->dev; + u32 reg; + + /* + * This routes the USB DMA traffic to go through FPD path instead + * of reaching DDR directly. This traffic routing is needed to + * make SMMU and CCI work with USB DMA. + */ + if (of_dma_is_coherent(dev->of_node) || device_iommu_mapped(dev)) { + reg = readl(priv_data->regs + coherency_offset); + reg |= XLNX_USB_TRAFFIC_ROUTE_FPD; + writel(reg, priv_data->regs + coherency_offset); + } +} + static int dwc3_xlnx_init_versal(struct dwc3_xlnx *priv_data) { struct device *dev = priv_data->dev; @@ -92,6 +112,7 @@ static int dwc3_xlnx_init_versal(struct dwc3_xlnx *priv_data) } dwc3_xlnx_mask_phy_rst(priv_data, true); + dwc3_xlnx_set_coherency(priv_data, XLNX_USB2_TRAFFIC_ROUTE_CONFIG); return 0; } @@ -102,7 +123,6 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) struct reset_control *crst, *hibrst, *apbrst; struct gpio_desc *reset_gpio; int ret = 0; - u32 reg; priv_data->usb3_phy = devm_phy_optional_get(dev, "usb3-phy"); if (IS_ERR(priv_data->usb3_phy)) { @@ -219,17 +239,7 @@ skip_usb3_phy: usleep_range(5000, 10000); } - /* - * This routes the USB DMA traffic to go through FPD path instead - * of reaching DDR directly. This traffic routing is needed to - * make SMMU and CCI work with USB DMA. - */ - if (of_dma_is_coherent(dev->of_node) || device_iommu_mapped(dev)) { - reg = readl(priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG); - reg |= XLNX_USB_TRAFFIC_ROUTE_FPD; - writel(reg, priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG); - } - + dwc3_xlnx_set_coherency(priv_data, XLNX_USB_TRAFFIC_ROUTE_CONFIG); err: return ret; } @@ -422,6 +432,7 @@ static const struct dev_pm_ops dwc3_xlnx_dev_pm_ops = { static struct platform_driver dwc3_xlnx_driver = { .probe = dwc3_xlnx_probe, .remove = dwc3_xlnx_remove, + .shutdown = dwc3_xlnx_remove, .driver = { .name = "dwc3-xilinx", .of_match_table = dwc3_xlnx_of_match, diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 74968f93d4a3..25db36c63951 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -924,11 +924,9 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) if (ret) return ret; - if (!(dep->flags & DWC3_EP_RESOURCE_ALLOCATED)) { - ret = dwc3_gadget_set_xfer_resource(dep); - if (ret) - return ret; - } + ret = dwc3_gadget_set_xfer_resource(dep); + if (ret) + return ret; if (!(dep->flags & DWC3_EP_ENABLED)) { struct dwc3_trb *trb_st_hw; @@ -3497,7 +3495,7 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, struct dwc3_request *req, struct dwc3_trb *trb, - const struct dwc3_event_depevt *event, int status, int chain) + const struct dwc3_event_depevt *event, int status) { unsigned int count; @@ -3549,7 +3547,8 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN) return 1; - if (event->status & DEPEVT_STATUS_SHORT && !chain) + if (event->status & DEPEVT_STATUS_SHORT && + !(trb->ctrl & DWC3_TRB_CTRL_CHN)) return 1; if ((trb->ctrl & DWC3_TRB_CTRL_ISP_IMI) && @@ -3576,8 +3575,7 @@ static int dwc3_gadget_ep_reclaim_trb_sg(struct dwc3_ep *dep, trb = &dep->trb_pool[dep->trb_dequeue]; ret = dwc3_gadget_ep_reclaim_completed_trb(dep, req, - trb, event, status, - !!(trb->ctrl & DWC3_TRB_CTRL_CHN)); + trb, event, status); if (ret) break; } diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index 341408410ed9..41118bba9197 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -681,6 +681,10 @@ int __init early_xdbc_setup_hardware(void) xdbc.table_base = NULL; xdbc.out_buf = NULL; + + early_iounmap(xdbc.xhci_base, xdbc.xhci_length); + xdbc.xhci_base = NULL; + xdbc.xhci_length = 0; } return ret; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 8dbc132a505e..5b3866909b75 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1011,7 +1011,7 @@ static int set_config(struct usb_composite_dev *cdev, ep = (struct usb_endpoint_descriptor *)*descriptors; addr = ((ep->bEndpointAddress & 0x80) >> 3) - | (ep->bEndpointAddress & 0x0f); + | usb_endpoint_num(ep); set_bit(addr, f->endpoints); } @@ -1194,30 +1194,6 @@ static void remove_config(struct usb_composite_dev *cdev, } } -/** - * usb_remove_config() - remove a configuration from a device. - * @cdev: wraps the USB gadget - * @config: the configuration - * - * Drivers must call usb_gadget_disconnect before calling this function - * to disconnect the device from the host and make sure the host will not - * try to enumerate the device while we are changing the config list. - */ -void usb_remove_config(struct usb_composite_dev *cdev, - struct usb_configuration *config) -{ - unsigned long flags; - - spin_lock_irqsave(&cdev->lock, flags); - - if (cdev->config == config) - reset_config(cdev); - - spin_unlock_irqrestore(&cdev->lock, flags); - - remove_config(cdev, config); -} - /*-------------------------------------------------------------------------*/ /* We support strings in multiple languages ... string descriptor zero @@ -2489,6 +2465,11 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, if (!cdev->os_desc_req->buf) { ret = -ENOMEM; usb_ep_free_request(ep0, cdev->os_desc_req); + /* + * Set os_desc_req to NULL so that composite_dev_cleanup() + * will not try to free it again. + */ + cdev->os_desc_req = NULL; goto end; } cdev->os_desc_req->context = cdev; diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 95f144a54ed9..256364d4b941 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -54,59 +54,6 @@ usb_descriptor_fillbuf(void *buf, unsigned buflen, EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf); /** - * usb_gadget_config_buf - builts a complete configuration descriptor - * @config: Header for the descriptor, including characteristics such - * as power requirements and number of interfaces. - * @buf: Buffer for the resulting configuration descriptor. - * @length: Length of buffer. If this is not big enough to hold the - * entire configuration descriptor, an error code will be returned. - * @desc: Null-terminated vector of pointers to the descriptors (interface, - * endpoint, etc) defining all functions in this device configuration. - * - * This copies descriptors into the response buffer, building a descriptor - * for that configuration. It returns the buffer length or a negative - * status code. The config.wTotalLength field is set to match the length - * of the result, but other descriptor fields (including power usage and - * interface count) must be set by the caller. - * - * Gadget drivers could use this when constructing a config descriptor - * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the - * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. - */ -int usb_gadget_config_buf( - const struct usb_config_descriptor *config, - void *buf, - unsigned length, - const struct usb_descriptor_header **desc -) -{ - struct usb_config_descriptor *cp = buf; - int len; - - /* config descriptor first */ - if (length < USB_DT_CONFIG_SIZE || !desc) - return -EINVAL; - *cp = *config; - - /* then interface/endpoint/class/vendor/... */ - len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8 *)buf, - length - USB_DT_CONFIG_SIZE, desc); - if (len < 0) - return len; - len += USB_DT_CONFIG_SIZE; - if (len > 0xffff) - return -EINVAL; - - /* patch up the config descriptor */ - cp->bLength = USB_DT_CONFIG_SIZE; - cp->bDescriptorType = USB_DT_CONFIG; - cp->wTotalLength = cpu_to_le16(len); - cp->bmAttributes |= USB_CONFIG_ATT_ONE; - return len; -} -EXPORT_SYMBOL_GPL(usb_gadget_config_buf); - -/** * usb_copy_descriptors - copy a vector of USB descriptors * @src: null-terminated vector to copy * Context: initialization code, which may sleep diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index ea5f0af1e8d2..08a251df20c4 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -854,7 +854,6 @@ static void ffs_user_copy_worker(struct work_struct *work) work); int ret = io_data->status; bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD; - unsigned long flags; if (io_data->read && ret > 0) { kthread_use_mm(io_data->mm); @@ -867,10 +866,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd) eventfd_signal(io_data->ffs->ffs_eventfd); - spin_lock_irqsave(&io_data->ffs->eps_lock, flags); usb_ep_free_request(io_data->ep, io_data->req); - io_data->req = NULL; - spin_unlock_irqrestore(&io_data->ffs->eps_lock, flags); if (io_data->read) kfree(io_data->to_free); @@ -1211,19 +1207,13 @@ ffs_epfile_open(struct inode *inode, struct file *file) static int ffs_aio_cancel(struct kiocb *kiocb) { struct ffs_io_data *io_data = kiocb->private; - struct ffs_epfile *epfile = kiocb->ki_filp->private_data; - unsigned long flags; int value; - spin_lock_irqsave(&epfile->ffs->eps_lock, flags); - if (io_data && io_data->ep && io_data->req) value = usb_ep_dequeue(io_data->ep, io_data->req); else value = -EINVAL; - spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags); - return value; } @@ -3294,7 +3284,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, if (ffs_ep->descs[ep_desc_id]) { pr_err("two %sspeed descriptors for EP %d\n", speed_names[ep_desc_id], - ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + usb_endpoint_num(ds)); return -EINVAL; } ffs_ep->descs[ep_desc_id] = ds; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 97a62b926415..8e1d1e884050 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -1278,18 +1278,19 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) if (!hidg->workqueue) { status = -ENOMEM; - goto fail; + goto fail_free_descs; } /* create char device */ cdev_init(&hidg->cdev, &f_hidg_fops); status = cdev_device_add(&hidg->cdev, &hidg->dev); if (status) - goto fail_free_descs; + goto fail_free_all; return 0; -fail_free_descs: +fail_free_all: destroy_workqueue(hidg->workqueue); +fail_free_descs: usb_free_all_descriptors(f); fail: ERROR(f->config->cdev, "hidg_bind FAILED\n"); diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index c87e74afc881..9da9fb4e1239 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -1634,7 +1634,7 @@ static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \ int result; \ \ mutex_lock(&opts->lock); \ - result = scnprintf(page, sizeof(opts->name), "%s", opts->name); \ + result = sysfs_emit(page, "%s", opts->name); \ mutex_unlock(&opts->lock); \ \ return result; \ diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 9b324821c93b..dd252ff2fb4e 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -2052,7 +2052,7 @@ static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ int result; \ \ mutex_lock(&opts->lock); \ - result = scnprintf(page, sizeof(opts->name), "%s", opts->name); \ + result = sysfs_emit(page, "%s", opts->name); \ mutex_unlock(&opts->lock); \ \ return result; \ diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 540dc5ab96fc..1cce5317181a 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -1501,13 +1501,7 @@ void gserial_suspend(struct gserial *gser) spin_unlock_irqrestore(&serial_port_lock, flags); if (!gserial_wakeup_host(gser)) return; - - /* Check if port is valid after acquiring lock back */ spin_lock_irqsave(&serial_port_lock, flags); - if (!port) { - spin_unlock_irqrestore(&serial_port_lock, flags); - return; - } } spin_lock(&port->port_lock); diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index f131943254a4..a4a2d3dcb0d6 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -2916,8 +2916,15 @@ static struct config_group *uvcg_framebased_make(struct config_group *group, 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; + struct uvcg_color_matching *color_match; + struct config_item *streaming; struct uvcg_framebased *h; + streaming = group->cg_item.ci_parent; + color_match = uvcg_format_get_default_color_match(streaming); + if (!color_match) + return ERR_PTR(-EINVAL); + h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) return ERR_PTR(-ENOMEM); @@ -2936,6 +2943,9 @@ static struct config_group *uvcg_framebased_make(struct config_group *group, INIT_LIST_HEAD(&h->fmt.frames); h->fmt.type = UVCG_FRAMEBASED; + + h->fmt.color_matching = color_match; + color_match->refcnt++; config_group_init_type_name(&h->fmt.group, name, &uvcg_framebased_type); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 27c9699365ab..21dbfb0b3bac 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -623,7 +623,7 @@ static int dummy_enable(struct usb_ep *_ep, dev_dbg(udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d stream %s\n", _ep->name, - desc->bEndpointAddress & 0x0f, + usb_endpoint_num(desc), (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", usb_ep_type_string(usb_endpoint_type(desc)), max, str_enabled_disabled(ep->stream_en)); diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index 715791737499..54885175b8a4 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -359,7 +359,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, ep->pipenum = pipenum; ep->ep.maxpacket = usb_endpoint_maxp(desc); m66592->pipenum2ep[pipenum] = ep; - m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep; + m66592->epaddr2ep[usb_endpoint_num(desc)] = ep; INIT_LIST_HEAD(&ep->queue); } @@ -391,7 +391,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, BUG_ON(ep->pipenum); - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_BULK: if (m66592->bulk >= M66592_MAX_NUM_BULK) { if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { @@ -433,7 +433,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, } ep->type = info.type; - info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + info.epnum = usb_endpoint_num(desc); info.maxpacket = usb_endpoint_maxp(desc); info.interval = desc->bInterval; if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index b2903e4bbf54..8ea1adc7461d 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -203,13 +203,13 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) } /* erratum 0119 workaround ties up an endpoint number */ - if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE) { + if (usb_endpoint_num(desc) == EP_DONTUSE) { ret = -EDOM; goto print_err; } if (dev->quirks & PLX_PCIE) { - if ((desc->bEndpointAddress & 0x0f) >= 0x0c) { + if (usb_endpoint_num(desc) >= 0x0c) { ret = -EDOM; goto print_err; } @@ -255,7 +255,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) else tmp &= ~USB3380_EP_CFG_MASK_OUT; } - type = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + type = usb_endpoint_type(desc); if (type == USB_ENDPOINT_XFER_INT) { /* erratum 0105 workaround prevents hs NYET */ if (dev->chiprev == 0100 && @@ -1334,7 +1334,7 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) retval = -ESHUTDOWN; goto print_err; } - if (ep->desc /* not ep0 */ && (ep->desc->bmAttributes & 0x03) + if (ep->desc /* not ep0 */ && usb_endpoint_type(ep->desc) == USB_ENDPOINT_XFER_ISOC) { retval = -EINVAL; goto print_err; diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 169f72665739..0b20ecbe64f9 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -988,7 +988,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep, pch_udc_ep_fifo_flush(ep, ep->in); /* Configure the endpoint */ val = ep->num << UDC_CSR_NE_NUM_SHIFT | ep->in << UDC_CSR_NE_DIR_SHIFT | - ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) << + (usb_endpoint_type(desc) << UDC_CSR_NE_TYPE_SHIFT) | (cfg->cur_cfg << UDC_CSR_NE_CFG_SHIFT) | (cfg->cur_intf << UDC_CSR_NE_INTF_SHIFT) | diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 3e4d56457597..7cdcc9d16b8b 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2657,6 +2657,7 @@ static void renesas_usb3_remove(struct platform_device *pdev) struct renesas_usb3 *usb3 = platform_get_drvdata(pdev); debugfs_remove_recursive(usb3->dentry); + put_device(usb3->host_dev); device_remove_file(&pdev->dev, &dev_attr_role); cancel_work_sync(&usb3->role_work); @@ -2973,7 +2974,6 @@ err_alloc_prd: return ret; } -#ifdef CONFIG_PM_SLEEP static int renesas_usb3_suspend(struct device *dev) { struct renesas_usb3 *usb3 = dev_get_drvdata(dev); @@ -3004,17 +3004,16 @@ static int renesas_usb3_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(renesas_usb3_pm_ops, renesas_usb3_suspend, - renesas_usb3_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(renesas_usb3_pm_ops, renesas_usb3_suspend, + renesas_usb3_resume); static struct platform_driver renesas_usb3_driver = { .probe = renesas_usb3_probe, .remove = renesas_usb3_remove, .driver = { .name = udc_name, - .pm = &renesas_usb3_pm_ops, + .pm = pm_sleep_ptr(&renesas_usb3_pm_ops), .of_match_table = usb3_of_match, }, }; @@ -3023,4 +3022,3 @@ module_platform_driver(renesas_usb3_driver); MODULE_DESCRIPTION("Renesas USB3.0 Peripheral driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>"); -MODULE_ALIAS("platform:renesas_usb3"); diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index fa94cc065274..8d803a612bb1 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -813,10 +813,10 @@ static int __xudc_ep_enable(struct xusb_ep *ep, ep->is_in = ((desc->bEndpointAddress & USB_DIR_IN) != 0); /* Bit 3...0:endpoint number */ - ep->epnumber = (desc->bEndpointAddress & 0x0f); + ep->epnumber = usb_endpoint_num(desc); ep->desc = desc; ep->ep_usb.desc = desc; - tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + tmp = usb_endpoint_type(desc); ep->ep_usb.maxpacket = maxpacket = le16_to_cpu(desc->wMaxPacketSize); switch (tmp) { diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c index 8f75cb7b197c..5e6b545c30e6 100644 --- a/drivers/usb/host/ehci-sysfs.c +++ b/drivers/usb/host/ehci-sysfs.c @@ -12,21 +12,17 @@ static ssize_t companion_show(struct device *dev, char *buf) { struct ehci_hcd *ehci; - int nports, index, n; - int count = PAGE_SIZE; - char *ptr = buf; + int nports, index; + int len = 0; ehci = hcd_to_ehci(dev_get_drvdata(dev)); nports = HCS_N_PORTS(ehci->hcs_params); for (index = 0; index < nports; ++index) { - if (test_bit(index, &ehci->companion_ports)) { - n = scnprintf(ptr, count, "%d\n", index + 1); - ptr += n; - count -= n; - } + if (test_bit(index, &ehci->companion_ports)) + len += sysfs_emit_at(buf, len, "%d\n", index + 1); } - return ptr - buf; + return len; } /* @@ -70,11 +66,9 @@ static ssize_t uframe_periodic_max_show(struct device *dev, char *buf) { struct ehci_hcd *ehci; - int n; ehci = hcd_to_ehci(dev_get_drvdata(dev)); - n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max); - return n; + return sysfs_emit(buf, "%d\n", ehci->uframe_periodic_max); } diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 4e67b9471986..edfb63543029 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -327,8 +327,7 @@ static void fsl_usb2_mpc5121_exit(struct platform_device *pdev) pdata->regs = NULL; - if (pdata->clk) - clk_disable_unprepare(pdata->clk); + clk_disable_unprepare(pdata->clk); } static struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = { diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 5df793dcb25d..12fdb18934cf 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -193,7 +193,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, if (irq < 0) return irq; - hcd = usb_create_hcd(driver, dev, "at91"); + hcd = usb_create_hcd(driver, dev, dev_name(dev)); if (!hcd) return -ENOMEM; ohci_at91 = hcd_to_ohci_at91_priv(hcd); diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index d7131e5a4477..6843d7cb3f9f 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -103,8 +103,7 @@ static void spear_ohci_hcd_drv_remove(struct platform_device *pdev) struct spear_ohci *sohci_p = to_spear_ohci(hcd); usb_remove_hcd(hcd); - if (sohci_p->clk) - clk_disable_unprepare(sohci_p->clk); + clk_disable_unprepare(sohci_p->clk); usb_put_hcd(hcd); } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 6680afa4f596..07289333a1e8 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1195,6 +1195,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma | dev->eps[0].ring->cycle_state); + ep0_ctx->tx_info = cpu_to_le32(EP_AVG_TRB_LENGTH(8)); + trace_xhci_setup_addressable_virt_device(dev); /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index c79d5ed48a08..5eb51797de32 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -152,7 +152,7 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s int ret; int irq; struct xhci_plat_priv *priv = NULL; - bool of_match; + const struct of_device_id *of_match; if (usb_disabled()) return -ENODEV; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 94c9c9271658..ecd757d482c5 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1376,12 +1376,15 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, */ void xhci_hc_died(struct xhci_hcd *xhci) { + bool notify; int i, j; if (xhci->xhc_state & XHCI_STATE_DYING) return; - xhci_err(xhci, "xHCI host controller not responding, assume dead\n"); + notify = !(xhci->xhc_state & XHCI_STATE_REMOVING); + if (notify) + xhci_err(xhci, "xHCI host controller not responding, assume dead\n"); xhci->xhc_state |= XHCI_STATE_DYING; xhci_cleanup_command_queue(xhci); @@ -1395,7 +1398,7 @@ void xhci_hc_died(struct xhci_hcd *xhci) } /* inform usb core hc died if PCI remove isn't already handling it */ - if (!(xhci->xhc_state & XHCI_STATE_REMOVING)) + if (notify) usb_hc_died(xhci_to_hcd(xhci)); } @@ -4372,7 +4375,8 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, if ((xhci->xhc_state & XHCI_STATE_DYING) || (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n"); + xhci_dbg(xhci, "xHCI dying or halted, can't queue_command. state: 0x%x\n", + xhci->xhc_state); return -ESHUTDOWN; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8a819e853288..47151ca527bf 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -121,7 +121,8 @@ int xhci_halt(struct xhci_hcd *xhci) ret = xhci_handshake(&xhci->op_regs->status, STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); if (ret) { - xhci_warn(xhci, "Host halt failed, %d\n", ret); + if (!(xhci->xhc_state & XHCI_STATE_DYING)) + xhci_warn(xhci, "Host halt failed, %d\n", ret); return ret; } @@ -180,7 +181,8 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) state = readl(&xhci->op_regs->status); if (state == ~(u32)0) { - xhci_warn(xhci, "Host not accessible, reset failed.\n"); + if (!(xhci->xhc_state & XHCI_STATE_DYING)) + xhci_warn(xhci, "Host not accessible, reset failed.\n"); return -ENODEV; } diff --git a/drivers/usb/misc/apple-mfi-fastcharge.c b/drivers/usb/misc/apple-mfi-fastcharge.c index ac8695195c13..8e852f4b8262 100644 --- a/drivers/usb/misc/apple-mfi-fastcharge.c +++ b/drivers/usb/misc/apple-mfi-fastcharge.c @@ -44,6 +44,7 @@ MODULE_DEVICE_TABLE(usb, mfi_fc_id_table); struct mfi_device { struct usb_device *udev; struct power_supply *battery; + struct power_supply_desc battery_desc; int charge_type; }; @@ -178,6 +179,7 @@ static int mfi_fc_probe(struct usb_device *udev) { struct power_supply_config battery_cfg = {}; struct mfi_device *mfi = NULL; + char *battery_name; int err; if (!mfi_fc_match(udev)) @@ -187,23 +189,38 @@ static int mfi_fc_probe(struct usb_device *udev) if (!mfi) return -ENOMEM; + battery_name = kasprintf(GFP_KERNEL, "apple_mfi_fastcharge_%d-%d", + udev->bus->busnum, udev->devnum); + if (!battery_name) { + err = -ENOMEM; + goto err_free_mfi; + } + + mfi->battery_desc = apple_mfi_fc_desc; + mfi->battery_desc.name = battery_name; + battery_cfg.drv_data = mfi; mfi->charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; mfi->battery = power_supply_register(&udev->dev, - &apple_mfi_fc_desc, + &mfi->battery_desc, &battery_cfg); if (IS_ERR(mfi->battery)) { dev_err(&udev->dev, "Can't register battery\n"); err = PTR_ERR(mfi->battery); - kfree(mfi); - return err; + goto err_free_name; } mfi->udev = usb_get_dev(udev); dev_set_drvdata(&udev->dev, mfi); return 0; + +err_free_name: + kfree(battery_name); +err_free_mfi: + kfree(mfi); + return err; } static void mfi_fc_disconnect(struct usb_device *udev) @@ -213,6 +230,7 @@ static void mfi_fc_disconnect(struct usb_device *udev) mfi = dev_get_drvdata(&udev->dev); if (mfi->battery) power_supply_unregister(mfi->battery); + kfree(mfi->battery_desc.name); dev_set_drvdata(&udev->dev, NULL); usb_put_dev(mfi->udev); kfree(mfi); diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c index 5b481876af1b..41360a7591e5 100644 --- a/drivers/usb/misc/onboard_usb_dev.c +++ b/drivers/usb/misc/onboard_usb_dev.c @@ -564,6 +564,7 @@ static struct platform_driver onboard_dev_driver = { /************************** USB driver **************************/ +#define VENDOR_ID_BISON 0x5986 #define VENDOR_ID_CYPRESS 0x04b4 #define VENDOR_ID_GENESYS 0x05e3 #define VENDOR_ID_MICROCHIP 0x0424 @@ -647,6 +648,7 @@ static void onboard_dev_usbdev_disconnect(struct usb_device *udev) } static const struct usb_device_id onboard_dev_id_table[] = { + { USB_DEVICE(VENDOR_ID_BISON, 0x1198) }, /* Bison Electronics Inc. Integrated Camera */ { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6500) }, /* CYUSB330x 3.0 HUB */ { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6502) }, /* CYUSB330x 2.0 HUB */ { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6503) }, /* CYUSB33{0,1}x 2.0 HUB, Vendor Mode */ diff --git a/drivers/usb/misc/onboard_usb_dev.h b/drivers/usb/misc/onboard_usb_dev.h index e017b8e22f93..c1462be5526d 100644 --- a/drivers/usb/misc/onboard_usb_dev.h +++ b/drivers/usb/misc/onboard_usb_dev.h @@ -73,6 +73,13 @@ static const struct onboard_dev_pdata ti_tusb8041_data = { .is_hub = true, }; +static const struct onboard_dev_pdata bison_intcamera_data = { + .reset_us = 1000, + .num_supplies = 1, + .supply_names = { "vdd" }, + .is_hub = false, +}; + static const struct onboard_dev_pdata cypress_hx3_data = { .reset_us = 10000, .num_supplies = 2, @@ -144,6 +151,7 @@ static const struct of_device_id onboard_dev_match[] = { { .compatible = "usb2109,817", .data = &vialab_vl817_data, }, { .compatible = "usb2109,2817", .data = &vialab_vl817_data, }, { .compatible = "usb20b1,0013", .data = &xmos_xvf3500_data, }, + { .compatible = "usb5986,1198", .data = &bison_intcamera_data, }, {} }; diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 9e45d12b81d3..f56929267eaa 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -84,7 +84,8 @@ config USB_MUSB_TUSB6010 config USB_MUSB_OMAP2PLUS tristate "OMAP2430 and onwards" - depends on ARCH_OMAP2PLUS && USB + depends on ARCH_OMAP2PLUS || COMPILE_TEST + depends on USB depends on OMAP_CONTROL_PHY || !OMAP_CONTROL_PHY select GENERIC_PHY diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 2970967a4fd2..c35c07b7488c 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -318,13 +318,11 @@ static int omap2430_probe(struct platform_device *pdev) glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) - goto err0; + return -ENOMEM; musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err0; - } + if (!musb) + return -ENOMEM; musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &omap2430_dmamask; @@ -349,15 +347,15 @@ static int omap2430_probe(struct platform_device *pdev) pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) - goto err2; + goto err_put_musb; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) - goto err2; + goto err_put_musb; config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); if (!config) - goto err2; + goto err_put_musb; of_property_read_u32(np, "mode", (u32 *)&pdata->mode); of_property_read_u32(np, "interface-type", @@ -380,7 +378,7 @@ static int omap2430_probe(struct platform_device *pdev) if (!control_pdev) { dev_err(&pdev->dev, "Failed to get control device\n"); ret = -EINVAL; - goto err2; + goto err_put_musb; } glue->control_otghs = &control_pdev->dev; } @@ -400,7 +398,7 @@ static int omap2430_probe(struct platform_device *pdev) ret = platform_device_add_resources(musb, pdev->resource, pdev->num_resources); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err2; + goto err_put_control_otghs; } if (populate_irqs) { @@ -413,7 +411,7 @@ static int omap2430_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -EINVAL; - goto err2; + goto err_put_control_otghs; } musb_res[i].start = res->start; @@ -441,14 +439,14 @@ static int omap2430_probe(struct platform_device *pdev) ret = platform_device_add_resources(musb, musb_res, i); if (ret) { dev_err(&pdev->dev, "failed to add IRQ resources\n"); - goto err2; + goto err_put_control_otghs; } } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err2; + goto err_put_control_otghs; } pm_runtime_enable(glue->dev); @@ -456,18 +454,19 @@ static int omap2430_probe(struct platform_device *pdev) ret = platform_device_add(musb); if (ret) { dev_err(&pdev->dev, "failed to register musb device\n"); - goto err3; + goto err_disable_rpm; } return 0; -err3: +err_disable_rpm: pm_runtime_disable(glue->dev); - -err2: +err_put_control_otghs: + if (!IS_ERR(glue->control_otghs)) + put_device(glue->control_otghs); +err_put_musb: platform_device_put(musb); -err0: return ret; } @@ -477,6 +476,8 @@ static void omap2430_remove(struct platform_device *pdev) platform_device_unregister(glue->musb); pm_runtime_disable(glue->dev); + if (!IS_ERR(glue->control_otghs)) + put_device(glue->control_otghs); } #ifdef CONFIG_PM diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index bee222967f6b..fb9031628d39 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -711,58 +711,6 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) return utmip_pad_power_off(phy); } -static void utmi_phy_preresume(struct tegra_usb_phy *phy) -{ - void __iomem *base = phy->regs; - u32 val; - - val = readl_relaxed(base + UTMIP_TX_CFG0); - val |= UTMIP_HS_DISCON_DISABLE; - writel_relaxed(val, base + UTMIP_TX_CFG0); -} - -static void utmi_phy_postresume(struct tegra_usb_phy *phy) -{ - void __iomem *base = phy->regs; - u32 val; - - val = readl_relaxed(base + UTMIP_TX_CFG0); - val &= ~UTMIP_HS_DISCON_DISABLE; - writel_relaxed(val, base + UTMIP_TX_CFG0); -} - -static void utmi_phy_restore_start(struct tegra_usb_phy *phy, - enum tegra_usb_phy_port_speed port_speed) -{ - void __iomem *base = phy->regs; - u32 val; - - val = readl_relaxed(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); - if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) - val |= UTMIP_DPDM_OBSERVE_SEL_FS_K; - else - val |= UTMIP_DPDM_OBSERVE_SEL_FS_J; - writel_relaxed(val, base + UTMIP_MISC_CFG0); - usleep_range(1, 10); - - val = readl_relaxed(base + UTMIP_MISC_CFG0); - val |= UTMIP_DPDM_OBSERVE; - writel_relaxed(val, base + UTMIP_MISC_CFG0); - usleep_range(10, 100); -} - -static void utmi_phy_restore_end(struct tegra_usb_phy *phy) -{ - void __iomem *base = phy->regs; - u32 val; - - val = readl_relaxed(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE; - writel_relaxed(val, base + UTMIP_MISC_CFG0); - usleep_range(10, 100); -} - static int ulpi_phy_power_on(struct tegra_usb_phy *phy) { void __iomem *base = phy->regs; @@ -1123,43 +1071,6 @@ disable_clk: return err; } -void tegra_usb_phy_preresume(struct usb_phy *u_phy) -{ - struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy); - - if (!phy->is_ulpi_phy) - utmi_phy_preresume(phy); -} -EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume); - -void tegra_usb_phy_postresume(struct usb_phy *u_phy) -{ - struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy); - - if (!phy->is_ulpi_phy) - utmi_phy_postresume(phy); -} -EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); - -void tegra_ehci_phy_restore_start(struct usb_phy *u_phy, - enum tegra_usb_phy_port_speed port_speed) -{ - struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy); - - if (!phy->is_ulpi_phy) - utmi_phy_restore_start(phy, port_speed); -} -EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start); - -void tegra_ehci_phy_restore_end(struct usb_phy *u_phy) -{ - struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy); - - if (!phy->is_ulpi_phy) - utmi_phy_restore_end(phy); -} -EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); - static int read_utmi_param(struct platform_device *pdev, const char *param, u8 *dest) { diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index f52418fe3fd4..18a6ef4dce51 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -823,7 +823,7 @@ static void usbhs_remove(struct platform_device *pdev) usbhs_pipe_remove(priv); } -static __maybe_unused int usbhsc_suspend(struct device *dev) +static int usbhsc_suspend(struct device *dev) { struct usbhs_priv *priv = dev_get_drvdata(dev); struct usbhs_mod *mod = usbhs_mod_get_current(priv); @@ -839,7 +839,7 @@ static __maybe_unused int usbhsc_suspend(struct device *dev) return 0; } -static __maybe_unused int usbhsc_resume(struct device *dev) +static int usbhsc_resume(struct device *dev) { struct usbhs_priv *priv = dev_get_drvdata(dev); struct platform_device *pdev = usbhs_priv_to_pdev(priv); @@ -856,12 +856,12 @@ static __maybe_unused int usbhsc_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(usbhsc_pm_ops, usbhsc_suspend, usbhsc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(usbhsc_pm_ops, usbhsc_suspend, usbhsc_resume); static struct platform_driver renesas_usbhs_driver = { .driver = { .name = "renesas_usbhs", - .pm = &usbhsc_pm_ops, + .pm = pm_sleep_ptr(&usbhsc_pm_ops), .of_match_table = usbhs_of_match, }, .probe = usbhs_probe, diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 10607e273879..bac6f8fd0055 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -123,7 +123,7 @@ struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt) if (fifo) chan = usbhsf_dma_chan_get(fifo, pkt); if (chan) { - dmaengine_terminate_all(chan); + dmaengine_terminate_sync(chan); usbhsf_dma_unmap(pkt); } else { if (usbhs_pipe_is_dir_in(pipe)) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 9960ac2b10b7..cfa1d68c7919 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -1504,7 +1504,7 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio) return !!(mask & BIT(gpio)); } -static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) +static int cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) { struct usb_serial *serial = gpiochip_get_data(gc); struct cp210x_serial_private *priv = usb_get_serial_data(serial); @@ -1559,7 +1559,10 @@ out: if (result < 0) { dev_err(&serial->interface->dev, "failed to set GPIO value: %d\n", result); + return result; } + + return 0; } static int cp210x_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio) @@ -1599,9 +1602,8 @@ static int cp210x_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, struct cp210x_serial_private *priv = usb_get_serial_data(serial); priv->gpio_input &= ~BIT(gpio); - cp210x_gpio_set(gc, gpio, value); - return 0; + return cp210x_gpio_set(gc, gpio, value); } static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio, @@ -1960,7 +1962,7 @@ static int cp210x_gpio_init(struct usb_serial *serial) priv->gc.direction_input = cp210x_gpio_direction_input; priv->gc.direction_output = cp210x_gpio_direction_output; priv->gc.get = cp210x_gpio_get; - priv->gc.set = cp210x_gpio_set; + priv->gc.set_rv = cp210x_gpio_set; priv->gc.set_config = cp210x_gpio_set_config; priv->gc.init_valid_mask = cp210x_gpio_init_valid_mask; priv->gc.owner = THIS_MODULE; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index abfcfca3f971..7737285a84ba 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1859,10 +1859,11 @@ static int ftdi_gpio_get(struct gpio_chip *gc, unsigned int gpio) return !!(result & BIT(gpio)); } -static void ftdi_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) +static int ftdi_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) { struct usb_serial_port *port = gpiochip_get_data(gc); struct ftdi_private *priv = usb_get_serial_port_data(port); + int result; mutex_lock(&priv->gpio_lock); @@ -1871,9 +1872,11 @@ static void ftdi_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) else priv->gpio_value &= ~BIT(gpio); - ftdi_set_cbus_pins(port); + result = ftdi_set_cbus_pins(port); mutex_unlock(&priv->gpio_lock); + + return result; } static int ftdi_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, @@ -1891,19 +1894,22 @@ static int ftdi_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, return 0; } -static void ftdi_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, +static int ftdi_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits) { struct usb_serial_port *port = gpiochip_get_data(gc); struct ftdi_private *priv = usb_get_serial_port_data(port); + int result; mutex_lock(&priv->gpio_lock); priv->gpio_value &= ~(*mask); priv->gpio_value |= *bits & *mask; - ftdi_set_cbus_pins(port); + result = ftdi_set_cbus_pins(port); mutex_unlock(&priv->gpio_lock); + + return result; } static int ftdi_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio) @@ -2144,9 +2150,9 @@ static int ftdi_gpio_init(struct usb_serial_port *port) priv->gc.direction_output = ftdi_gpio_direction_output; priv->gc.init_valid_mask = ftdi_gpio_init_valid_mask; priv->gc.get = ftdi_gpio_get; - priv->gc.set = ftdi_gpio_set; + priv->gc.set_rv = ftdi_gpio_set; priv->gc.get_multiple = ftdi_gpio_get_multiple; - priv->gc.set_multiple = ftdi_gpio_set_multiple; + priv->gc.set_multiple_rv = ftdi_gpio_set_multiple; priv->gc.owner = THIS_MODULE; priv->gc.parent = &serial->interface->dev; priv->gc.base = -1; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 147ca50c94be..e5cd33093423 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2346,6 +2346,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe145, 0xff), /* Foxconn T99W651 RNDIS */ .driver_info = RSVD(5) | RSVD(6) }, + { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe15f, 0xff), /* Foxconn T99W709 */ + .driver_info = RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe167, 0xff), /* Foxconn T99W640 MBIM */ .driver_info = RSVD(3) }, { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */ diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index c18dfa2ca034..7dea28c2b8ee 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -748,7 +748,7 @@ static void rts51x_modi_suspend_timer(struct rts51x_chip *chip) usb_stor_dbg(us, "state:%d\n", rts51x_get_stat(chip)); - chip->timer_expires = jiffies + msecs_to_jiffies(1000*ss_delay); + chip->timer_expires = jiffies + secs_to_jiffies(ss_delay); mod_timer(&chip->rts51x_suspend_timer, chip->timer_expires); } diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index d8b906ec4d1c..1dcb77faf85d 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -65,6 +65,13 @@ struct dp_altmode { enum dp_state state; bool hpd; bool pending_hpd; + u32 irq_hpd_count; + /* + * hpd is mandatory for irq_hpd assertion, so irq_hpd also needs its own pending flag if + * both hpd and irq_hpd are asserted in the first Status Update before the pin assignment + * is configured. + */ + bool pending_irq_hpd; struct mutex lock; /* device lock */ struct work_struct work; @@ -151,6 +158,7 @@ static int dp_altmode_status_update(struct dp_altmode *dp) { bool configured = !!DP_CONF_GET_PIN_ASSIGN(dp->data.conf); bool hpd = !!(dp->data.status & DP_STATUS_HPD_STATE); + bool irq_hpd = !!(dp->data.status & DP_STATUS_IRQ_HPD); u8 con = DP_STATUS_CONNECTION(dp->data.status); int ret = 0; @@ -170,6 +178,8 @@ static int dp_altmode_status_update(struct dp_altmode *dp) dp->hpd = hpd; dp->pending_hpd = true; } + if (dp->hpd && dp->pending_hpd && irq_hpd) + dp->pending_irq_hpd = true; } } else { drm_connector_oob_hotplug_event(dp->connector_fwnode, @@ -177,6 +187,10 @@ static int dp_altmode_status_update(struct dp_altmode *dp) connector_status_disconnected); dp->hpd = hpd; sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); + if (hpd && irq_hpd) { + dp->irq_hpd_count++; + sysfs_notify(&dp->alt->dev.kobj, "displayport", "irq_hpd"); + } } return ret; @@ -196,6 +210,11 @@ static int dp_altmode_configured(struct dp_altmode *dp) connector_status_connected); sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); dp->pending_hpd = false; + if (dp->pending_irq_hpd) { + dp->irq_hpd_count++; + sysfs_notify(&dp->alt->dev.kobj, "displayport", "irq_hpd"); + dp->pending_irq_hpd = false; + } } return dp_altmode_notify(dp); @@ -706,10 +725,19 @@ static ssize_t hpd_show(struct device *dev, struct device_attribute *attr, char } static DEVICE_ATTR_RO(hpd); +static ssize_t irq_hpd_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dp_altmode *dp = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", dp->irq_hpd_count); +} +static DEVICE_ATTR_RO(irq_hpd); + static struct attribute *displayport_attrs[] = { &dev_attr_configuration.attr, &dev_attr_pin_assignment.attr, &dev_attr_hpd.attr, + &dev_attr_irq_hpd.attr, NULL }; diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c index 65dda9183e6f..1698428654ab 100644 --- a/drivers/usb/typec/mux/intel_pmc_mux.c +++ b/drivers/usb/typec/mux/intel_pmc_mux.c @@ -754,7 +754,7 @@ static int pmc_usb_probe(struct platform_device *pdev) pmc->ipc = devm_intel_scu_ipc_dev_get(&pdev->dev); if (!pmc->ipc) - return -ENODEV; + return -EPROBE_DEFER; pmc->dev = &pdev->dev; diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index f15c63d3a8f4..a4ff2403ddd6 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -104,6 +104,7 @@ struct fusb302_chip { bool vconn_on; bool vbus_on; bool charge_on; + bool pd_rx_on; bool vbus_present; enum typec_cc_polarity cc_polarity; enum typec_cc_status cc1; @@ -841,6 +842,11 @@ static int tcpm_set_pd_rx(struct tcpc_dev *dev, bool on) int ret = 0; mutex_lock(&chip->lock); + if (chip->pd_rx_on == on) { + fusb302_log(chip, "pd is already %s", str_on_off(on)); + goto done; + } + ret = fusb302_pd_rx_flush(chip); if (ret < 0) { fusb302_log(chip, "cannot flush pd rx buffer, ret=%d", ret); @@ -863,6 +869,8 @@ static int tcpm_set_pd_rx(struct tcpc_dev *dev, bool on) str_on_off(on), ret); goto done; } + + chip->pd_rx_on = on; fusb302_log(chip, "pd := %s", str_on_off(on)); done: mutex_unlock(&chip->lock); @@ -1477,9 +1485,6 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id) struct fusb302_chip *chip = dev_id; unsigned long flags; - /* Disable our level triggered IRQ until our irq_work has cleared it */ - disable_irq_nosync(chip->gpio_int_n_irq); - spin_lock_irqsave(&chip->irq_lock, flags); if (chip->irq_suspended) chip->irq_while_suspended = true; @@ -1622,7 +1627,6 @@ static void fusb302_irq_work(struct work_struct *work) } done: mutex_unlock(&chip->lock); - enable_irq(chip->gpio_int_n_irq); } static int init_gpio(struct fusb302_chip *chip) @@ -1747,9 +1751,10 @@ static int fusb302_probe(struct i2c_client *client) goto destroy_workqueue; } - ret = request_irq(chip->gpio_int_n_irq, fusb302_irq_intn, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "fsc_interrupt_int_n", chip); + ret = devm_request_threaded_irq(dev, chip->gpio_int_n_irq, + NULL, fusb302_irq_intn, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "fsc_interrupt_int_n", chip); if (ret < 0) { dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret); goto tcpm_unregister_port; @@ -1774,7 +1779,6 @@ static void fusb302_remove(struct i2c_client *client) struct fusb302_chip *chip = i2c_get_clientdata(client); disable_irq_wake(chip->gpio_int_n_irq); - free_irq(chip->gpio_int_n_irq, chip); cancel_work_sync(&chip->irq_work); cancel_delayed_work_sync(&chip->bc_lvl_handler); tcpm_unregister_port(chip->tcpm_port); diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c index b5a5ed40faea..19f638650796 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c @@ -421,21 +421,6 @@ static irqreturn_t max_tcpci_isr(int irq, void *dev_id) return IRQ_WAKE_THREAD; } -static int max_tcpci_init_alert(struct max_tcpci_chip *chip, struct i2c_client *client) -{ - int ret; - - ret = devm_request_threaded_irq(chip->dev, client->irq, max_tcpci_isr, max_tcpci_irq, - (IRQF_TRIGGER_LOW | IRQF_ONESHOT), dev_name(chip->dev), - chip); - - if (ret < 0) - return ret; - - enable_irq_wake(client->irq); - return 0; -} - static int max_tcpci_start_toggling(struct tcpci *tcpci, struct tcpci_data *tdata, enum typec_cc_status cc) { @@ -532,7 +517,9 @@ static int max_tcpci_probe(struct i2c_client *client) chip->port = tcpci_get_tcpm_port(chip->tcpci); - ret = max_tcpci_init_alert(chip, client); + ret = devm_request_threaded_irq(&client->dev, client->irq, max_tcpci_isr, max_tcpci_irq, + (IRQF_TRIGGER_LOW | IRQF_ONESHOT), dev_name(chip->dev), + chip); if (ret < 0) return dev_err_probe(&client->dev, ret, "IRQ initialization failed\n"); @@ -544,24 +531,50 @@ static int max_tcpci_probe(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM_SLEEP +static int max_tcpci_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret = 0; + + if (client->irq && device_may_wakeup(dev)) + ret = disable_irq_wake(client->irq); + + return ret; +} + +static int max_tcpci_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret = 0; + + if (client->irq && device_may_wakeup(dev)) + ret = enable_irq_wake(client->irq); + + return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(max_tcpci_pm_ops, max_tcpci_suspend, max_tcpci_resume); + static const struct i2c_device_id max_tcpci_id[] = { { "maxtcpc" }, { } }; MODULE_DEVICE_TABLE(i2c, max_tcpci_id); -#ifdef CONFIG_OF static const struct of_device_id max_tcpci_of_match[] = { { .compatible = "maxim,max33359", }, {}, }; MODULE_DEVICE_TABLE(of, max_tcpci_of_match); -#endif static struct i2c_driver max_tcpci_i2c_driver = { .driver = { .name = "maxtcpc", - .of_match_table = of_match_ptr(max_tcpci_of_match), + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = max_tcpci_of_match, + .pm = &max_tcpci_pm_ops, }, .probe = max_tcpci_probe, .id_table = max_tcpci_id, diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 8bf8fefb4f07..7fcb1e1de5d6 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -85,6 +85,8 @@ config CROS_EC_UCSI config UCSI_LENOVO_YOGA_C630 tristate "UCSI Interface Driver for Lenovo Yoga C630" depends on EC_LENOVO_YOGA_C630 + depends on DRM || !DRM + select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF help This driver enables UCSI support on the Lenovo Yoga C630 laptop. diff --git a/drivers/usb/typec/ucsi/cros_ec_ucsi.c b/drivers/usb/typec/ucsi/cros_ec_ucsi.c index 4ec1c6d22310..eed2a7d0ebc6 100644 --- a/drivers/usb/typec/ucsi/cros_ec_ucsi.c +++ b/drivers/usb/typec/ucsi/cros_ec_ucsi.c @@ -137,6 +137,7 @@ static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci, static const struct ucsi_operations cros_ucsi_ops = { .read_version = cros_ucsi_read_version, .read_cci = cros_ucsi_read_cci, + .poll_cci = cros_ucsi_read_cci, .read_message_in = cros_ucsi_read_message_in, .async_control = cros_ucsi_async_control, .sync_control = cros_ucsi_sync_control, diff --git a/drivers/usb/typec/ucsi/psy.c b/drivers/usb/typec/ucsi/psy.c index 62ac69730405..62a9d68bb66d 100644 --- a/drivers/usb/typec/ucsi/psy.c +++ b/drivers/usb/typec/ucsi/psy.c @@ -164,7 +164,7 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con, case UCSI_CONSTAT_PWR_OPMODE_DEFAULT: /* UCSI can't tell b/w DCP/CDP or USB2/3x1/3x2 SDP chargers */ default: - val->intval = 0; + val->intval = UCSI_TYPEC_DEFAULT_CURRENT * 1000; break; } return 0; diff --git a/drivers/usb/typec/ucsi/trace.c b/drivers/usb/typec/ucsi/trace.c index 596a9542d401..13a38422743a 100644 --- a/drivers/usb/typec/ucsi/trace.c +++ b/drivers/usb/typec/ucsi/trace.c @@ -33,23 +33,6 @@ const char *ucsi_cmd_str(u64 raw_cmd) return ucsi_cmd_strs[(cmd >= ARRAY_SIZE(ucsi_cmd_strs)) ? 0 : cmd]; } -const char *ucsi_cci_str(u32 cci) -{ - if (UCSI_CCI_CONNECTOR(cci)) { - if (cci & UCSI_CCI_ACK_COMPLETE) - return "Event pending (ACK completed)"; - if (cci & UCSI_CCI_COMMAND_COMPLETE) - return "Event pending (command completed)"; - return "Connector Change"; - } - if (cci & UCSI_CCI_ACK_COMPLETE) - return "ACK completed"; - if (cci & UCSI_CCI_COMMAND_COMPLETE) - return "Command completed"; - - return ""; -} - static const char * const ucsi_recipient_strs[] = { [UCSI_RECIPIENT_CON] = "port", [UCSI_RECIPIENT_SOP] = "partner", diff --git a/drivers/usb/typec/ucsi/trace.h b/drivers/usb/typec/ucsi/trace.h index 41701dee7056..9554a0207276 100644 --- a/drivers/usb/typec/ucsi/trace.h +++ b/drivers/usb/typec/ucsi/trace.h @@ -10,7 +10,6 @@ #include <linux/usb/typec_altmode.h> const char *ucsi_cmd_str(u64 raw_cmd); -const char *ucsi_cci_str(u32 cci); const char *ucsi_recipient_str(u8 recipient); DECLARE_EVENT_CLASS(ucsi_log_command, diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 01ce858a1a2b..5739ea2abdd1 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -531,13 +531,12 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient) * Update the original altmode table as some ppms may report * multiple DP altmodes. */ - if (recipient == UCSI_RECIPIENT_CON) - multi_dp = ucsi->ops->update_altmodes(ucsi, orig, updated); + multi_dp = ucsi->ops->update_altmodes(ucsi, recipient, orig, updated); /* now register altmodes */ for (i = 0; i < max_altmodes; i++) { memset(&desc, 0, sizeof(desc)); - if (multi_dp && recipient == UCSI_RECIPIENT_CON) { + if (multi_dp) { desc.svid = updated[i].svid; desc.vdo = updated[i].mid; } else { @@ -1246,6 +1245,7 @@ static void ucsi_handle_connector_change(struct work_struct *work) if (change & UCSI_CONSTAT_POWER_DIR_CHANGE) { typec_set_pwr_role(con->port, role); + ucsi_port_psy_changed(con); /* Complete pending power role swap */ if (!completion_done(&con->complete)) diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 5a8f947fcece..ebd7c27c2cc7 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -50,6 +50,7 @@ struct dentry; /* Command Status and Connector Change Indication (CCI) bits */ #define UCSI_CCI_CONNECTOR(_c_) (((_c_) & GENMASK(7, 1)) >> 1) #define UCSI_CCI_LENGTH(_c_) (((_c_) & GENMASK(15, 8)) >> 8) +#define UCSI_SET_CCI_LENGTH(_c_) ((_c_) << 8) #define UCSI_CCI_NOT_SUPPORTED BIT(25) #define UCSI_CCI_CANCEL_COMPLETE BIT(26) #define UCSI_CCI_RESET_COMPLETE BIT(27) @@ -82,7 +83,8 @@ struct ucsi_operations { int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci, void *data, size_t size); int (*async_control)(struct ucsi *ucsi, u64 command); - bool (*update_altmodes)(struct ucsi *ucsi, struct ucsi_altmode *orig, + bool (*update_altmodes)(struct ucsi *ucsi, u8 recipient, + struct ucsi_altmode *orig, struct ucsi_altmode *updated); void (*update_connector)(struct ucsi_connector *con); void (*connector_status)(struct ucsi_connector *con); @@ -481,9 +483,10 @@ struct ucsi { #define UCSI_MAX_SVID 5 #define UCSI_MAX_ALTMODES (UCSI_MAX_SVID * 6) -#define UCSI_TYPEC_VSAFE5V 5000 -#define UCSI_TYPEC_1_5_CURRENT 1500 -#define UCSI_TYPEC_3_0_CURRENT 3000 +#define UCSI_TYPEC_VSAFE5V 5000 +#define UCSI_TYPEC_DEFAULT_CURRENT 100 +#define UCSI_TYPEC_1_5_CURRENT 1500 +#define UCSI_TYPEC_3_0_CURRENT 3000 struct ucsi_connector { int num; diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index e9a9df1431af..d83a0051c737 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -394,6 +394,7 @@ static void ucsi_ccg_update_get_current_cam_cmd(struct ucsi_ccg *uc, u8 *data) } static bool ucsi_ccg_update_altmodes(struct ucsi *ucsi, + u8 recipient, struct ucsi_altmode *orig, struct ucsi_altmode *updated) { @@ -402,6 +403,9 @@ static bool ucsi_ccg_update_altmodes(struct ucsi *ucsi, int i, j, k = 0; bool found = false; + if (recipient != UCSI_RECIPIENT_CON) + return false; + alt = uc->orig; new_alt = uc->updated; memset(uc->updated, 0, sizeof(uc->updated)); diff --git a/drivers/usb/typec/ucsi/ucsi_yoga_c630.c b/drivers/usb/typec/ucsi/ucsi_yoga_c630.c index d33e3f2dd1d8..0187c1c4b21a 100644 --- a/drivers/usb/typec/ucsi/ucsi_yoga_c630.c +++ b/drivers/usb/typec/ucsi/ucsi_yoga_c630.c @@ -7,18 +7,33 @@ */ #include <linux/auxiliary_bus.h> #include <linux/bitops.h> +#include <linux/bitfield.h> #include <linux/completion.h> #include <linux/container_of.h> #include <linux/module.h> #include <linux/notifier.h> +#include <linux/of.h> +#include <linux/property.h> #include <linux/string.h> #include <linux/platform_data/lenovo-yoga-c630.h> +#include <linux/usb/typec_dp.h> + +#include <drm/bridge/aux-bridge.h> #include "ucsi.h" +#define LENOVO_EC_USB_MUX 0x08 + +#define USB_MUX_MUXC GENMASK(1, 0) +#define USB_MUX_CCST GENMASK(3, 2) +#define USB_MUX_DPPN GENMASK(7, 4) +#define USB_MUX_HPDS BIT(8) +#define USB_MUX_HSFL GENMASK(11, 9) + struct yoga_c630_ucsi { struct yoga_c630_ec *ec; struct ucsi *ucsi; + struct auxiliary_device *bridge; struct notifier_block nb; u16 version; }; @@ -71,15 +86,127 @@ static int yoga_c630_ucsi_async_control(struct ucsi *ucsi, u64 command) return yoga_c630_ec_ucsi_write(uec->ec, (u8*)&command); } +static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi, + u64 command, + u32 *cci, + void *data, size_t size) +{ + int ret; + + /* + * EC doesn't return connector's DP mode even though it is supported. + * Fake it. + */ + if (UCSI_COMMAND(command) == UCSI_GET_ALTERNATE_MODES && + UCSI_GET_ALTMODE_GET_CONNECTOR_NUMBER(command) == 1 && + UCSI_ALTMODE_RECIPIENT(command) == UCSI_RECIPIENT_CON && + UCSI_ALTMODE_OFFSET(command) == 0) { + static const struct ucsi_altmode alt = { + .svid = USB_TYPEC_DP_SID, + .mid = USB_TYPEC_DP_MODE, + }; + + dev_dbg(ucsi->dev, "faking DP altmode for con1\n"); + memset(data, 0, size); + memcpy(data, &alt, min(sizeof(alt), size)); + *cci = UCSI_CCI_COMMAND_COMPLETE | UCSI_SET_CCI_LENGTH(sizeof(alt)); + return 0; + } + + /* + * EC can return AltModes present on CON1 (port0, right) for CON2 + * (port1, left) too. Ignore all requests going to CON2 (it doesn't + * support DP anyway). + */ + if (UCSI_COMMAND(command) == UCSI_GET_ALTERNATE_MODES && + UCSI_GET_ALTMODE_GET_CONNECTOR_NUMBER(command) == 2) { + dev_dbg(ucsi->dev, "ignoring altmodes for con2\n"); + memset(data, 0, size); + *cci = UCSI_CCI_COMMAND_COMPLETE; + return 0; + } + + ret = ucsi_sync_control_common(ucsi, command, cci, data, size); + if (ret < 0) + return ret; + + /* UCSI_GET_CURRENT_CAM is off-by-one on all ports */ + if (UCSI_COMMAND(command) == UCSI_GET_CURRENT_CAM && data) + ((u8 *)data)[0]--; + + return ret; +} + +static bool yoga_c630_ucsi_update_altmodes(struct ucsi *ucsi, + u8 recipient, + struct ucsi_altmode *orig, + struct ucsi_altmode *updated) +{ + int i; + + if (orig[0].svid == 0 || recipient != UCSI_RECIPIENT_SOP) + return false; + + /* EC is nice and repeats altmodes again and again. Ignore copies. */ + for (i = 1; i < UCSI_MAX_ALTMODES; i++) { + if (orig[i].svid == orig[0].svid) { + dev_dbg(ucsi->dev, "Found duplicate altmodes, starting from %d\n", i); + memset(&orig[i], 0, (UCSI_MAX_ALTMODES - i) * sizeof(*orig)); + break; + } + } + + return false; +} + +static void yoga_c630_ucsi_update_connector(struct ucsi_connector *con) +{ + if (con->num == 1) + con->typec_cap.orientation_aware = true; +} + static const struct ucsi_operations yoga_c630_ucsi_ops = { .read_version = yoga_c630_ucsi_read_version, .read_cci = yoga_c630_ucsi_read_cci, .poll_cci = yoga_c630_ucsi_read_cci, .read_message_in = yoga_c630_ucsi_read_message_in, - .sync_control = ucsi_sync_control_common, + .sync_control = yoga_c630_ucsi_sync_control, .async_control = yoga_c630_ucsi_async_control, + .update_altmodes = yoga_c630_ucsi_update_altmodes, + .update_connector = yoga_c630_ucsi_update_connector, }; +static void yoga_c630_ucsi_read_port0_status(struct yoga_c630_ucsi *uec) +{ + int val; + unsigned int muxc, ccst, dppn, hpds, hsfl; + + val = yoga_c630_ec_read16(uec->ec, LENOVO_EC_USB_MUX); + + muxc = FIELD_GET(USB_MUX_MUXC, val); + ccst = FIELD_GET(USB_MUX_CCST, val); + dppn = FIELD_GET(USB_MUX_DPPN, val); + hpds = FIELD_GET(USB_MUX_HPDS, val); + hsfl = FIELD_GET(USB_MUX_HSFL, val); + + dev_dbg(uec->ucsi->dev, " mux %04x (muxc %d ccst %d dppn %d hpds %d hsfl %d)\n", + val, + muxc, ccst, dppn, hpds, hsfl); + + if (uec->ucsi->connector && uec->ucsi->connector[0].port) + typec_set_orientation(uec->ucsi->connector[0].port, + ccst == 1 ? + TYPEC_ORIENTATION_REVERSE : + TYPEC_ORIENTATION_NORMAL); + + if (uec->bridge) + drm_aux_hpd_bridge_notify(&uec->bridge->dev, + dppn != 0 ? + connector_status_connected : + connector_status_disconnected); + +} + static int yoga_c630_ucsi_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -90,6 +217,7 @@ static int yoga_c630_ucsi_notify(struct notifier_block *nb, switch (action) { case LENOVO_EC_EVENT_USB: case LENOVO_EC_EVENT_HPD: + yoga_c630_ucsi_read_port0_status(uec); ucsi_connector_change(uec->ucsi, 1); return NOTIFY_OK; @@ -121,6 +249,24 @@ static int yoga_c630_ucsi_probe(struct auxiliary_device *adev, uec->ec = ec; uec->nb.notifier_call = yoga_c630_ucsi_notify; + device_for_each_child_node_scoped(&adev->dev, fwnode) { + u32 port; + + ret = fwnode_property_read_u32(fwnode, "reg", &port); + if (ret < 0) { + dev_err(&adev->dev, "missing reg property of %pfwP\n", fwnode); + return ret; + } + + /* DP is only on port0 */ + if (port != 0) + continue; + + uec->bridge = devm_drm_dp_hpd_bridge_alloc(&adev->dev, to_of_node(fwnode)); + if (IS_ERR(uec->bridge)) + return PTR_ERR(uec->bridge); + } + uec->ucsi = ucsi_create(&adev->dev, &yoga_c630_ucsi_ops); if (IS_ERR(uec->ucsi)) return PTR_ERR(uec->ucsi); @@ -133,17 +279,39 @@ static int yoga_c630_ucsi_probe(struct auxiliary_device *adev, ret = yoga_c630_ec_register_notify(ec, &uec->nb); if (ret) - return ret; + goto err_destroy; + + ret = ucsi_register(uec->ucsi); + if (ret) + goto err_unregister; + + if (uec->bridge) { + ret = devm_drm_dp_hpd_bridge_add(&adev->dev, uec->bridge); + if (ret) + goto err_ucsi_unregister; + } - return ucsi_register(uec->ucsi); + return 0; + +err_ucsi_unregister: + ucsi_unregister(uec->ucsi); + +err_unregister: + yoga_c630_ec_unregister_notify(uec->ec, &uec->nb); + +err_destroy: + ucsi_destroy(uec->ucsi); + + return ret; } static void yoga_c630_ucsi_remove(struct auxiliary_device *adev) { struct yoga_c630_ucsi *uec = auxiliary_get_drvdata(adev); - yoga_c630_ec_unregister_notify(uec->ec, &uec->nb); ucsi_unregister(uec->ucsi); + yoga_c630_ec_unregister_notify(uec->ec, &uec->nb); + ucsi_destroy(uec->ucsi); } static const struct auxiliary_device_id yoga_c630_ucsi_id_table[] = { diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 5d231ce8709b..49f20c2f99bf 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -118,7 +118,6 @@ struct fsl_usb2_platform_data { #define FSL_USB2_PORT0_ENABLED 0x00000001 #define FSL_USB2_PORT1_ENABLED 0x00000002 -#define FLS_USB2_WORKAROUND_ENGCM09152 (1 << 0) struct spi_device; diff --git a/include/linux/usb.h b/include/linux/usb.h index 92c752f5446f..9d662c6abb4d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1455,6 +1455,10 @@ typedef void (*usb_complete_t)(struct urb *); * @sg: scatter gather buffer list, the buffer size of each element in * the list (except the last) must be divisible by the endpoint's * max packet size if no_sg_constraint isn't set in 'struct usb_bus' + * @sgt: used to hold a scatter gather table returned by usb_alloc_noncoherent(), + * which describes the allocated non-coherent and possibly non-contiguous + * memory and is guaranteed to have 1 single DMA mapped segment. The + * allocated memory needs to be freed by usb_free_noncoherent(). * @num_mapped_sgs: (internal) number of mapped sg entries * @num_sgs: number of entries in the sg list * @transfer_buffer_length: How big is transfer_buffer. The transfer may @@ -1621,6 +1625,7 @@ struct urb { void *transfer_buffer; /* (in) associated data buffer */ dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ struct scatterlist *sg; /* (in) scatter gather buffer list */ + struct sg_table *sgt; /* (in) scatter gather table for noncoherent buffer */ int num_mapped_sgs; /* (internal) mapped sg entries */ int num_sgs; /* (in) number of entries in the sg list */ u32 transfer_buffer_length; /* (in) data buffer length */ @@ -1782,7 +1787,6 @@ extern void usb_block_urb(struct urb *urb); extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); extern void usb_poison_anchored_urbs(struct usb_anchor *anchor); extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor); -extern void usb_unlink_anchored_urbs(struct usb_anchor *anchor); extern void usb_anchor_suspend_wakeups(struct usb_anchor *anchor); extern void usb_anchor_resume_wakeups(struct usb_anchor *anchor); extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); @@ -1827,6 +1831,16 @@ void *usb_alloc_coherent(struct usb_device *dev, size_t size, void usb_free_coherent(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma); +enum dma_data_direction; + +void *usb_alloc_noncoherent(struct usb_device *dev, size_t size, + gfp_t mem_flags, dma_addr_t *dma, + enum dma_data_direction dir, + struct sg_table **table); +void usb_free_noncoherent(struct usb_device *dev, size_t size, + void *addr, enum dma_data_direction dir, + struct sg_table *table); + /*-------------------------------------------------------------------* * SYNCHRONOUS CALL SUPPORT * *-------------------------------------------------------------------*/ diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index ebdfef124b2b..e17ebeee24e3 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -72,6 +72,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_IMX_HSIC_ACTIVE_EVENT 2 #define CI_HDRC_IMX_HSIC_SUSPEND_EVENT 3 #define CI_HDRC_CONTROLLER_VBUS_EVENT 4 +#define CI_HDRC_CONTROLLER_PULLUP_EVENT 5 int (*notify_event) (struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; struct usb_otg_caps ci_otg_caps; diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index d8c4e9f73839..c18041fafa52 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -339,9 +339,6 @@ int usb_add_config(struct usb_composite_dev *, struct usb_configuration *, int (*)(struct usb_configuration *)); -void usb_remove_config(struct usb_composite_dev *, - struct usb_configuration *); - /* predefined index for usb_composite_driver */ enum { USB_GADGET_MANUFACTURER_IDX = 0, diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index df33333650a0..0f28c5512fcb 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -860,10 +860,6 @@ container_of(str_item, struct gadget_string, item) int usb_descriptor_fillbuf(void *, unsigned, const struct usb_descriptor_header **); -/* build config descriptor from single descriptor vector */ -int usb_gadget_config_buf(const struct usb_config_descriptor *config, - void *buf, unsigned buflen, const struct usb_descriptor_header **desc); - /* copy a NULL-terminated vector of descriptors */ struct usb_descriptor_header **usb_copy_descriptors( struct usb_descriptor_header **); diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index e6c14f2b1f9b..40afcee8b4f5 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -80,13 +80,4 @@ struct tegra_usb_phy { bool powered_on; }; -void tegra_usb_phy_preresume(struct usb_phy *phy); - -void tegra_usb_phy_postresume(struct usb_phy *phy); - -void tegra_ehci_phy_restore_start(struct usb_phy *phy, - enum tegra_usb_phy_port_speed port_speed); - -void tegra_ehci_phy_restore_end(struct usb_phy *phy); - #endif /* __TEGRA_USB_PHY_H */ |