diff options
110 files changed, 2417 insertions, 1205 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index bf2c1968525f..73eb23bc1f34 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -154,17 +154,6 @@ Description: files hold a string value (enable or disable) indicating whether or not USB3 hardware LPM U1 or U2 is enabled for the device. -What: /sys/bus/usb/devices/.../removable -Date: February 2012 -Contact: Matthew Garrett <mjg@redhat.com> -Description: - Some information about whether a given USB device is - physically fixed to the platform can be inferred from a - combination of hub descriptor bits and platform-specific data - such as ACPI. This file will read either "removable" or - "fixed" if the information is available, and "unknown" - otherwise. - What: /sys/bus/usb/devices/.../ltm_capable Date: July 2012 Contact: Sarah Sharp <sarah.a.sharp@linux.intel.com> diff --git a/Documentation/ABI/testing/sysfs-devices-removable b/Documentation/ABI/testing/sysfs-devices-removable new file mode 100644 index 000000000000..bda6c320c8d3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-removable @@ -0,0 +1,18 @@ +What: /sys/devices/.../removable +Date: May 2021 +Contact: Rajat Jain <rajatxjain@gmail.com> +Description: + Information about whether a given device can be removed from the + platform by the user. This is determined by its subsystem in a + bus / platform-specific way. This attribute is only present for + devices that can support determining such information: + + "removable": device can be removed from the platform by the user + "fixed": device is fixed to the platform / cannot be removed + by the user. + "unknown": The information is unavailable / cannot be deduced. + + Currently this is only supported by USB (which infers the + information from a combination of hub descriptor bits and + platform-specific data such as ACPI) and PCI (which gets this + from ACPI / device tree). diff --git a/Documentation/devicetree/bindings/phy/allwinner,sun8i-h3-usb-phy.yaml b/Documentation/devicetree/bindings/phy/allwinner,sun8i-h3-usb-phy.yaml index f80431060803..e288450e0844 100644 --- a/Documentation/devicetree/bindings/phy/allwinner,sun8i-h3-usb-phy.yaml +++ b/Documentation/devicetree/bindings/phy/allwinner,sun8i-h3-usb-phy.yaml @@ -15,7 +15,9 @@ properties: const: 1 compatible: - const: allwinner,sun8i-h3-usb-phy + enum: + - allwinner,sun8i-h3-usb-phy + - allwinner,sun50i-h616-usb-phy reg: items: diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml index 0f520f17735e..933fa356d2ce 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml @@ -22,6 +22,9 @@ properties: - allwinner,sun8i-a83t-musb - allwinner,sun50i-h6-musb - const: allwinner,sun8i-a33-musb + - items: + - const: allwinner,sun50i-h616-musb + - const: allwinner,sun8i-h3-musb reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml index e5ee51b7b470..10c7d9b6cc53 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.yaml +++ b/Documentation/devicetree/bindings/usb/dwc2.yaml @@ -24,6 +24,7 @@ properties: - rockchip,rk3188-usb - rockchip,rk3228-usb - rockchip,rk3288-usb + - rockchip,rk3308-usb - rockchip,rk3328-usb - rockchip,rk3368-usb - rockchip,rv1108-usb diff --git a/Documentation/devicetree/bindings/usb/nxp,isp1760.yaml b/Documentation/devicetree/bindings/usb/nxp,isp1760.yaml new file mode 100644 index 000000000000..a88f99adfe8e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/nxp,isp1760.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/nxp,isp1760.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP ISP1760 family controller bindings + +maintainers: + - Sebastian Siewior <bigeasy@linutronix.de> + - Laurent Pinchart <laurent.pinchart@ideasonboard.com> + +description: | + NXP ISP1760 family, which includes ISP1760/1761/1763 devicetree controller + bindings + +properties: + compatible: + enum: + - nxp,usb-isp1760 + - nxp,usb-isp1761 + - nxp,usb-isp1763 + reg: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 2 + items: + - description: Host controller interrupt + - description: Device controller interrupt in isp1761 + + interrupt-names: + minItems: 1 + maxItems: 2 + items: + - const: host + - const: peripheral + + bus-width: + description: + Number of data lines. + enum: [8, 16, 32] + default: 32 + + dr_mode: + enum: + - host + - peripheral + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + usb@40200000 { + compatible = "nxp,usb-isp1763"; + reg = <0x40200000 0x100000>; + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>; + bus-width = <16>; + dr_mode = "host"; + }; + +... diff --git a/Documentation/driver-api/usb/error-codes.rst b/Documentation/driver-api/usb/error-codes.rst index a3e84bfac776..8f9790c2d6f8 100644 --- a/Documentation/driver-api/usb/error-codes.rst +++ b/Documentation/driver-api/usb/error-codes.rst @@ -61,6 +61,9 @@ USB-specific: (c) requested data transfer length is invalid: negative or too large for the host controller. +``-EBADR`` The wLength value in a control URB's setup packet does + not match the URB's transfer_buffer_length. + ``-ENOSPC`` This request would overcommit the usb bandwidth reserved for periodic transfers (interrupt, isochronous). diff --git a/arch/arm/boot/dts/arm-realview-eb.dtsi b/arch/arm/boot/dts/arm-realview-eb.dtsi index a534a8e444d9..04e8a27ba1eb 100644 --- a/arch/arm/boot/dts/arm-realview-eb.dtsi +++ b/arch/arm/boot/dts/arm-realview-eb.dtsi @@ -148,7 +148,7 @@ usb: usb@4f000000 { compatible = "nxp,usb-isp1761"; reg = <0x4f000000 0x20000>; - port1-otg; + dr_mode = "peripheral"; }; bridge { diff --git a/arch/arm/boot/dts/arm-realview-pb1176.dts b/arch/arm/boot/dts/arm-realview-pb1176.dts index f925782f8560..366687fb1ee3 100644 --- a/arch/arm/boot/dts/arm-realview-pb1176.dts +++ b/arch/arm/boot/dts/arm-realview-pb1176.dts @@ -166,7 +166,7 @@ reg = <0x3b000000 0x20000>; interrupt-parent = <&intc_fpga1176>; interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>; - port1-otg; + dr_mode = "peripheral"; }; bridge { diff --git a/arch/arm/boot/dts/arm-realview-pb11mp.dts b/arch/arm/boot/dts/arm-realview-pb11mp.dts index 0c7dabef4a5f..228a51a38f95 100644 --- a/arch/arm/boot/dts/arm-realview-pb11mp.dts +++ b/arch/arm/boot/dts/arm-realview-pb11mp.dts @@ -712,7 +712,7 @@ reg = <0x4f000000 0x20000>; interrupt-parent = <&intc_tc11mp>; interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>; - port1-otg; + dr_mode = "peripheral"; }; }; }; diff --git a/arch/arm/boot/dts/arm-realview-pbx.dtsi b/arch/arm/boot/dts/arm-realview-pbx.dtsi index ac95667ed781..ccf6f756b6ed 100644 --- a/arch/arm/boot/dts/arm-realview-pbx.dtsi +++ b/arch/arm/boot/dts/arm-realview-pbx.dtsi @@ -164,7 +164,7 @@ usb: usb@4f000000 { compatible = "nxp,usb-isp1761"; reg = <0x4f000000 0x20000>; - port1-otg; + dr_mode = "peripheral"; }; bridge { diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi index 4f7220b11f2d..2ad9fd7c94ec 100644 --- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi @@ -144,7 +144,7 @@ compatible = "nxp,usb-isp1761"; reg = <2 0x03000000 0x20000>; interrupts = <16>; - port1-otg; + dr_mode = "peripheral"; }; iofpga-bus@300000000 { diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi index 2ac41ed3a57c..ec13ceb9ed36 100644 --- a/arch/arm/boot/dts/vexpress-v2m.dtsi +++ b/arch/arm/boot/dts/vexpress-v2m.dtsi @@ -62,7 +62,7 @@ compatible = "nxp,usb-isp1761"; reg = <3 0x03000000 0x20000>; interrupts = <16>; - port1-otg; + dr_mode = "peripheral"; }; iofpga@7,00000000 { diff --git a/drivers/base/core.c b/drivers/base/core.c index 54ba506e5a89..aafdce004712 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -2409,6 +2409,25 @@ static ssize_t online_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(online); +static ssize_t removable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + const char *loc; + + switch (dev->removable) { + case DEVICE_REMOVABLE: + loc = "removable"; + break; + case DEVICE_FIXED: + loc = "fixed"; + break; + default: + loc = "unknown"; + } + return sysfs_emit(buf, "%s\n", loc); +} +static DEVICE_ATTR_RO(removable); + int device_add_groups(struct device *dev, const struct attribute_group **groups) { return sysfs_create_groups(&dev->kobj, groups); @@ -2586,8 +2605,16 @@ static int device_add_attrs(struct device *dev) goto err_remove_dev_online; } + if (dev_removable_is_valid(dev)) { + error = device_create_file(dev, &dev_attr_removable); + if (error) + goto err_remove_dev_waiting_for_supplier; + } + return 0; + err_remove_dev_waiting_for_supplier: + device_remove_file(dev, &dev_attr_waiting_for_supplier); err_remove_dev_online: device_remove_file(dev, &dev_attr_online); err_remove_dev_groups: @@ -2607,6 +2634,7 @@ static void device_remove_attrs(struct device *dev) struct class *class = dev->class; const struct device_type *type = dev->type; + device_remove_file(dev, &dev_attr_removable); device_remove_file(dev, &dev_attr_waiting_for_supplier); device_remove_file(dev, &dev_attr_online); device_remove_groups(dev, dev->groups); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 3a62d09b8869..812e0d7fd7a7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1575,6 +1575,26 @@ static void set_pcie_untrusted(struct pci_dev *dev) dev->untrusted = true; } +static void pci_set_removable(struct pci_dev *dev) +{ + struct pci_dev *parent = pci_upstream_bridge(dev); + + /* + * We (only) consider everything downstream from an external_facing + * device to be removable by the user. We're mainly concerned with + * consumer platforms with user accessible thunderbolt ports that are + * vulnerable to DMA attacks, and we expect those ports to be marked by + * the firmware as external_facing. Devices in traditional hotplug + * slots can technically be removed, but the expectation is that unless + * the port is marked with external_facing, such devices are less + * accessible to user / may not be removed by end user, and thus not + * exposed as "removable" to userspace. + */ + if (parent && + (parent->external_facing || dev_is_removable(&parent->dev))) + dev_set_removable(&dev->dev, DEVICE_REMOVABLE); +} + /** * pci_ext_cfg_is_aliased - Is ext config space just an alias of std config? * @dev: PCI device @@ -1822,6 +1842,8 @@ int pci_setup_device(struct pci_dev *dev) /* Early fixups, before probing the BARs */ pci_fixup_device(pci_fixup_early, dev); + pci_set_removable(dev); + pci_info(dev, "[%04x:%04x] type %02x class %#08x\n", dev->vendor, dev->device, dev->hdr_type, dev->class); diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 4d3947476f0e..4ce7cba2b48a 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -180,7 +180,7 @@ struct cxacru_data { struct mutex poll_state_serialize; enum cxacru_poll_state poll_state; - /* contol handles */ + /* control handles */ struct mutex cm_serialize; u8 *rcv_buf; u8 *snd_buf; diff --git a/drivers/usb/cdns3/cdns3-ep0.c b/drivers/usb/cdns3/cdns3-ep0.c index 9a17802275d5..02ec7ab4bb48 100644 --- a/drivers/usb/cdns3/cdns3-ep0.c +++ b/drivers/usb/cdns3/cdns3-ep0.c @@ -677,7 +677,7 @@ static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value) } /** - * cdns3_gadget_ep0_queue Transfer data on endpoint zero + * cdns3_gadget_ep0_queue - Transfer data on endpoint zero * @ep: pointer to endpoint zero object * @request: pointer to request object * @gfp_flags: gfp flags @@ -772,7 +772,7 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep, } /** - * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint + * cdns3_gadget_ep_set_wedge - Set wedge on selected endpoint * @ep: endpoint object * * Returns 0 @@ -865,7 +865,7 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev) } /** - * cdns3_init_ep0 Initializes software endpoint 0 of gadget + * cdns3_init_ep0 - Initializes software endpoint 0 of gadget * @priv_dev: extended gadget object * @priv_ep: extended endpoint object * diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index a8b7b50abf64..279077dae86a 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -155,7 +155,7 @@ static struct cdns3_request *cdns3_next_priv_request(struct list_head *list) } /** - * select_ep - selects endpoint + * cdns3_select_ep - selects endpoint * @priv_dev: extended gadget object * @ep: endpoint address */ @@ -1835,7 +1835,7 @@ __must_hold(&priv_dev->lock) } /** - * cdns3_device_irq_handler- interrupt handler for device part of controller + * cdns3_device_irq_handler - interrupt handler for device part of controller * * @irq: irq number for cdns3 core device * @data: structure of cdns3 @@ -1879,7 +1879,7 @@ static irqreturn_t cdns3_device_irq_handler(int irq, void *data) } /** - * cdns3_device_thread_irq_handler- interrupt handler for device part + * cdns3_device_thread_irq_handler - interrupt handler for device part * of controller * * @irq: irq number for cdns3 core device @@ -2022,7 +2022,7 @@ static void cdns3_configure_dmult(struct cdns3_device *priv_dev, } /** - * cdns3_ep_config Configure hardware endpoint + * cdns3_ep_config - Configure hardware endpoint * @priv_ep: extended endpoint object * @enable: set EP_CFG_ENABLE bit in ep_cfg register. */ @@ -2223,7 +2223,7 @@ usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, } /** - * cdns3_gadget_ep_alloc_request Allocates request + * cdns3_gadget_ep_alloc_request - Allocates request * @ep: endpoint object associated with request * @gfp_flags: gfp flags * @@ -2246,7 +2246,7 @@ struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep, } /** - * cdns3_gadget_ep_free_request Free memory occupied by request + * cdns3_gadget_ep_free_request - Free memory occupied by request * @ep: endpoint object associated with request * @request: request to free memory */ @@ -2263,7 +2263,7 @@ void cdns3_gadget_ep_free_request(struct usb_ep *ep, } /** - * cdns3_gadget_ep_enable Enable endpoint + * cdns3_gadget_ep_enable - Enable endpoint * @ep: endpoint object * @desc: endpoint descriptor * @@ -2398,7 +2398,7 @@ exit: } /** - * cdns3_gadget_ep_disable Disable endpoint + * cdns3_gadget_ep_disable - Disable endpoint * @ep: endpoint object * * Returns 0 on success, error code elsewhere @@ -2488,7 +2488,7 @@ static int cdns3_gadget_ep_disable(struct usb_ep *ep) } /** - * cdns3_gadget_ep_queue Transfer data on endpoint + * __cdns3_gadget_ep_queue - Transfer data on endpoint * @ep: endpoint object * @request: request object * @gfp_flags: gfp flags @@ -2588,7 +2588,7 @@ static int cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, } /** - * cdns3_gadget_ep_dequeue Remove request from transfer queue + * cdns3_gadget_ep_dequeue - Remove request from transfer queue * @ep: endpoint object associated with request * @request: request object * @@ -2655,7 +2655,7 @@ not_found: } /** - * __cdns3_gadget_ep_set_halt Sets stall on selected endpoint + * __cdns3_gadget_ep_set_halt - Sets stall on selected endpoint * Should be called after acquiring spin_lock and selecting ep * @priv_ep: endpoint object to set stall on. */ @@ -2676,7 +2676,7 @@ void __cdns3_gadget_ep_set_halt(struct cdns3_endpoint *priv_ep) } /** - * __cdns3_gadget_ep_clear_halt Clears stall on selected endpoint + * __cdns3_gadget_ep_clear_halt - Clears stall on selected endpoint * Should be called after acquiring spin_lock and selecting ep * @priv_ep: endpoint object to clear stall on */ @@ -2721,7 +2721,7 @@ int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep) } /** - * cdns3_gadget_ep_set_halt Sets/clears stall on selected endpoint + * cdns3_gadget_ep_set_halt - Sets/clears stall on selected endpoint * @ep: endpoint object to set/clear stall on * @value: 1 for set stall, 0 for clear stall * @@ -2767,7 +2767,7 @@ static const struct usb_ep_ops cdns3_gadget_ep_ops = { }; /** - * cdns3_gadget_get_frame Returns number of actual ITP frame + * cdns3_gadget_get_frame - Returns number of actual ITP frame * @gadget: gadget object * * Returns number of actual ITP frame @@ -2876,7 +2876,7 @@ static void cdns3_gadget_config(struct cdns3_device *priv_dev) } /** - * cdns3_gadget_udc_start Gadget start + * cdns3_gadget_udc_start - Gadget start * @gadget: gadget object * @driver: driver which operates on this gadget * @@ -2922,7 +2922,7 @@ static int cdns3_gadget_udc_start(struct usb_gadget *gadget, } /** - * cdns3_gadget_udc_stop Stops gadget + * cdns3_gadget_udc_stop - Stops gadget * @gadget: gadget object * * Returns 0 @@ -2985,7 +2985,7 @@ static void cdns3_free_all_eps(struct cdns3_device *priv_dev) } /** - * cdns3_init_eps Initializes software endpoints of gadget + * cdns3_init_eps - Initializes software endpoints of gadget * @priv_dev: extended gadget object * * Returns 0 on success, error code elsewhere diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c index 74e758dc0895..59860d1753fd 100644 --- a/drivers/usb/cdns3/cdns3-imx.c +++ b/drivers/usb/cdns3/cdns3-imx.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * cdns3-imx.c - NXP i.MX specific Glue layer for Cadence USB Controller * * Copyright (C) 2019 NXP diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c index e1deeada425c..4d0f027e5bd3 100644 --- a/drivers/usb/cdns3/cdns3-plat.c +++ b/drivers/usb/cdns3/cdns3-plat.c @@ -170,7 +170,7 @@ err_phy3_init: } /** - * cdns3_remove - unbind drd driver and clean up + * cdns3_plat_remove() - unbind drd driver and clean up * @pdev: Pointer to Linux platform device * * Returns 0 on success otherwise negative errno diff --git a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c index eccb1c766bba..07c318770362 100644 --- a/drivers/usb/cdns3/cdns3-ti.c +++ b/drivers/usb/cdns3/cdns3-ti.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * cdns3-ti.c - TI specific Glue layer for Cadence USB Controller * * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c index c083985e387b..c23f53e9b1ef 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.c +++ b/drivers/usb/cdns3/cdnsp-gadget.c @@ -56,7 +56,8 @@ u32 cdnsp_port_state_to_neutral(u32 state) } /** - * Find the offset of the extended capabilities with capability ID id. + * cdnsp_find_next_ext_cap - Find the offset of the extended capabilities + * with capability ID id. * @base: PCI MMIO registers base address. * @start: Address at which to start looking, (0 or HCC_PARAMS to start at * beginning of list) @@ -1151,7 +1152,7 @@ static int cdnsp_gadget_ep_set_halt(struct usb_ep *ep, int value) struct cdnsp_ep *pep = to_cdnsp_ep(ep); struct cdnsp_device *pdev = pep->pdev; struct cdnsp_request *preq; - unsigned long flags = 0; + unsigned long flags; int ret; spin_lock_irqsave(&pdev->lock, flags); @@ -1176,7 +1177,7 @@ static int cdnsp_gadget_ep_set_wedge(struct usb_ep *ep) { struct cdnsp_ep *pep = to_cdnsp_ep(ep); struct cdnsp_device *pdev = pep->pdev; - unsigned long flags = 0; + unsigned long flags; int ret; spin_lock_irqsave(&pdev->lock, flags); diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index bb739d88179f..dbcdf3b24b47 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -332,7 +332,7 @@ exit: } /** - * cdsn3_role_get - get current role of controller. + * cdns_role_get - get current role of controller. * * @sw: pointer to USB role switch structure * @@ -419,7 +419,7 @@ static irqreturn_t cdns_wakeup_irq(int irq, void *data) } /** - * cdns_probe - probe for cdns3/cdnsp core device + * cdns_init - probe for cdns3/cdnsp core device * @cdns: Pointer to cdns structure. * * Returns 0 on success otherwise negative errno diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 0697eb980e5f..99440baa6458 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -195,7 +195,6 @@ struct hw_bank { * @phy: pointer to PHY, if any * @usb_phy: pointer to USB PHY, if any and if using the USB PHY framework * @hcd: pointer to usb_hcd for ehci host driver - * @debugfs: root dentry for this controller in debugfs * @id_event: indicates there is an id event, and handled at ci_otg_work * @b_sess_valid_event: indicates there is a vbus event, and handled * at ci_otg_work @@ -249,7 +248,6 @@ struct ci_hdrc { /* old usb_phy interface */ struct usb_phy *usb_phy; struct usb_hcd *hcd; - struct dentry *debugfs; bool id_event; bool b_sess_valid_event; bool imx28_write_fix; diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 3f6c21406dbd..2b18f5088ae4 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -335,7 +335,7 @@ static int _ci_usb_phy_init(struct ci_hdrc *ci) } /** - * _ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy + * ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy * interfaces * @ci: the controller */ diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index da5d18cf6840..faf6b078b6c4 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -342,26 +342,20 @@ DEFINE_SHOW_ATTRIBUTE(ci_registers); */ void dbg_create_files(struct ci_hdrc *ci) { - ci->debugfs = debugfs_create_dir(dev_name(ci->dev), usb_debug_root); - - debugfs_create_file("device", S_IRUGO, ci->debugfs, ci, - &ci_device_fops); - debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs, ci, - &ci_port_test_fops); - debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci, - &ci_qheads_fops); - debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci, - &ci_requests_fops); - - if (ci_otg_is_fsm_mode(ci)) { - debugfs_create_file("otg", S_IRUGO, ci->debugfs, ci, - &ci_otg_fops); - } + struct dentry *dir; + + dir = debugfs_create_dir(dev_name(ci->dev), usb_debug_root); + + debugfs_create_file("device", S_IRUGO, dir, ci, &ci_device_fops); + debugfs_create_file("port_test", S_IRUGO | S_IWUSR, dir, ci, &ci_port_test_fops); + debugfs_create_file("qheads", S_IRUGO, dir, ci, &ci_qheads_fops); + debugfs_create_file("requests", S_IRUGO, dir, ci, &ci_requests_fops); + + if (ci_otg_is_fsm_mode(ci)) + debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops); - debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci, - &ci_role_fops); - debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci, - &ci_registers_fops); + debugfs_create_file("role", S_IRUGO | S_IWUSR, dir, ci, &ci_role_fops); + debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops); } /** @@ -370,5 +364,5 @@ void dbg_create_files(struct ci_hdrc *ci) */ void dbg_remove_files(struct ci_hdrc *ci) { - debugfs_remove_recursive(ci->debugfs); + debugfs_remove(debugfs_lookup(dev_name(ci->dev), usb_debug_root)); } diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index d3aada3ce7ec..8dd59282827b 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -22,7 +22,7 @@ #include "otg_fsm.h" /** - * hw_read_otgsc returns otgsc register bits value. + * hw_read_otgsc - returns otgsc register bits value. * @ci: the controller * @mask: bitfield mask */ @@ -75,7 +75,7 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) } /** - * hw_write_otgsc updates target bits of OTGSC register. + * hw_write_otgsc - updates target bits of OTGSC register. * @ci: the controller * @mask: bitfield mask * @data: to be written @@ -140,8 +140,9 @@ void ci_handle_vbus_change(struct ci_hdrc *ci) } /** - * When we switch to device mode, the vbus value should be lower - * than OTGSC_BSV before connecting to host. + * hw_wait_vbus_lower_bsv - When we switch to device mode, the vbus value + * should be lower than OTGSC_BSV before connecting + * to host. * * @ci: the controller * diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 393f216b9161..8834ca613721 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -238,7 +238,7 @@ static int hw_ep_set_halt(struct ci_hdrc *ci, int num, int dir, int value) } /** - * hw_is_port_high_speed: test if port is high speed + * hw_port_is_high_speed: test if port is high speed * @ci: the controller * * This function returns true if high speed port diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index ce5e6f6711f7..7e13b74e60e5 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -141,7 +141,7 @@ static const struct device_type ulpi_dev_type = { /* -------------------------------------------------------------------------- */ /** - * ulpi_register_driver - register a driver with the ULPI bus + * __ulpi_register_driver - register a driver with the ULPI bus * @drv: driver being registered * @module: ends up being THIS_MODULE * diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c index 6c4e3a19f42c..0158148cb054 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -83,11 +83,11 @@ static void usb_conn_detect_cable(struct work_struct *work) else role = USB_ROLE_NONE; - dev_dbg(info->dev, "role %d/%d, gpios: id %d, vbus %d\n", - info->last_role, role, id, vbus); + dev_dbg(info->dev, "role %s -> %s, gpios: id %d, vbus %d\n", + usb_role_string(info->last_role), usb_role_string(role), id, vbus); if (info->last_role == role) { - dev_warn(info->dev, "repeated role: %d\n", role); + dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role)); return; } @@ -149,14 +149,32 @@ static int usb_charger_get_property(struct power_supply *psy, return 0; } -static int usb_conn_probe(struct platform_device *pdev) +static int usb_conn_psy_register(struct usb_conn_info *info) { - struct device *dev = &pdev->dev; - struct power_supply_desc *desc; - struct usb_conn_info *info; + struct device *dev = info->dev; + struct power_supply_desc *desc = &info->desc; struct power_supply_config cfg = { .of_node = dev->of_node, }; + + desc->name = "usb-charger"; + desc->properties = usb_charger_properties; + desc->num_properties = ARRAY_SIZE(usb_charger_properties); + desc->get_property = usb_charger_get_property; + desc->type = POWER_SUPPLY_TYPE_USB; + cfg.drv_data = info; + + info->charger = devm_power_supply_register(dev, desc, &cfg); + if (IS_ERR(info->charger)) + dev_err(dev, "Unable to register charger\n"); + + return PTR_ERR_OR_ZERO(info->charger); +} + +static int usb_conn_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb_conn_info *info; bool need_vbus = true; int ret = 0; @@ -205,18 +223,18 @@ static int usb_conn_probe(struct platform_device *pdev) } if (IS_ERR(info->vbus)) { - if (PTR_ERR(info->vbus) != -EPROBE_DEFER) - dev_err(dev, "failed to get vbus: %ld\n", PTR_ERR(info->vbus)); - return PTR_ERR(info->vbus); + ret = PTR_ERR(info->vbus); + return dev_err_probe(dev, ret, "failed to get vbus :%d\n", ret); } info->role_sw = usb_role_switch_get(dev); - if (IS_ERR(info->role_sw)) { - if (PTR_ERR(info->role_sw) != -EPROBE_DEFER) - dev_err(dev, "failed to get role switch\n"); + if (IS_ERR(info->role_sw)) + return dev_err_probe(dev, PTR_ERR(info->role_sw), + "failed to get role switch\n"); - return PTR_ERR(info->role_sw); - } + ret = usb_conn_psy_register(info); + if (ret) + goto put_role_sw; if (info->id_gpiod) { info->id_irq = gpiod_to_irq(info->id_gpiod); @@ -252,20 +270,6 @@ static int usb_conn_probe(struct platform_device *pdev) } } - desc = &info->desc; - desc->name = "usb-charger"; - desc->properties = usb_charger_properties; - desc->num_properties = ARRAY_SIZE(usb_charger_properties); - desc->get_property = usb_charger_get_property; - desc->type = POWER_SUPPLY_TYPE_USB; - cfg.drv_data = info; - - info->charger = devm_power_supply_register(dev, desc, &cfg); - if (IS_ERR(info->charger)) { - dev_err(dev, "Unable to register charger\n"); - return PTR_ERR(info->charger); - } - platform_set_drvdata(pdev, info); /* Perform initial detection */ diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2218941d35a3..b97464498763 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1162,7 +1162,7 @@ static int do_proc_control(struct usb_dev_state *ps, tbuf, ctrl->wLength); usb_unlock_device(dev); - i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl->bRequest, + i = usb_control_msg(dev, pipe, ctrl->bRequest, ctrl->bRequestType, ctrl->wValue, ctrl->wIndex, tbuf, ctrl->wLength, tmo); usb_lock_device(dev); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 6119fb41d736..0f8b7c93310e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2111,6 +2111,136 @@ int usb_hcd_get_frame_number (struct usb_device *udev) } /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_HCD_TEST_MODE + +static void usb_ehset_completion(struct urb *urb) +{ + struct completion *done = urb->context; + + complete(done); +} +/* + * Allocate and initialize a control URB. This request will be used by the + * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages + * of the GetDescriptor request are sent 15 seconds after the SETUP stage. + * Return NULL if failed. + */ +static struct urb *request_single_step_set_feature_urb( + struct usb_device *udev, + void *dr, + void *buf, + struct completion *done) +{ + struct urb *urb; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct usb_host_endpoint *ep; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return NULL; + + urb->pipe = usb_rcvctrlpipe(udev, 0); + ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) { + usb_free_urb(urb); + return NULL; + } + + urb->ep = ep; + urb->dev = udev; + urb->setup_packet = (void *)dr; + urb->transfer_buffer = buf; + urb->transfer_buffer_length = USB_DT_DEVICE_SIZE; + urb->complete = usb_ehset_completion; + urb->status = -EINPROGRESS; + urb->actual_length = 0; + urb->transfer_flags = URB_DIR_IN; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + if (map_urb_for_dma(hcd, urb, GFP_KERNEL)) { + usb_put_urb(urb); + usb_free_urb(urb); + return NULL; + } + + urb->context = done; + return urb; +} + +int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) +{ + int retval = -ENOMEM; + struct usb_ctrlrequest *dr; + struct urb *urb; + struct usb_device *udev; + struct usb_device_descriptor *buf; + DECLARE_COMPLETION_ONSTACK(done); + + /* Obtain udev of the rhub's child port */ + udev = usb_hub_find_child(hcd->self.root_hub, port); + if (!udev) { + dev_err(hcd->self.controller, "No device attached to the RootHub\n"); + return -ENODEV; + } + buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!dr) { + kfree(buf); + return -ENOMEM; + } + + /* Fill Setup packet for GetDescriptor */ + dr->bRequestType = USB_DIR_IN; + dr->bRequest = USB_REQ_GET_DESCRIPTOR; + dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8); + dr->wIndex = 0; + dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE); + urb = request_single_step_set_feature_urb(udev, dr, buf, &done); + if (!urb) + goto cleanup; + + /* Submit just the SETUP stage */ + retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 1); + if (retval) + goto out1; + if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + dev_err(hcd->self.controller, + "%s SETUP stage timed out on ep0\n", __func__); + goto out1; + } + msleep(15 * 1000); + + /* Complete remaining DATA and STATUS stages using the same URB */ + urb->status = -EINPROGRESS; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 0); + if (!retval && !wait_for_completion_timeout(&done, + msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + dev_err(hcd->self.controller, + "%s IN stage timed out on ep0\n", __func__); + } +out1: + usb_free_urb(urb); +cleanup: + kfree(dr); + kfree(buf); + return retval; +} +EXPORT_SYMBOL_GPL(ehset_single_step_set_feature); +#endif /* CONFIG_USB_HCD_TEST_MODE */ + +/*-------------------------------------------------------------------------*/ #ifdef CONFIG_PM diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index fc7d6cdacf16..3bd379d5d1be 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2432,6 +2432,8 @@ static void set_usb_port_removable(struct usb_device *udev) u16 wHubCharacteristics; bool removable = true; + dev_set_removable(&udev->dev, DEVICE_REMOVABLE_UNKNOWN); + if (!hdev) return; @@ -2443,11 +2445,11 @@ static void set_usb_port_removable(struct usb_device *udev) */ switch (hub->ports[udev->portnum - 1]->connect_type) { case USB_PORT_CONNECT_TYPE_HOT_PLUG: - udev->removable = USB_DEVICE_REMOVABLE; + dev_set_removable(&udev->dev, DEVICE_REMOVABLE); return; case USB_PORT_CONNECT_TYPE_HARD_WIRED: case USB_PORT_NOT_USED: - udev->removable = USB_DEVICE_FIXED; + dev_set_removable(&udev->dev, DEVICE_FIXED); return; default: break; @@ -2472,9 +2474,9 @@ static void set_usb_port_removable(struct usb_device *udev) } if (removable) - udev->removable = USB_DEVICE_REMOVABLE; + dev_set_removable(&udev->dev, DEVICE_REMOVABLE); else - udev->removable = USB_DEVICE_FIXED; + dev_set_removable(&udev->dev, DEVICE_FIXED); } @@ -2546,8 +2548,7 @@ int usb_new_device(struct usb_device *udev) device_enable_async_suspend(&udev->dev); /* check whether the hub or firmware marks this port as non-removable */ - if (udev->parent) - set_usb_port_removable(udev); + set_usb_port_removable(udev); /* Register the device. The device driver is responsible * for configuring the device and invoking the add-device @@ -3385,6 +3386,26 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) status = 0; } if (status) { + /* Check if the port has been suspended for the timeout case + * to prevent the suspended port from incorrect handling. + */ + if (status == -ETIMEDOUT) { + int ret; + u16 portstatus, portchange; + + portstatus = portchange = 0; + ret = hub_port_status(hub, port1, &portstatus, + &portchange); + + dev_dbg(&port_dev->dev, + "suspend timeout, status %04x\n", portstatus); + + if (ret == 0 && port_is_suspended(hub, portstatus)) { + status = 0; + goto suspend_done; + } + } + dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status); /* Try to enable USB3 LTM again */ @@ -3401,6 +3422,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) if (!PMSG_IS_AUTO(msg)) status = 0; } else { + suspend_done: dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n", (PMSG_IS_AUTO(msg) ? "auto-" : ""), udev->do_remote_wakeup); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 21e7522655ac..6114cf83bb44 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -406,7 +406,6 @@ static const struct usb_device_id usb_quirk_list[] = { /* Realtek hub in Dell WD19 (Type-C) */ { USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM }, - { USB_DEVICE(0x0bda, 0x5487), .driver_info = USB_QUIRK_RESET_RESUME }, /* Generic RTL8153 based ethernet adapters */ { USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM }, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 5a168ba9fc51..fa2e49d432ff 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -301,29 +301,6 @@ static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(urbnum); -static ssize_t removable_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct usb_device *udev; - char *state; - - udev = to_usb_device(dev); - - switch (udev->removable) { - case USB_DEVICE_REMOVABLE: - state = "removable"; - break; - case USB_DEVICE_FIXED: - state = "fixed"; - break; - default: - state = "unknown"; - } - - return sprintf(buf, "%s\n", state); -} -static DEVICE_ATTR_RO(removable); - static ssize_t ltm_capable_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -828,7 +805,6 @@ static struct attribute *dev_attrs[] = { &dev_attr_avoid_reset_quirk.attr, &dev_attr_authorized.attr, &dev_attr_remove.attr, - &dev_attr_removable.attr, &dev_attr_ltm_capable.attr, #ifdef CONFIG_OF &dev_attr_devspec.attr, diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 357b149b20d3..30727729a44c 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -407,6 +407,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) return -ENOEXEC; is_out = !(setup->bRequestType & USB_DIR_IN) || !setup->wLength; + dev_WARN_ONCE(&dev->dev, (usb_pipeout(urb->pipe) != is_out), + "BOGUS control dir, pipe %x doesn't match bRequestType %x\n", + urb->pipe, setup->bRequestType); + if (le16_to_cpu(setup->wLength) != urb->transfer_buffer_length) { + dev_dbg(&dev->dev, "BOGUS control len %d doesn't match transfer length %d\n", + le16_to_cpu(setup->wLength), + urb->transfer_buffer_length); + return -EBADR; + } } else { is_out = usb_endpoint_dir_out(&ep->desc); } diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 184964174dc0..c581ee41ac81 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1496,8 +1496,8 @@ static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hs = hs_ep->parent; - unsigned long flags = 0; - int ret = 0; + unsigned long flags; + int ret; spin_lock_irqsave(&hs->lock, flags); ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags); @@ -3338,7 +3338,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) static int dwc2_hsotg_ep_disable(struct usb_ep *ep); /** - * dwc2_hsotg_core_init - issue softreset to the core + * dwc2_hsotg_core_init_disconnected - issue softreset to the core * @hsotg: The device state * @is_usb_reset: Usb resetting flag * @@ -4374,8 +4374,8 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hs = hs_ep->parent; - unsigned long flags = 0; - int ret = 0; + unsigned long flags; + int ret; spin_lock_irqsave(&hs->lock, flags); ret = dwc2_hsotg_ep_sethalt(ep, value, false); @@ -4505,7 +4505,7 @@ err: static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) { struct dwc2_hsotg *hsotg = to_hsotg(gadget); - unsigned long flags = 0; + unsigned long flags; int ep; if (!hsotg) @@ -4577,7 +4577,7 @@ static int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget, static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) { struct dwc2_hsotg *hsotg = to_hsotg(gadget); - unsigned long flags = 0; + unsigned long flags; dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, hsotg->op_state); diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 621a4846bd05..89a788326c56 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -675,7 +675,7 @@ static int dwc2_hs_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, } /** - * dwc2_ls_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule() + * dwc2_hs_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule() * * @hsotg: The HCD state structure for the DWC OTG controller. * @qh: QH for the periodic transfer. diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 7a6089fa81e1..67c5eb140232 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -784,8 +784,8 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg) } /** - * During device initialization, read various hardware configuration - * registers and interpret the contents. + * dwc2_get_hwparams() - During device initialization, read various hardware + * configuration registers and interpret the contents. * * @hsotg: Programming view of the DWC_otg controller * diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c index 0000151e3ca9..a93559b4ecdb 100644 --- a/drivers/usb/dwc2/pci.c +++ b/drivers/usb/dwc2/pci.c @@ -64,7 +64,7 @@ struct dwc2_pci_glue { }; /** - * dwc2_pci_probe() - Provides the cleanup entry points for the DWC_otg PCI + * dwc2_pci_remove() - Provides the cleanup entry points for the DWC_otg PCI * driver * * @pci: The programming view of DWC_otg PCI diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 520a0beef77c..c8f18f3ba9e3 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -408,7 +408,7 @@ static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg) } /** - * Check core version + * dwc2_check_core_version() - Check core version * * @hsotg: Programming view of the DWC_otg controller * diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index e2b68bb770d1..8fcbac10510c 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -596,7 +596,6 @@ int dwc3_drd_init(struct dwc3 *dwc) dwc3_drd_update(dwc); } else { dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG); - dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG; /* use OTG block to get ID event */ irq = dwc3_otg_get_irq(dwc); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 1e51460938b8..2b37bdd39a74 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -36,7 +36,7 @@ #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e #define PCI_DEVICE_ID_INTEL_CNPV 0xa3b0 #define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee -#define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e +#define PCI_DEVICE_ID_INTEL_EHL 0x4b7e #define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee #define PCI_DEVICE_ID_INTEL_TGPH 0x43ee #define PCI_DEVICE_ID_INTEL_JSP 0x4dee @@ -167,7 +167,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc) if (pdev->vendor == PCI_VENDOR_ID_INTEL) { if (pdev->device == PCI_DEVICE_ID_INTEL_BXT || pdev->device == PCI_DEVICE_ID_INTEL_BXT_M || - pdev->device == PCI_DEVICE_ID_INTEL_EHLLP) { + pdev->device == PCI_DEVICE_ID_INTEL_EHL) { guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid); dwc->has_dsm_for_pm = true; } @@ -375,8 +375,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL), + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 51d18e8d1602..cb998ba50fea 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -222,8 +222,6 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, TP_STRUCT__entry( __string(name, dep->name) __field(struct dwc3_trb *, trb) - __field(u32, allocated) - __field(u32, queued) __field(u32, bpl) __field(u32, bph) __field(u32, size) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 1125f4715830..0c964be58406 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -1117,7 +1117,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi) hidg->func.setup = hidg_setup; hidg->func.free_func = hidg_free; - /* this could me made configurable at some point */ + /* this could be made configurable at some point */ hidg->qlen = 4; return &hidg->func; diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h index 84e6da302499..98d6af558c03 100644 --- a/drivers/usb/gadget/function/u_hid.h +++ b/drivers/usb/gadget/function/u_hid.h @@ -29,8 +29,8 @@ struct f_hid_opts { * Protect the data form concurrent access by read/write * and create symlink/remove symlink. */ - struct mutex lock; - int refcnt; + struct mutex lock; + int refcnt; }; int ghid_setup(struct usb_gadget *g, int count); diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h index f6e14af7f566..2e400b495cb8 100644 --- a/drivers/usb/gadget/function/u_midi.h +++ b/drivers/usb/gadget/function/u_midi.h @@ -29,8 +29,8 @@ struct f_midi_opts { * Protect the data form concurrent access by read/write * and create symlink/remove symlink. */ - struct mutex lock; - int refcnt; + struct mutex lock; + int refcnt; }; #endif /* U_MIDI_H */ diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index cd28dec837dd..77d64031aa9c 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -914,8 +914,6 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, target_fmt = container_of(to_config_group(target), struct uvcg_format, group); - if (!target_fmt) - goto out; uvcg_format_set_indices(to_config_group(target)); @@ -955,8 +953,6 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, mutex_lock(&opts->lock); target_fmt = container_of(to_config_group(target), struct uvcg_format, group); - if (!target_fmt) - goto out; list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry) if (format_ptr->fmt == target_fmt) { @@ -968,7 +964,6 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, --target_fmt->linked; -out: mutex_unlock(&opts->lock); mutex_unlock(su_mutex); } diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 9cd4a70ccdd6..a9f07c59fc37 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -288,7 +288,6 @@ struct bcm63xx_req { * @ep0_req_completed: ep0 request has completed; worker has not seen it yet. * @ep0_reply: Pending reply from gadget driver. * @ep0_request: Outstanding ep0 request. - * @debugfs_root: debugfs directory: /sys/kernel/debug/<DRV_MODULE_NAME>. */ struct bcm63xx_udc { spinlock_t lock; @@ -327,8 +326,6 @@ struct bcm63xx_udc { unsigned ep0_req_completed:1; struct usb_request *ep0_reply; struct usb_request *ep0_request; - - struct dentry *debugfs_root; }; static const struct usb_ep_ops bcm63xx_udc_ep_ops; @@ -2250,8 +2247,6 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc) return; root = debugfs_create_dir(udc->gadget.name, usb_debug_root); - udc->debugfs_root = root; - debugfs_create_file("usbd", 0400, root, udc, &bcm63xx_usbd_dbg_fops); debugfs_create_file("iudma", 0400, root, udc, &bcm63xx_iudma_dbg_fops); } @@ -2264,7 +2259,7 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc) */ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc) { - debugfs_remove_recursive(udc->debugfs_root); + debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root)); } /*********************************************************************** diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index fa66449b3907..8e8588933628 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -541,6 +541,7 @@ static int qe_ep_init(struct qe_udc *udc, case USB_SPEED_HIGH: if ((max == 128) || (max == 256) || (max == 512)) break; + fallthrough; default: switch (max) { case 4: @@ -562,9 +563,11 @@ static int qe_ep_init(struct qe_udc *udc, case USB_SPEED_HIGH: if (max <= 1024) break; + fallthrough; case USB_SPEED_FULL: if (max <= 64) break; + fallthrough; default: if (max <= 8) break; @@ -579,6 +582,7 @@ static int qe_ep_init(struct qe_udc *udc, case USB_SPEED_HIGH: if (max <= 1024) break; + fallthrough; case USB_SPEED_FULL: if (max <= 1023) break; @@ -605,6 +609,7 @@ static int qe_ep_init(struct qe_udc *udc, default: goto en_done; } + fallthrough; case USB_SPEED_LOW: switch (max) { case 1: diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index ad6ff9c4188e..2b357b3f64c0 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -547,7 +547,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, unsigned short max = 0; unsigned char mult = 0, zlt; int retval = -EINVAL; - unsigned long flags = 0; + unsigned long flags; ep = container_of(_ep, struct fsl_ep, ep); @@ -631,7 +631,7 @@ static int fsl_ep_disable(struct usb_ep *_ep) { struct fsl_udc *udc = NULL; struct fsl_ep *ep = NULL; - unsigned long flags = 0; + unsigned long flags; u32 epctrl; int ep_num; @@ -1001,7 +1001,7 @@ out: epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); static int fsl_ep_set_halt(struct usb_ep *_ep, int value) { struct fsl_ep *ep = NULL; - unsigned long flags = 0; + unsigned long flags; int status = -EOPNOTSUPP; /* operation not supported */ unsigned char ep_dir = 0, ep_num = 0; struct fsl_udc *udc = NULL; @@ -1938,7 +1938,7 @@ static int fsl_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { int retval = 0; - unsigned long flags = 0; + unsigned long flags; /* lock is needed but whether should use this lock or another */ spin_lock_irqsave(&udc_controller->lock, flags); diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 3f1c62adce4b..a25d01c89564 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -127,7 +127,6 @@ struct lpc32xx_udc { struct usb_gadget_driver *driver; struct platform_device *pdev; struct device *dev; - struct dentry *pde; spinlock_t lock; struct i2c_client *isp1301_i2c_client; @@ -528,12 +527,12 @@ DEFINE_SHOW_ATTRIBUTE(udc); static void create_debug_file(struct lpc32xx_udc *udc) { - udc->pde = debugfs_create_file(debug_filename, 0, NULL, udc, &udc_fops); + debugfs_create_file(debug_filename, 0, NULL, udc, &udc_fops); } static void remove_debug_file(struct lpc32xx_udc *udc) { - debugfs_remove(udc->pde); + debugfs_remove(debugfs_lookup(debug_filename, NULL)); } #else diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index 5486f5a70868..ce3d7a3eb7e3 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -941,7 +941,7 @@ mv_u3d_ep_set_stall(struct mv_u3d *u3d, u8 ep_num, u8 direction, int stall) static int mv_u3d_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) { struct mv_u3d_ep *ep; - unsigned long flags = 0; + unsigned long flags; int status = 0; struct mv_u3d *u3d; diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 0fb4ef464321..7f24ce400b59 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -888,7 +888,7 @@ static int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction) static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) { struct mv_ep *ep; - unsigned long flags = 0; + unsigned long flags; int status = 0; struct mv_udc *udc; diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 10324a7334fe..69ef1e669d0c 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1338,10 +1338,10 @@ DEFINE_SHOW_ATTRIBUTE(udc_debug); #define create_debug_files(dev) \ do { \ - dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \ + debugfs_create_file(dev->gadget.name, \ S_IRUGO, NULL, dev, &udc_debug_fops); \ } while (0) -#define remove_debug_files(dev) debugfs_remove(dev->debugfs_udc) +#define remove_debug_files(dev) debugfs_remove(debugfs_lookup(dev->gadget.name, NULL)) #else /* !CONFIG_USB_GADGET_DEBUG_FILES */ diff --git a/drivers/usb/gadget/udc/pxa25x_udc.h b/drivers/usb/gadget/udc/pxa25x_udc.h index ccc6b921f067..aa4b68fd9fc0 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.h +++ b/drivers/usb/gadget/udc/pxa25x_udc.h @@ -116,10 +116,6 @@ struct pxa25x_udc { struct usb_phy *transceiver; u64 dma_mask; struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS]; - -#ifdef CONFIG_USB_GADGET_DEBUG_FS - struct dentry *debugfs_udc; -#endif void __iomem *regs; }; #define to_pxa25x(g) (container_of((g), struct pxa25x_udc, gadget)) diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index ce57961dfd2d..f4b7a2a3e711 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -208,8 +208,6 @@ static void pxa_init_debugfs(struct pxa_udc *udc) struct dentry *root; root = debugfs_create_dir(udc->gadget.name, usb_debug_root); - udc->debugfs_root = root; - debugfs_create_file("udcstate", 0400, root, udc, &state_dbg_fops); debugfs_create_file("queues", 0400, root, udc, &queues_dbg_fops); debugfs_create_file("epstate", 0400, root, udc, &eps_dbg_fops); @@ -217,7 +215,7 @@ static void pxa_init_debugfs(struct pxa_udc *udc) static void pxa_cleanup_debugfs(struct pxa_udc *udc) { - debugfs_remove_recursive(udc->debugfs_root); + debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root)); } #else @@ -1730,7 +1728,7 @@ static void udc_enable(struct pxa_udc *udc) } /** - * pxa27x_start - Register gadget driver + * pxa27x_udc_start - Register gadget driver * @g: gadget * @driver: gadget driver * diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h index 13b2977399ab..0a6bc18a1264 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.h +++ b/drivers/usb/gadget/udc/pxa27x_udc.h @@ -440,7 +440,6 @@ struct udc_stats { * @last_interface: UDC interface of the last SET_INTERFACE host request * @last_alternate: UDC altsetting of the last SET_INTERFACE host request * @udccsr0: save of udccsr0 in case of suspend - * @debugfs_root: root entry of debug filesystem * @debugfs_state: debugfs entry for "udcstate" * @debugfs_queues: debugfs entry for "queues" * @debugfs_eps: debugfs entry for "epstate" @@ -474,9 +473,6 @@ struct pxa_udc { #ifdef CONFIG_PM unsigned udccsr0; #endif -#ifdef CONFIG_USB_GADGET_DEBUG_FS - struct dentry *debugfs_root; -#endif }; #define to_pxa(g) (container_of((g), struct pxa_udc, gadget)) diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index 7bd5182ce3ef..89f1f8c9f02e 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -1220,9 +1220,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev) struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev); int ret, i; - hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) + - sizeof(struct s3c_hsudc_ep) * pd->epnum, - GFP_KERNEL); + hsudc = devm_kzalloc(&pdev->dev, struct_size(hsudc, ep, pd->epnum), + GFP_KERNEL); if (!hsudc) return -ENOMEM; diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index b154b62abefa..179777cb699f 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -198,7 +198,7 @@ static inline void s3c2410_udc_set_ep0_de(void __iomem *base) udc_writeb(base, S3C2410_UDC_EP0_CSR_DE, S3C2410_UDC_EP0_CSR_REG); } -inline void s3c2410_udc_set_ep0_ss(void __iomem *b) +static inline void s3c2410_udc_set_ep0_ss(void __iomem *b) { udc_writeb(b, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); udc_writeb(b, S3C2410_UDC_EP0_CSR_SENDSTL, S3C2410_UDC_EP0_CSR_REG); @@ -1843,9 +1843,8 @@ static int s3c2410_udc_probe(struct platform_device *pdev) if (retval) goto err_add_udc; - udc->regs_info = debugfs_create_file("registers", S_IRUGO, - s3c2410_udc_debugfs_root, udc, - &s3c2410_udc_debugfs_fops); + debugfs_create_file("registers", S_IRUGO, s3c2410_udc_debugfs_root, udc, + &s3c2410_udc_debugfs_fops); dev_dbg(dev, "probe ok\n"); @@ -1889,7 +1888,7 @@ static int s3c2410_udc_remove(struct platform_device *pdev) return -EBUSY; usb_del_gadget_udc(&udc->gadget); - debugfs_remove(udc->regs_info); + debugfs_remove(debugfs_lookup("registers", s3c2410_udc_debugfs_root)); if (udc_info && !udc_info->udc_command && gpio_is_valid(udc_info->pullup_pin)) diff --git a/drivers/usb/gadget/udc/s3c2410_udc.h b/drivers/usb/gadget/udc/s3c2410_udc.h index 68bdf3e5aac2..135a5bff3c74 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.h +++ b/drivers/usb/gadget/udc/s3c2410_udc.h @@ -89,7 +89,6 @@ struct s3c2410_udc { unsigned req_config : 1; unsigned req_pending : 1; u8 vbus; - struct dentry *regs_info; int irq; }; #define to_s3c2410(g) (container_of((g), struct s3c2410_udc, gadget)) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 2319c9737c2b..a54d1cef17db 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -1907,7 +1907,7 @@ static void tegra_xudc_ep_free_request(struct usb_ep *usb_ep, kfree(req); } -static struct usb_ep_ops tegra_xudc_ep_ops = { +static const struct usb_ep_ops tegra_xudc_ep_ops = { .enable = tegra_xudc_ep_enable, .disable = tegra_xudc_ep_disable, .alloc_request = tegra_xudc_ep_alloc_request, @@ -1928,7 +1928,7 @@ static int tegra_xudc_ep0_disable(struct usb_ep *usb_ep) return -EBUSY; } -static struct usb_ep_ops tegra_xudc_ep0_ops = { +static const struct usb_ep_ops tegra_xudc_ep0_ops = { .enable = tegra_xudc_ep0_enable, .disable = tegra_xudc_ep0_disable, .alloc_request = tegra_xudc_ep_alloc_request, @@ -2168,7 +2168,7 @@ static int tegra_xudc_set_selfpowered(struct usb_gadget *gadget, int is_on) return 0; } -static struct usb_gadget_ops tegra_xudc_gadget_ops = { +static const struct usb_gadget_ops tegra_xudc_gadget_ops = { .get_frame = tegra_xudc_gadget_get_frame, .wakeup = tegra_xudc_gadget_wakeup, .pullup = tegra_xudc_gadget_pullup, @@ -3508,10 +3508,8 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc) xudc->utmi_phy[i] = devm_phy_optional_get(xudc->dev, phy_name); if (IS_ERR(xudc->utmi_phy[i])) { err = PTR_ERR(xudc->utmi_phy[i]); - if (err != -EPROBE_DEFER) - dev_err(xudc->dev, "failed to get usb2-%d PHY: %d\n", - i, err); - + dev_err_probe(xudc->dev, err, + "failed to get usb2-%d PHY\n", i); goto clean_up; } else if (xudc->utmi_phy[i]) { /* Get usb-phy, if utmi phy is available */ @@ -3520,8 +3518,8 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc) &xudc->vbus_nb); if (IS_ERR(xudc->usbphy[i])) { err = PTR_ERR(xudc->usbphy[i]); - dev_err(xudc->dev, "failed to get usbphy-%d: %d\n", - i, err); + dev_err_probe(xudc->dev, err, + "failed to get usbphy-%d\n", i); goto clean_up; } } else if (!xudc->utmi_phy[i]) { @@ -3538,10 +3536,8 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc) xudc->usb3_phy[i] = devm_phy_optional_get(xudc->dev, phy_name); if (IS_ERR(xudc->usb3_phy[i])) { err = PTR_ERR(xudc->usb3_phy[i]); - if (err != -EPROBE_DEFER) - dev_err(xudc->dev, "failed to get usb3-%d PHY: %d\n", - usb3, err); - + dev_err_probe(xudc->dev, err, + "failed to get usb3-%d PHY\n", usb3); goto clean_up; } else if (xudc->usb3_phy[i]) dev_dbg(xudc->dev, "usb3-%d PHY registered", usb3); @@ -3781,9 +3777,7 @@ static int tegra_xudc_probe(struct platform_device *pdev) err = devm_clk_bulk_get(&pdev->dev, xudc->soc->num_clks, xudc->clks); if (err) { - if (err != -EPROBE_DEFER) - dev_err(xudc->dev, "failed to request clocks: %d\n", err); - + dev_err_probe(xudc->dev, err, "failed to request clocks\n"); return err; } @@ -3798,9 +3792,7 @@ static int tegra_xudc_probe(struct platform_device *pdev) err = devm_regulator_bulk_get(&pdev->dev, xudc->soc->num_supplies, xudc->supplies); if (err) { - if (err != -EPROBE_DEFER) - dev_err(xudc->dev, "failed to request regulators: %d\n", err); - + dev_err_probe(xudc->dev, err, "failed to request regulators\n"); return err; } diff --git a/drivers/usb/gadget/udc/trace.c b/drivers/usb/gadget/udc/trace.c index 7430624c0bd7..19e837de2a20 100644 --- a/drivers/usb/gadget/udc/trace.c +++ b/drivers/usb/gadget/udc/trace.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * trace.c - USB Gadget Framework Trace Support * * Copyright (C) 2016 Intel Corporation diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h index 2d1f68b5ea76..98584f6b6c66 100644 --- a/drivers/usb/gadget/udc/trace.h +++ b/drivers/usb/gadget/udc/trace.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * udc.c - Core UDC Framework * * Copyright (C) 2016 Intel Corporation diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 72f2ea062d55..fb4ffedd6f0d 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -791,7 +791,7 @@ static int xudc_ep_set_halt(struct usb_ep *_ep, int value) } /** - * xudc_ep_enable - Enables the given endpoint. + * __xudc_ep_enable - Enables the given endpoint. * @ep: pointer to the xusb endpoint structure. * @desc: pointer to usb endpoint descriptor. * @@ -987,7 +987,7 @@ static void xudc_free_request(struct usb_ep *_ep, struct usb_request *_req) } /** - * xudc_ep0_queue - Adds the request to endpoint 0 queue. + * __xudc_ep0_queue - Adds the request to endpoint 0 queue. * @ep0: pointer to the xusb endpoint 0 structure. * @req: pointer to the xusb request structure. * diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 6f7bd6641694..385be30baad3 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -387,11 +387,11 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) /* EHCI registers start at offset 0x100 */ ehci->caps = hcd->regs + 0x100; -#ifdef CONFIG_PPC_83xx +#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_85xx) /* - * Deal with MPC834X that need port power to be cycled after the power - * fault condition is removed. Otherwise the state machine does not - * reflect PORTSC[CSC] correctly. + * Deal with MPC834X/85XX that need port power to be cycled + * after the power fault condition is removed. Otherwise the + * state machine does not reflect PORTSC[CSC] correctly. */ ehci->need_oc_pp_cycle = 1; #endif diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 94b5e64ae9a2..35eec0c0edcd 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1238,6 +1238,10 @@ static const struct hc_driver ehci_hc_driver = { * device support */ .free_dev = ehci_remove_device, +#ifdef CONFIG_USB_HCD_TEST_MODE + /* EH SINGLE_STEP_SET_FEATURE test support */ + .submit_single_step_set_feature = ehci_submit_single_step_set_feature, +#endif }; void ehci_init_driver(struct hc_driver *drv, diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 159cc27b1a36..c4f6a2559a98 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -727,145 +727,6 @@ ehci_hub_descriptor ( } /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_HCD_TEST_MODE - -#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06 - -static void usb_ehset_completion(struct urb *urb) -{ - struct completion *done = urb->context; - - complete(done); -} -static int submit_single_step_set_feature( - struct usb_hcd *hcd, - struct urb *urb, - int is_setup -); - -/* - * Allocate and initialize a control URB. This request will be used by the - * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages - * of the GetDescriptor request are sent 15 seconds after the SETUP stage. - * Return NULL if failed. - */ -static struct urb *request_single_step_set_feature_urb( - struct usb_device *udev, - void *dr, - void *buf, - struct completion *done -) { - struct urb *urb; - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - struct usb_host_endpoint *ep; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return NULL; - - urb->pipe = usb_rcvctrlpipe(udev, 0); - ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (!ep) { - usb_free_urb(urb); - return NULL; - } - - urb->ep = ep; - urb->dev = udev; - urb->setup_packet = (void *)dr; - urb->transfer_buffer = buf; - urb->transfer_buffer_length = USB_DT_DEVICE_SIZE; - urb->complete = usb_ehset_completion; - urb->status = -EINPROGRESS; - urb->actual_length = 0; - urb->transfer_flags = URB_DIR_IN; - usb_get_urb(urb); - atomic_inc(&urb->use_count); - atomic_inc(&urb->dev->urbnum); - urb->setup_dma = dma_map_single( - hcd->self.sysdev, - urb->setup_packet, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - urb->transfer_dma = dma_map_single( - hcd->self.sysdev, - urb->transfer_buffer, - urb->transfer_buffer_length, - DMA_FROM_DEVICE); - urb->context = done; - return urb; -} - -static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) -{ - int retval = -ENOMEM; - struct usb_ctrlrequest *dr; - struct urb *urb; - struct usb_device *udev; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct usb_device_descriptor *buf; - DECLARE_COMPLETION_ONSTACK(done); - - /* Obtain udev of the rhub's child port */ - udev = usb_hub_find_child(hcd->self.root_hub, port); - if (!udev) { - ehci_err(ehci, "No device attached to the RootHub\n"); - return -ENODEV; - } - buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!dr) { - kfree(buf); - return -ENOMEM; - } - - /* Fill Setup packet for GetDescriptor */ - dr->bRequestType = USB_DIR_IN; - dr->bRequest = USB_REQ_GET_DESCRIPTOR; - dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8); - dr->wIndex = 0; - dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE); - urb = request_single_step_set_feature_urb(udev, dr, buf, &done); - if (!urb) - goto cleanup; - - /* Submit just the SETUP stage */ - retval = submit_single_step_set_feature(hcd, urb, 1); - if (retval) - goto out1; - if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { - usb_kill_urb(urb); - retval = -ETIMEDOUT; - ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__); - goto out1; - } - msleep(15 * 1000); - - /* Complete remaining DATA and STATUS stages using the same URB */ - urb->status = -EINPROGRESS; - usb_get_urb(urb); - atomic_inc(&urb->use_count); - atomic_inc(&urb->dev->urbnum); - retval = submit_single_step_set_feature(hcd, urb, 0); - if (!retval && !wait_for_completion_timeout(&done, - msecs_to_jiffies(2000))) { - usb_kill_urb(urb); - retval = -ETIMEDOUT; - ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__); - } -out1: - usb_free_urb(urb); -cleanup: - kfree(dr); - kfree(buf); - return retval; -} -#endif /* CONFIG_USB_HCD_TEST_MODE */ -/*-------------------------------------------------------------------------*/ int ehci_hub_control( struct usb_hcd *hcd, diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index a826715ae9bd..2cbf4f85bff3 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1165,7 +1165,7 @@ submit_async ( * performed; TRUE - SETUP and FALSE - IN+STATUS * Returns 0 if success */ -static int submit_single_step_set_feature( +static int ehci_submit_single_step_set_feature( struct usb_hcd *hcd, struct urb *urb, int is_setup diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 9c2eda0918e1..05fb8d97cf02 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -850,7 +850,6 @@ static inline void create_debug_files(struct fotg210_hcd *fotg210) struct dentry *root; root = debugfs_create_dir(bus->bus_name, fotg210_debug_root); - fotg210->debug_dir = root; debugfs_create_file("async", S_IRUGO, root, bus, &debug_async_fops); debugfs_create_file("periodic", S_IRUGO, root, bus, @@ -861,7 +860,9 @@ static inline void create_debug_files(struct fotg210_hcd *fotg210) static inline void remove_debug_files(struct fotg210_hcd *fotg210) { - debugfs_remove_recursive(fotg210->debug_dir); + struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self; + + debugfs_remove(debugfs_lookup(bus->bus_name, fotg210_debug_root)); } /* handshake - spin reading hc until handshake completes or fails diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h index 6cee40ec65b4..0a91061a0551 100644 --- a/drivers/usb/host/fotg210.h +++ b/drivers/usb/host/fotg210.h @@ -184,9 +184,6 @@ struct fotg210_hcd { /* one per controller */ /* silicon clock */ struct clk *pclk; - - /* debug files */ - struct dentry *debug_dir; }; /* convert between an HCD pointer and the corresponding FOTG210_HCD */ diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index 8b90da5a6ed1..c07411d9b16f 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -476,6 +476,9 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset) u32 start_cs, last_cs; int i; + if (!sch_ep->sch_tt) + return 0; + start_ss = offset % 8; if (sch_ep->ep_type == ISOC_OUT_EP) { @@ -603,54 +606,47 @@ static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep) static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep) { + const u32 esit_boundary = get_esit_boundary(sch_ep); + const u32 bw_boundary = get_bw_boundary(sch_ep->speed); u32 offset; - u32 min_bw; - u32 min_index; u32 worst_bw; - u32 bw_boundary; - u32 esit_boundary; - u32 min_num_budget; - u32 min_cs_count; + u32 min_bw = ~0; + int min_index = -1; int ret = 0; /* * Search through all possible schedule microframes. * and find a microframe where its worst bandwidth is minimum. */ - min_bw = ~0; - min_index = 0; - min_cs_count = sch_ep->cs_count; - min_num_budget = sch_ep->num_budget_microframes; - esit_boundary = get_esit_boundary(sch_ep); for (offset = 0; offset < sch_ep->esit; offset++) { - if (sch_ep->sch_tt) { - ret = check_sch_tt(sch_ep, offset); - if (ret) - continue; - } + ret = check_sch_tt(sch_ep, offset); + if (ret) + continue; if ((offset + sch_ep->num_budget_microframes) > esit_boundary) break; worst_bw = get_max_bw(sch_bw, sch_ep, offset); + if (worst_bw > bw_boundary) + continue; + if (min_bw > worst_bw) { min_bw = worst_bw; min_index = offset; - min_cs_count = sch_ep->cs_count; - min_num_budget = sch_ep->num_budget_microframes; } + + /* use first-fit for LS/FS */ + if (sch_ep->sch_tt && min_index >= 0) + break; + if (min_bw == 0) break; } - bw_boundary = get_bw_boundary(sch_ep->speed); - /* check bandwidth */ - if (min_bw > bw_boundary) + if (min_index < 0) return ret ? ret : -ESCH_BW_OVERFLOW; sch_ep->offset = min_index; - sch_ep->cs_count = min_cs_count; - sch_ep->num_budget_microframes = min_num_budget; return load_ep_bw(sch_bw, sch_ep, true); } diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index b2058b3bc834..2548976bcf05 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -495,8 +495,6 @@ static int xhci_mtk_probe(struct platform_device *pdev) goto put_usb2_hcd; } mtk->has_ippc = true; - } else { - mtk->has_ippc = false; } device_init_wakeup(dev, true); diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index cd3a37bb73e6..94a59b3d178f 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -138,17 +138,17 @@ struct xhci_hcd_mtk { struct mu3h_sch_bw_info *sch_array; struct list_head bw_ep_chk_list; struct mu3c_ippc_regs __iomem *ippc_regs; - bool has_ippc; int num_u2_ports; int num_u3_ports; int u3p_dis_msk; struct regulator *vusb33; struct regulator *vbus; struct clk_bulk_data clks[BULK_CLKS_NUM]; - bool lpm_support; - bool u2_lpm_disable; + unsigned int has_ippc:1; + unsigned int lpm_support:1; + unsigned int u2_lpm_disable:1; /* usb remote wakeup */ - bool uwk_en; + unsigned int uwk_en:1; struct regmap *uwk; u32 uwk_reg_base; u32 uwk_vers; diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig index b1022cc490a2..2ed2b73291d1 100644 --- a/drivers/usb/isp1760/Kconfig +++ b/drivers/usb/isp1760/Kconfig @@ -1,10 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 config USB_ISP1760 - tristate "NXP ISP 1760/1761 support" + tristate "NXP ISP 1760/1761/1763 support" depends on USB || USB_GADGET + select REGMAP_MMIO help - Say Y or M here if your system as an ISP1760 USB host controller + Say Y or M here if your system as an ISP1760/1763 USB host controller or an ISP1761 USB dual-role controller. This driver does not support isochronous transfers or OTG. diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c index fdeb4cf97cc5..ff07e2890692 100644 --- a/drivers/usb/isp1760/isp1760-core.c +++ b/drivers/usb/isp1760/isp1760-core.c @@ -2,12 +2,14 @@ /* * Driver for the NXP ISP1760 chip * + * Copyright 2021 Linaro, Rui Miguel Silva * Copyright 2014 Laurent Pinchart * Copyright 2007 Sebastian Siewior * * Contacts: * Sebastian Siewior <bigeasy@linutronix.de> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * Rui Miguel Silva <rui.silva@linaro.org> */ #include <linux/delay.h> @@ -15,6 +17,7 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <linux/usb.h> @@ -23,10 +26,10 @@ #include "isp1760-regs.h" #include "isp1760-udc.h" -static void isp1760_init_core(struct isp1760_device *isp) +static int isp1760_init_core(struct isp1760_device *isp) { - u32 otgctrl; - u32 hwmode; + struct isp1760_hcd *hcd = &isp->hcd; + struct isp1760_udc *udc = &isp->udc; /* Low-level chip reset */ if (isp->rst_gpio) { @@ -39,24 +42,29 @@ static void isp1760_init_core(struct isp1760_device *isp) * Reset the host controller, including the CPU interface * configuration. */ - isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL); + isp1760_field_set(hcd->fields, SW_RESET_RESET_ALL); msleep(100); /* Setup HW Mode Control: This assumes a level active-low interrupt */ - hwmode = HW_DATA_BUS_32BIT; + if ((isp->devflags & ISP1760_FLAG_ANALOG_OC) && hcd->is_isp1763) { + dev_err(isp->dev, "isp1763 analog overcurrent not available\n"); + return -EINVAL; + } if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16) - hwmode &= ~HW_DATA_BUS_32BIT; + isp1760_field_clear(hcd->fields, HW_DATA_BUS_WIDTH); + if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_8) + isp1760_field_set(hcd->fields, HW_DATA_BUS_WIDTH); if (isp->devflags & ISP1760_FLAG_ANALOG_OC) - hwmode |= HW_ANA_DIGI_OC; + isp1760_field_set(hcd->fields, HW_ANA_DIGI_OC); if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH) - hwmode |= HW_DACK_POL_HIGH; + isp1760_field_set(hcd->fields, HW_DACK_POL_HIGH); if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH) - hwmode |= HW_DREQ_POL_HIGH; + isp1760_field_set(hcd->fields, HW_DREQ_POL_HIGH); if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH) - hwmode |= HW_INTR_HIGH_ACT; + isp1760_field_set(hcd->fields, HW_INTR_HIGH_ACT); if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG) - hwmode |= HW_INTR_EDGE_TRIG; + isp1760_field_set(hcd->fields, HW_INTR_EDGE_TRIG); /* * The ISP1761 has a dedicated DC IRQ line but supports sharing the HC @@ -65,59 +73,425 @@ static void isp1760_init_core(struct isp1760_device *isp) * spurious interrupts during HCD registration. */ if (isp->devflags & ISP1760_FLAG_ISP1761) { - isp1760_write32(isp->regs, DC_MODE, 0); - hwmode |= HW_COMN_IRQ; + isp1760_reg_write(udc->regs, ISP176x_DC_MODE, 0); + isp1760_field_set(hcd->fields, HW_COMN_IRQ); } /* - * We have to set this first in case we're in 16-bit mode. - * Write it twice to ensure correct upper bits if switching - * to 16-bit mode. - */ - isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode); - isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode); - - /* * PORT 1 Control register of the ISP1760 is the OTG control register * on ISP1761. * * TODO: Really support OTG. For now we configure port 1 in device mode - * when OTG is requested. */ - if ((isp->devflags & ISP1760_FLAG_ISP1761) && - (isp->devflags & ISP1760_FLAG_OTG_EN)) - otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16) - | HW_OTG_DISABLE; - else - otgctrl = (HW_SW_SEL_HC_DC << 16) - | (HW_VBUS_DRV | HW_SEL_CP_EXT); - - isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl); + if (((isp->devflags & ISP1760_FLAG_ISP1761) || + (isp->devflags & ISP1760_FLAG_ISP1763)) && + (isp->devflags & ISP1760_FLAG_PERIPHERAL_EN)) { + isp1760_field_set(hcd->fields, HW_DM_PULLDOWN); + isp1760_field_set(hcd->fields, HW_DP_PULLDOWN); + isp1760_field_set(hcd->fields, HW_OTG_DISABLE); + } else { + isp1760_field_set(hcd->fields, HW_SW_SEL_HC_DC); + isp1760_field_set(hcd->fields, HW_VBUS_DRV); + isp1760_field_set(hcd->fields, HW_SEL_CP_EXT); + } - dev_info(isp->dev, "bus width: %u, oc: %s\n", + dev_info(isp->dev, "%s bus width: %u, oc: %s\n", + hcd->is_isp1763 ? "isp1763" : "isp1760", + isp->devflags & ISP1760_FLAG_BUS_WIDTH_8 ? 8 : isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32, + hcd->is_isp1763 ? "not available" : isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital"); + + return 0; } void isp1760_set_pullup(struct isp1760_device *isp, bool enable) { - isp1760_write32(isp->regs, HW_OTG_CTRL_SET, - enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16); + struct isp1760_udc *udc = &isp->udc; + + if (enable) + isp1760_field_set(udc->fields, HW_DP_PULLUP); + else + isp1760_field_set(udc->fields, HW_DP_PULLUP_CLEAR); } +/* + * ISP1760/61: + * + * 60kb divided in: + * - 32 blocks @ 256 bytes + * - 20 blocks @ 1024 bytes + * - 4 blocks @ 8192 bytes + */ +static const struct isp1760_memory_layout isp176x_memory_conf = { + .blocks[0] = 32, + .blocks_size[0] = 256, + .blocks[1] = 20, + .blocks_size[1] = 1024, + .blocks[2] = 4, + .blocks_size[2] = 8192, + + .slot_num = 32, + .payload_blocks = 32 + 20 + 4, + .payload_area_size = 0xf000, +}; + +/* + * ISP1763: + * + * 20kb divided in: + * - 8 blocks @ 256 bytes + * - 2 blocks @ 1024 bytes + * - 4 blocks @ 4096 bytes + */ +static const struct isp1760_memory_layout isp1763_memory_conf = { + .blocks[0] = 8, + .blocks_size[0] = 256, + .blocks[1] = 2, + .blocks_size[1] = 1024, + .blocks[2] = 4, + .blocks_size[2] = 4096, + + .slot_num = 16, + .payload_blocks = 8 + 2 + 4, + .payload_area_size = 0x5000, +}; + +static const struct regmap_range isp176x_hc_volatile_ranges[] = { + regmap_reg_range(ISP176x_HC_USBCMD, ISP176x_HC_ATL_PTD_LASTPTD), + regmap_reg_range(ISP176x_HC_BUFFER_STATUS, ISP176x_HC_MEMORY), + regmap_reg_range(ISP176x_HC_INTERRUPT, ISP176x_HC_OTG_CTRL_CLEAR), +}; + +static const struct regmap_access_table isp176x_hc_volatile_table = { + .yes_ranges = isp176x_hc_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(isp176x_hc_volatile_ranges), +}; + +static const struct regmap_config isp1760_hc_regmap_conf = { + .name = "isp1760-hc", + .reg_bits = 16, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, + .max_register = ISP176x_HC_OTG_CTRL_CLEAR, + .volatile_table = &isp176x_hc_volatile_table, +}; + +static const struct reg_field isp1760_hc_reg_fields[] = { + [HCS_PPC] = REG_FIELD(ISP176x_HC_HCSPARAMS, 4, 4), + [HCS_N_PORTS] = REG_FIELD(ISP176x_HC_HCSPARAMS, 0, 3), + [HCC_ISOC_CACHE] = REG_FIELD(ISP176x_HC_HCCPARAMS, 7, 7), + [HCC_ISOC_THRES] = REG_FIELD(ISP176x_HC_HCCPARAMS, 4, 6), + [CMD_LRESET] = REG_FIELD(ISP176x_HC_USBCMD, 7, 7), + [CMD_RESET] = REG_FIELD(ISP176x_HC_USBCMD, 1, 1), + [CMD_RUN] = REG_FIELD(ISP176x_HC_USBCMD, 0, 0), + [STS_PCD] = REG_FIELD(ISP176x_HC_USBSTS, 2, 2), + [HC_FRINDEX] = REG_FIELD(ISP176x_HC_FRINDEX, 0, 13), + [FLAG_CF] = REG_FIELD(ISP176x_HC_CONFIGFLAG, 0, 0), + [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_DONEMAP, 0, 31), + [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_SKIPMAP, 0, 31), + [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ISO_PTD_LASTPTD, 0, 31), + [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_INT_PTD_DONEMAP, 0, 31), + [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_INT_PTD_SKIPMAP, 0, 31), + [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_INT_PTD_LASTPTD, 0, 31), + [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_DONEMAP, 0, 31), + [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_SKIPMAP, 0, 31), + [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ATL_PTD_LASTPTD, 0, 31), + [PORT_OWNER] = REG_FIELD(ISP176x_HC_PORTSC1, 13, 13), + [PORT_POWER] = REG_FIELD(ISP176x_HC_PORTSC1, 12, 12), + [PORT_LSTATUS] = REG_FIELD(ISP176x_HC_PORTSC1, 10, 11), + [PORT_RESET] = REG_FIELD(ISP176x_HC_PORTSC1, 8, 8), + [PORT_SUSPEND] = REG_FIELD(ISP176x_HC_PORTSC1, 7, 7), + [PORT_RESUME] = REG_FIELD(ISP176x_HC_PORTSC1, 6, 6), + [PORT_PE] = REG_FIELD(ISP176x_HC_PORTSC1, 2, 2), + [PORT_CSC] = REG_FIELD(ISP176x_HC_PORTSC1, 1, 1), + [PORT_CONNECT] = REG_FIELD(ISP176x_HC_PORTSC1, 0, 0), + [ALL_ATX_RESET] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 31, 31), + [HW_ANA_DIGI_OC] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 15, 15), + [HW_COMN_IRQ] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 10, 10), + [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 8, 8), + [HW_DACK_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 6, 6), + [HW_DREQ_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 5, 5), + [HW_INTR_HIGH_ACT] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 2, 2), + [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 1, 1), + [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 0, 0), + [HC_CHIP_REV] = REG_FIELD(ISP176x_HC_CHIP_ID, 16, 31), + [HC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_HC_CHIP_ID, 8, 15), + [HC_CHIP_ID_LOW] = REG_FIELD(ISP176x_HC_CHIP_ID, 0, 7), + [HC_SCRATCH] = REG_FIELD(ISP176x_HC_SCRATCH, 0, 31), + [SW_RESET_RESET_ALL] = REG_FIELD(ISP176x_HC_RESET, 0, 0), + [ISO_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 2, 2), + [INT_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 1, 1), + [ATL_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 0, 0), + [MEM_BANK_SEL] = REG_FIELD(ISP176x_HC_MEMORY, 16, 17), + [MEM_START_ADDR] = REG_FIELD(ISP176x_HC_MEMORY, 0, 15), + [HC_INTERRUPT] = REG_FIELD(ISP176x_HC_INTERRUPT, 0, 9), + [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 8, 8), + [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 7), + [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_OR, 0, 31), + [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_OR, 0, 31), + [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_OR, 0, 31), + [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_AND, 0, 31), + [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_AND, 0, 31), + [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_AND, 0, 31), + [HW_OTG_DISABLE] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 10, 10), + [HW_SW_SEL_HC_DC] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 7, 7), + [HW_VBUS_DRV] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 4, 4), + [HW_SEL_CP_EXT] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 3, 3), + [HW_DM_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 2, 2), + [HW_DP_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 1, 1), + [HW_DP_PULLUP] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 0, 0), + [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 10, 10), + [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 7, 7), + [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 4, 4), + [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 3, 3), + [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 2, 2), + [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 1, 1), + [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 0, 0), +}; + +static const struct reg_field isp1763_hc_reg_fields[] = { + [CMD_LRESET] = REG_FIELD(ISP1763_HC_USBCMD, 7, 7), + [CMD_RESET] = REG_FIELD(ISP1763_HC_USBCMD, 1, 1), + [CMD_RUN] = REG_FIELD(ISP1763_HC_USBCMD, 0, 0), + [STS_PCD] = REG_FIELD(ISP1763_HC_USBSTS, 2, 2), + [HC_FRINDEX] = REG_FIELD(ISP1763_HC_FRINDEX, 0, 13), + [FLAG_CF] = REG_FIELD(ISP1763_HC_CONFIGFLAG, 0, 0), + [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_DONEMAP, 0, 15), + [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_SKIPMAP, 0, 15), + [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ISO_PTD_LASTPTD, 0, 15), + [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_INT_PTD_DONEMAP, 0, 15), + [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_INT_PTD_SKIPMAP, 0, 15), + [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_INT_PTD_LASTPTD, 0, 15), + [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_DONEMAP, 0, 15), + [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_SKIPMAP, 0, 15), + [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ATL_PTD_LASTPTD, 0, 15), + [PORT_OWNER] = REG_FIELD(ISP1763_HC_PORTSC1, 13, 13), + [PORT_POWER] = REG_FIELD(ISP1763_HC_PORTSC1, 12, 12), + [PORT_LSTATUS] = REG_FIELD(ISP1763_HC_PORTSC1, 10, 11), + [PORT_RESET] = REG_FIELD(ISP1763_HC_PORTSC1, 8, 8), + [PORT_SUSPEND] = REG_FIELD(ISP1763_HC_PORTSC1, 7, 7), + [PORT_RESUME] = REG_FIELD(ISP1763_HC_PORTSC1, 6, 6), + [PORT_PE] = REG_FIELD(ISP1763_HC_PORTSC1, 2, 2), + [PORT_CSC] = REG_FIELD(ISP1763_HC_PORTSC1, 1, 1), + [PORT_CONNECT] = REG_FIELD(ISP1763_HC_PORTSC1, 0, 0), + [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 4, 4), + [HW_DACK_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 6, 6), + [HW_DREQ_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 5, 5), + [HW_INTF_LOCK] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 3, 3), + [HW_INTR_HIGH_ACT] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 2, 2), + [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 1, 1), + [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 0, 0), + [SW_RESET_RESET_ATX] = REG_FIELD(ISP1763_HC_RESET, 3, 3), + [SW_RESET_RESET_ALL] = REG_FIELD(ISP1763_HC_RESET, 0, 0), + [HC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_HC_CHIP_ID, 0, 15), + [HC_CHIP_ID_LOW] = REG_FIELD(ISP1763_HC_CHIP_REV, 8, 15), + [HC_CHIP_REV] = REG_FIELD(ISP1763_HC_CHIP_REV, 0, 7), + [HC_SCRATCH] = REG_FIELD(ISP1763_HC_SCRATCH, 0, 15), + [ISO_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 2, 2), + [INT_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 1, 1), + [ATL_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 0, 0), + [MEM_START_ADDR] = REG_FIELD(ISP1763_HC_MEMORY, 0, 15), + [HC_DATA] = REG_FIELD(ISP1763_HC_DATA, 0, 15), + [HC_INTERRUPT] = REG_FIELD(ISP1763_HC_INTERRUPT, 0, 10), + [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 8, 8), + [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 7, 7), + [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_OR, 0, 15), + [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_OR, 0, 15), + [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_OR, 0, 15), + [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_AND, 0, 15), + [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_AND, 0, 15), + [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_AND, 0, 15), + [HW_HC_2_DIS] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 15, 15), + [HW_OTG_DISABLE] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 10, 10), + [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 7, 7), + [HW_VBUS_DRV] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 4, 4), + [HW_SEL_CP_EXT] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 3, 3), + [HW_DM_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 2, 2), + [HW_DP_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 1, 1), + [HW_DP_PULLUP] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 0, 0), + [HW_HC_2_DIS_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 15, 15), + [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 10, 10), + [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 7, 7), + [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 4, 4), + [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 3, 3), + [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 2, 2), + [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 1, 1), + [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 0, 0), +}; + +static const struct regmap_range isp1763_hc_volatile_ranges[] = { + regmap_reg_range(ISP1763_HC_USBCMD, ISP1763_HC_ATL_PTD_LASTPTD), + regmap_reg_range(ISP1763_HC_BUFFER_STATUS, ISP1763_HC_DATA), + regmap_reg_range(ISP1763_HC_INTERRUPT, ISP1763_HC_OTG_CTRL_CLEAR), +}; + +static const struct regmap_access_table isp1763_hc_volatile_table = { + .yes_ranges = isp1763_hc_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(isp1763_hc_volatile_ranges), +}; + +static const struct regmap_config isp1763_hc_regmap_conf = { + .name = "isp1763-hc", + .reg_bits = 8, + .reg_stride = 2, + .val_bits = 16, + .fast_io = true, + .max_register = ISP1763_HC_OTG_CTRL_CLEAR, + .volatile_table = &isp1763_hc_volatile_table, +}; + +static const struct regmap_range isp176x_dc_volatile_ranges[] = { + regmap_reg_range(ISP176x_DC_EPMAXPKTSZ, ISP176x_DC_EPTYPE), + regmap_reg_range(ISP176x_DC_BUFLEN, ISP176x_DC_EPINDEX), +}; + +static const struct regmap_access_table isp176x_dc_volatile_table = { + .yes_ranges = isp176x_dc_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(isp176x_dc_volatile_ranges), +}; + +static const struct regmap_config isp1761_dc_regmap_conf = { + .name = "isp1761-dc", + .reg_bits = 16, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, + .max_register = ISP176x_DC_TESTMODE, + .volatile_table = &isp176x_dc_volatile_table, +}; + +static const struct reg_field isp1761_dc_reg_fields[] = { + [DC_DEVEN] = REG_FIELD(ISP176x_DC_ADDRESS, 7, 7), + [DC_DEVADDR] = REG_FIELD(ISP176x_DC_ADDRESS, 0, 6), + [DC_VBUSSTAT] = REG_FIELD(ISP176x_DC_MODE, 8, 8), + [DC_SFRESET] = REG_FIELD(ISP176x_DC_MODE, 4, 4), + [DC_GLINTENA] = REG_FIELD(ISP176x_DC_MODE, 3, 3), + [DC_CDBGMOD_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 6, 6), + [DC_DDBGMODIN_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 4, 4), + [DC_DDBGMODOUT_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 2, 2), + [DC_INTPOL] = REG_FIELD(ISP176x_DC_INTCONF, 0, 0), + [DC_IEPRXTX_7] = REG_FIELD(ISP176x_DC_INTENABLE, 25, 25), + [DC_IEPRXTX_6] = REG_FIELD(ISP176x_DC_INTENABLE, 23, 23), + [DC_IEPRXTX_5] = REG_FIELD(ISP176x_DC_INTENABLE, 21, 21), + [DC_IEPRXTX_4] = REG_FIELD(ISP176x_DC_INTENABLE, 19, 19), + [DC_IEPRXTX_3] = REG_FIELD(ISP176x_DC_INTENABLE, 17, 17), + [DC_IEPRXTX_2] = REG_FIELD(ISP176x_DC_INTENABLE, 15, 15), + [DC_IEPRXTX_1] = REG_FIELD(ISP176x_DC_INTENABLE, 13, 13), + [DC_IEPRXTX_0] = REG_FIELD(ISP176x_DC_INTENABLE, 11, 11), + [DC_IEP0SETUP] = REG_FIELD(ISP176x_DC_INTENABLE, 8, 8), + [DC_IEVBUS] = REG_FIELD(ISP176x_DC_INTENABLE, 7, 7), + [DC_IEHS_STA] = REG_FIELD(ISP176x_DC_INTENABLE, 5, 5), + [DC_IERESM] = REG_FIELD(ISP176x_DC_INTENABLE, 4, 4), + [DC_IESUSP] = REG_FIELD(ISP176x_DC_INTENABLE, 3, 3), + [DC_IEBRST] = REG_FIELD(ISP176x_DC_INTENABLE, 0, 0), + [DC_EP0SETUP] = REG_FIELD(ISP176x_DC_EPINDEX, 5, 5), + [DC_ENDPIDX] = REG_FIELD(ISP176x_DC_EPINDEX, 1, 4), + [DC_EPDIR] = REG_FIELD(ISP176x_DC_EPINDEX, 0, 0), + [DC_CLBUF] = REG_FIELD(ISP176x_DC_CTRLFUNC, 4, 4), + [DC_VENDP] = REG_FIELD(ISP176x_DC_CTRLFUNC, 3, 3), + [DC_DSEN] = REG_FIELD(ISP176x_DC_CTRLFUNC, 2, 2), + [DC_STATUS] = REG_FIELD(ISP176x_DC_CTRLFUNC, 1, 1), + [DC_STALL] = REG_FIELD(ISP176x_DC_CTRLFUNC, 0, 0), + [DC_BUFLEN] = REG_FIELD(ISP176x_DC_BUFLEN, 0, 15), + [DC_FFOSZ] = REG_FIELD(ISP176x_DC_EPMAXPKTSZ, 0, 10), + [DC_EPENABLE] = REG_FIELD(ISP176x_DC_EPTYPE, 3, 3), + [DC_ENDPTYP] = REG_FIELD(ISP176x_DC_EPTYPE, 0, 1), + [DC_UFRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 11, 13), + [DC_FRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 0, 10), + [DC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_DC_CHIPID, 16, 31), + [DC_CHIP_ID_LOW] = REG_FIELD(ISP176x_DC_CHIPID, 0, 15), + [DC_SCRATCH] = REG_FIELD(ISP176x_DC_SCRATCH, 0, 15), +}; + +static const struct regmap_range isp1763_dc_volatile_ranges[] = { + regmap_reg_range(ISP1763_DC_EPMAXPKTSZ, ISP1763_DC_EPTYPE), + regmap_reg_range(ISP1763_DC_BUFLEN, ISP1763_DC_EPINDEX), +}; + +static const struct regmap_access_table isp1763_dc_volatile_table = { + .yes_ranges = isp1763_dc_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(isp1763_dc_volatile_ranges), +}; + +static const struct reg_field isp1763_dc_reg_fields[] = { + [DC_DEVEN] = REG_FIELD(ISP1763_DC_ADDRESS, 7, 7), + [DC_DEVADDR] = REG_FIELD(ISP1763_DC_ADDRESS, 0, 6), + [DC_VBUSSTAT] = REG_FIELD(ISP1763_DC_MODE, 8, 8), + [DC_SFRESET] = REG_FIELD(ISP1763_DC_MODE, 4, 4), + [DC_GLINTENA] = REG_FIELD(ISP1763_DC_MODE, 3, 3), + [DC_CDBGMOD_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 6, 6), + [DC_DDBGMODIN_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 4, 4), + [DC_DDBGMODOUT_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 2, 2), + [DC_INTPOL] = REG_FIELD(ISP1763_DC_INTCONF, 0, 0), + [DC_IEPRXTX_7] = REG_FIELD(ISP1763_DC_INTENABLE, 25, 25), + [DC_IEPRXTX_6] = REG_FIELD(ISP1763_DC_INTENABLE, 23, 23), + [DC_IEPRXTX_5] = REG_FIELD(ISP1763_DC_INTENABLE, 21, 21), + [DC_IEPRXTX_4] = REG_FIELD(ISP1763_DC_INTENABLE, 19, 19), + [DC_IEPRXTX_3] = REG_FIELD(ISP1763_DC_INTENABLE, 17, 17), + [DC_IEPRXTX_2] = REG_FIELD(ISP1763_DC_INTENABLE, 15, 15), + [DC_IEPRXTX_1] = REG_FIELD(ISP1763_DC_INTENABLE, 13, 13), + [DC_IEPRXTX_0] = REG_FIELD(ISP1763_DC_INTENABLE, 11, 11), + [DC_IEP0SETUP] = REG_FIELD(ISP1763_DC_INTENABLE, 8, 8), + [DC_IEVBUS] = REG_FIELD(ISP1763_DC_INTENABLE, 7, 7), + [DC_IEHS_STA] = REG_FIELD(ISP1763_DC_INTENABLE, 5, 5), + [DC_IERESM] = REG_FIELD(ISP1763_DC_INTENABLE, 4, 4), + [DC_IESUSP] = REG_FIELD(ISP1763_DC_INTENABLE, 3, 3), + [DC_IEBRST] = REG_FIELD(ISP1763_DC_INTENABLE, 0, 0), + [DC_EP0SETUP] = REG_FIELD(ISP1763_DC_EPINDEX, 5, 5), + [DC_ENDPIDX] = REG_FIELD(ISP1763_DC_EPINDEX, 1, 4), + [DC_EPDIR] = REG_FIELD(ISP1763_DC_EPINDEX, 0, 0), + [DC_CLBUF] = REG_FIELD(ISP1763_DC_CTRLFUNC, 4, 4), + [DC_VENDP] = REG_FIELD(ISP1763_DC_CTRLFUNC, 3, 3), + [DC_DSEN] = REG_FIELD(ISP1763_DC_CTRLFUNC, 2, 2), + [DC_STATUS] = REG_FIELD(ISP1763_DC_CTRLFUNC, 1, 1), + [DC_STALL] = REG_FIELD(ISP1763_DC_CTRLFUNC, 0, 0), + [DC_BUFLEN] = REG_FIELD(ISP1763_DC_BUFLEN, 0, 15), + [DC_FFOSZ] = REG_FIELD(ISP1763_DC_EPMAXPKTSZ, 0, 10), + [DC_EPENABLE] = REG_FIELD(ISP1763_DC_EPTYPE, 3, 3), + [DC_ENDPTYP] = REG_FIELD(ISP1763_DC_EPTYPE, 0, 1), + [DC_UFRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 11, 13), + [DC_FRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 0, 10), + [DC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_DC_CHIPID_HIGH, 0, 15), + [DC_CHIP_ID_LOW] = REG_FIELD(ISP1763_DC_CHIPID_LOW, 0, 15), + [DC_SCRATCH] = REG_FIELD(ISP1763_DC_SCRATCH, 0, 15), +}; + +static const struct regmap_config isp1763_dc_regmap_conf = { + .name = "isp1763-dc", + .reg_bits = 8, + .reg_stride = 2, + .val_bits = 16, + .fast_io = true, + .max_register = ISP1763_DC_TESTMODE, + .volatile_table = &isp1763_dc_volatile_table, +}; + int isp1760_register(struct resource *mem, int irq, unsigned long irqflags, struct device *dev, unsigned int devflags) { + const struct regmap_config *hc_regmap; + const struct reg_field *hc_reg_fields; + const struct regmap_config *dc_regmap; + const struct reg_field *dc_reg_fields; struct isp1760_device *isp; - bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761); + struct isp1760_hcd *hcd; + struct isp1760_udc *udc; + struct regmap_field *f; + bool udc_enabled; int ret; + int i; /* * If neither the HCD not the UDC is enabled return an error, as no * device would be registered. */ + udc_enabled = ((devflags & ISP1760_FLAG_ISP1763) || + (devflags & ISP1760_FLAG_ISP1761)); + if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) && - (!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || udc_disabled)) + (!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || !udc_enabled)) return -ENODEV; isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); @@ -126,28 +500,81 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags, isp->dev = dev; isp->devflags = devflags; + hcd = &isp->hcd; + udc = &isp->udc; + + hcd->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763); + udc->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763); + + if (!hcd->is_isp1763 && (devflags & ISP1760_FLAG_BUS_WIDTH_8)) { + dev_err(dev, "isp1760/61 do not support data width 8\n"); + return -EINVAL; + } + + if (hcd->is_isp1763) { + hc_regmap = &isp1763_hc_regmap_conf; + hc_reg_fields = &isp1763_hc_reg_fields[0]; + dc_regmap = &isp1763_dc_regmap_conf; + dc_reg_fields = &isp1763_dc_reg_fields[0]; + } else { + hc_regmap = &isp1760_hc_regmap_conf; + hc_reg_fields = &isp1760_hc_reg_fields[0]; + dc_regmap = &isp1761_dc_regmap_conf; + dc_reg_fields = &isp1761_dc_reg_fields[0]; + } isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); if (IS_ERR(isp->rst_gpio)) return PTR_ERR(isp->rst_gpio); - isp->regs = devm_ioremap_resource(dev, mem); - if (IS_ERR(isp->regs)) - return PTR_ERR(isp->regs); + hcd->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(hcd->base)) + return PTR_ERR(hcd->base); + + hcd->regs = devm_regmap_init_mmio(dev, hcd->base, hc_regmap); + if (IS_ERR(hcd->regs)) + return PTR_ERR(hcd->regs); + + for (i = 0; i < HC_FIELD_MAX; i++) { + f = devm_regmap_field_alloc(dev, hcd->regs, hc_reg_fields[i]); + if (IS_ERR(f)) + return PTR_ERR(f); + + hcd->fields[i] = f; + } + + udc->regs = devm_regmap_init_mmio(dev, hcd->base, dc_regmap); + if (IS_ERR(udc->regs)) + return PTR_ERR(udc->regs); + + for (i = 0; i < DC_FIELD_MAX; i++) { + f = devm_regmap_field_alloc(dev, udc->regs, dc_reg_fields[i]); + if (IS_ERR(f)) + return PTR_ERR(f); + + udc->fields[i] = f; + } + + if (hcd->is_isp1763) + hcd->memory_layout = &isp1763_memory_conf; + else + hcd->memory_layout = &isp176x_memory_conf; - isp1760_init_core(isp); + ret = isp1760_init_core(isp); + if (ret < 0) + return ret; if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) { - ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq, + ret = isp1760_hcd_register(hcd, mem, irq, irqflags | IRQF_SHARED, dev); if (ret < 0) return ret; } - if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) { + if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && udc_enabled) { ret = isp1760_udc_register(isp, irq, irqflags); if (ret < 0) { - isp1760_hcd_unregister(&isp->hcd); + isp1760_hcd_unregister(hcd); return ret; } } diff --git a/drivers/usb/isp1760/isp1760-core.h b/drivers/usb/isp1760/isp1760-core.h index d9a0a4cc467c..91e0ee3992a7 100644 --- a/drivers/usb/isp1760/isp1760-core.h +++ b/drivers/usb/isp1760/isp1760-core.h @@ -2,18 +2,21 @@ /* * Driver for the NXP ISP1760 chip * + * Copyright 2021 Linaro, Rui Miguel Silva * Copyright 2014 Laurent Pinchart * Copyright 2007 Sebastian Siewior * * Contacts: * Sebastian Siewior <bigeasy@linutronix.de> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * Rui Miguel Silva <rui.silva@linaro.org> */ #ifndef _ISP1760_CORE_H_ #define _ISP1760_CORE_H_ #include <linux/ioport.h> +#include <linux/regmap.h> #include "isp1760-hcd.h" #include "isp1760-udc.h" @@ -27,18 +30,19 @@ struct gpio_desc; * a sane default configuration. */ #define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */ -#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */ +#define ISP1760_FLAG_PERIPHERAL_EN 0x00000004 /* Port 1 supports Peripheral mode*/ #define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */ #define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */ #define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */ #define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */ #define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */ #define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */ +#define ISP1760_FLAG_ISP1763 0x00000200 /* Chip is ISP1763 */ +#define ISP1760_FLAG_BUS_WIDTH_8 0x00000400 /* 8-bit data bus width */ struct isp1760_device { struct device *dev; - void __iomem *regs; unsigned int devflags; struct gpio_desc *rst_gpio; @@ -52,14 +56,42 @@ void isp1760_unregister(struct device *dev); void isp1760_set_pullup(struct isp1760_device *isp, bool enable); -static inline u32 isp1760_read32(void __iomem *base, u32 reg) +static inline u32 isp1760_field_read(struct regmap_field **fields, u32 field) { - return readl(base + reg); + unsigned int val; + + regmap_field_read(fields[field], &val); + + return val; +} + +static inline void isp1760_field_write(struct regmap_field **fields, u32 field, + u32 val) +{ + regmap_field_write(fields[field], val); +} + +static inline void isp1760_field_set(struct regmap_field **fields, u32 field) +{ + isp1760_field_write(fields, field, 0xFFFFFFFF); } -static inline void isp1760_write32(void __iomem *base, u32 reg, u32 val) +static inline void isp1760_field_clear(struct regmap_field **fields, u32 field) { - writel(val, base + reg); + isp1760_field_write(fields, field, 0); } +static inline u32 isp1760_reg_read(struct regmap *regs, u32 reg) +{ + unsigned int val; + + regmap_read(regs, reg, &val); + + return val; +} + +static inline void isp1760_reg_write(struct regmap *regs, u32 reg, u32 val) +{ + regmap_write(regs, reg, val); +} #endif diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c index 33ae656c4b68..016a54ea76f4 100644 --- a/drivers/usb/isp1760/isp1760-hcd.c +++ b/drivers/usb/isp1760/isp1760-hcd.c @@ -11,6 +11,8 @@ * * (c) 2011 Arvid Brodin <arvid.brodin@enea.com> * + * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org> + * */ #include <linux/gpio/consumer.h> #include <linux/module.h> @@ -44,6 +46,9 @@ static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) return *(struct isp1760_hcd **)hcd->hcd_priv; } +#define dw_to_le32(x) (cpu_to_le32((__force u32)x)) +#define le32_to_dw(x) ((__force __dw)(le32_to_cpu(x))) + /* urb state*/ #define DELETE_URB (0x0008) #define NO_TRANSFER_ACTIVE (0xffffffff) @@ -60,50 +65,69 @@ struct ptd { __dw dw6; __dw dw7; }; + +struct ptd_le32 { + __le32 dw0; + __le32 dw1; + __le32 dw2; + __le32 dw3; + __le32 dw4; + __le32 dw5; + __le32 dw6; + __le32 dw7; +}; + #define PTD_OFFSET 0x0400 #define ISO_PTD_OFFSET 0x0400 #define INT_PTD_OFFSET 0x0800 #define ATL_PTD_OFFSET 0x0c00 #define PAYLOAD_OFFSET 0x1000 - -/* ATL */ -/* DW0 */ -#define DW0_VALID_BIT 1 -#define FROM_DW0_VALID(x) ((x) & 0x01) -#define TO_DW0_LENGTH(x) (((u32) x) << 3) -#define TO_DW0_MAXPACKET(x) (((u32) x) << 18) -#define TO_DW0_MULTI(x) (((u32) x) << 29) -#define TO_DW0_ENDPOINT(x) (((u32) x) << 31) +#define ISP_BANK_0 0x00 +#define ISP_BANK_1 0x01 +#define ISP_BANK_2 0x02 +#define ISP_BANK_3 0x03 + +#define TO_DW(x) ((__force __dw)x) +#define TO_U32(x) ((__force u32)x) + + /* ATL */ + /* DW0 */ +#define DW0_VALID_BIT TO_DW(1) +#define FROM_DW0_VALID(x) (TO_U32(x) & 0x01) +#define TO_DW0_LENGTH(x) TO_DW((((u32)x) << 3)) +#define TO_DW0_MAXPACKET(x) TO_DW((((u32)x) << 18)) +#define TO_DW0_MULTI(x) TO_DW((((u32)x) << 29)) +#define TO_DW0_ENDPOINT(x) TO_DW((((u32)x) << 31)) /* DW1 */ -#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3) -#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10) -#define DW1_TRANS_BULK ((u32) 2 << 12) -#define DW1_TRANS_INT ((u32) 3 << 12) -#define DW1_TRANS_SPLIT ((u32) 1 << 14) -#define DW1_SE_USB_LOSPEED ((u32) 2 << 16) -#define TO_DW1_PORT_NUM(x) (((u32) x) << 18) -#define TO_DW1_HUB_NUM(x) (((u32) x) << 25) +#define TO_DW1_DEVICE_ADDR(x) TO_DW((((u32)x) << 3)) +#define TO_DW1_PID_TOKEN(x) TO_DW((((u32)x) << 10)) +#define DW1_TRANS_BULK TO_DW(((u32)2 << 12)) +#define DW1_TRANS_INT TO_DW(((u32)3 << 12)) +#define DW1_TRANS_SPLIT TO_DW(((u32)1 << 14)) +#define DW1_SE_USB_LOSPEED TO_DW(((u32)2 << 16)) +#define TO_DW1_PORT_NUM(x) TO_DW((((u32)x) << 18)) +#define TO_DW1_HUB_NUM(x) TO_DW((((u32)x) << 25)) /* DW2 */ -#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8) -#define TO_DW2_RL(x) ((x) << 25) -#define FROM_DW2_RL(x) (((x) >> 25) & 0xf) +#define TO_DW2_DATA_START_ADDR(x) TO_DW((((u32)x) << 8)) +#define TO_DW2_RL(x) TO_DW(((x) << 25)) +#define FROM_DW2_RL(x) ((TO_U32(x) >> 25) & 0xf) /* DW3 */ -#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff) -#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff) -#define TO_DW3_NAKCOUNT(x) ((x) << 19) -#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf) -#define TO_DW3_CERR(x) ((x) << 23) -#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3) -#define TO_DW3_DATA_TOGGLE(x) ((x) << 25) -#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1) -#define TO_DW3_PING(x) ((x) << 26) -#define FROM_DW3_PING(x) (((x) >> 26) & 0x1) -#define DW3_ERROR_BIT (1 << 28) -#define DW3_BABBLE_BIT (1 << 29) -#define DW3_HALT_BIT (1 << 30) -#define DW3_ACTIVE_BIT (1 << 31) -#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01) +#define FROM_DW3_NRBYTESTRANSFERRED(x) TO_U32((x) & 0x3fff) +#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) TO_U32((x) & 0x07ff) +#define TO_DW3_NAKCOUNT(x) TO_DW(((x) << 19)) +#define FROM_DW3_NAKCOUNT(x) ((TO_U32(x) >> 19) & 0xf) +#define TO_DW3_CERR(x) TO_DW(((x) << 23)) +#define FROM_DW3_CERR(x) ((TO_U32(x) >> 23) & 0x3) +#define TO_DW3_DATA_TOGGLE(x) TO_DW(((x) << 25)) +#define FROM_DW3_DATA_TOGGLE(x) ((TO_U32(x) >> 25) & 0x1) +#define TO_DW3_PING(x) TO_DW(((x) << 26)) +#define FROM_DW3_PING(x) ((TO_U32(x) >> 26) & 0x1) +#define DW3_ERROR_BIT TO_DW((1 << 28)) +#define DW3_BABBLE_BIT TO_DW((1 << 29)) +#define DW3_HALT_BIT TO_DW((1 << 30)) +#define DW3_ACTIVE_BIT TO_DW((1 << 31)) +#define FROM_DW3_ACTIVE(x) ((TO_U32(x) >> 31) & 0x01) #define INT_UNDERRUN (1 << 2) #define INT_BABBLE (1 << 1) @@ -116,7 +140,7 @@ struct ptd { /* Errata 1 */ #define RL_COUNTER (0) #define NAK_COUNTER (0) -#define ERR_COUNTER (2) +#define ERR_COUNTER (3) struct isp1760_qtd { u8 packet_type; @@ -158,17 +182,124 @@ struct urb_listitem { struct urb *urb; }; +static const u32 isp1763_hc_portsc1_fields[] = { + [PORT_OWNER] = BIT(13), + [PORT_POWER] = BIT(12), + [PORT_LSTATUS] = BIT(10), + [PORT_RESET] = BIT(8), + [PORT_SUSPEND] = BIT(7), + [PORT_RESUME] = BIT(6), + [PORT_PE] = BIT(2), + [PORT_CSC] = BIT(1), + [PORT_CONNECT] = BIT(0), +}; + +/* + * Access functions for isp176x registers regmap fields + */ +static u32 isp1760_hcd_read(struct usb_hcd *hcd, u32 field) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + return isp1760_field_read(priv->fields, field); +} + /* - * Access functions for isp176x registers (addresses 0..0x03FF). + * We need, in isp1763, to write directly the values to the portsc1 + * register so it will make the other values to trigger. */ -static u32 reg_read32(void __iomem *base, u32 reg) +static void isp1760_hcd_portsc1_set_clear(struct isp1760_hcd *priv, u32 field, + u32 val) +{ + u32 bit = isp1763_hc_portsc1_fields[field]; + u32 port_status = readl(priv->base + ISP1763_HC_PORTSC1); + + if (val) + writel(port_status | bit, priv->base + ISP1763_HC_PORTSC1); + else + writel(port_status & ~bit, priv->base + ISP1763_HC_PORTSC1); +} + +static void isp1760_hcd_write(struct usb_hcd *hcd, u32 field, u32 val) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + if (unlikely(priv->is_isp1763 && + (field >= PORT_OWNER && field <= PORT_CONNECT))) + return isp1760_hcd_portsc1_set_clear(priv, field, val); + + isp1760_field_write(priv->fields, field, val); +} + +static void isp1760_hcd_set(struct usb_hcd *hcd, u32 field) +{ + isp1760_hcd_write(hcd, field, 0xFFFFFFFF); +} + +static void isp1760_hcd_clear(struct usb_hcd *hcd, u32 field) { - return isp1760_read32(base, reg); + isp1760_hcd_write(hcd, field, 0); } -static void reg_write32(void __iomem *base, u32 reg, u32 val) +static int isp1760_hcd_set_and_wait(struct usb_hcd *hcd, u32 field, + u32 timeout_us) { - isp1760_write32(base, reg, val); + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 val; + + isp1760_hcd_set(hcd, field); + + return regmap_field_read_poll_timeout(priv->fields[field], val, + val, 10, timeout_us); +} + +static int isp1760_hcd_set_and_wait_swap(struct usb_hcd *hcd, u32 field, + u32 timeout_us) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 val; + + isp1760_hcd_set(hcd, field); + + return regmap_field_read_poll_timeout(priv->fields[field], val, + !val, 10, timeout_us); +} + +static int isp1760_hcd_clear_and_wait(struct usb_hcd *hcd, u32 field, + u32 timeout_us) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 val; + + isp1760_hcd_clear(hcd, field); + + return regmap_field_read_poll_timeout(priv->fields[field], val, + !val, 10, timeout_us); +} + +static bool isp1760_hcd_is_set(struct usb_hcd *hcd, u32 field) +{ + return !!isp1760_hcd_read(hcd, field); +} + +static bool isp1760_hcd_ppc_is_set(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + if (priv->is_isp1763) + return true; + + return isp1760_hcd_is_set(hcd, HCS_PPC); +} + +static u32 isp1760_hcd_n_ports(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + if (priv->is_isp1763) + return 1; + + return isp1760_hcd_read(hcd, HCS_N_PORTS); } /* @@ -176,7 +307,7 @@ static void reg_write32(void __iomem *base, u32 reg, u32 val) * * bank_reads8() reads memory locations prefetched by an earlier write to * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi- - * bank optimizations, you should use the more generic mem_reads8() below. + * bank optimizations, you should use the more generic mem_read() below. * * For access to ptd memory, use the specialized ptd_read() and ptd_write() * below. @@ -196,7 +327,7 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr, if (src_offset < PAYLOAD_OFFSET) { while (bytes >= 4) { - *dst = le32_to_cpu(__raw_readl(src)); + *dst = readl_relaxed(src); bytes -= 4; src++; dst++; @@ -217,7 +348,7 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr, * allocated. */ if (src_offset < PAYLOAD_OFFSET) - val = le32_to_cpu(__raw_readl(src)); + val = readl_relaxed(src); else val = __raw_readl(src); @@ -231,16 +362,59 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr, } } -static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst, - u32 bytes) +static void isp1760_mem_read(struct usb_hcd *hcd, u32 src_offset, void *dst, + u32 bytes) { - reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0)); - ndelay(90); - bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes); + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0); + isp1760_hcd_write(hcd, MEM_START_ADDR, src_offset); + ndelay(100); + + bank_reads8(priv->base, src_offset, ISP_BANK_0, dst, bytes); } -static void mem_writes8(void __iomem *dst_base, u32 dst_offset, - __u32 const *src, u32 bytes) +/* + * ISP1763 does not have the banks direct host controller memory access, + * needs to use the HC_DATA register. Add data read/write according to this, + * and also adjust 16bit access. + */ +static void isp1763_mem_read(struct usb_hcd *hcd, u16 srcaddr, + u16 *dstptr, u32 bytes) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + /* Write the starting device address to the hcd memory register */ + isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, srcaddr); + ndelay(100); /* Delay between consecutive access */ + + /* As long there are at least 16-bit to read ... */ + while (bytes >= 2) { + *dstptr = __raw_readw(priv->base + ISP1763_HC_DATA); + bytes -= 2; + dstptr++; + } + + /* If there are no more bytes to read, return */ + if (bytes <= 0) + return; + + *((u8 *)dstptr) = (u8)(readw(priv->base + ISP1763_HC_DATA) & 0xFF); +} + +static void mem_read(struct usb_hcd *hcd, u32 src_offset, __u32 *dst, + u32 bytes) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + if (!priv->is_isp1763) + return isp1760_mem_read(hcd, src_offset, (u16 *)dst, bytes); + + isp1763_mem_read(hcd, (u16)src_offset, (u16 *)dst, bytes); +} + +static void isp1760_mem_write(void __iomem *dst_base, u32 dst_offset, + __u32 const *src, u32 bytes) { __u32 __iomem *dst; @@ -248,7 +422,7 @@ static void mem_writes8(void __iomem *dst_base, u32 dst_offset, if (dst_offset < PAYLOAD_OFFSET) { while (bytes >= 4) { - __raw_writel(cpu_to_le32(*src), dst); + writel_relaxed(*src, dst); bytes -= 4; src++; dst++; @@ -269,74 +443,168 @@ static void mem_writes8(void __iomem *dst_base, u32 dst_offset, */ if (dst_offset < PAYLOAD_OFFSET) - __raw_writel(cpu_to_le32(*src), dst); + writel_relaxed(*src, dst); else __raw_writel(*src, dst); } +static void isp1763_mem_write(struct usb_hcd *hcd, u16 dstaddr, u16 *src, + u32 bytes) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + /* Write the starting device address to the hcd memory register */ + isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, dstaddr); + ndelay(100); /* Delay between consecutive access */ + + while (bytes >= 2) { + /* Get and write the data; then adjust the data ptr and len */ + __raw_writew(*src, priv->base + ISP1763_HC_DATA); + bytes -= 2; + src++; + } + + /* If there are no more bytes to process, return */ + if (bytes <= 0) + return; + + /* + * The only way to get here is if there is a single byte left, + * get it and write it to the data reg; + */ + writew(*((u8 *)src), priv->base + ISP1763_HC_DATA); +} + +static void mem_write(struct usb_hcd *hcd, u32 dst_offset, __u32 *src, + u32 bytes) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + if (!priv->is_isp1763) + return isp1760_mem_write(priv->base, dst_offset, src, bytes); + + isp1763_mem_write(hcd, dst_offset, (u16 *)src, bytes); +} + /* * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET, * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32. */ -static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot, - struct ptd *ptd) +static void isp1760_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot, + struct ptd *ptd) { - reg_write32(base, HC_MEMORY_REG, - ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd)); + u16 src_offset = ptd_offset + slot * sizeof(*ptd); + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0); + isp1760_hcd_write(hcd, MEM_START_ADDR, src_offset); ndelay(90); - bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0), - (void *) ptd, sizeof(*ptd)); + + bank_reads8(priv->base, src_offset, ISP_BANK_0, (void *)ptd, + sizeof(*ptd)); +} + +static void isp1763_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot, + struct ptd *ptd) +{ + u16 src_offset = ptd_offset + slot * sizeof(*ptd); + struct ptd_le32 le32_ptd; + + isp1763_mem_read(hcd, src_offset, (u16 *)&le32_ptd, sizeof(le32_ptd)); + /* Normalize the data obtained */ + ptd->dw0 = le32_to_dw(le32_ptd.dw0); + ptd->dw1 = le32_to_dw(le32_ptd.dw1); + ptd->dw2 = le32_to_dw(le32_ptd.dw2); + ptd->dw3 = le32_to_dw(le32_ptd.dw3); + ptd->dw4 = le32_to_dw(le32_ptd.dw4); + ptd->dw5 = le32_to_dw(le32_ptd.dw5); + ptd->dw6 = le32_to_dw(le32_ptd.dw6); + ptd->dw7 = le32_to_dw(le32_ptd.dw7); +} + +static void ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot, + struct ptd *ptd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + if (!priv->is_isp1763) + return isp1760_ptd_read(hcd, ptd_offset, slot, ptd); + + isp1763_ptd_read(hcd, ptd_offset, slot, ptd); } -static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot, - struct ptd *ptd) +static void isp1763_ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot, + struct ptd *cpu_ptd) { - mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0), - &ptd->dw1, 7*sizeof(ptd->dw1)); - /* Make sure dw0 gets written last (after other dw's and after payload) - since it contains the enable bit */ + u16 dst_offset = ptd_offset + slot * sizeof(*cpu_ptd); + struct ptd_le32 ptd; + + ptd.dw0 = dw_to_le32(cpu_ptd->dw0); + ptd.dw1 = dw_to_le32(cpu_ptd->dw1); + ptd.dw2 = dw_to_le32(cpu_ptd->dw2); + ptd.dw3 = dw_to_le32(cpu_ptd->dw3); + ptd.dw4 = dw_to_le32(cpu_ptd->dw4); + ptd.dw5 = dw_to_le32(cpu_ptd->dw5); + ptd.dw6 = dw_to_le32(cpu_ptd->dw6); + ptd.dw7 = dw_to_le32(cpu_ptd->dw7); + + isp1763_mem_write(hcd, dst_offset, (u16 *)&ptd.dw0, + 8 * sizeof(ptd.dw0)); +} + +static void isp1760_ptd_write(void __iomem *base, u32 ptd_offset, u32 slot, + struct ptd *ptd) +{ + u32 dst_offset = ptd_offset + slot * sizeof(*ptd); + + /* + * Make sure dw0 gets written last (after other dw's and after payload) + * since it contains the enable bit + */ + isp1760_mem_write(base, dst_offset + sizeof(ptd->dw0), + (__force u32 *)&ptd->dw1, 7 * sizeof(ptd->dw1)); wmb(); - mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0, - sizeof(ptd->dw0)); + isp1760_mem_write(base, dst_offset, (__force u32 *)&ptd->dw0, + sizeof(ptd->dw0)); } +static void ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot, + struct ptd *ptd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + if (!priv->is_isp1763) + return isp1760_ptd_write(priv->base, ptd_offset, slot, ptd); + + isp1763_ptd_write(hcd, ptd_offset, slot, ptd); +} /* memory management of the 60kb on the chip from 0x1000 to 0xffff */ static void init_memory(struct isp1760_hcd *priv) { - int i, curr; + const struct isp1760_memory_layout *mem = priv->memory_layout; + int i, j, curr; u32 payload_addr; payload_addr = PAYLOAD_OFFSET; - for (i = 0; i < BLOCK_1_NUM; i++) { - priv->memory_pool[i].start = payload_addr; - priv->memory_pool[i].size = BLOCK_1_SIZE; - priv->memory_pool[i].free = 1; - payload_addr += priv->memory_pool[i].size; - } - curr = i; - for (i = 0; i < BLOCK_2_NUM; i++) { - priv->memory_pool[curr + i].start = payload_addr; - priv->memory_pool[curr + i].size = BLOCK_2_SIZE; - priv->memory_pool[curr + i].free = 1; - payload_addr += priv->memory_pool[curr + i].size; - } - - curr = i; - for (i = 0; i < BLOCK_3_NUM; i++) { - priv->memory_pool[curr + i].start = payload_addr; - priv->memory_pool[curr + i].size = BLOCK_3_SIZE; - priv->memory_pool[curr + i].free = 1; - payload_addr += priv->memory_pool[curr + i].size; + for (i = 0, curr = 0; i < ARRAY_SIZE(mem->blocks); i++) { + for (j = 0; j < mem->blocks[i]; j++, curr++) { + priv->memory_pool[curr + j].start = payload_addr; + priv->memory_pool[curr + j].size = mem->blocks_size[i]; + priv->memory_pool[curr + j].free = 1; + payload_addr += priv->memory_pool[curr + j].size; + } } - WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE); + WARN_ON(payload_addr - priv->memory_pool[0].start > + mem->payload_area_size); } static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) { struct isp1760_hcd *priv = hcd_to_priv(hcd); + const struct isp1760_memory_layout *mem = priv->memory_layout; int i; WARN_ON(qtd->payload_addr); @@ -344,7 +612,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) if (!qtd->length) return; - for (i = 0; i < BLOCKS; i++) { + for (i = 0; i < mem->payload_blocks; i++) { if (priv->memory_pool[i].size >= qtd->length && priv->memory_pool[i].free) { priv->memory_pool[i].free = 0; @@ -357,12 +625,13 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) { struct isp1760_hcd *priv = hcd_to_priv(hcd); + const struct isp1760_memory_layout *mem = priv->memory_layout; int i; if (!qtd->payload_addr) return; - for (i = 0; i < BLOCKS; i++) { + for (i = 0; i < mem->payload_blocks; i++) { if (priv->memory_pool[i].start == qtd->payload_addr) { WARN_ON(priv->memory_pool[i].free); priv->memory_pool[i].free = 1; @@ -377,34 +646,15 @@ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) qtd->payload_addr = 0; } -static int handshake(struct usb_hcd *hcd, u32 reg, - u32 mask, u32 done, int usec) -{ - u32 result; - int ret; - - ret = readl_poll_timeout_atomic(hcd->regs + reg, result, - ((result & mask) == done || - result == U32_MAX), 1, usec); - if (result == U32_MAX) - return -ENODEV; - - return ret; -} - /* reset a non-running (STS_HALT == 1) controller */ static int ehci_reset(struct usb_hcd *hcd) { struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 command = reg_read32(hcd->regs, HC_USBCMD); - - command |= CMD_RESET; - reg_write32(hcd->regs, HC_USBCMD, command); hcd->state = HC_STATE_HALT; priv->next_statechange = jiffies; - return handshake(hcd, HC_USBCMD, CMD_RESET, 0, 250 * 1000); + return isp1760_hcd_set_and_wait_swap(hcd, CMD_RESET, 250 * 1000); } static struct isp1760_qh *qh_alloc(gfp_t flags) @@ -432,8 +682,9 @@ static void qh_free(struct isp1760_qh *qh) /* one-time init, only for memory state */ static int priv_init(struct usb_hcd *hcd) { - struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 hcc_params; + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 isoc_cache; + u32 isoc_thres; int i; spin_lock_init(&priv->lock); @@ -447,13 +698,20 @@ static int priv_init(struct usb_hcd *hcd) */ priv->periodic_size = DEFAULT_I_TDPS; + if (priv->is_isp1763) { + priv->i_thresh = 2; + return 0; + } + /* controllers may cache some of the periodic schedule ... */ - hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS); + isoc_cache = isp1760_hcd_read(hcd, HCC_ISOC_CACHE); + isoc_thres = isp1760_hcd_read(hcd, HCC_ISOC_THRES); + /* full frame cache */ - if (HCC_ISOC_CACHE(hcc_params)) + if (isoc_cache) priv->i_thresh = 8; else /* N microframes cached */ - priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); + priv->i_thresh = 2 + isoc_thres; return 0; } @@ -461,15 +719,24 @@ static int priv_init(struct usb_hcd *hcd) static int isp1760_hc_setup(struct usb_hcd *hcd) { struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 atx_reset; int result; - u32 scratch, hwmode; + u32 scratch; + u32 pattern; + + if (priv->is_isp1763) + pattern = 0xcafe; + else + pattern = 0xdeadcafe; + + isp1760_hcd_write(hcd, HC_SCRATCH, pattern); - reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe); /* Change bus pattern */ - scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG); - scratch = reg_read32(hcd->regs, HC_SCRATCH_REG); - if (scratch != 0xdeadbabe) { - dev_err(hcd->self.controller, "Scratch test failed.\n"); + scratch = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH); + dev_err(hcd->self.controller, "Scratch test 0x%08x\n", scratch); + scratch = isp1760_hcd_read(hcd, HC_SCRATCH); + if (scratch != pattern) { + dev_err(hcd->self.controller, "Scratch test failed. 0x%08x\n", scratch); return -ENODEV; } @@ -481,10 +748,13 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) * the host controller through the EHCI USB Command register. The device * has been reset in core code anyway, so this shouldn't matter. */ - reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0); - reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); - reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); - reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); + isp1760_hcd_clear(hcd, ISO_BUF_FILL); + isp1760_hcd_clear(hcd, INT_BUF_FILL); + isp1760_hcd_clear(hcd, ATL_BUF_FILL); + + isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP); + isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP); + isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP); result = ehci_reset(hcd); if (result) @@ -493,14 +763,26 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) /* Step 11 passed */ /* ATL reset */ - hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET; - reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET); + if (priv->is_isp1763) + atx_reset = SW_RESET_RESET_ATX; + else + atx_reset = ALL_ATX_RESET; + + isp1760_hcd_set(hcd, atx_reset); mdelay(10); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); + isp1760_hcd_clear(hcd, atx_reset); + + if (priv->is_isp1763) { + isp1760_hcd_set(hcd, HW_OTG_DISABLE); + isp1760_hcd_set(hcd, HW_SW_SEL_HC_DC_CLEAR); + isp1760_hcd_set(hcd, HW_HC_2_DIS_CLEAR); + mdelay(10); - reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK); + isp1760_hcd_set(hcd, HW_INTF_LOCK); + } - priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS); + isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE); + isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE); return priv_init(hcd); } @@ -553,7 +835,7 @@ static void create_ptd_atl(struct isp1760_qh *qh, ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe)); /* DW1 */ - ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1; + ptd->dw1 = TO_DW((usb_pipeendpoint(qtd->urb->pipe) >> 1)); ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe)); ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type); @@ -575,7 +857,7 @@ static void create_ptd_atl(struct isp1760_qh *qh, /* SE bit for Split INT transfers */ if (usb_pipeint(qtd->urb->pipe) && (qtd->urb->dev->speed == USB_SPEED_LOW)) - ptd->dw1 |= 2 << 16; + ptd->dw1 |= DW1_SE_USB_LOSPEED; rl = 0; nak = 0; @@ -647,14 +929,14 @@ static void transform_add_int(struct isp1760_qh *qh, * that number come from? 0xff seems to work fine... */ /* ptd->dw5 = 0x1c; */ - ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */ + ptd->dw5 = TO_DW(0xff); /* Execute Complete Split on any uFrame */ } period = period >> 1;/* Ensure equal or shorter period than requested */ period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */ - ptd->dw2 |= period; - ptd->dw4 = usof; + ptd->dw2 |= TO_DW(period); + ptd->dw4 = TO_DW(usof); } static void create_ptd_int(struct isp1760_qh *qh, @@ -720,41 +1002,45 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot, struct ptd *ptd) { struct isp1760_hcd *priv = hcd_to_priv(hcd); + const struct isp1760_memory_layout *mem = priv->memory_layout; int skip_map; - WARN_ON((slot < 0) || (slot > 31)); + WARN_ON((slot < 0) || (slot > mem->slot_num - 1)); WARN_ON(qtd->length && !qtd->payload_addr); WARN_ON(slots[slot].qtd); WARN_ON(slots[slot].qh); WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC); + if (priv->is_isp1763) + ndelay(100); + /* Make sure done map has not triggered from some unlinked transfer */ if (ptd_offset == ATL_PTD_OFFSET) { - priv->atl_done_map |= reg_read32(hcd->regs, - HC_ATL_PTD_DONEMAP_REG); + skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP); + isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, + skip_map | (1 << slot)); + priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP); priv->atl_done_map &= ~(1 << slot); } else { - priv->int_done_map |= reg_read32(hcd->regs, - HC_INT_PTD_DONEMAP_REG); + skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP); + isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, + skip_map | (1 << slot)); + priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP); priv->int_done_map &= ~(1 << slot); } + skip_map &= ~(1 << slot); qh->slot = slot; qtd->status = QTD_XFER_STARTED; slots[slot].timestamp = jiffies; slots[slot].qtd = qtd; slots[slot].qh = qh; - ptd_write(hcd->regs, ptd_offset, slot, ptd); + ptd_write(hcd, ptd_offset, slot, ptd); - if (ptd_offset == ATL_PTD_OFFSET) { - skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); - skip_map &= ~(1 << qh->slot); - reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); - } else { - skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); - skip_map &= ~(1 << qh->slot); - reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); - } + if (ptd_offset == ATL_PTD_OFFSET) + isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map); + else + isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map); } static int is_short_bulk(struct isp1760_qtd *qtd) @@ -766,9 +1052,9 @@ static int is_short_bulk(struct isp1760_qtd *qtd) static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, struct list_head *urb_list) { - int last_qtd; struct isp1760_qtd *qtd, *qtd_next; struct urb_listitem *urb_listitem; + int last_qtd; list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) { if (qtd->status < QTD_XFER_COMPLETE) @@ -783,9 +1069,9 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, if (qtd->actual_length) { switch (qtd->packet_type) { case IN_PID: - mem_reads8(hcd->regs, qtd->payload_addr, - qtd->data_buffer, - qtd->actual_length); + mem_read(hcd, qtd->payload_addr, + qtd->data_buffer, + qtd->actual_length); fallthrough; case OUT_PID: qtd->urb->actual_length += @@ -829,6 +1115,8 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh) { struct isp1760_hcd *priv = hcd_to_priv(hcd); + const struct isp1760_memory_layout *mem = priv->memory_layout; + int slot_num = mem->slot_num; int ptd_offset; struct isp1760_slotinfo *slots; int curr_slot, free_slot; @@ -855,7 +1143,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh) } free_slot = -1; - for (curr_slot = 0; curr_slot < 32; curr_slot++) { + for (curr_slot = 0; curr_slot < slot_num; curr_slot++) { if ((free_slot == -1) && (slots[curr_slot].qtd == NULL)) free_slot = curr_slot; if (slots[curr_slot].qh == qh) @@ -870,11 +1158,10 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh) if ((qtd->length) && (!qtd->payload_addr)) break; - if ((qtd->length) && - ((qtd->packet_type == SETUP_PID) || - (qtd->packet_type == OUT_PID))) { - mem_writes8(hcd->regs, qtd->payload_addr, - qtd->data_buffer, qtd->length); + if (qtd->length && (qtd->packet_type == SETUP_PID || + qtd->packet_type == OUT_PID)) { + mem_write(hcd, qtd->payload_addr, + qtd->data_buffer, qtd->length); } qtd->status = QTD_PAYLOAD_ALLOC; @@ -887,7 +1174,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh) "available for transfer\n", __func__); */ /* Start xfer for this endpoint if not already done */ - if ((curr_slot > 31) && (free_slot > -1)) { + if ((curr_slot > slot_num - 1) && (free_slot > -1)) { if (usb_pipeint(qtd->urb->pipe)) create_ptd_int(qh, qtd, &ptd); else @@ -977,10 +1264,10 @@ static void schedule_ptds(struct usb_hcd *hcd) static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd, struct urb *urb) { - __dw dw4; + u32 dw4; int i; - dw4 = ptd->dw4; + dw4 = TO_U32(ptd->dw4); dw4 >>= 8; /* FIXME: ISP1761 datasheet does not say what to do with these. Do we @@ -1074,9 +1361,9 @@ static void handle_done_ptds(struct usb_hcd *hcd) int modified; int skip_map; - skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); + skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP); priv->int_done_map &= ~skip_map; - skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); + skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP); priv->atl_done_map &= ~skip_map; modified = priv->int_done_map || priv->atl_done_map; @@ -1094,7 +1381,7 @@ static void handle_done_ptds(struct usb_hcd *hcd) continue; } ptd_offset = INT_PTD_OFFSET; - ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd); + ptd_read(hcd, INT_PTD_OFFSET, slot, &ptd); state = check_int_transfer(hcd, &ptd, slots[slot].qtd->urb); } else { @@ -1109,7 +1396,7 @@ static void handle_done_ptds(struct usb_hcd *hcd) continue; } ptd_offset = ATL_PTD_OFFSET; - ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); + ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd); state = check_atl_transfer(hcd, &ptd, slots[slot].qtd->urb); } @@ -1134,7 +1421,7 @@ static void handle_done_ptds(struct usb_hcd *hcd) qtd->status = QTD_XFER_COMPLETE; if (list_is_last(&qtd->qtd_list, &qh->qtd_list) || - is_short_bulk(qtd)) + is_short_bulk(qtd)) qtd = NULL; else qtd = list_entry(qtd->qtd_list.next, @@ -1202,25 +1489,30 @@ static void handle_done_ptds(struct usb_hcd *hcd) static irqreturn_t isp1760_irq(struct usb_hcd *hcd) { struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 imask; irqreturn_t irqret = IRQ_NONE; + u32 int_reg; + u32 imask; spin_lock(&priv->lock); if (!(hcd->state & HC_STATE_RUNNING)) goto leave; - imask = reg_read32(hcd->regs, HC_INTERRUPT_REG); + imask = isp1760_hcd_read(hcd, HC_INTERRUPT); if (unlikely(!imask)) goto leave; - reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */ - priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG); - priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG); + int_reg = priv->is_isp1763 ? ISP1763_HC_INTERRUPT : + ISP176x_HC_INTERRUPT; + isp1760_reg_write(priv->regs, int_reg, imask); + + priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP); + priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP); handle_done_ptds(hcd); irqret = IRQ_HANDLED; + leave: spin_unlock(&priv->lock); @@ -1261,17 +1553,18 @@ static void errata2_function(struct timer_list *unused) { struct usb_hcd *hcd = errata2_timer_hcd; struct isp1760_hcd *priv = hcd_to_priv(hcd); + const struct isp1760_memory_layout *mem = priv->memory_layout; int slot; struct ptd ptd; unsigned long spinflags; spin_lock_irqsave(&priv->lock, spinflags); - for (slot = 0; slot < 32; slot++) + for (slot = 0; slot < mem->slot_num; slot++) if (priv->atl_slots[slot].qh && time_after(jiffies, priv->atl_slots[slot].timestamp + msecs_to_jiffies(SLOT_TIMEOUT))) { - ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); + ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd); if (!FROM_DW0_VALID(ptd.dw0) && !FROM_DW3_ACTIVE(ptd.dw3)) priv->atl_done_map |= 1 << slot; @@ -1286,35 +1579,121 @@ static void errata2_function(struct timer_list *unused) add_timer(&errata2_timer); } +static int isp1763_run(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int retval; + u32 chipid_h; + u32 chipid_l; + u32 chip_rev; + u32 ptd_atl_int; + u32 ptd_iso; + + hcd->uses_new_polling = 1; + hcd->state = HC_STATE_RUNNING; + + chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH); + chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW); + chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV); + dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n", + chipid_h, chipid_l, chip_rev); + + isp1760_hcd_clear(hcd, ISO_BUF_FILL); + isp1760_hcd_clear(hcd, INT_BUF_FILL); + isp1760_hcd_clear(hcd, ATL_BUF_FILL); + + isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP); + isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP); + isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP); + ndelay(100); + isp1760_hcd_clear(hcd, HC_ATL_PTD_DONEMAP); + isp1760_hcd_clear(hcd, HC_INT_PTD_DONEMAP); + isp1760_hcd_clear(hcd, HC_ISO_PTD_DONEMAP); + + isp1760_hcd_set(hcd, HW_OTG_DISABLE); + isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, BIT(7)); + isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, BIT(15)); + mdelay(10); + + isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE); + isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE); + + isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN); + + isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND); + isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND); + isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND); + + isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR); + isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR); + isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR); + + ptd_atl_int = 0x8000; + ptd_iso = 0x0001; + + isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int); + isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int); + isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso); + + isp1760_hcd_set(hcd, ATL_BUF_FILL); + isp1760_hcd_set(hcd, INT_BUF_FILL); + + isp1760_hcd_clear(hcd, CMD_LRESET); + isp1760_hcd_clear(hcd, CMD_RESET); + + retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000); + if (retval) + return retval; + + down_write(&ehci_cf_port_reset_rwsem); + retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000); + up_write(&ehci_cf_port_reset_rwsem); + retval = 0; + if (retval) + return retval; + + return 0; +} + static int isp1760_run(struct usb_hcd *hcd) { + struct isp1760_hcd *priv = hcd_to_priv(hcd); int retval; - u32 temp; - u32 command; - u32 chipid; + u32 chipid_h; + u32 chipid_l; + u32 chip_rev; + u32 ptd_atl_int; + u32 ptd_iso; + + /* + * ISP1763 have some differences in the setup and order to enable + * the ports, disable otg, setup buffers, and ATL, INT, ISO status. + * So, just handle it a separate sequence. + */ + if (priv->is_isp1763) + return isp1763_run(hcd); hcd->uses_new_polling = 1; hcd->state = HC_STATE_RUNNING; /* Set PTD interrupt AND & OR maps */ - reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0); - reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff); - reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0); - reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff); - reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0); - reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff); + isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND); + isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND); + isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND); + + isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR); + isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR); + isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR); + /* step 23 passed */ - temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN); + isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN); - command = reg_read32(hcd->regs, HC_USBCMD); - command &= ~(CMD_LRESET|CMD_RESET); - command |= CMD_RUN; - reg_write32(hcd->regs, HC_USBCMD, command); + isp1760_hcd_clear(hcd, CMD_LRESET); + isp1760_hcd_clear(hcd, CMD_RESET); - retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000); + retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000); if (retval) return retval; @@ -1324,9 +1703,8 @@ static int isp1760_run(struct usb_hcd *hcd) * the semaphore while doing so. */ down_write(&ehci_cf_port_reset_rwsem); - reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF); - retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000); + retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000); up_write(&ehci_cf_port_reset_rwsem); if (retval) return retval; @@ -1336,21 +1714,28 @@ static int isp1760_run(struct usb_hcd *hcd) errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD); add_timer(&errata2_timer); - chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG); - dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n", - chipid & 0xffff, chipid >> 16); + chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH); + chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW); + chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV); + dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n", + chipid_h, chipid_l, chip_rev); /* PTD Register Init Part 2, Step 28 */ /* Setup registers controlling PTD checking */ - reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000); - reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000); - reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001); - reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff); - reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff); - reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff); - reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, - ATL_BUF_FILL | INT_BUF_FILL); + ptd_atl_int = 0x80000000; + ptd_iso = 0x00000001; + + isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int); + isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int); + isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso); + + isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP); + isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP); + isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP); + + isp1760_hcd_set(hcd, ATL_BUF_FILL); + isp1760_hcd_set(hcd, INT_BUF_FILL); /* GRR this is run-once init(), being done every time the HC starts. * So long as they're part of class devices, we can't do it init() @@ -1363,8 +1748,6 @@ static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len) { qtd->data_buffer = databuffer; - if (len > MAX_PAYLOAD_SIZE) - len = MAX_PAYLOAD_SIZE; qtd->length = len; return qtd->length; @@ -1388,6 +1771,8 @@ static void qtd_list_free(struct list_head *qtd_list) static void packetize_urb(struct usb_hcd *hcd, struct urb *urb, struct list_head *head, gfp_t flags) { + struct isp1760_hcd *priv = hcd_to_priv(hcd); + const struct isp1760_memory_layout *mem = priv->memory_layout; struct isp1760_qtd *qtd; void *buf; int len, maxpacketsize; @@ -1440,6 +1825,10 @@ static void packetize_urb(struct usb_hcd *hcd, qtd = qtd_alloc(flags, urb, packet_type); if (!qtd) goto cleanup; + + if (len > mem->blocks_size[ISP176x_BLOCK_NUM - 1]) + len = mem->blocks_size[ISP176x_BLOCK_NUM - 1]; + this_qtd_len = qtd_fill(qtd, buf, len); list_add_tail(&qtd->qtd_list, head); @@ -1584,15 +1973,16 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb, /* We need to forcefully reclaim the slot since some transfers never return, e.g. interrupt transfers and NAKed bulk transfers. */ if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) { - skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); + skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP); skip_map |= (1 << qh->slot); - reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); + isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map); + ndelay(100); priv->atl_slots[qh->slot].qh = NULL; priv->atl_slots[qh->slot].qtd = NULL; } else { - skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); + skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP); skip_map |= (1 << qh->slot); - reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); + isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map); priv->int_slots[qh->slot].qh = NULL; priv->int_slots[qh->slot].qtd = NULL; } @@ -1705,8 +2095,7 @@ out: static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) { struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 temp, status = 0; - u32 mask; + u32 status = 0; int retval = 1; unsigned long flags; @@ -1716,17 +2105,13 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) /* init status to no-changes */ buf[0] = 0; - mask = PORT_CSC; spin_lock_irqsave(&priv->lock, flags); - temp = reg_read32(hcd->regs, HC_PORTSC1); - if (temp & PORT_OWNER) { - if (temp & PORT_CSC) { - temp &= ~PORT_CSC; - reg_write32(hcd->regs, HC_PORTSC1, temp); - goto done; - } + if (isp1760_hcd_is_set(hcd, PORT_OWNER) && + isp1760_hcd_is_set(hcd, PORT_CSC)) { + isp1760_hcd_clear(hcd, PORT_CSC); + goto done; } /* @@ -1735,11 +2120,9 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) * high-speed device is switched over to the companion * controller by the user. */ - - if ((temp & mask) != 0 - || ((temp & PORT_RESUME) != 0 - && time_after_eq(jiffies, - priv->reset_done))) { + if (isp1760_hcd_is_set(hcd, PORT_CSC) || + (isp1760_hcd_is_set(hcd, PORT_RESUME) && + time_after_eq(jiffies, priv->reset_done))) { buf [0] |= 1 << (0 + 1); status = STS_PCD; } @@ -1752,9 +2135,11 @@ done: static void isp1760_hub_descriptor(struct isp1760_hcd *priv, struct usb_hub_descriptor *desc) { - int ports = HCS_N_PORTS(priv->hcs_params); + int ports; u16 temp; + ports = isp1760_hcd_n_ports(priv->hcd); + desc->bDescriptorType = USB_DT_HUB; /* priv 1.0, 2.3.9 says 20ms max */ desc->bPwrOn2PwrGood = 10; @@ -1770,7 +2155,7 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv, /* per-port overcurrent reporting */ temp = HUB_CHAR_INDV_PORT_OCPM; - if (HCS_PPC(priv->hcs_params)) + if (isp1760_hcd_ppc_is_set(priv->hcd)) /* per-port power control */ temp |= HUB_CHAR_INDV_PORT_LPSM; else @@ -1781,38 +2166,37 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv, #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) -static int check_reset_complete(struct usb_hcd *hcd, int index, - int port_status) +static void check_reset_complete(struct usb_hcd *hcd, int index) { - if (!(port_status & PORT_CONNECT)) - return port_status; + if (!(isp1760_hcd_is_set(hcd, PORT_CONNECT))) + return; /* if reset finished and it's still not enabled -- handoff */ - if (!(port_status & PORT_PE)) { - + if (!isp1760_hcd_is_set(hcd, PORT_PE)) { dev_info(hcd->self.controller, - "port %d full speed --> companion\n", - index + 1); + "port %d full speed --> companion\n", index + 1); - port_status |= PORT_OWNER; - port_status &= ~PORT_RWC_BITS; - reg_write32(hcd->regs, HC_PORTSC1, port_status); + isp1760_hcd_set(hcd, PORT_OWNER); - } else + isp1760_hcd_clear(hcd, PORT_CSC); + } else { dev_info(hcd->self.controller, "port %d high speed\n", - index + 1); + index + 1); + } - return port_status; + return; } static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct isp1760_hcd *priv = hcd_to_priv(hcd); - int ports = HCS_N_PORTS(priv->hcs_params); - u32 temp, status; + u32 status; unsigned long flags; int retval = 0; + int ports; + + ports = isp1760_hcd_n_ports(hcd); /* * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. @@ -1837,7 +2221,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = reg_read32(hcd->regs, HC_PORTSC1); /* * Even if OWNER is set, so the port is owned by the @@ -1848,22 +2231,22 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, switch (wValue) { case USB_PORT_FEAT_ENABLE: - reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE); + isp1760_hcd_clear(hcd, PORT_PE); break; case USB_PORT_FEAT_C_ENABLE: /* XXX error? */ break; case USB_PORT_FEAT_SUSPEND: - if (temp & PORT_RESET) + if (isp1760_hcd_is_set(hcd, PORT_RESET)) goto error; - if (temp & PORT_SUSPEND) { - if ((temp & PORT_PE) == 0) + if (isp1760_hcd_is_set(hcd, PORT_SUSPEND)) { + if (!isp1760_hcd_is_set(hcd, PORT_PE)) goto error; /* resume signaling for 20 msec */ - temp &= ~(PORT_RWC_BITS); - reg_write32(hcd->regs, HC_PORTSC1, - temp | PORT_RESUME); + isp1760_hcd_clear(hcd, PORT_CSC); + isp1760_hcd_set(hcd, PORT_RESUME); + priv->reset_done = jiffies + msecs_to_jiffies(USB_RESUME_TIMEOUT); } @@ -1872,12 +2255,11 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, /* we auto-clear this feature */ break; case USB_PORT_FEAT_POWER: - if (HCS_PPC(priv->hcs_params)) - reg_write32(hcd->regs, HC_PORTSC1, - temp & ~PORT_POWER); + if (isp1760_hcd_ppc_is_set(hcd)) + isp1760_hcd_clear(hcd, PORT_POWER); break; case USB_PORT_FEAT_C_CONNECTION: - reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC); + isp1760_hcd_set(hcd, PORT_CSC); break; case USB_PORT_FEAT_C_OVER_CURRENT: /* XXX error ?*/ @@ -1888,7 +2270,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, default: goto error; } - reg_read32(hcd->regs, HC_USBCMD); + isp1760_hcd_read(hcd, CMD_RUN); break; case GetHubDescriptor: isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *) @@ -1903,15 +2285,13 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, goto error; wIndex--; status = 0; - temp = reg_read32(hcd->regs, HC_PORTSC1); /* wPortChange bits */ - if (temp & PORT_CSC) + if (isp1760_hcd_is_set(hcd, PORT_CSC)) status |= USB_PORT_STAT_C_CONNECTION << 16; - /* whoever resumes must GetPortStatus to complete it!! */ - if (temp & PORT_RESUME) { + if (isp1760_hcd_is_set(hcd, PORT_RESUME)) { dev_err(hcd->self.controller, "Port resume should be skipped.\n"); /* Remote Wakeup received? */ @@ -1930,44 +2310,39 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, priv->reset_done = 0; /* stop resume signaling */ - temp = reg_read32(hcd->regs, HC_PORTSC1); - reg_write32(hcd->regs, HC_PORTSC1, - temp & ~(PORT_RWC_BITS | PORT_RESUME)); - retval = handshake(hcd, HC_PORTSC1, - PORT_RESUME, 0, 2000 /* 2msec */); + isp1760_hcd_clear(hcd, PORT_CSC); + + retval = isp1760_hcd_clear_and_wait(hcd, + PORT_RESUME, 2000); if (retval != 0) { dev_err(hcd->self.controller, "port %d resume error %d\n", wIndex + 1, retval); goto error; } - temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); } } /* whoever resets must GetPortStatus to complete it!! */ - if ((temp & PORT_RESET) - && time_after_eq(jiffies, - priv->reset_done)) { + if (isp1760_hcd_is_set(hcd, PORT_RESET) && + time_after_eq(jiffies, priv->reset_done)) { status |= USB_PORT_STAT_C_RESET << 16; priv->reset_done = 0; /* force reset to complete */ - reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET); /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ - retval = handshake(hcd, HC_PORTSC1, - PORT_RESET, 0, 750); + retval = isp1760_hcd_clear_and_wait(hcd, PORT_RESET, + 750); if (retval != 0) { dev_err(hcd->self.controller, "port %d reset error %d\n", - wIndex + 1, retval); + wIndex + 1, retval); goto error; } /* see what we found out */ - temp = check_reset_complete(hcd, wIndex, - reg_read32(hcd->regs, HC_PORTSC1)); + check_reset_complete(hcd, wIndex); } /* * Even if OWNER is set, there's no harm letting hub_wq @@ -1975,21 +2350,22 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, * for PORT_POWER anyway). */ - if (temp & PORT_OWNER) + if (isp1760_hcd_is_set(hcd, PORT_OWNER)) dev_err(hcd->self.controller, "PORT_OWNER is set\n"); - if (temp & PORT_CONNECT) { + if (isp1760_hcd_is_set(hcd, PORT_CONNECT)) { status |= USB_PORT_STAT_CONNECTION; /* status may be from integrated TT */ status |= USB_PORT_STAT_HIGH_SPEED; } - if (temp & PORT_PE) + if (isp1760_hcd_is_set(hcd, PORT_PE)) status |= USB_PORT_STAT_ENABLE; - if (temp & (PORT_SUSPEND|PORT_RESUME)) + if (isp1760_hcd_is_set(hcd, PORT_SUSPEND) && + isp1760_hcd_is_set(hcd, PORT_RESUME)) status |= USB_PORT_STAT_SUSPEND; - if (temp & PORT_RESET) + if (isp1760_hcd_is_set(hcd, PORT_RESET)) status |= USB_PORT_STAT_RESET; - if (temp & PORT_POWER) + if (isp1760_hcd_is_set(hcd, PORT_POWER)) status |= USB_PORT_STAT_POWER; put_unaligned(cpu_to_le32(status), (__le32 *) buf); @@ -2009,41 +2385,40 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = reg_read32(hcd->regs, HC_PORTSC1); - if (temp & PORT_OWNER) + + if (isp1760_hcd_is_set(hcd, PORT_OWNER)) break; -/* temp &= ~PORT_RWC_BITS; */ switch (wValue) { case USB_PORT_FEAT_ENABLE: - reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE); + isp1760_hcd_set(hcd, PORT_PE); break; case USB_PORT_FEAT_SUSPEND: - if ((temp & PORT_PE) == 0 - || (temp & PORT_RESET) != 0) + if (!isp1760_hcd_is_set(hcd, PORT_PE) || + isp1760_hcd_is_set(hcd, PORT_RESET)) goto error; - reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND); + isp1760_hcd_set(hcd, PORT_SUSPEND); break; case USB_PORT_FEAT_POWER: - if (HCS_PPC(priv->hcs_params)) - reg_write32(hcd->regs, HC_PORTSC1, - temp | PORT_POWER); + if (isp1760_hcd_ppc_is_set(hcd)) + isp1760_hcd_set(hcd, PORT_POWER); break; case USB_PORT_FEAT_RESET: - if (temp & PORT_RESUME) + if (isp1760_hcd_is_set(hcd, PORT_RESUME)) goto error; /* line status bits may report this as low speed, * which can be fine if this root hub has a * transaction translator built in. */ - if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT - && PORT_USB11(temp)) { - temp |= PORT_OWNER; + if ((isp1760_hcd_is_set(hcd, PORT_CONNECT) && + !isp1760_hcd_is_set(hcd, PORT_PE)) && + (isp1760_hcd_read(hcd, PORT_LSTATUS) == 1)) { + isp1760_hcd_set(hcd, PORT_OWNER); } else { - temp |= PORT_RESET; - temp &= ~PORT_PE; + isp1760_hcd_set(hcd, PORT_RESET); + isp1760_hcd_clear(hcd, PORT_PE); /* * caller must wait, then call GetPortStatus @@ -2052,12 +2427,10 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, priv->reset_done = jiffies + msecs_to_jiffies(50); } - reg_write32(hcd->regs, HC_PORTSC1, temp); break; default: goto error; } - reg_read32(hcd->regs, HC_USBCMD); break; default: @@ -2074,14 +2447,13 @@ static int isp1760_get_frame(struct usb_hcd *hcd) struct isp1760_hcd *priv = hcd_to_priv(hcd); u32 fr; - fr = reg_read32(hcd->regs, HC_FRINDEX); + fr = isp1760_hcd_read(hcd, HC_FRINDEX); return (fr >> 3) % priv->periodic_size; } static void isp1760_stop(struct usb_hcd *hcd) { struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 temp; del_timer(&errata2_timer); @@ -2092,24 +2464,19 @@ static void isp1760_stop(struct usb_hcd *hcd) spin_lock_irq(&priv->lock); ehci_reset(hcd); /* Disable IRQ */ - temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN); + isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN); spin_unlock_irq(&priv->lock); - reg_write32(hcd->regs, HC_CONFIGFLAG, 0); + isp1760_hcd_clear(hcd, FLAG_CF); } static void isp1760_shutdown(struct usb_hcd *hcd) { - u32 command, temp; - isp1760_stop(hcd); - temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN); - command = reg_read32(hcd->regs, HC_USBCMD); - command &= ~CMD_RUN; - reg_write32(hcd->regs, HC_USBCMD, command); + isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN); + + isp1760_hcd_clear(hcd, CMD_RUN); } static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd, @@ -2182,10 +2549,11 @@ void isp1760_deinit_kmem_cache(void) kmem_cache_destroy(urb_listitem_cachep); } -int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs, - struct resource *mem, int irq, unsigned long irqflags, +int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem, + int irq, unsigned long irqflags, struct device *dev) { + const struct isp1760_memory_layout *mem_layout = priv->memory_layout; struct usb_hcd *hcd; int ret; @@ -2197,10 +2565,23 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs, priv->hcd = hcd; + priv->atl_slots = kcalloc(mem_layout->slot_num, + sizeof(struct isp1760_slotinfo), GFP_KERNEL); + if (!priv->atl_slots) { + ret = -ENOMEM; + goto put_hcd; + } + + priv->int_slots = kcalloc(mem_layout->slot_num, + sizeof(struct isp1760_slotinfo), GFP_KERNEL); + if (!priv->int_slots) { + ret = -ENOMEM; + goto free_atl_slots; + } + init_memory(priv); hcd->irq = irq; - hcd->regs = regs; hcd->rsrc_start = mem->start; hcd->rsrc_len = resource_size(mem); @@ -2209,13 +2590,17 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs, ret = usb_add_hcd(hcd, irq, irqflags); if (ret) - goto error; + goto free_int_slots; device_wakeup_enable(hcd->self.controller); return 0; -error: +free_int_slots: + kfree(priv->int_slots); +free_atl_slots: + kfree(priv->atl_slots); +put_hcd: usb_put_hcd(hcd); return ret; } @@ -2227,4 +2612,6 @@ void isp1760_hcd_unregister(struct isp1760_hcd *priv) usb_remove_hcd(priv->hcd); usb_put_hcd(priv->hcd); + kfree(priv->atl_slots); + kfree(priv->int_slots); } diff --git a/drivers/usb/isp1760/isp1760-hcd.h b/drivers/usb/isp1760/isp1760-hcd.h index f1bb2deb1ccf..ee3063a34de3 100644 --- a/drivers/usb/isp1760/isp1760-hcd.h +++ b/drivers/usb/isp1760/isp1760-hcd.h @@ -3,30 +3,15 @@ #define _ISP1760_HCD_H_ #include <linux/spinlock.h> +#include <linux/regmap.h> + +#include "isp1760-regs.h" struct isp1760_qh; struct isp1760_qtd; struct resource; struct usb_hcd; -/* - * 60kb divided in: - * - 32 blocks @ 256 bytes - * - 20 blocks @ 1024 bytes - * - 4 blocks @ 8192 bytes - */ - -#define BLOCK_1_NUM 32 -#define BLOCK_2_NUM 20 -#define BLOCK_3_NUM 4 - -#define BLOCK_1_SIZE 256 -#define BLOCK_2_SIZE 1024 -#define BLOCK_3_SIZE 8192 -#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM) -#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE -#define PAYLOAD_AREA_SIZE 0xf000 - struct isp1760_slotinfo { struct isp1760_qh *qh; struct isp1760_qtd *qtd; @@ -34,6 +19,18 @@ struct isp1760_slotinfo { }; /* chip memory management */ +#define ISP176x_BLOCK_MAX (32 + 20 + 4) +#define ISP176x_BLOCK_NUM 3 + +struct isp1760_memory_layout { + unsigned int blocks[ISP176x_BLOCK_NUM]; + unsigned int blocks_size[ISP176x_BLOCK_NUM]; + + unsigned int slot_num; + unsigned int payload_blocks; + unsigned int payload_area_size; +}; + struct isp1760_memory_chunk { unsigned int start; unsigned int size; @@ -48,16 +45,22 @@ enum isp1760_queue_head_types { }; struct isp1760_hcd { -#ifdef CONFIG_USB_ISP1760_HCD struct usb_hcd *hcd; - u32 hcs_params; + void __iomem *base; + + struct regmap *regs; + struct regmap_field *fields[HC_FIELD_MAX]; + + bool is_isp1763; + const struct isp1760_memory_layout *memory_layout; + spinlock_t lock; - struct isp1760_slotinfo atl_slots[32]; + struct isp1760_slotinfo *atl_slots; int atl_done_map; - struct isp1760_slotinfo int_slots[32]; + struct isp1760_slotinfo *int_slots; int int_done_map; - struct isp1760_memory_chunk memory_pool[BLOCKS]; + struct isp1760_memory_chunk memory_pool[ISP176x_BLOCK_MAX]; struct list_head qh_list[QH_END]; /* periodic schedule support */ @@ -66,20 +69,18 @@ struct isp1760_hcd { unsigned i_thresh; unsigned long reset_done; unsigned long next_statechange; -#endif }; #ifdef CONFIG_USB_ISP1760_HCD -int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs, - struct resource *mem, int irq, unsigned long irqflags, - struct device *dev); +int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem, + int irq, unsigned long irqflags, struct device *dev); void isp1760_hcd_unregister(struct isp1760_hcd *priv); int isp1760_init_kmem_once(void); void isp1760_deinit_kmem_cache(void); #else static inline int isp1760_hcd_register(struct isp1760_hcd *priv, - void __iomem *regs, struct resource *mem, + struct resource *mem, int irq, unsigned long irqflags, struct device *dev) { diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c index ccd30f835888..7cc349c0b2ad 100644 --- a/drivers/usb/isp1760/isp1760-if.c +++ b/drivers/usb/isp1760/isp1760-if.c @@ -7,6 +7,7 @@ * - PDEV (generic platform device centralized driver model) * * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> + * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org> * */ @@ -16,8 +17,8 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/usb/isp1760.h> #include <linux/usb/hcd.h> +#include <linux/usb/otg.h> #include "isp1760-core.h" #include "isp1760-regs.h" @@ -75,9 +76,9 @@ static int isp1761_pci_init(struct pci_dev *dev) /*by default host is in 16bit mode, so * io operations at this stage must be 16 bit * */ - writel(0xface, iobase + HC_SCRATCH_REG); + writel(0xface, iobase + ISP176x_HC_SCRATCH); udelay(100); - reg_data = readl(iobase + HC_SCRATCH_REG) & 0x0000ffff; + reg_data = readl(iobase + ISP176x_HC_SCRATCH) & 0x0000ffff; retry_count--; } @@ -209,13 +210,21 @@ static int isp1760_plat_probe(struct platform_device *pdev) if (of_device_is_compatible(dp, "nxp,usb-isp1761")) devflags |= ISP1760_FLAG_ISP1761; - /* Some systems wire up only 16 of the 32 data lines */ + if (of_device_is_compatible(dp, "nxp,usb-isp1763")) + devflags |= ISP1760_FLAG_ISP1763; + + /* + * Some systems wire up only 8 of 16 data lines or + * 16 of the 32 data lines + */ of_property_read_u32(dp, "bus-width", &bus_width); if (bus_width == 16) devflags |= ISP1760_FLAG_BUS_WIDTH_16; + else if (bus_width == 8) + devflags |= ISP1760_FLAG_BUS_WIDTH_8; - if (of_property_read_bool(dp, "port1-otg")) - devflags |= ISP1760_FLAG_OTG_EN; + if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL) + devflags |= ISP1760_FLAG_PERIPHERAL_EN; if (of_property_read_bool(dp, "analog-oc")) devflags |= ISP1760_FLAG_ANALOG_OC; @@ -225,22 +234,9 @@ static int isp1760_plat_probe(struct platform_device *pdev) if (of_property_read_bool(dp, "dreq-polarity")) devflags |= ISP1760_FLAG_DREQ_POL_HIGH; - } else if (dev_get_platdata(&pdev->dev)) { - struct isp1760_platform_data *pdata = - dev_get_platdata(&pdev->dev); - - if (pdata->is_isp1761) - devflags |= ISP1760_FLAG_ISP1761; - if (pdata->bus_width_16) - devflags |= ISP1760_FLAG_BUS_WIDTH_16; - if (pdata->port1_otg) - devflags |= ISP1760_FLAG_OTG_EN; - if (pdata->analog_oc) - devflags |= ISP1760_FLAG_ANALOG_OC; - if (pdata->dack_polarity_high) - devflags |= ISP1760_FLAG_DACK_POL_HIGH; - if (pdata->dreq_polarity_high) - devflags |= ISP1760_FLAG_DREQ_POL_HIGH; + } else { + pr_err("isp1760: no platform data\n"); + return -ENXIO; } ret = isp1760_register(mem_res, irq_res->start, irqflags, &pdev->dev, @@ -263,6 +259,7 @@ static int isp1760_plat_remove(struct platform_device *pdev) static const struct of_device_id isp1760_of_match[] = { { .compatible = "nxp,usb-isp1760", }, { .compatible = "nxp,usb-isp1761", }, + { .compatible = "nxp,usb-isp1763", }, { }, }; MODULE_DEVICE_TABLE(of, isp1760_of_match); diff --git a/drivers/usb/isp1760/isp1760-regs.h b/drivers/usb/isp1760/isp1760-regs.h index fedc4f5cded0..94ea60c20b2a 100644 --- a/drivers/usb/isp1760/isp1760-regs.h +++ b/drivers/usb/isp1760/isp1760-regs.h @@ -2,226 +2,291 @@ /* * Driver for the NXP ISP1760 chip * + * Copyright 2021 Linaro, Rui Miguel Silva * Copyright 2014 Laurent Pinchart * Copyright 2007 Sebastian Siewior * * Contacts: * Sebastian Siewior <bigeasy@linutronix.de> * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * Rui Miguel Silva <rui.silva@linaro.org> */ -#ifndef _ISP1760_REGS_H_ -#define _ISP1760_REGS_H_ +#ifndef _ISP176x_REGS_H_ +#define _ISP176x_REGS_H_ /* ----------------------------------------------------------------------------- * Host Controller */ +/* ISP1760/31 */ /* EHCI capability registers */ -#define HC_CAPLENGTH 0x000 -#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */ -#define HC_VERSION(p) (((p) >> 16) & 0xffff) /* bits 31:16 */ +#define ISP176x_HC_VERSION 0x002 +#define ISP176x_HC_HCSPARAMS 0x004 +#define ISP176x_HC_HCCPARAMS 0x008 -#define HC_HCSPARAMS 0x004 -#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* true: has port indicators */ -#define HCS_PPC(p) ((p) & (1 << 4)) /* true: port power control */ -#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) /* bits 3:0, ports on HC */ +/* EHCI operational registers */ +#define ISP176x_HC_USBCMD 0x020 +#define ISP176x_HC_USBSTS 0x024 +#define ISP176x_HC_FRINDEX 0x02c + +#define ISP176x_HC_CONFIGFLAG 0x060 +#define ISP176x_HC_PORTSC1 0x064 + +#define ISP176x_HC_ISO_PTD_DONEMAP 0x130 +#define ISP176x_HC_ISO_PTD_SKIPMAP 0x134 +#define ISP176x_HC_ISO_PTD_LASTPTD 0x138 +#define ISP176x_HC_INT_PTD_DONEMAP 0x140 +#define ISP176x_HC_INT_PTD_SKIPMAP 0x144 +#define ISP176x_HC_INT_PTD_LASTPTD 0x148 +#define ISP176x_HC_ATL_PTD_DONEMAP 0x150 +#define ISP176x_HC_ATL_PTD_SKIPMAP 0x154 +#define ISP176x_HC_ATL_PTD_LASTPTD 0x158 -#define HC_HCCPARAMS 0x008 -#define HCC_ISOC_CACHE(p) ((p) & (1 << 7)) /* true: can cache isoc frame */ -#define HCC_ISOC_THRES(p) (((p) >> 4) & 0x7) /* bits 6:4, uframes cached */ +/* Configuration Register */ +#define ISP176x_HC_HW_MODE_CTRL 0x300 +#define ISP176x_HC_CHIP_ID 0x304 +#define ISP176x_HC_SCRATCH 0x308 +#define ISP176x_HC_RESET 0x30c +#define ISP176x_HC_BUFFER_STATUS 0x334 +#define ISP176x_HC_MEMORY 0x33c +/* Interrupt Register */ +#define ISP176x_HC_INTERRUPT 0x310 +#define ISP176x_HC_INTERRUPT_ENABLE 0x314 +#define ISP176x_HC_ISO_IRQ_MASK_OR 0x318 +#define ISP176x_HC_INT_IRQ_MASK_OR 0x31c +#define ISP176x_HC_ATL_IRQ_MASK_OR 0x320 +#define ISP176x_HC_ISO_IRQ_MASK_AND 0x324 +#define ISP176x_HC_INT_IRQ_MASK_AND 0x328 +#define ISP176x_HC_ATL_IRQ_MASK_AND 0x32c + +#define ISP176x_HC_OTG_CTRL_SET 0x374 +#define ISP176x_HC_OTG_CTRL_CLEAR 0x376 + +enum isp176x_host_controller_fields { + /* HC_PORTSC1 */ + PORT_OWNER, PORT_POWER, PORT_LSTATUS, PORT_RESET, PORT_SUSPEND, + PORT_RESUME, PORT_PE, PORT_CSC, PORT_CONNECT, + /* HC_HCSPARAMS */ + HCS_PPC, HCS_N_PORTS, + /* HC_HCCPARAMS */ + HCC_ISOC_CACHE, HCC_ISOC_THRES, + /* HC_USBCMD */ + CMD_LRESET, CMD_RESET, CMD_RUN, + /* HC_USBSTS */ + STS_PCD, + /* HC_FRINDEX */ + HC_FRINDEX, + /* HC_CONFIGFLAG */ + FLAG_CF, + /* ISO/INT/ATL PTD */ + HC_ISO_PTD_DONEMAP, HC_ISO_PTD_SKIPMAP, HC_ISO_PTD_LASTPTD, + HC_INT_PTD_DONEMAP, HC_INT_PTD_SKIPMAP, HC_INT_PTD_LASTPTD, + HC_ATL_PTD_DONEMAP, HC_ATL_PTD_SKIPMAP, HC_ATL_PTD_LASTPTD, + /* HC_HW_MODE_CTRL */ + ALL_ATX_RESET, HW_ANA_DIGI_OC, HW_DEV_DMA, HW_COMN_IRQ, HW_COMN_DMA, + HW_DATA_BUS_WIDTH, HW_DACK_POL_HIGH, HW_DREQ_POL_HIGH, HW_INTR_HIGH_ACT, + HW_INTF_LOCK, HW_INTR_EDGE_TRIG, HW_GLOBAL_INTR_EN, + /* HC_CHIP_ID */ + HC_CHIP_ID_HIGH, HC_CHIP_ID_LOW, HC_CHIP_REV, + /* HC_SCRATCH */ + HC_SCRATCH, + /* HC_RESET */ + SW_RESET_RESET_ATX, SW_RESET_RESET_HC, SW_RESET_RESET_ALL, + /* HC_BUFFER_STATUS */ + ISO_BUF_FILL, INT_BUF_FILL, ATL_BUF_FILL, + /* HC_MEMORY */ + MEM_BANK_SEL, MEM_START_ADDR, + /* HC_DATA */ + HC_DATA, + /* HC_INTERRUPT */ + HC_INTERRUPT, + /* HC_INTERRUPT_ENABLE */ + HC_INT_IRQ_ENABLE, HC_ATL_IRQ_ENABLE, + /* INTERRUPT MASKS */ + HC_ISO_IRQ_MASK_OR, HC_INT_IRQ_MASK_OR, HC_ATL_IRQ_MASK_OR, + HC_ISO_IRQ_MASK_AND, HC_INT_IRQ_MASK_AND, HC_ATL_IRQ_MASK_AND, + /* HW_OTG_CTRL_SET */ + HW_OTG_DISABLE, HW_SW_SEL_HC_DC, HW_VBUS_DRV, HW_SEL_CP_EXT, + HW_DM_PULLDOWN, HW_DP_PULLDOWN, HW_DP_PULLUP, HW_HC_2_DIS, + /* HW_OTG_CTRL_CLR */ + HW_OTG_DISABLE_CLEAR, HW_SW_SEL_HC_DC_CLEAR, HW_VBUS_DRV_CLEAR, + HW_SEL_CP_EXT_CLEAR, HW_DM_PULLDOWN_CLEAR, HW_DP_PULLDOWN_CLEAR, + HW_DP_PULLUP_CLEAR, HW_HC_2_DIS_CLEAR, + /* Last element */ + HC_FIELD_MAX, +}; + +/* ISP1763 */ /* EHCI operational registers */ -#define HC_USBCMD 0x020 -#define CMD_LRESET (1 << 7) /* partial reset (no ports, etc) */ -#define CMD_RESET (1 << 1) /* reset HC not bus */ -#define CMD_RUN (1 << 0) /* start/stop HC */ - -#define HC_USBSTS 0x024 -#define STS_PCD (1 << 2) /* port change detect */ - -#define HC_FRINDEX 0x02c - -#define HC_CONFIGFLAG 0x060 -#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */ - -#define HC_PORTSC1 0x064 -#define PORT_OWNER (1 << 13) /* true: companion hc owns this port */ -#define PORT_POWER (1 << 12) /* true: has power (see PPC) */ -#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */ -#define PORT_RESET (1 << 8) /* reset port */ -#define PORT_SUSPEND (1 << 7) /* suspend port */ -#define PORT_RESUME (1 << 6) /* resume it */ -#define PORT_PE (1 << 2) /* port enable */ -#define PORT_CSC (1 << 1) /* connect status change */ -#define PORT_CONNECT (1 << 0) /* device connected */ -#define PORT_RWC_BITS (PORT_CSC) - -#define HC_ISO_PTD_DONEMAP_REG 0x130 -#define HC_ISO_PTD_SKIPMAP_REG 0x134 -#define HC_ISO_PTD_LASTPTD_REG 0x138 -#define HC_INT_PTD_DONEMAP_REG 0x140 -#define HC_INT_PTD_SKIPMAP_REG 0x144 -#define HC_INT_PTD_LASTPTD_REG 0x148 -#define HC_ATL_PTD_DONEMAP_REG 0x150 -#define HC_ATL_PTD_SKIPMAP_REG 0x154 -#define HC_ATL_PTD_LASTPTD_REG 0x158 +#define ISP1763_HC_USBCMD 0x8c +#define ISP1763_HC_USBSTS 0x90 +#define ISP1763_HC_FRINDEX 0x98 + +#define ISP1763_HC_CONFIGFLAG 0x9c +#define ISP1763_HC_PORTSC1 0xa0 + +#define ISP1763_HC_ISO_PTD_DONEMAP 0xa4 +#define ISP1763_HC_ISO_PTD_SKIPMAP 0xa6 +#define ISP1763_HC_ISO_PTD_LASTPTD 0xa8 +#define ISP1763_HC_INT_PTD_DONEMAP 0xaa +#define ISP1763_HC_INT_PTD_SKIPMAP 0xac +#define ISP1763_HC_INT_PTD_LASTPTD 0xae +#define ISP1763_HC_ATL_PTD_DONEMAP 0xb0 +#define ISP1763_HC_ATL_PTD_SKIPMAP 0xb2 +#define ISP1763_HC_ATL_PTD_LASTPTD 0xb4 /* Configuration Register */ -#define HC_HW_MODE_CTRL 0x300 -#define ALL_ATX_RESET (1 << 31) -#define HW_ANA_DIGI_OC (1 << 15) -#define HW_DEV_DMA (1 << 11) -#define HW_COMN_IRQ (1 << 10) -#define HW_COMN_DMA (1 << 9) -#define HW_DATA_BUS_32BIT (1 << 8) -#define HW_DACK_POL_HIGH (1 << 6) -#define HW_DREQ_POL_HIGH (1 << 5) -#define HW_INTR_HIGH_ACT (1 << 2) -#define HW_INTR_EDGE_TRIG (1 << 1) -#define HW_GLOBAL_INTR_EN (1 << 0) - -#define HC_CHIP_ID_REG 0x304 -#define HC_SCRATCH_REG 0x308 - -#define HC_RESET_REG 0x30c -#define SW_RESET_RESET_HC (1 << 1) -#define SW_RESET_RESET_ALL (1 << 0) - -#define HC_BUFFER_STATUS_REG 0x334 -#define ISO_BUF_FILL (1 << 2) -#define INT_BUF_FILL (1 << 1) -#define ATL_BUF_FILL (1 << 0) - -#define HC_MEMORY_REG 0x33c -#define ISP_BANK(x) ((x) << 16) - -#define HC_PORT1_CTRL 0x374 -#define PORT1_POWER (3 << 3) -#define PORT1_INIT1 (1 << 7) -#define PORT1_INIT2 (1 << 23) -#define HW_OTG_CTRL_SET 0x374 -#define HW_OTG_CTRL_CLR 0x376 -#define HW_OTG_DISABLE (1 << 10) -#define HW_OTG_SE0_EN (1 << 9) -#define HW_BDIS_ACON_EN (1 << 8) -#define HW_SW_SEL_HC_DC (1 << 7) -#define HW_VBUS_CHRG (1 << 6) -#define HW_VBUS_DISCHRG (1 << 5) -#define HW_VBUS_DRV (1 << 4) -#define HW_SEL_CP_EXT (1 << 3) -#define HW_DM_PULLDOWN (1 << 2) -#define HW_DP_PULLDOWN (1 << 1) -#define HW_DP_PULLUP (1 << 0) +#define ISP1763_HC_HW_MODE_CTRL 0xb6 +#define ISP1763_HC_CHIP_REV 0x70 +#define ISP1763_HC_CHIP_ID 0x72 +#define ISP1763_HC_SCRATCH 0x78 +#define ISP1763_HC_RESET 0xb8 +#define ISP1763_HC_BUFFER_STATUS 0xba +#define ISP1763_HC_MEMORY 0xc4 +#define ISP1763_HC_DATA 0xc6 /* Interrupt Register */ -#define HC_INTERRUPT_REG 0x310 - -#define HC_INTERRUPT_ENABLE 0x314 -#define HC_ISO_INT (1 << 9) -#define HC_ATL_INT (1 << 8) -#define HC_INTL_INT (1 << 7) -#define HC_EOT_INT (1 << 3) -#define HC_SOT_INT (1 << 1) -#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT) - -#define HC_ISO_IRQ_MASK_OR_REG 0x318 -#define HC_INT_IRQ_MASK_OR_REG 0x31c -#define HC_ATL_IRQ_MASK_OR_REG 0x320 -#define HC_ISO_IRQ_MASK_AND_REG 0x324 -#define HC_INT_IRQ_MASK_AND_REG 0x328 -#define HC_ATL_IRQ_MASK_AND_REG 0x32c +#define ISP1763_HC_INTERRUPT 0xd4 +#define ISP1763_HC_INTERRUPT_ENABLE 0xd6 +#define ISP1763_HC_ISO_IRQ_MASK_OR 0xd8 +#define ISP1763_HC_INT_IRQ_MASK_OR 0xda +#define ISP1763_HC_ATL_IRQ_MASK_OR 0xdc +#define ISP1763_HC_ISO_IRQ_MASK_AND 0xde +#define ISP1763_HC_INT_IRQ_MASK_AND 0xe0 +#define ISP1763_HC_ATL_IRQ_MASK_AND 0xe2 + +#define ISP1763_HC_OTG_CTRL_SET 0xe4 +#define ISP1763_HC_OTG_CTRL_CLEAR 0xe6 /* ----------------------------------------------------------------------------- * Peripheral Controller */ -/* Initialization Registers */ -#define DC_ADDRESS 0x0200 -#define DC_DEVEN (1 << 7) - -#define DC_MODE 0x020c -#define DC_DMACLKON (1 << 9) -#define DC_VBUSSTAT (1 << 8) -#define DC_CLKAON (1 << 7) -#define DC_SNDRSU (1 << 6) -#define DC_GOSUSP (1 << 5) -#define DC_SFRESET (1 << 4) -#define DC_GLINTENA (1 << 3) -#define DC_WKUPCS (1 << 2) - -#define DC_INTCONF 0x0210 -#define DC_CDBGMOD_ACK_NAK (0 << 6) -#define DC_CDBGMOD_ACK (1 << 6) -#define DC_CDBGMOD_ACK_1NAK (2 << 6) -#define DC_DDBGMODIN_ACK_NAK (0 << 4) -#define DC_DDBGMODIN_ACK (1 << 4) -#define DC_DDBGMODIN_ACK_1NAK (2 << 4) -#define DC_DDBGMODOUT_ACK_NYET_NAK (0 << 2) -#define DC_DDBGMODOUT_ACK_NYET (1 << 2) -#define DC_DDBGMODOUT_ACK_NYET_1NAK (2 << 2) -#define DC_INTLVL (1 << 1) -#define DC_INTPOL (1 << 0) - -#define DC_DEBUG 0x0212 -#define DC_INTENABLE 0x0214 #define DC_IEPTX(n) (1 << (11 + 2 * (n))) #define DC_IEPRX(n) (1 << (10 + 2 * (n))) #define DC_IEPRXTX(n) (3 << (10 + 2 * (n))) -#define DC_IEP0SETUP (1 << 8) -#define DC_IEVBUS (1 << 7) -#define DC_IEDMA (1 << 6) -#define DC_IEHS_STA (1 << 5) -#define DC_IERESM (1 << 4) -#define DC_IESUSP (1 << 3) -#define DC_IEPSOF (1 << 2) -#define DC_IESOF (1 << 1) -#define DC_IEBRST (1 << 0) + +#define ISP176x_DC_CDBGMOD_ACK BIT(6) +#define ISP176x_DC_DDBGMODIN_ACK BIT(4) +#define ISP176x_DC_DDBGMODOUT_ACK BIT(2) + +#define ISP176x_DC_IEP0SETUP BIT(8) +#define ISP176x_DC_IEVBUS BIT(7) +#define ISP176x_DC_IEHS_STA BIT(5) +#define ISP176x_DC_IERESM BIT(4) +#define ISP176x_DC_IESUSP BIT(3) +#define ISP176x_DC_IEBRST BIT(0) + +#define ISP176x_DC_ENDPTYP_ISOC 0x01 +#define ISP176x_DC_ENDPTYP_BULK 0x02 +#define ISP176x_DC_ENDPTYP_INTERRUPT 0x03 + +/* Initialization Registers */ +#define ISP176x_DC_ADDRESS 0x0200 +#define ISP176x_DC_MODE 0x020c +#define ISP176x_DC_INTCONF 0x0210 +#define ISP176x_DC_DEBUG 0x0212 +#define ISP176x_DC_INTENABLE 0x0214 + +/* Data Flow Registers */ +#define ISP176x_DC_EPMAXPKTSZ 0x0204 +#define ISP176x_DC_EPTYPE 0x0208 + +#define ISP176x_DC_BUFLEN 0x021c +#define ISP176x_DC_BUFSTAT 0x021e +#define ISP176x_DC_DATAPORT 0x0220 + +#define ISP176x_DC_CTRLFUNC 0x0228 +#define ISP176x_DC_EPINDEX 0x022c + +/* DMA Registers */ +#define ISP176x_DC_DMACMD 0x0230 +#define ISP176x_DC_DMATXCOUNT 0x0234 +#define ISP176x_DC_DMACONF 0x0238 +#define ISP176x_DC_DMAHW 0x023c +#define ISP176x_DC_DMAINTREASON 0x0250 +#define ISP176x_DC_DMAINTEN 0x0254 +#define ISP176x_DC_DMAEP 0x0258 +#define ISP176x_DC_DMABURSTCOUNT 0x0264 + +/* General Registers */ +#define ISP176x_DC_INTERRUPT 0x0218 +#define ISP176x_DC_CHIPID 0x0270 +#define ISP176x_DC_FRAMENUM 0x0274 +#define ISP176x_DC_SCRATCH 0x0278 +#define ISP176x_DC_UNLOCKDEV 0x027c +#define ISP176x_DC_INTPULSEWIDTH 0x0280 +#define ISP176x_DC_TESTMODE 0x0284 + +enum isp176x_device_controller_fields { + /* DC_ADDRESS */ + DC_DEVEN, DC_DEVADDR, + /* DC_MODE */ + DC_VBUSSTAT, DC_SFRESET, DC_GLINTENA, + /* DC_INTCONF */ + DC_CDBGMOD_ACK, DC_DDBGMODIN_ACK, DC_DDBGMODOUT_ACK, DC_INTPOL, + /* DC_INTENABLE */ + DC_IEPRXTX_7, DC_IEPRXTX_6, DC_IEPRXTX_5, DC_IEPRXTX_4, DC_IEPRXTX_3, + DC_IEPRXTX_2, DC_IEPRXTX_1, DC_IEPRXTX_0, + DC_IEP0SETUP, DC_IEVBUS, DC_IEHS_STA, DC_IERESM, DC_IESUSP, DC_IEBRST, + /* DC_EPINDEX */ + DC_EP0SETUP, DC_ENDPIDX, DC_EPDIR, + /* DC_CTRLFUNC */ + DC_CLBUF, DC_VENDP, DC_DSEN, DC_STATUS, DC_STALL, + /* DC_BUFLEN */ + DC_BUFLEN, + /* DC_EPMAXPKTSZ */ + DC_FFOSZ, + /* DC_EPTYPE */ + DC_EPENABLE, DC_ENDPTYP, + /* DC_FRAMENUM */ + DC_FRAMENUM, DC_UFRAMENUM, + /* DC_CHIP_ID */ + DC_CHIP_ID_HIGH, DC_CHIP_ID_LOW, + /* DC_SCRATCH */ + DC_SCRATCH, + /* Last element */ + DC_FIELD_MAX, +}; + +/* ISP1763 */ +/* Initialization Registers */ +#define ISP1763_DC_ADDRESS 0x00 +#define ISP1763_DC_MODE 0x0c +#define ISP1763_DC_INTCONF 0x10 +#define ISP1763_DC_INTENABLE 0x14 /* Data Flow Registers */ -#define DC_EPINDEX 0x022c -#define DC_EP0SETUP (1 << 5) -#define DC_ENDPIDX(n) ((n) << 1) -#define DC_EPDIR (1 << 0) - -#define DC_CTRLFUNC 0x0228 -#define DC_CLBUF (1 << 4) -#define DC_VENDP (1 << 3) -#define DC_DSEN (1 << 2) -#define DC_STATUS (1 << 1) -#define DC_STALL (1 << 0) - -#define DC_DATAPORT 0x0220 -#define DC_BUFLEN 0x021c -#define DC_DATACOUNT_MASK 0xffff -#define DC_BUFSTAT 0x021e -#define DC_EPMAXPKTSZ 0x0204 - -#define DC_EPTYPE 0x0208 -#define DC_NOEMPKT (1 << 4) -#define DC_EPENABLE (1 << 3) -#define DC_DBLBUF (1 << 2) -#define DC_ENDPTYP_ISOC (1 << 0) -#define DC_ENDPTYP_BULK (2 << 0) -#define DC_ENDPTYP_INTERRUPT (3 << 0) +#define ISP1763_DC_EPMAXPKTSZ 0x04 +#define ISP1763_DC_EPTYPE 0x08 + +#define ISP1763_DC_BUFLEN 0x1c +#define ISP1763_DC_BUFSTAT 0x1e +#define ISP1763_DC_DATAPORT 0x20 + +#define ISP1763_DC_CTRLFUNC 0x28 +#define ISP1763_DC_EPINDEX 0x2c /* DMA Registers */ -#define DC_DMACMD 0x0230 -#define DC_DMATXCOUNT 0x0234 -#define DC_DMACONF 0x0238 -#define DC_DMAHW 0x023c -#define DC_DMAINTREASON 0x0250 -#define DC_DMAINTEN 0x0254 -#define DC_DMAEP 0x0258 -#define DC_DMABURSTCOUNT 0x0264 +#define ISP1763_DC_DMACMD 0x30 +#define ISP1763_DC_DMATXCOUNT 0x34 +#define ISP1763_DC_DMACONF 0x38 +#define ISP1763_DC_DMAHW 0x3c +#define ISP1763_DC_DMAINTREASON 0x50 +#define ISP1763_DC_DMAINTEN 0x54 +#define ISP1763_DC_DMAEP 0x58 +#define ISP1763_DC_DMABURSTCOUNT 0x64 /* General Registers */ -#define DC_INTERRUPT 0x0218 -#define DC_CHIPID 0x0270 -#define DC_FRAMENUM 0x0274 -#define DC_SCRATCH 0x0278 -#define DC_UNLOCKDEV 0x027c -#define DC_INTPULSEWIDTH 0x0280 -#define DC_TESTMODE 0x0284 +#define ISP1763_DC_INTERRUPT 0x18 +#define ISP1763_DC_CHIPID_LOW 0x70 +#define ISP1763_DC_CHIPID_HIGH 0x72 +#define ISP1763_DC_FRAMENUM 0x74 +#define ISP1763_DC_SCRATCH 0x78 +#define ISP1763_DC_UNLOCKDEV 0x7c +#define ISP1763_DC_INTPULSEWIDTH 0x80 +#define ISP1763_DC_TESTMODE 0x84 #endif diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index 1714b2258b54..a78da59d6417 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -2,10 +2,12 @@ /* * Driver for the NXP ISP1761 device controller * + * Copyright 2021 Linaro, Rui Miguel Silva * Copyright 2014 Ideas on Board Oy * * Contacts: * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * Rui Miguel Silva <rui.silva@linaro.org> */ #include <linux/interrupt.h> @@ -45,16 +47,62 @@ static inline struct isp1760_request *req_to_udc_req(struct usb_request *req) return container_of(req, struct isp1760_request, req); } -static inline u32 isp1760_udc_read(struct isp1760_udc *udc, u16 reg) +static u32 isp1760_udc_read(struct isp1760_udc *udc, u16 field) { - return isp1760_read32(udc->regs, reg); + return isp1760_field_read(udc->fields, field); } -static inline void isp1760_udc_write(struct isp1760_udc *udc, u16 reg, u32 val) +static void isp1760_udc_write(struct isp1760_udc *udc, u16 field, u32 val) { - isp1760_write32(udc->regs, reg, val); + isp1760_field_write(udc->fields, field, val); } +static u32 isp1760_udc_read_raw(struct isp1760_udc *udc, u16 reg) +{ + __le32 val; + + regmap_raw_read(udc->regs, reg, &val, 4); + + return le32_to_cpu(val); +} + +static u16 isp1760_udc_read_raw16(struct isp1760_udc *udc, u16 reg) +{ + __le16 val; + + regmap_raw_read(udc->regs, reg, &val, 2); + + return le16_to_cpu(val); +} + +static void isp1760_udc_write_raw(struct isp1760_udc *udc, u16 reg, u32 val) +{ + __le32 val_le = cpu_to_le32(val); + + regmap_raw_write(udc->regs, reg, &val_le, 4); +} + +static void isp1760_udc_write_raw16(struct isp1760_udc *udc, u16 reg, u16 val) +{ + __le16 val_le = cpu_to_le16(val); + + regmap_raw_write(udc->regs, reg, &val_le, 2); +} + +static void isp1760_udc_set(struct isp1760_udc *udc, u32 field) +{ + isp1760_udc_write(udc, field, 0xFFFFFFFF); +} + +static void isp1760_udc_clear(struct isp1760_udc *udc, u32 field) +{ + isp1760_udc_write(udc, field, 0); +} + +static bool isp1760_udc_is_set(struct isp1760_udc *udc, u32 field) +{ + return !!isp1760_udc_read(udc, field); +} /* ----------------------------------------------------------------------------- * Endpoint Management */ @@ -75,16 +123,21 @@ static struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc, return NULL; } -static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir) +static void __isp1760_udc_select_ep(struct isp1760_udc *udc, + struct isp1760_ep *ep, int dir) { - isp1760_udc_write(ep->udc, DC_EPINDEX, - DC_ENDPIDX(ep->addr & USB_ENDPOINT_NUMBER_MASK) | - (dir == USB_DIR_IN ? DC_EPDIR : 0)); + isp1760_udc_write(udc, DC_ENDPIDX, ep->addr & USB_ENDPOINT_NUMBER_MASK); + + if (dir == USB_DIR_IN) + isp1760_udc_set(udc, DC_EPDIR); + else + isp1760_udc_clear(udc, DC_EPDIR); } /** * isp1760_udc_select_ep - Select an endpoint for register access * @ep: The endpoint + * @udc: Reference to the device controller * * The ISP1761 endpoint registers are banked. This function selects the target * endpoint for banked register access. The selection remains valid until the @@ -93,9 +146,10 @@ static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir) * * Called with the UDC spinlock held. */ -static void isp1760_udc_select_ep(struct isp1760_ep *ep) +static void isp1760_udc_select_ep(struct isp1760_udc *udc, + struct isp1760_ep *ep) { - __isp1760_udc_select_ep(ep, ep->addr & USB_ENDPOINT_DIR_MASK); + __isp1760_udc_select_ep(udc, ep, ep->addr & USB_ENDPOINT_DIR_MASK); } /* Called with the UDC spinlock held. */ @@ -108,9 +162,13 @@ static void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir) * the direction opposite to the data stage data packets, we thus need * to select the OUT/IN endpoint for IN/OUT transfers. */ - isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) | - (dir == USB_DIR_IN ? 0 : DC_EPDIR)); - isp1760_udc_write(udc, DC_CTRLFUNC, DC_STATUS); + if (dir == USB_DIR_IN) + isp1760_udc_clear(udc, DC_EPDIR); + else + isp1760_udc_set(udc, DC_EPDIR); + + isp1760_udc_write(udc, DC_ENDPIDX, 1); + isp1760_udc_set(udc, DC_STATUS); /* * The hardware will terminate the request automatically and go back to @@ -157,10 +215,10 @@ static void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep) spin_lock_irqsave(&udc->lock, flags); /* Stall both the IN and OUT endpoints. */ - __isp1760_udc_select_ep(ep, USB_DIR_OUT); - isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL); - __isp1760_udc_select_ep(ep, USB_DIR_IN); - isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL); + __isp1760_udc_select_ep(udc, ep, USB_DIR_OUT); + isp1760_udc_set(udc, DC_STALL); + __isp1760_udc_select_ep(udc, ep, USB_DIR_IN); + isp1760_udc_set(udc, DC_STALL); /* A protocol stall completes the control transaction. */ udc->ep0_state = ISP1760_CTRL_SETUP; @@ -181,8 +239,8 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep, u32 *buf; int i; - isp1760_udc_select_ep(ep); - len = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK; + isp1760_udc_select_ep(udc, ep); + len = isp1760_udc_read(udc, DC_BUFLEN); dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n", __func__, len, req->req.actual, req->req.length); @@ -198,7 +256,7 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep, * datasheet doesn't clearly document how this should be * handled. */ - isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF); + isp1760_udc_set(udc, DC_CLBUF); return false; } @@ -209,9 +267,9 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep, * the next packet might be removed from the FIFO. */ for (i = len; i > 2; i -= 4, ++buf) - *buf = le32_to_cpu(isp1760_udc_read(udc, DC_DATAPORT)); + *buf = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT); if (i > 0) - *(u16 *)buf = le16_to_cpu(readw(udc->regs + DC_DATAPORT)); + *(u16 *)buf = isp1760_udc_read_raw16(udc, ISP176x_DC_DATAPORT); req->req.actual += len; @@ -253,7 +311,7 @@ static void isp1760_udc_transmit(struct isp1760_ep *ep, __func__, req->packet_size, req->req.actual, req->req.length); - __isp1760_udc_select_ep(ep, USB_DIR_IN); + __isp1760_udc_select_ep(udc, ep, USB_DIR_IN); if (req->packet_size) isp1760_udc_write(udc, DC_BUFLEN, req->packet_size); @@ -265,14 +323,14 @@ static void isp1760_udc_transmit(struct isp1760_ep *ep, * the FIFO for this kind of conditions, but doesn't seem to work. */ for (i = req->packet_size; i > 2; i -= 4, ++buf) - isp1760_udc_write(udc, DC_DATAPORT, cpu_to_le32(*buf)); + isp1760_udc_write_raw(udc, ISP176x_DC_DATAPORT, *buf); if (i > 0) - writew(cpu_to_le16(*(u16 *)buf), udc->regs + DC_DATAPORT); + isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, *(u16 *)buf); if (ep->addr == 0) - isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN); + isp1760_udc_set(udc, DC_DSEN); if (!req->packet_size) - isp1760_udc_write(udc, DC_CTRLFUNC, DC_VENDP); + isp1760_udc_set(udc, DC_VENDP); } static void isp1760_ep_rx_ready(struct isp1760_ep *ep) @@ -408,19 +466,24 @@ static int __isp1760_udc_set_halt(struct isp1760_ep *ep, bool halt) return -EINVAL; } - isp1760_udc_select_ep(ep); - isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0); + isp1760_udc_select_ep(udc, ep); + + if (halt) + isp1760_udc_set(udc, DC_STALL); + else + isp1760_udc_clear(udc, DC_STALL); if (ep->addr == 0) { /* When halting the control endpoint, stall both IN and OUT. */ - __isp1760_udc_select_ep(ep, USB_DIR_IN); - isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0); + __isp1760_udc_select_ep(udc, ep, USB_DIR_IN); + if (halt) + isp1760_udc_set(udc, DC_STALL); + else + isp1760_udc_clear(udc, DC_STALL); } else if (!halt) { /* Reset the data PID by cycling the endpoint enable bit. */ - u16 eptype = isp1760_udc_read(udc, DC_EPTYPE); - - isp1760_udc_write(udc, DC_EPTYPE, eptype & ~DC_EPENABLE); - isp1760_udc_write(udc, DC_EPTYPE, eptype); + isp1760_udc_clear(udc, DC_EPENABLE); + isp1760_udc_set(udc, DC_EPENABLE); /* * Disabling the endpoint emptied the transmit FIFO, fill it @@ -479,12 +542,14 @@ static int isp1760_udc_get_status(struct isp1760_udc *udc, return -EINVAL; } - isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) | DC_EPDIR); + isp1760_udc_set(udc, DC_EPDIR); + isp1760_udc_write(udc, DC_ENDPIDX, 1); + isp1760_udc_write(udc, DC_BUFLEN, 2); - writew(cpu_to_le16(status), udc->regs + DC_DATAPORT); + isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, status); - isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN); + isp1760_udc_set(udc, DC_DSEN); dev_dbg(udc->isp->dev, "%s: status 0x%04x\n", __func__, status); @@ -508,7 +573,8 @@ static int isp1760_udc_set_address(struct isp1760_udc *udc, u16 addr) usb_gadget_set_state(&udc->gadget, addr ? USB_STATE_ADDRESS : USB_STATE_DEFAULT); - isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN | addr); + isp1760_udc_write(udc, DC_DEVADDR, addr); + isp1760_udc_set(udc, DC_DEVEN); spin_lock(&udc->lock); isp1760_udc_ctrl_send_status(&udc->ep[0], USB_DIR_OUT); @@ -650,9 +716,9 @@ static void isp1760_ep0_setup(struct isp1760_udc *udc) spin_lock(&udc->lock); - isp1760_udc_write(udc, DC_EPINDEX, DC_EP0SETUP); + isp1760_udc_set(udc, DC_EP0SETUP); - count = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK; + count = isp1760_udc_read(udc, DC_BUFLEN); if (count != sizeof(req)) { spin_unlock(&udc->lock); @@ -663,8 +729,8 @@ static void isp1760_ep0_setup(struct isp1760_udc *udc) return; } - req.data[0] = isp1760_udc_read(udc, DC_DATAPORT); - req.data[1] = isp1760_udc_read(udc, DC_DATAPORT); + req.data[0] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT); + req.data[1] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT); if (udc->ep0_state != ISP1760_CTRL_SETUP) { spin_unlock(&udc->lock); @@ -732,13 +798,13 @@ static int isp1760_ep_enable(struct usb_ep *ep, switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_ISOC: - type = DC_ENDPTYP_ISOC; + type = ISP176x_DC_ENDPTYP_ISOC; break; case USB_ENDPOINT_XFER_BULK: - type = DC_ENDPTYP_BULK; + type = ISP176x_DC_ENDPTYP_BULK; break; case USB_ENDPOINT_XFER_INT: - type = DC_ENDPTYP_INTERRUPT; + type = ISP176x_DC_ENDPTYP_INTERRUPT; break; case USB_ENDPOINT_XFER_CONTROL: default: @@ -755,10 +821,13 @@ static int isp1760_ep_enable(struct usb_ep *ep, uep->halted = false; uep->wedged = false; - isp1760_udc_select_ep(uep); - isp1760_udc_write(udc, DC_EPMAXPKTSZ, uep->maxpacket); + isp1760_udc_select_ep(udc, uep); + + isp1760_udc_write(udc, DC_FFOSZ, uep->maxpacket); isp1760_udc_write(udc, DC_BUFLEN, uep->maxpacket); - isp1760_udc_write(udc, DC_EPTYPE, DC_EPENABLE | type); + + isp1760_udc_write(udc, DC_ENDPTYP, type); + isp1760_udc_set(udc, DC_EPENABLE); spin_unlock_irqrestore(&udc->lock, flags); @@ -786,8 +855,9 @@ static int isp1760_ep_disable(struct usb_ep *ep) uep->desc = NULL; uep->maxpacket = 0; - isp1760_udc_select_ep(uep); - isp1760_udc_write(udc, DC_EPTYPE, 0); + isp1760_udc_select_ep(udc, uep); + isp1760_udc_clear(udc, DC_EPENABLE); + isp1760_udc_clear(udc, DC_ENDPTYP); /* TODO Synchronize with the IRQ handler */ @@ -864,8 +934,8 @@ static int isp1760_ep_queue(struct usb_ep *ep, struct usb_request *_req, case ISP1760_CTRL_DATA_OUT: list_add_tail(&req->queue, &uep->queue); - __isp1760_udc_select_ep(uep, USB_DIR_OUT); - isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN); + __isp1760_udc_select_ep(udc, uep, USB_DIR_OUT); + isp1760_udc_set(udc, DC_DSEN); break; case ISP1760_CTRL_STATUS: @@ -1025,14 +1095,14 @@ static void isp1760_ep_fifo_flush(struct usb_ep *ep) spin_lock_irqsave(&udc->lock, flags); - isp1760_udc_select_ep(uep); + isp1760_udc_select_ep(udc, uep); /* * Set the CLBUF bit twice to flush both buffers in case double * buffering is enabled. */ - isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF); - isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF); + isp1760_udc_set(udc, DC_CLBUF); + isp1760_udc_set(udc, DC_CLBUF); spin_unlock_irqrestore(&udc->lock, flags); } @@ -1082,6 +1152,10 @@ static void isp1760_udc_disconnect(struct isp1760_udc *udc) static void isp1760_udc_init_hw(struct isp1760_udc *udc) { + u32 intconf = udc->is_isp1763 ? ISP1763_DC_INTCONF : ISP176x_DC_INTCONF; + u32 intena = udc->is_isp1763 ? ISP1763_DC_INTENABLE : + ISP176x_DC_INTENABLE; + /* * The device controller currently shares its interrupt with the host * controller, the DC_IRQ polarity and signaling mode are ignored. Set @@ -1091,19 +1165,22 @@ static void isp1760_udc_init_hw(struct isp1760_udc *udc) * ACK tokens only (and NYET for the out pipe). The default * configuration also generates an interrupt on the first NACK token. */ - isp1760_udc_write(udc, DC_INTCONF, DC_CDBGMOD_ACK | DC_DDBGMODIN_ACK | - DC_DDBGMODOUT_ACK_NYET); - - isp1760_udc_write(udc, DC_INTENABLE, DC_IEPRXTX(7) | DC_IEPRXTX(6) | - DC_IEPRXTX(5) | DC_IEPRXTX(4) | DC_IEPRXTX(3) | - DC_IEPRXTX(2) | DC_IEPRXTX(1) | DC_IEPRXTX(0) | - DC_IEP0SETUP | DC_IEVBUS | DC_IERESM | DC_IESUSP | - DC_IEHS_STA | DC_IEBRST); + isp1760_reg_write(udc->regs, intconf, + ISP176x_DC_CDBGMOD_ACK | ISP176x_DC_DDBGMODIN_ACK | + ISP176x_DC_DDBGMODOUT_ACK); + + isp1760_reg_write(udc->regs, intena, DC_IEPRXTX(7) | + DC_IEPRXTX(6) | DC_IEPRXTX(5) | DC_IEPRXTX(4) | + DC_IEPRXTX(3) | DC_IEPRXTX(2) | DC_IEPRXTX(1) | + DC_IEPRXTX(0) | ISP176x_DC_IEP0SETUP | + ISP176x_DC_IEVBUS | ISP176x_DC_IERESM | + ISP176x_DC_IESUSP | ISP176x_DC_IEHS_STA | + ISP176x_DC_IEBRST); if (udc->connected) isp1760_set_pullup(udc->isp, true); - isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN); + isp1760_udc_set(udc, DC_DEVEN); } static void isp1760_udc_reset(struct isp1760_udc *udc) @@ -1152,7 +1229,7 @@ static int isp1760_udc_get_frame(struct usb_gadget *gadget) { struct isp1760_udc *udc = gadget_to_udc(gadget); - return isp1760_udc_read(udc, DC_FRAMENUM) & ((1 << 11) - 1); + return isp1760_udc_read(udc, DC_FRAMENUM); } static int isp1760_udc_wakeup(struct usb_gadget *gadget) @@ -1219,7 +1296,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget, usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED); /* DMA isn't supported yet, don't enable the DMA clock. */ - isp1760_udc_write(udc, DC_MODE, DC_GLINTENA); + isp1760_udc_set(udc, DC_GLINTENA); isp1760_udc_init_hw(udc); @@ -1232,13 +1309,14 @@ static int isp1760_udc_start(struct usb_gadget *gadget, static int isp1760_udc_stop(struct usb_gadget *gadget) { struct isp1760_udc *udc = gadget_to_udc(gadget); + u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE; unsigned long flags; dev_dbg(udc->isp->dev, "%s\n", __func__); del_timer_sync(&udc->vbus_timer); - isp1760_udc_write(udc, DC_MODE, 0); + isp1760_reg_write(udc->regs, mode_reg, 0); spin_lock_irqsave(&udc->lock, flags); udc->driver = NULL; @@ -1260,15 +1338,30 @@ static const struct usb_gadget_ops isp1760_udc_ops = { * Interrupt Handling */ +static u32 isp1760_udc_irq_get_status(struct isp1760_udc *udc) +{ + u32 status; + + if (udc->is_isp1763) { + status = isp1760_reg_read(udc->regs, ISP1763_DC_INTERRUPT) + & isp1760_reg_read(udc->regs, ISP1763_DC_INTENABLE); + isp1760_reg_write(udc->regs, ISP1763_DC_INTERRUPT, status); + } else { + status = isp1760_reg_read(udc->regs, ISP176x_DC_INTERRUPT) + & isp1760_reg_read(udc->regs, ISP176x_DC_INTENABLE); + isp1760_reg_write(udc->regs, ISP176x_DC_INTERRUPT, status); + } + + return status; +} + static irqreturn_t isp1760_udc_irq(int irq, void *dev) { struct isp1760_udc *udc = dev; unsigned int i; u32 status; - status = isp1760_udc_read(udc, DC_INTERRUPT) - & isp1760_udc_read(udc, DC_INTENABLE); - isp1760_udc_write(udc, DC_INTERRUPT, status); + status = isp1760_udc_irq_get_status(udc); if (status & DC_IEVBUS) { dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__); @@ -1313,7 +1406,7 @@ static irqreturn_t isp1760_udc_irq(int irq, void *dev) dev_dbg(udc->isp->dev, "%s(SUSP)\n", __func__); spin_lock(&udc->lock); - if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT)) + if (!isp1760_udc_is_set(udc, DC_VBUSSTAT)) isp1760_udc_disconnect(udc); else isp1760_udc_suspend(udc); @@ -1335,7 +1428,7 @@ static void isp1760_udc_vbus_poll(struct timer_list *t) spin_lock_irqsave(&udc->lock, flags); - if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT)) + if (!(isp1760_udc_is_set(udc, DC_VBUSSTAT))) isp1760_udc_disconnect(udc); else if (udc->gadget.state >= USB_STATE_POWERED) mod_timer(&udc->vbus_timer, @@ -1403,6 +1496,7 @@ static void isp1760_udc_init_eps(struct isp1760_udc *udc) static int isp1760_udc_init(struct isp1760_udc *udc) { + u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE; u16 scratch; u32 chipid; @@ -1413,7 +1507,8 @@ static int isp1760_udc_init(struct isp1760_udc *udc) * and scratch register contents must match the expected values. */ isp1760_udc_write(udc, DC_SCRATCH, 0xbabe); - chipid = isp1760_udc_read(udc, DC_CHIPID); + chipid = isp1760_udc_read(udc, DC_CHIP_ID_HIGH) << 16; + chipid |= isp1760_udc_read(udc, DC_CHIP_ID_LOW); scratch = isp1760_udc_read(udc, DC_SCRATCH); if (scratch != 0xbabe) { @@ -1423,15 +1518,16 @@ static int isp1760_udc_init(struct isp1760_udc *udc) return -ENODEV; } - if (chipid != 0x00011582 && chipid != 0x00158210) { + if (chipid != 0x00011582 && chipid != 0x00158210 && + chipid != 0x00176320) { dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid); return -ENODEV; } /* Reset the device controller. */ - isp1760_udc_write(udc, DC_MODE, DC_SFRESET); + isp1760_udc_set(udc, DC_SFRESET); usleep_range(10000, 11000); - isp1760_udc_write(udc, DC_MODE, 0); + isp1760_reg_write(udc->regs, mode_reg, 0); usleep_range(10000, 11000); return 0; @@ -1445,7 +1541,6 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq, udc->irq = -1; udc->isp = isp; - udc->regs = isp->regs; spin_lock_init(&udc->lock); timer_setup(&udc->vbus_timer, isp1760_udc_vbus_poll, 0); diff --git a/drivers/usb/isp1760/isp1760-udc.h b/drivers/usb/isp1760/isp1760-udc.h index d2df650d54e9..22044e86bc0e 100644 --- a/drivers/usb/isp1760/isp1760-udc.h +++ b/drivers/usb/isp1760/isp1760-udc.h @@ -2,10 +2,12 @@ /* * Driver for the NXP ISP1761 device controller * + * Copyright 2021 Linaro, Rui Miguel Silva * Copyright 2014 Ideas on Board Oy * * Contacts: * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * Rui Miguel Silva <rui.silva@linaro.org> */ #ifndef _ISP1760_UDC_H_ @@ -17,6 +19,8 @@ #include <linux/timer.h> #include <linux/usb/gadget.h> +#include "isp1760-regs.h" + struct isp1760_device; struct isp1760_udc; @@ -48,7 +52,7 @@ struct isp1760_ep { * struct isp1760_udc - UDC state information * irq: IRQ number * irqname: IRQ name (as passed to request_irq) - * regs: Base address of the UDC registers + * regs: regmap for UDC registers * driver: Gadget driver * gadget: Gadget device * lock: Protects driver, vbus_timer, ep, ep0_*, DC_EPINDEX register @@ -59,12 +63,13 @@ struct isp1760_ep { * connected: Tracks gadget driver bus connection state */ struct isp1760_udc { -#ifdef CONFIG_USB_ISP1761_UDC struct isp1760_device *isp; int irq; char *irqname; - void __iomem *regs; + + struct regmap *regs; + struct regmap_field *fields[DC_FIELD_MAX]; struct usb_gadget_driver *driver; struct usb_gadget gadget; @@ -79,9 +84,9 @@ struct isp1760_udc { u16 ep0_length; bool connected; + bool is_isp1763; unsigned int devstatus; -#endif }; #ifdef CONFIG_USB_ISP1761_UDC diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 8f09a387b773..71ae84031c1f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2055,6 +2055,15 @@ static void musb_pm_runtime_check_session(struct musb *musb) dev_err(musb->controller, "Could not enable: %i\n", error); musb->quirk_retries = 3; + + /* + * We can get a spurious MUSB_INTR_SESSREQ interrupt on start-up + * in B-peripheral mode with nothing connected and the session + * bit clears silently. Check status again in 3 seconds. + */ + if (devctl & MUSB_DEVCTL_BDEVICE) + schedule_delayed_work(&musb->irq_work, + msecs_to_jiffies(3000)); } else { musb_dbg(musb, "Allow PM with no session: %02x", devctl); pm_runtime_mark_last_busy(musb->controller); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index ef374d4dd94a..98c0f4c1bffd 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -611,7 +611,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) * mode 0 only. So we do not get endpoint interrupts due to DMA * completion. We only get interrupts from DMA controller. * - * We could operate in DMA mode 1 if we knew the size of the tranfer + * We could operate in DMA mode 1 if we knew the size of the transfer * in advance. For mass storage class, request->length = what the host * sends, so that'd work. But for pretty much everything else, * request->length is routinely more than what the host sends. For diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 30c5e7de0761..9ff7d891b4b7 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -563,10 +563,9 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum) ep->rx_reinit = 0; } -static void musb_tx_dma_set_mode_mentor(struct dma_controller *dma, - struct musb_hw_ep *hw_ep, struct musb_qh *qh, - struct urb *urb, u32 offset, - u32 *length, u8 *mode) +static void musb_tx_dma_set_mode_mentor(struct musb_hw_ep *hw_ep, + struct musb_qh *qh, + u32 *length, u8 *mode) { struct dma_channel *channel = hw_ep->tx_channel; void __iomem *epio = hw_ep->regs; @@ -602,12 +601,8 @@ static void musb_tx_dma_set_mode_mentor(struct dma_controller *dma, musb_writew(epio, MUSB_TXCSR, csr); } -static void musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma, - struct musb_hw_ep *hw_ep, - struct musb_qh *qh, +static void musb_tx_dma_set_mode_cppi_tusb(struct musb_hw_ep *hw_ep, struct urb *urb, - u32 offset, - u32 *length, u8 *mode) { struct dma_channel *channel = hw_ep->tx_channel; @@ -630,11 +625,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma, u8 mode; if (musb_dma_inventra(hw_ep->musb) || musb_dma_ux500(hw_ep->musb)) - musb_tx_dma_set_mode_mentor(dma, hw_ep, qh, urb, offset, + musb_tx_dma_set_mode_mentor(hw_ep, qh, &length, &mode); else if (is_cppi_enabled(hw_ep->musb) || tusb_dma_omap(hw_ep->musb)) - musb_tx_dma_set_mode_cppi_tusb(dma, hw_ep, qh, urb, offset, - &length, &mode); + musb_tx_dma_set_mode_cppi_tusb(hw_ep, urb, &mode); else return false; diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 4804d4d85c15..63298bd233e0 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -61,10 +61,6 @@ extern void musb_host_tx(struct musb *, u8); extern void musb_host_rx(struct musb *, u8); extern void musb_root_disconnect(struct musb *musb); extern void musb_host_free(struct musb *); -extern void musb_host_cleanup(struct musb *); -extern void musb_host_tx(struct musb *, u8); -extern void musb_host_rx(struct musb *, u8); -extern void musb_root_disconnect(struct musb *musb); extern void musb_host_resume_root_hub(struct musb *musb); extern void musb_host_poke_root_hub(struct musb *musb); extern int musb_port_suspend(struct musb *musb, bool do_suspend); diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 4232f1ce3fbf..640a46f0d118 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -33,6 +33,8 @@ struct omap2430_glue { enum musb_vbus_id_status status; struct work_struct omap_musb_mailbox_work; struct device *control_otghs; + unsigned int is_runtime_suspended:1; + unsigned int needs_resume:1; }; #define glue_to_musb(g) platform_get_drvdata(g->musb) @@ -459,6 +461,8 @@ static int omap2430_runtime_suspend(struct device *dev) phy_power_off(musb->phy); phy_exit(musb->phy); + glue->is_runtime_suspended = 1; + return 0; } @@ -480,12 +484,40 @@ static int omap2430_runtime_resume(struct device *dev) /* Wait for musb to get oriented. Otherwise we can get babble */ usleep_range(200000, 250000); + glue->is_runtime_suspended = 0; + return 0; } +static int omap2430_suspend(struct device *dev) +{ + struct omap2430_glue *glue = dev_get_drvdata(dev); + + if (glue->is_runtime_suspended) + return 0; + + glue->needs_resume = 1; + + return omap2430_runtime_suspend(dev); +} + +static int omap2430_resume(struct device *dev) +{ + struct omap2430_glue *glue = dev_get_drvdata(dev); + + if (!glue->needs_resume) + return 0; + + glue->needs_resume = 0; + + return omap2430_runtime_resume(dev); +} + static const struct dev_pm_ops omap2430_pm_ops = { .runtime_suspend = omap2430_runtime_suspend, .runtime_resume = omap2430_runtime_resume, + .suspend = omap2430_suspend, + .resume = omap2430_resume, }; #define DEV_PM_OPS (&omap2430_pm_ops) diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index 02bb7ddd4bd6..f3e9b3b6ac3e 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -555,7 +555,7 @@ pullup: case OTG_STATE_A_PERIPHERAL: if (otg_ctrl & OTG_PULLUP) goto pullup; - /* FALLTHROUGH */ + fallthrough; // case OTG_STATE_B_WAIT_ACON: default: pulldown: diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c index 6cf6fbd39237..ad3d57f1c273 100644 --- a/drivers/usb/phy/phy-isp1301.c +++ b/drivers/usb/phy/phy-isp1301.c @@ -142,24 +142,17 @@ static struct i2c_driver isp1301_driver = { module_i2c_driver(isp1301_driver); -static int match(struct device *dev, const void *data) -{ - const struct device_node *node = (const struct device_node *)data; - return (dev->of_node == node) && - (dev->driver == &isp1301_driver.driver); -} - struct i2c_client *isp1301_get_client(struct device_node *node) { - if (node) { /* reference of ISP1301 I2C node via DT */ - struct device *dev = bus_find_device(&i2c_bus_type, NULL, - node, match); - if (!dev) - return NULL; - return to_i2c_client(dev); - } else { /* non-DT: only one ISP1301 chip supported */ - return isp1301_i2c_client; - } + struct i2c_client *client; + + /* reference of ISP1301 I2C node via DT */ + client = of_find_i2c_device_by_node(node); + if (client) + return client; + + /* non-DT: only one ISP1301 chip supported */ + return isp1301_i2c_client; } EXPORT_SYMBOL_GPL(isp1301_get_client); diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 33b637d0d8d9..dfaed7eee94f 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -214,6 +214,15 @@ static const char * const usb_roles[] = { [USB_ROLE_DEVICE] = "device", }; +const char *usb_role_string(enum usb_role role) +{ + if (role < 0 || role >= ARRAY_SIZE(usb_roles)) + return "unknown"; + + return usb_roles[role]; +} +EXPORT_SYMBOL_GPL(usb_role_string); + static ssize_t role_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index 8514bec7e1b8..603f3e698cc0 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -17,21 +17,12 @@ #include "class.h" #include "mux.h" -static bool dev_name_ends_with(struct device *dev, const char *suffix) -{ - const char *name = dev_name(dev); - const int name_len = strlen(name); - const int suffix_len = strlen(suffix); - - if (suffix_len > name_len) - return false; - - return strcmp(name + (name_len - suffix_len), suffix) == 0; -} - static int switch_fwnode_match(struct device *dev, const void *fwnode) { - return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-switch"); + if (!is_typec_switch(dev)) + return 0; + + return dev_fwnode(dev) == fwnode; } static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id, @@ -39,9 +30,6 @@ static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id, { struct device *dev; - if (id && !fwnode_property_present(fwnode, id)) - return NULL; - dev = class_find_device(&typec_mux_class, NULL, fwnode, switch_fwnode_match); @@ -90,7 +78,7 @@ static void typec_switch_release(struct device *dev) kfree(to_typec_switch(dev)); } -static const struct device_type typec_switch_dev_type = { +const struct device_type typec_switch_dev_type = { .name = "orientation_switch", .release = typec_switch_release, }; @@ -180,7 +168,10 @@ EXPORT_SYMBOL_GPL(typec_switch_get_drvdata); static int mux_fwnode_match(struct device *dev, const void *fwnode) { - return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-mux"); + if (!is_typec_mux(dev)) + return 0; + + return dev_fwnode(dev) == fwnode; } static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id, @@ -295,7 +286,7 @@ static void typec_mux_release(struct device *dev) kfree(to_typec_mux(dev)); } -static const struct device_type typec_mux_dev_type = { +const struct device_type typec_mux_dev_type = { .name = "mode_switch", .release = typec_mux_release, }; diff --git a/drivers/usb/typec/mux.h b/drivers/usb/typec/mux.h index 4fd9426ee44f..b1d6e837cb74 100644 --- a/drivers/usb/typec/mux.h +++ b/drivers/usb/typec/mux.h @@ -18,4 +18,10 @@ struct typec_mux { #define to_typec_switch(_dev_) container_of(_dev_, struct typec_switch, dev) #define to_typec_mux(_dev_) container_of(_dev_, struct typec_mux, dev) +extern const struct device_type typec_switch_dev_type; +extern const struct device_type typec_mux_dev_type; + +#define is_typec_switch(dev) ((dev)->type == &typec_switch_dev_type) +#define is_typec_mux(dev) ((dev)->type == &typec_mux_dev_type) + #endif /* __USB_TYPEC_MUX__ */ diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index 25b480752266..22862345d1ab 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -115,6 +115,33 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) return 0; } +static int tcpci_apply_rc(struct tcpc_dev *tcpc, enum typec_cc_status cc, + enum typec_cc_polarity polarity) +{ + struct tcpci *tcpci = tcpc_to_tcpci(tcpc); + unsigned int reg; + int ret; + + ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, ®); + if (ret < 0) + return ret; + + /* + * APPLY_RC state is when ROLE_CONTROL.CC1 != ROLE_CONTROL.CC2 and vbus autodischarge on + * disconnect is disabled. Bail out when ROLE_CONTROL.CC1 != ROLE_CONTROL.CC2. + */ + if (((reg & (TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT)) >> + TCPC_ROLE_CTRL_CC2_SHIFT) != + ((reg & (TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT)) >> + TCPC_ROLE_CTRL_CC1_SHIFT)) + return 0; + + return regmap_update_bits(tcpci->regmap, TCPC_ROLE_CTRL, polarity == TYPEC_POLARITY_CC1 ? + TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT : + TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT, + TCPC_ROLE_CTRL_CC_OPEN); +} + static int tcpci_start_toggling(struct tcpc_dev *tcpc, enum typec_port_type port_type, enum typec_cc_status cc) @@ -728,6 +755,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) tcpci->tcpc.get_vbus = tcpci_get_vbus; tcpci->tcpc.set_vbus = tcpci_set_vbus; tcpci->tcpc.set_cc = tcpci_set_cc; + tcpci->tcpc.apply_rc = tcpci_apply_rc; tcpci->tcpc.get_cc = tcpci_get_cc; tcpci->tcpc.set_polarity = tcpci_set_polarity; tcpci->tcpc.set_vconn = tcpci_set_vconn; diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 9ce8c9af4da5..0db685d5d9c0 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -774,6 +774,34 @@ static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc) port->tcpc->set_cc(port->tcpc, cc); } +static int tcpm_enable_auto_vbus_discharge(struct tcpm_port *port, bool enable) +{ + int ret = 0; + + if (port->tcpc->enable_auto_vbus_discharge) { + ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, enable); + tcpm_log_force(port, "%s vbus discharge ret:%d", enable ? "enable" : "disable", + ret); + if (!ret) + port->auto_vbus_discharge_enabled = enable; + } + + return ret; +} + +static void tcpm_apply_rc(struct tcpm_port *port) +{ + /* + * TCPCI: Move to APPLY_RC state to prevent disconnect during PR_SWAP + * when Vbus auto discharge on disconnect is enabled. + */ + if (port->tcpc->enable_auto_vbus_discharge && port->tcpc->apply_rc) { + tcpm_log(port, "Apply_RC"); + port->tcpc->apply_rc(port->tcpc, port->cc_req, port->polarity); + tcpm_enable_auto_vbus_discharge(port, false); + } +} + /* * Determine RP value to set based on maximum current supported * by a port if configured as source. @@ -3505,12 +3533,7 @@ static int tcpm_src_attach(struct tcpm_port *port) if (ret < 0) return ret; - if (port->tcpc->enable_auto_vbus_discharge) { - ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true); - tcpm_log_force(port, "enable vbus discharge ret:%d", ret); - if (!ret) - port->auto_vbus_discharge_enabled = true; - } + tcpm_enable_auto_vbus_discharge(port, true); ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port)); if (ret < 0) @@ -3587,14 +3610,7 @@ static void tcpm_set_partner_usb_comm_capable(struct tcpm_port *port, bool capab static void tcpm_reset_port(struct tcpm_port *port) { - int ret; - - if (port->tcpc->enable_auto_vbus_discharge) { - ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, false); - tcpm_log_force(port, "Disable vbus discharge ret:%d", ret); - if (!ret) - port->auto_vbus_discharge_enabled = false; - } + tcpm_enable_auto_vbus_discharge(port, false); port->in_ams = false; port->ams = NONE_AMS; port->vdm_sm_running = false; @@ -3662,13 +3678,7 @@ static int tcpm_snk_attach(struct tcpm_port *port) if (ret < 0) return ret; - if (port->tcpc->enable_auto_vbus_discharge) { - tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V); - ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true); - tcpm_log_force(port, "enable vbus discharge ret:%d", ret); - if (!ret) - port->auto_vbus_discharge_enabled = true; - } + tcpm_enable_auto_vbus_discharge(port, true); ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port)); if (ret < 0) @@ -4505,6 +4515,7 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, ready_state(port), 0); break; case PR_SWAP_START: + tcpm_apply_rc(port); if (port->pwr_role == TYPEC_SOURCE) tcpm_set_state(port, PR_SWAP_SRC_SNK_TRANSITION_OFF, PD_T_SRC_TRANSITION); @@ -4544,6 +4555,7 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, ERROR_RECOVERY, PD_T_PS_SOURCE_ON_PRS); break; case PR_SWAP_SRC_SNK_SINK_ON: + tcpm_enable_auto_vbus_discharge(port, true); /* Set the vbus disconnect threshold for implicit contract */ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V); tcpm_set_state(port, SNK_STARTUP, 0); @@ -4560,6 +4572,7 @@ static void run_state_machine(struct tcpm_port *port) PD_T_PS_SOURCE_OFF); break; case PR_SWAP_SNK_SRC_SOURCE_ON: + tcpm_enable_auto_vbus_discharge(port, true); tcpm_set_cc(port, tcpm_rp_cc(port)); tcpm_set_vbus(port, true); /* @@ -5188,6 +5201,9 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port) tcpm_set_state(port, SNK_UNATTACHED, 0); } break; + case PR_SWAP_SNK_SRC_SINK_OFF: + /* Do nothing, vsafe0v is expected during transition */ + break; default: if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled) tcpm_set_state(port, SNK_UNATTACHED, 0); diff --git a/drivers/usb/typec/tcpm/wcove.c b/drivers/usb/typec/tcpm/wcove.c index 79ae63950050..8072e222eb99 100644 --- a/drivers/usb/typec/tcpm/wcove.c +++ b/drivers/usb/typec/tcpm/wcove.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * typec_wcove.c - WhiskeyCove PMIC USB Type-C PHY driver * * Copyright (C) 2017 Intel Corporation diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index b433169ef6fa..4e1973fbdf0d 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1279,7 +1279,7 @@ void *ucsi_get_drvdata(struct ucsi *ucsi) EXPORT_SYMBOL_GPL(ucsi_get_drvdata); /** - * ucsi_get_drvdata - Assign private driver data pointer + * ucsi_set_drvdata - Assign private driver data pointer * @ucsi: UCSI interface * @data: Private data pointer */ diff --git a/include/linux/device.h b/include/linux/device.h index f1a00040fa53..73b9d7810502 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -351,6 +351,22 @@ enum dl_dev_state { }; /** + * enum device_removable - Whether the device is removable. The criteria for a + * device to be classified as removable is determined by its subsystem or bus. + * @DEVICE_REMOVABLE_NOT_SUPPORTED: This attribute is not supported for this + * device (default). + * @DEVICE_REMOVABLE_UNKNOWN: Device location is Unknown. + * @DEVICE_FIXED: Device is not removable by the user. + * @DEVICE_REMOVABLE: Device is removable by the user. + */ +enum device_removable { + DEVICE_REMOVABLE_NOT_SUPPORTED = 0, /* must be 0 */ + DEVICE_REMOVABLE_UNKNOWN, + DEVICE_FIXED, + DEVICE_REMOVABLE, +}; + +/** * struct dev_links_info - Device data related to device links. * @suppliers: List of links to supplier devices. * @consumers: List of links to consumer devices. @@ -431,6 +447,9 @@ struct dev_links_info { * device (i.e. the bus driver that discovered the device). * @iommu_group: IOMMU group the device belongs to. * @iommu: Per device generic IOMMU runtime data + * @removable: Whether the device can be removed from the system. This + * should be set by the subsystem / bus driver that discovered + * the device. * * @offline_disabled: If set, the device is permanently online. * @offline: Set after successful invocation of bus type's .offline(). @@ -544,6 +563,8 @@ struct device { struct iommu_group *iommu_group; struct dev_iommu *iommu; + enum device_removable removable; + bool offline_disabled:1; bool offline:1; bool of_node_reused:1; @@ -780,6 +801,22 @@ static inline bool dev_has_sync_state(struct device *dev) return false; } +static inline void dev_set_removable(struct device *dev, + enum device_removable removable) +{ + dev->removable = removable; +} + +static inline bool dev_is_removable(struct device *dev) +{ + return dev->removable == DEVICE_REMOVABLE; +} + +static inline bool dev_removable_is_valid(struct device *dev) +{ + return dev->removable != DEVICE_REMOVABLE_NOT_SUPPORTED; +} + /* * High level routines for use by the bus drivers */ diff --git a/include/linux/usb.h b/include/linux/usb.h index eaae24217e8a..7ccaa76a9a96 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -473,12 +473,6 @@ struct usb_dev_state; struct usb_tt; -enum usb_device_removable { - USB_DEVICE_REMOVABLE_UNKNOWN = 0, - USB_DEVICE_REMOVABLE, - USB_DEVICE_FIXED, -}; - enum usb_port_connect_type { USB_PORT_CONNECT_TYPE_UNKNOWN = 0, USB_PORT_CONNECT_TYPE_HOT_PLUG, @@ -703,7 +697,6 @@ struct usb_device { #endif struct wusb_dev *wusb_dev; int slot_id; - enum usb_device_removable removable; struct usb2_lpm_parameters l1_params; struct usb3_lpm_parameters u1_params; struct usb3_lpm_parameters u2_params; @@ -1485,7 +1478,7 @@ typedef void (*usb_complete_t)(struct urb *); * * Note that transfer_buffer must still be set if the controller * does not support DMA (as indicated by hcd_uses_dma()) and when talking - * to root hub. If you have to trasfer between highmem zone and the device + * to root hub. If you have to transfer between highmem zone and the device * on such controller, create a bounce buffer or bail out with an error. * If transfer_buffer cannot be set (is in highmem) and the controller is DMA * capable, assign NULL to it, so that usbmon knows not to use the value. diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index c71150f2c639..9d2762279286 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -271,7 +271,7 @@ int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, * @bConfigurationValue: Copied into configuration descriptor. * @iConfiguration: Copied into configuration descriptor. * @bmAttributes: Copied into configuration descriptor. - * @MaxPower: Power consumtion in mA. Used to compute bMaxPower in the + * @MaxPower: Power consumption in mA. Used to compute bMaxPower in the * configuration descriptor after considering the bus speed. * @cdev: assigned by @usb_add_config() before calling @bind(); this is * the device associated with this configuration. diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index ee04ef214ce8..8811eb96e5cc 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -197,7 +197,7 @@ struct usb_ep_caps { * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" * @ops: Function pointers used to access hardware-specific operations. * @ep_list:the gadget's ep_list holds all of its endpoints - * @caps:The structure describing types and directions supported by endoint. + * @caps:The structure describing types and directions supported by endpoint. * @enabled: The current endpoint enabled/disabled state. * @claimed: True if this endpoint is claimed by a function. * @maxpacket:The maximum packet size used on this endpoint. The initial diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 96281cd50ff6..548a028f2dab 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -59,7 +59,7 @@ * USB Host Controller Driver (usb_hcd) framework * * Since "struct usb_bus" is so thin, you can't share much code in it. - * This framework is a layer over that, and should be more sharable. + * This framework is a layer over that, and should be more shareable. */ /*-------------------------------------------------------------------------*/ @@ -299,7 +299,7 @@ struct hc_driver { * (optional) these hooks allow an HCD to override the default DMA * mapping and unmapping routines. In general, they shouldn't be * necessary unless the host controller has special DMA requirements, - * such as alignment contraints. If these are not specified, the + * such as alignment constraints. If these are not specified, the * general usb_hcd_(un)?map_urb_for_dma functions will be used instead * (and it may be a good idea to call these functions in your HCD * implementation) @@ -409,7 +409,10 @@ struct hc_driver { int (*find_raw_port_number)(struct usb_hcd *, int); /* Call for power on/off the port if necessary */ int (*port_power)(struct usb_hcd *hcd, int portnum, bool enable); - + /* Call for SINGLE_STEP_SET_FEATURE Test for USB2 EH certification */ +#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06 + int (*submit_single_step_set_feature)(struct usb_hcd *, + struct urb *, int); }; static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd) @@ -474,6 +477,14 @@ int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr, struct platform_device; extern void usb_hcd_platform_shutdown(struct platform_device *dev); +#ifdef CONFIG_USB_HCD_TEST_MODE +extern int ehset_single_step_set_feature(struct usb_hcd *hcd, int port); +#else +static inline int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) +{ + return 0; +} +#endif /* CONFIG_USB_HCD_TEST_MODE */ #ifdef CONFIG_USB_PCI struct pci_dev; diff --git a/include/linux/usb/isp1760.h b/include/linux/usb/isp1760.h deleted file mode 100644 index b75ded28db81..000000000000 --- a/include/linux/usb/isp1760.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * board initialization should put one of these into dev->platform_data - * and place the isp1760 onto platform_bus named "isp1760-hcd". - */ - -#ifndef __LINUX_USB_ISP1760_H -#define __LINUX_USB_ISP1760_H - -struct isp1760_platform_data { - unsigned is_isp1761:1; /* Chip is ISP1761 */ - unsigned bus_width_16:1; /* 16/32-bit data bus width */ - unsigned port1_otg:1; /* Port 1 supports OTG */ - unsigned analog_oc:1; /* Analog overcurrent */ - unsigned dack_polarity_high:1; /* DACK active high */ - unsigned dreq_polarity_high:1; /* DREQ active high */ -}; - -#endif /* __LINUX_USB_ISP1760_H */ diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h index e78eb577d0fa..3aee78dda16d 100644 --- a/include/linux/usb/otg-fsm.h +++ b/include/linux/usb/otg-fsm.h @@ -98,7 +98,7 @@ enum otg_fsm_timer { * @b_bus_req: TRUE during the time that the Application running on the * B-device wants to use the bus * - * Auxilary inputs (OTG v1.3 only. Obsolete now.) + * Auxiliary inputs (OTG v1.3 only. Obsolete now.) * @a_sess_vld: TRUE if the A-device detects that VBUS is above VA_SESS_VLD * @b_bus_suspend: TRUE when the A-device detects that the B-device has put * the bus into suspend @@ -153,7 +153,7 @@ struct otg_fsm { int a_bus_req; int b_bus_req; - /* Auxilary inputs */ + /* Auxiliary inputs */ int a_sess_vld; int b_bus_resume; int b_bus_suspend; @@ -177,7 +177,7 @@ struct otg_fsm { int a_bus_req_inf; int a_clr_err_inf; int b_bus_req_inf; - /* Auxilary informative variables */ + /* Auxiliary informative variables */ int a_suspend_req_inf; /* Timeout indicator for timers */ diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 69f1b6328532..7ceeecbb9e02 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -125,7 +125,7 @@ enum usb_dr_mode { * @dev: Pointer to the given device * * The function gets phy interface string from property 'dr_mode', - * and returns the correspondig enum usb_dr_mode + * and returns the corresponding enum usb_dr_mode */ extern enum usb_dr_mode usb_get_dr_mode(struct device *dev); diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 5e4c497f54d6..eeb7c2157c72 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -32,7 +32,7 @@ #define USB_QUIRK_DELAY_INIT BIT(6) /* - * For high speed and super speed interupt endpoints, the USB 2.0 and + * For high speed and super speed interrupt endpoints, the USB 2.0 and * USB 3.0 spec require the interval in microframes * (1 microframe = 125 microseconds) to be calculated as * interval = 2 ^ (bInterval-1). diff --git a/include/linux/usb/role.h b/include/linux/usb/role.h index 0164fed31b06..031f148ab373 100644 --- a/include/linux/usb/role.h +++ b/include/linux/usb/role.h @@ -65,6 +65,7 @@ void usb_role_switch_unregister(struct usb_role_switch *sw); void usb_role_switch_set_drvdata(struct usb_role_switch *sw, void *data); void *usb_role_switch_get_drvdata(struct usb_role_switch *sw); +const char *usb_role_string(enum usb_role role); #else static inline int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role) @@ -109,6 +110,11 @@ static inline void *usb_role_switch_get_drvdata(struct usb_role_switch *sw) return NULL; } +static inline const char *usb_role_string(enum usb_role role) +{ + return "unknown"; +} + #endif #endif /* __LINUX_USB_ROLE_H */ diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 8c63fa9bfc74..b81eb604e092 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -395,7 +395,7 @@ static inline void usb_serial_debug_data(struct device *dev, } /* - * Macro for reporting errors in write path to avoid inifinite loop + * Macro for reporting errors in write path to avoid infinite loop * when port is used as a console. */ #define dev_err_console(usport, fmt, ...) \ diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index 42fcfbe10590..bffc8d3e14ad 100644 --- a/include/linux/usb/tcpm.h +++ b/include/linux/usb/tcpm.h @@ -66,6 +66,8 @@ enum tcpm_transmit_type { * For example, some tcpcs may include BC1.2 charger detection * and use that in this case. * @set_cc: Called to set value of CC pins + * @apply_rc: Optional; Needed to move TCPCI based chipset to APPLY_RC state + * as stated by the TCPCI specification. * @get_cc: Called to read current CC pin values * @set_polarity: * Called to set polarity @@ -120,6 +122,8 @@ struct tcpc_dev { int (*get_vbus)(struct tcpc_dev *dev); int (*get_current_limit)(struct tcpc_dev *dev); int (*set_cc)(struct tcpc_dev *dev, enum typec_cc_status cc); + int (*apply_rc)(struct tcpc_dev *dev, enum typec_cc_status cc, + enum typec_cc_polarity polarity); int (*get_cc)(struct tcpc_dev *dev, enum typec_cc_status *cc1, enum typec_cc_status *cc2); int (*set_polarity)(struct tcpc_dev *dev, diff --git a/include/linux/usb/typec_dp.h b/include/linux/usb/typec_dp.h index fc4c7edb2e8a..cfb916cccd31 100644 --- a/include/linux/usb/typec_dp.h +++ b/include/linux/usb/typec_dp.h @@ -97,7 +97,7 @@ enum { #define DP_CONF_PIN_ASSIGNEMENT_SHIFT 8 #define DP_CONF_PIN_ASSIGNEMENT_MASK GENMASK(15, 8) -/* Helper for setting/getting the pin assignement value to the configuration */ +/* Helper for setting/getting the pin assignment value to the configuration */ #define DP_CONF_SET_PIN_ASSIGN(_a_) ((_a_) << 8) #define DP_CONF_GET_PIN_ASSIGN(_conf_) (((_conf_) & GENMASK(15, 8)) >> 8) |