diff options
Diffstat (limited to 'drivers/usb')
171 files changed, 1977 insertions, 1224 deletions
diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c index 1f6320d98a76..591d149de8f3 100644 --- a/drivers/usb/cdns3/cdns3-pci-wrap.c +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c @@ -37,8 +37,7 @@ struct cdns3_wrap { #define PCI_DRIVER_NAME "cdns3-pci-usbss" #define PLAT_DRIVER_NAME "cdns-usb3" -#define CDNS_VENDOR_ID 0x17cd -#define CDNS_DEVICE_ID 0x0100 +#define PCI_DEVICE_ID_CDNS_USB3 0x0100 static struct pci_dev *cdns3_get_second_fun(struct pci_dev *pdev) { @@ -190,7 +189,7 @@ static void cdns3_pci_remove(struct pci_dev *pdev) } static const struct pci_device_id cdns3_pci_ids[] = { - { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), }, + { PCI_VDEVICE(CDNS, PCI_DEVICE_ID_CDNS_USB3) }, { 0, } }; diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h index dbee6f085277..84887dfea763 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.h +++ b/drivers/usb/cdns3/cdnsp-gadget.h @@ -811,6 +811,7 @@ struct cdnsp_stream_info { * generate Missed Service Error Event. * Set skip flag when receive a Missed Service Error Event and * process the missed tds on the endpoint ring. + * @wa1_nop_trb: hold pointer to NOP trb. */ struct cdnsp_ep { struct usb_ep endpoint; @@ -838,6 +839,8 @@ struct cdnsp_ep { #define EP_UNCONFIGURED BIT(7) bool skip; + union cdnsp_trb *wa1_nop_trb; + }; /** diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c index 225540fc81ba..2d05368a6745 100644 --- a/drivers/usb/cdns3/cdnsp-pci.c +++ b/drivers/usb/cdns3/cdnsp-pci.c @@ -28,10 +28,11 @@ #define PCI_DRIVER_NAME "cdns-pci-usbssp" #define PLAT_DRIVER_NAME "cdns-usbssp" -#define CDNS_VENDOR_ID 0x17cd -#define CDNS_DEVICE_ID 0x0200 -#define CDNS_DRD_ID 0x0100 -#define CDNS_DRD_IF (PCI_CLASS_SERIAL_USB << 8 | 0x80) +#define PCI_DEVICE_ID_CDNS_USB3 0x0100 +#define PCI_DEVICE_ID_CDNS_UDC 0x0200 + +#define PCI_CLASS_SERIAL_USB_CDNS_USB3 (PCI_CLASS_SERIAL_USB << 8 | 0x80) +#define PCI_CLASS_SERIAL_USB_CDNS_UDC PCI_CLASS_SERIAL_USB_DEVICE static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev) { @@ -40,10 +41,10 @@ static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev) * Platform has two function. The fist keeps resources for * Host/Device while the secon keeps resources for DRD/OTG. */ - if (pdev->device == CDNS_DEVICE_ID) - return pci_get_device(pdev->vendor, CDNS_DRD_ID, NULL); - else if (pdev->device == CDNS_DRD_ID) - return pci_get_device(pdev->vendor, CDNS_DEVICE_ID, NULL); + if (pdev->device == PCI_DEVICE_ID_CDNS_UDC) + return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_USB3, NULL); + if (pdev->device == PCI_DEVICE_ID_CDNS_USB3) + return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_UDC, NULL); return NULL; } @@ -220,12 +221,12 @@ static const struct dev_pm_ops cdnsp_pci_pm_ops = { }; static const struct pci_device_id cdnsp_pci_ids[] = { - { PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_SERIAL_USB_DEVICE, PCI_ANY_ID }, - { PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, - CDNS_DRD_IF, PCI_ANY_ID }, - { PCI_VENDOR_ID_CDNS, CDNS_DRD_ID, PCI_ANY_ID, PCI_ANY_ID, - CDNS_DRD_IF, PCI_ANY_ID }, + { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_UDC), + .class = PCI_CLASS_SERIAL_USB_CDNS_UDC }, + { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_UDC), + .class = PCI_CLASS_SERIAL_USB_CDNS_USB3 }, + { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USB3), + .class = PCI_CLASS_SERIAL_USB_CDNS_USB3 }, { 0, } }; diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c index 02f297f5637d..46852529499d 100644 --- a/drivers/usb/cdns3/cdnsp-ring.c +++ b/drivers/usb/cdns3/cdnsp-ring.c @@ -402,7 +402,7 @@ static u64 cdnsp_get_hw_deq(struct cdnsp_device *pdev, struct cdnsp_stream_ctx *st_ctx; struct cdnsp_ep *pep; - pep = &pdev->eps[stream_id]; + pep = &pdev->eps[ep_index]; if (pep->ep_state & EP_HAS_STREAMS) { st_ctx = &pep->stream_info.stream_ctx_array[stream_id]; @@ -718,7 +718,8 @@ int cdnsp_remove_request(struct cdnsp_device *pdev, seg = cdnsp_trb_in_td(pdev, cur_td->start_seg, cur_td->first_trb, cur_td->last_trb, hw_deq); - if (seg && (pep->ep_state & EP_ENABLED)) + if (seg && (pep->ep_state & EP_ENABLED) && + !(pep->ep_state & EP_DIS_IN_RROGRESS)) cdnsp_find_new_dequeue_state(pdev, pep, preq->request.stream_id, cur_td, &deq_state); else @@ -736,7 +737,8 @@ int cdnsp_remove_request(struct cdnsp_device *pdev, * During disconnecting all endpoint will be disabled so we don't * have to worry about updating dequeue pointer. */ - if (pdev->cdnsp_state & CDNSP_STATE_DISCONNECT_PENDING) { + if (pdev->cdnsp_state & CDNSP_STATE_DISCONNECT_PENDING || + pep->ep_state & EP_DIS_IN_RROGRESS) { status = -ESHUTDOWN; ret = cdnsp_cmd_set_deq(pdev, pep, &deq_state); } @@ -1905,6 +1907,23 @@ int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq) return ret; /* + * workaround 1: STOP EP command on LINK TRB with TC bit set to 1 + * causes that internal cycle bit can have incorrect state after + * command complete. In consequence empty transfer ring can be + * incorrectly detected when EP is resumed. + * NOP TRB before LINK TRB avoid such scenario. STOP EP command is + * then on NOP TRB and internal cycle bit is not changed and have + * correct value. + */ + if (pep->wa1_nop_trb) { + field = le32_to_cpu(pep->wa1_nop_trb->trans_event.flags); + field ^= TRB_CYCLE; + + pep->wa1_nop_trb->trans_event.flags = cpu_to_le32(field); + pep->wa1_nop_trb = NULL; + } + + /* * Don't give the first TRB to the hardware (by toggling the cycle bit) * until we've finished creating all the other TRBs. The ring's cycle * state may change as we enqueue the other TRBs, so save it too. @@ -1999,6 +2018,17 @@ int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq) send_addr = addr; } + if (cdnsp_trb_is_link(ring->enqueue + 1)) { + field = TRB_TYPE(TRB_TR_NOOP) | TRB_IOC; + if (!ring->cycle_state) + field |= TRB_CYCLE; + + pep->wa1_nop_trb = ring->enqueue; + + cdnsp_queue_trb(pdev, ring, 0, 0x0, 0x0, + TRB_INTR_TARGET(0), field); + } + cdnsp_check_trb_math(preq, enqd_len); ret = cdnsp_giveback_first_trb(pdev, pep, preq->request.stream_id, start_cycle, start_trb); diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c index ceca4d839dfd..7ba760ee62e3 100644 --- a/drivers/usb/cdns3/host.c +++ b/drivers/usb/cdns3/host.c @@ -62,7 +62,9 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = { .resume_quirk = xhci_cdns3_resume_quirk, }; -static const struct xhci_plat_priv xhci_plat_cdnsp_xhci; +static const struct xhci_plat_priv xhci_plat_cdnsp_xhci = { + .quirks = XHCI_CDNS_SCTX_QUIRK, +}; static int __cdns_host_init(struct cdns *cdns) { diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index bdc04ce919f7..c64ab0e07ea0 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -128,7 +128,7 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) * In case the fsl,usbmisc property is not present this device doesn't * need usbmisc. Return NULL (which is no error here) */ - if (!of_get_property(np, "fsl,usbmisc", NULL)) + if (!of_property_present(np, "fsl,usbmisc")) return NULL; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); diff --git a/drivers/usb/chipidea/ci_hdrc_npcm.c b/drivers/usb/chipidea/ci_hdrc_npcm.c index b14127873c55..3e5e05dbda89 100644 --- a/drivers/usb/chipidea/ci_hdrc_npcm.c +++ b/drivers/usb/chipidea/ci_hdrc_npcm.c @@ -18,7 +18,7 @@ struct npcm_udc_data { struct ci_hdrc_platform_data pdata; }; -static int npcm_udc_notify_event(struct ci_hdrc *ci, unsigned event) +static int npcm_udc_notify_event(struct ci_hdrc *ci, unsigned int event) { struct device *dev = ci->dev->parent; @@ -28,7 +28,7 @@ static int npcm_udc_notify_event(struct ci_hdrc *ci, unsigned event) hw_write(ci, OP_USBMODE, 0xffffffff, 0x0); break; default: - dev_dbg(dev, "unknown ci_hdrc event (%d)\n",event); + dev_dbg(dev, "unknown ci_hdrc event (%d)\n", event); break; } diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 2d7f616270c1..69ef3cd8d4f8 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -86,7 +86,7 @@ static int hw_device_state(struct ci_hdrc *ci, u32 dma) hw_write(ci, OP_ENDPTLISTADDR, ~0, dma); /* interrupt, error, port change, reset, sleep/suspend */ hw_write(ci, OP_USBINTR, ~0, - USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); + USBi_UI|USBi_UEI|USBi_PCI|USBi_URI); } else { hw_write(ci, OP_USBINTR, ~0, 0); } @@ -877,6 +877,7 @@ __releases(ci->lock) __acquires(ci->lock) { int retval; + u32 intr; spin_unlock(&ci->lock); if (ci->gadget.speed != USB_SPEED_UNKNOWN) @@ -890,6 +891,11 @@ __acquires(ci->lock) if (retval) goto done; + /* clear SLI */ + hw_write(ci, OP_USBSTS, USBi_SLI, USBi_SLI); + intr = hw_read(ci, OP_USBINTR, ~0); + hw_write(ci, OP_USBINTR, ~0, intr | USBi_SLI); + ci->status = usb_ep_alloc_request(&ci->ep0in->ep, GFP_ATOMIC); if (ci->status == NULL) retval = -ENOMEM; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 0e7439dba8fe..605fea461102 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -962,10 +962,12 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) struct acm *acm = tty->driver_data; ss->line = acm->minor; + mutex_lock(&acm->port.mutex); ss->close_delay = jiffies_to_msecs(acm->port.close_delay) / 10; ss->closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : jiffies_to_msecs(acm->port.closing_wait) / 10; + mutex_unlock(&acm->port.mutex); return 0; } @@ -1761,6 +1763,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */ .driver_info = SINGLE_RX_URB, }, + { USB_DEVICE(0x1901, 0x0006), /* GE Healthcare Patient Monitor UI Controller */ + .driver_info = DISABLE_ECHO, /* DISABLE ECHO in termios flag */ + }, { USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 6bd9fe565385..34e46ef308ab 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -754,7 +754,7 @@ static struct urb *usbtmc_create_urb(void) if (!urb) return NULL; - dmabuf = kmalloc(bufsize, GFP_KERNEL); + dmabuf = kzalloc(bufsize, GFP_KERNEL); if (!dmabuf) { usb_free_urb(urb); return NULL; diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index 59b55d6cf490..b7bea1015d7c 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -107,19 +107,18 @@ EXPORT_SYMBOL_GPL(usb_speed_string); */ enum usb_device_speed usb_get_maximum_speed(struct device *dev) { - const char *maximum_speed; + const char *p = "maximum-speed"; int ret; - ret = device_property_read_string(dev, "maximum-speed", &maximum_speed); - if (ret < 0) - return USB_SPEED_UNKNOWN; - - ret = match_string(ssp_rate, ARRAY_SIZE(ssp_rate), maximum_speed); + ret = device_property_match_property_string(dev, p, ssp_rate, ARRAY_SIZE(ssp_rate)); if (ret > 0) return USB_SPEED_SUPER_PLUS; - ret = match_string(speed_names, ARRAY_SIZE(speed_names), maximum_speed); - return (ret < 0) ? USB_SPEED_UNKNOWN : ret; + ret = device_property_match_property_string(dev, p, speed_names, ARRAY_SIZE(speed_names)); + if (ret > 0) + return ret; + + return USB_SPEED_UNKNOWN; } EXPORT_SYMBOL_GPL(usb_get_maximum_speed); @@ -276,14 +275,13 @@ EXPORT_SYMBOL_GPL(usb_decode_interval); */ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0) { - struct device_node *controller = NULL; + struct device_node *controller; struct of_phandle_args args; const char *dr_mode; int index; int err; - do { - controller = of_find_node_with_property(controller, "phys"); + for_each_node_with_property(controller, "phys") { if (!of_device_is_available(controller)) continue; index = 0; @@ -306,7 +304,7 @@ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0) goto finish; index++; } while (args.np); - } while (controller); + } finish: err = of_property_read_string(controller, "dr_mode", &dr_mode); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index d83231d6736a..61b6d978892c 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -670,6 +670,7 @@ static int add_power_attributes(struct device *dev) static void remove_power_attributes(struct device *dev) { + sysfs_unmerge_group(&dev->kobj, &usb3_hardware_lpm_attr_group); sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group); sysfs_unmerge_group(&dev->kobj, &power_attr_group); } diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 7f8a912d4fe2..21585ed89ef8 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -142,6 +142,53 @@ int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable) } EXPORT_SYMBOL_GPL(usb_acpi_set_power_state); +/** + * usb_acpi_add_usb4_devlink - add device link to USB4 Host Interface for tunneled USB3 devices + * + * @udev: Tunneled USB3 device connected to a roothub. + * + * Adds a device link between a tunneled USB3 device and the USB4 Host Interface + * device to ensure correct runtime PM suspend and resume order. This function + * should only be called for tunneled USB3 devices. + * The USB4 Host Interface this tunneled device depends on is found from the roothub + * port ACPI device specific data _DSD entry. + * + * Return: negative error code on failure, 0 otherwise + */ +static int usb_acpi_add_usb4_devlink(struct usb_device *udev) +{ + const struct device_link *link; + struct usb_port *port_dev; + struct usb_hub *hub; + + if (!udev->parent || udev->parent->parent) + return 0; + + hub = usb_hub_to_struct_hub(udev->parent); + port_dev = hub->ports[udev->portnum - 1]; + + struct fwnode_handle *nhi_fwnode __free(fwnode_handle) = + fwnode_find_reference(dev_fwnode(&port_dev->dev), "usb4-host-interface", 0); + + if (IS_ERR(nhi_fwnode)) + return 0; + + link = device_link_add(&port_dev->child->dev, nhi_fwnode->dev, + DL_FLAG_AUTOREMOVE_CONSUMER | + DL_FLAG_RPM_ACTIVE | + DL_FLAG_PM_RUNTIME); + if (!link) { + dev_err(&port_dev->dev, "Failed to created device link from %s to %s\n", + dev_name(&port_dev->child->dev), dev_name(nhi_fwnode->dev)); + return -EINVAL; + } + + dev_dbg(&port_dev->dev, "Created device link from %s to %s\n", + dev_name(&port_dev->child->dev), dev_name(nhi_fwnode->dev)); + + return 0; +} + /* * Private to usb-acpi, all the core needs to know is that * port_dev->location is non-zero when it has been set by the firmware. @@ -262,6 +309,12 @@ usb_acpi_find_companion_for_device(struct usb_device *udev) if (!hub) return NULL; + + /* Tunneled USB3 devices depend on USB4 Host Interface, set device link to it */ + if (udev->speed >= USB_SPEED_SUPER && + udev->tunnel_mode != USB_LINK_NATIVE) + usb_acpi_add_usb4_devlink(udev); + /* * This is an embedded USB device connected to a port and such * devices share port's ACPI companion. diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index 7c82ab590401..3116ac72747f 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -702,6 +702,7 @@ static int params_show(struct seq_file *seq, void *v) print_param(seq, p, uframe_sched); print_param(seq, p, external_id_pin_ctl); print_param(seq, p, power_down); + print_param(seq, p, no_clock_gating); print_param(seq, p, lpm); print_param(seq, p, lpm_clock_gating); print_param(seq, p, besl); diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c index a8605b02115b..1ad8fa3f862a 100644 --- a/drivers/usb/dwc2/drd.c +++ b/drivers/usb/dwc2/drd.c @@ -127,6 +127,15 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) role = USB_ROLE_DEVICE; } + if ((IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || + IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)) && + dwc2_is_device_mode(hsotg) && + hsotg->lx_state == DWC2_L2 && + hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && + hsotg->bus_suspended && + !hsotg->params.no_clock_gating) + dwc2_gadget_exit_clock_gating(hsotg, 0); + if (role == USB_ROLE_HOST) { already = dwc2_ovr_avalid(hsotg, true); } else if (role == USB_ROLE_DEVICE) { diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index a937eadbc9b3..68226defdc60 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -23,6 +23,7 @@ static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg) p->max_transfer_size = 65535; p->max_packet_count = 511; p->ahbcfg = 0x10; + p->no_clock_gating = true; } static void dwc2_set_his_params(struct dwc2_hsotg *hsotg) @@ -352,6 +353,7 @@ const struct of_device_id dwc2_of_match_table[] = { MODULE_DEVICE_TABLE(of, dwc2_of_match_table); const struct acpi_device_id dwc2_acpi_match[] = { + /* This ID refers to the same USB IP as of_device_id brcm,bcm2835-usb */ { "BCM2848", (kernel_ulong_t)dwc2_set_bcm_params }, { }, }; diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 7b84416dfc2b..c1b7209b9483 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -469,18 +469,6 @@ static int dwc2_driver_probe(struct platform_device *dev) spin_lock_init(&hsotg->lock); - hsotg->irq = platform_get_irq(dev, 0); - if (hsotg->irq < 0) - return hsotg->irq; - - dev_dbg(hsotg->dev, "registering common handler for irq%d\n", - hsotg->irq); - retval = devm_request_irq(hsotg->dev, hsotg->irq, - dwc2_handle_common_intr, IRQF_SHARED, - dev_name(hsotg->dev), hsotg); - if (retval) - return retval; - hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); if (IS_ERR(hsotg->vbus_supply)) { retval = PTR_ERR(hsotg->vbus_supply); @@ -524,6 +512,20 @@ static int dwc2_driver_probe(struct platform_device *dev) if (retval) goto error; + hsotg->irq = platform_get_irq(dev, 0); + if (hsotg->irq < 0) { + retval = hsotg->irq; + goto error; + } + + dev_dbg(hsotg->dev, "registering common handler for irq%d\n", + hsotg->irq); + retval = devm_request_irq(hsotg->dev, hsotg->irq, + dwc2_handle_common_intr, IRQF_SHARED, + dev_name(hsotg->dev), hsotg); + if (retval) + goto error; + /* * For OTG cores, set the force mode bits to reflect the value * of dr_mode. Force mode bits should not be touched at any diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 734de2a8bd21..9eb085f359ce 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -564,9 +564,17 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc) void dwc3_event_buffers_cleanup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; + u32 reg; if (!dwc->ev_buf) return; + /* + * Exynos platforms may not be able to access event buffer if the + * controller failed to halt on dwc3_core_exit(). + */ + reg = dwc3_readl(dwc->regs, DWC3_DSTS); + if (!(reg & DWC3_DSTS_DEVCTRLHLT)) + return; evt = dwc->ev_buf; @@ -1379,6 +1387,21 @@ static int dwc3_core_init(struct dwc3 *dwc) } /* + * STAR 9001285599: This issue affects DWC_usb3 version 3.20a + * only. If the PM TIMER ECM is enabled through GUCTL2[19], the + * link compliance test (TD7.21) may fail. If the ECN is not + * enabled (GUCTL2[19] = 0), the controller will use the old timer + * value (5us), which is still acceptable for the link compliance + * test. Therefore, do not enable PM TIMER ECM in 3.20a by + * setting GUCTL2[19] by default; instead, use GUCTL2[19] = 0. + */ + if (DWC3_VER_IS(DWC3, 320A)) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); + reg &= ~DWC3_GUCTL2_LC_TIMER; + dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); + } + + /* * When configured in HOST mode, after issuing U3/L2 exit controller * fails to send proper CRC checksum in CRC5 feild. Because of this * behaviour Transaction Error is generated, resulting in reset and diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 1e561fd8b86e..c71240e8f7c7 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -421,6 +421,7 @@ /* Global User Control Register 2 */ #define DWC3_GUCTL2_RST_ACTBITLATER BIT(14) +#define DWC3_GUCTL2_LC_TIMER BIT(19) /* Global User Control Register 3 */ #define DWC3_GUCTL3_SPLITDISABLE BIT(14) @@ -1269,6 +1270,7 @@ struct dwc3 { #define DWC3_REVISION_290A 0x5533290a #define DWC3_REVISION_300A 0x5533300a #define DWC3_REVISION_310A 0x5533310a +#define DWC3_REVISION_320A 0x5533320a #define DWC3_REVISION_330A 0x5533330a #define DWC31_REVISION_ANY 0x0 diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c index 8ee448068503..64c0cd1995aa 100644 --- a/drivers/usb/dwc3/dwc3-imx8mp.c +++ b/drivers/usb/dwc3/dwc3-imx8mp.c @@ -5,6 +5,7 @@ * Copyright (c) 2020 NXP. */ +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -96,7 +97,8 @@ static void imx8mp_configure_glue(struct dwc3_imx8mp *dwc3_imx) writel(value, dwc3_imx->glue_base + USB_CTRL1); } -static void dwc3_imx8mp_wakeup_enable(struct dwc3_imx8mp *dwc3_imx) +static void dwc3_imx8mp_wakeup_enable(struct dwc3_imx8mp *dwc3_imx, + pm_message_t msg) { struct dwc3 *dwc3 = platform_get_drvdata(dwc3_imx->dwc3); u32 val; @@ -106,12 +108,14 @@ static void dwc3_imx8mp_wakeup_enable(struct dwc3_imx8mp *dwc3_imx) val = readl(dwc3_imx->hsio_blk_base + USB_WAKEUP_CTRL); - if ((dwc3->current_dr_role == DWC3_GCTL_PRTCAP_HOST) && dwc3->xhci) - val |= USB_WAKEUP_EN | USB_WAKEUP_SS_CONN | - USB_WAKEUP_U3_EN | USB_WAKEUP_DPDM_EN; - else if (dwc3->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE) + if ((dwc3->current_dr_role == DWC3_GCTL_PRTCAP_HOST) && dwc3->xhci) { + val |= USB_WAKEUP_EN | USB_WAKEUP_DPDM_EN; + if (PMSG_IS_AUTO(msg)) + val |= USB_WAKEUP_SS_CONN | USB_WAKEUP_U3_EN; + } else { val |= USB_WAKEUP_EN | USB_WAKEUP_VBUS_EN | USB_WAKEUP_VBUS_SRC_SESS_VAL; + } writel(val, dwc3_imx->hsio_blk_base + USB_WAKEUP_CTRL); } @@ -144,10 +148,21 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx) return IRQ_HANDLED; } +static int dwc3_imx8mp_set_software_node(struct device *dev) +{ + struct property_entry props[3] = { 0 }; + int prop_idx = 0; + + props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-missing-cas-quirk"); + props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-skip-phy-init-quirk"); + + return device_create_managed_software_node(dev, props, NULL); +} + static int dwc3_imx8mp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *dwc3_np, *node = dev->of_node; + struct device_node *node = dev->of_node; struct dwc3_imx8mp *dwc3_imx; struct resource *res; int err, irq; @@ -178,39 +193,26 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) return PTR_ERR(dwc3_imx->glue_base); } - dwc3_imx->hsio_clk = devm_clk_get(dev, "hsio"); - if (IS_ERR(dwc3_imx->hsio_clk)) { - err = PTR_ERR(dwc3_imx->hsio_clk); - dev_err(dev, "Failed to get hsio clk, err=%d\n", err); - return err; - } - - err = clk_prepare_enable(dwc3_imx->hsio_clk); - if (err) { - dev_err(dev, "Failed to enable hsio clk, err=%d\n", err); - return err; - } - - dwc3_imx->suspend_clk = devm_clk_get(dev, "suspend"); - if (IS_ERR(dwc3_imx->suspend_clk)) { - err = PTR_ERR(dwc3_imx->suspend_clk); - dev_err(dev, "Failed to get suspend clk, err=%d\n", err); - goto disable_hsio_clk; - } + dwc3_imx->hsio_clk = devm_clk_get_enabled(dev, "hsio"); + if (IS_ERR(dwc3_imx->hsio_clk)) + return dev_err_probe(dev, PTR_ERR(dwc3_imx->hsio_clk), + "Failed to get hsio clk\n"); - err = clk_prepare_enable(dwc3_imx->suspend_clk); - if (err) { - dev_err(dev, "Failed to enable suspend clk, err=%d\n", err); - goto disable_hsio_clk; - } + dwc3_imx->suspend_clk = devm_clk_get_enabled(dev, "suspend"); + if (IS_ERR(dwc3_imx->suspend_clk)) + return dev_err_probe(dev, PTR_ERR(dwc3_imx->suspend_clk), + "Failed to get suspend clk\n"); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - err = irq; - goto disable_clks; - } + if (irq < 0) + return irq; dwc3_imx->irq = irq; + struct device_node *dwc3_np __free(device_node) = of_get_compatible_child(node, + "snps,dwc3"); + if (!dwc3_np) + return dev_err_probe(dev, -ENODEV, "failed to find dwc3 core child\n"); + imx8mp_configure_glue(dwc3_imx); pm_runtime_set_active(dev); @@ -219,17 +221,17 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) if (err < 0) goto disable_rpm; - dwc3_np = of_get_compatible_child(node, "snps,dwc3"); - if (!dwc3_np) { + err = dwc3_imx8mp_set_software_node(dev); + if (err) { err = -ENODEV; - dev_err(dev, "failed to find dwc3 core child\n"); + dev_err(dev, "failed to create software node\n"); goto disable_rpm; } err = of_platform_populate(node, NULL, NULL, dev); if (err) { dev_err(&pdev->dev, "failed to create dwc3 core\n"); - goto err_node_put; + goto disable_rpm; } dwc3_imx->dwc3 = of_find_device_by_node(dwc3_np); @@ -238,7 +240,6 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) err = -ENODEV; goto depopulate; } - of_node_put(dwc3_np); err = devm_request_threaded_irq(dev, irq, NULL, dwc3_imx8mp_interrupt, IRQF_ONESHOT, dev_name(dev), dwc3_imx); @@ -254,51 +255,39 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) depopulate: of_platform_depopulate(dev); -err_node_put: - of_node_put(dwc3_np); disable_rpm: pm_runtime_disable(dev); pm_runtime_put_noidle(dev); -disable_clks: - clk_disable_unprepare(dwc3_imx->suspend_clk); -disable_hsio_clk: - clk_disable_unprepare(dwc3_imx->hsio_clk); return err; } static void dwc3_imx8mp_remove(struct platform_device *pdev) { - struct dwc3_imx8mp *dwc3_imx = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; pm_runtime_get_sync(dev); of_platform_depopulate(dev); - clk_disable_unprepare(dwc3_imx->suspend_clk); - clk_disable_unprepare(dwc3_imx->hsio_clk); - pm_runtime_disable(dev); pm_runtime_put_noidle(dev); } -static int __maybe_unused dwc3_imx8mp_suspend(struct dwc3_imx8mp *dwc3_imx, - pm_message_t msg) +static int dwc3_imx8mp_suspend(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg) { if (dwc3_imx->pm_suspended) return 0; /* Wakeup enable */ if (PMSG_IS_AUTO(msg) || device_may_wakeup(dwc3_imx->dev)) - dwc3_imx8mp_wakeup_enable(dwc3_imx); + dwc3_imx8mp_wakeup_enable(dwc3_imx, msg); dwc3_imx->pm_suspended = true; return 0; } -static int __maybe_unused dwc3_imx8mp_resume(struct dwc3_imx8mp *dwc3_imx, - pm_message_t msg) +static int dwc3_imx8mp_resume(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg) { struct dwc3 *dwc = platform_get_drvdata(dwc3_imx->dwc3); int ret = 0; @@ -331,7 +320,7 @@ static int __maybe_unused dwc3_imx8mp_resume(struct dwc3_imx8mp *dwc3_imx, return ret; } -static int __maybe_unused dwc3_imx8mp_pm_suspend(struct device *dev) +static int dwc3_imx8mp_pm_suspend(struct device *dev) { struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); int ret; @@ -349,7 +338,7 @@ static int __maybe_unused dwc3_imx8mp_pm_suspend(struct device *dev) return ret; } -static int __maybe_unused dwc3_imx8mp_pm_resume(struct device *dev) +static int dwc3_imx8mp_pm_resume(struct device *dev) { struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); int ret; @@ -379,7 +368,7 @@ static int __maybe_unused dwc3_imx8mp_pm_resume(struct device *dev) return ret; } -static int __maybe_unused dwc3_imx8mp_runtime_suspend(struct device *dev) +static int dwc3_imx8mp_runtime_suspend(struct device *dev) { struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); @@ -388,7 +377,7 @@ static int __maybe_unused dwc3_imx8mp_runtime_suspend(struct device *dev) return dwc3_imx8mp_suspend(dwc3_imx, PMSG_AUTO_SUSPEND); } -static int __maybe_unused dwc3_imx8mp_runtime_resume(struct device *dev) +static int dwc3_imx8mp_runtime_resume(struct device *dev) { struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); @@ -398,9 +387,9 @@ static int __maybe_unused dwc3_imx8mp_runtime_resume(struct device *dev) } static const struct dev_pm_ops dwc3_imx8mp_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dwc3_imx8mp_pm_suspend, dwc3_imx8mp_pm_resume) - SET_RUNTIME_PM_OPS(dwc3_imx8mp_runtime_suspend, - dwc3_imx8mp_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(dwc3_imx8mp_pm_suspend, dwc3_imx8mp_pm_resume) + RUNTIME_PM_OPS(dwc3_imx8mp_runtime_suspend, dwc3_imx8mp_runtime_resume, + NULL) }; static const struct of_device_id dwc3_imx8mp_of_match[] = { @@ -414,7 +403,7 @@ static struct platform_driver dwc3_imx8mp_driver = { .remove_new = dwc3_imx8mp_remove, .driver = { .name = "imx8mp-dwc3", - .pm = &dwc3_imx8mp_dev_pm_ops, + .pm = pm_ptr(&dwc3_imx8mp_dev_pm_ops), .of_match_table = dwc3_imx8mp_of_match, }, }; diff --git a/drivers/usb/dwc3/dwc3-octeon.c b/drivers/usb/dwc3/dwc3-octeon.c index 6010135e1acc..1a3b205367fd 100644 --- a/drivers/usb/dwc3/dwc3-octeon.c +++ b/drivers/usb/dwc3/dwc3-octeon.c @@ -419,7 +419,7 @@ static int dwc3_octeon_probe(struct platform_device *pdev) int ref_clk_sel, ref_clk_fsel, mpll_mul; int power_active_low, power_gpio; int err, len; - u32 clock_rate; + u32 clock_rate, gpio_pwr[3]; if (of_property_read_u32(node, "refclk-frequency", &clock_rate)) { dev_err(dev, "No UCTL \"refclk-frequency\"\n"); @@ -476,21 +476,10 @@ static int dwc3_octeon_probe(struct platform_device *pdev) power_gpio = DWC3_GPIO_POWER_NONE; power_active_low = 0; - if (of_find_property(node, "power", &len)) { - u32 gpio_pwr[3]; - - switch (len) { - case 8: - of_property_read_u32_array(node, "power", gpio_pwr, 2); - break; - case 12: - of_property_read_u32_array(node, "power", gpio_pwr, 3); + len = of_property_read_variable_u32_array(node, "power", gpio_pwr, 2, 3); + if (len > 0) { + if (len == 3) power_active_low = gpio_pwr[2] & 0x01; - break; - default: - dev_err(dev, "invalid power configuration\n"); - return -EINVAL; - } power_gpio = gpio_pwr[1]; } diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index d5c77db4daa9..2a11fc0ee84f 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -522,11 +522,13 @@ static int dwc3_omap_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "failed to request IRQ #%d --> %d\n", omap->irq, ret); - goto err1; + goto err2; } dwc3_omap_enable_irqs(omap); return 0; +err2: + of_platform_depopulate(dev); err1: pm_runtime_put_sync(dev); pm_runtime_disable(dev); diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 88fb6706a18d..c1d4b52f25b0 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -4,6 +4,7 @@ * Inspired by dwc3-of-simple.c */ +#include <linux/cleanup.h> #include <linux/io.h> #include <linux/of.h> #include <linux/clk.h> @@ -702,11 +703,12 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count) static int dwc3_qcom_of_register_core(struct platform_device *pdev) { struct dwc3_qcom *qcom = platform_get_drvdata(pdev); - struct device_node *np = pdev->dev.of_node, *dwc3_np; + struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; int ret; - dwc3_np = of_get_compatible_child(np, "snps,dwc3"); + struct device_node *dwc3_np __free(device_node) = of_get_compatible_child(np, + "snps,dwc3"); if (!dwc3_np) { dev_err(dev, "failed to find dwc3 core child\n"); return -ENODEV; @@ -715,7 +717,7 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev) ret = of_platform_populate(np, NULL, NULL, dev); if (ret) { dev_err(dev, "failed to register dwc3 core - %d\n", ret); - goto node_put; + return ret; } qcom->dwc3 = of_find_device_by_node(dwc3_np); @@ -725,9 +727,6 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev) of_platform_depopulate(dev); } -node_put: - of_node_put(dwc3_np); - return ret; } @@ -736,7 +735,6 @@ static int dwc3_qcom_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct dwc3_qcom *qcom; - struct resource *res; int ret, i; bool ignore_pipe_clk; bool wakeup_source; @@ -774,9 +772,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev) goto reset_assert; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - qcom->qscratch_base = devm_ioremap_resource(dev, res); + qcom->qscratch_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(qcom->qscratch_base)) { ret = PTR_ERR(qcom->qscratch_base); goto clk_disable; diff --git a/drivers/usb/dwc3/dwc3-rtk.c b/drivers/usb/dwc3/dwc3-rtk.c index 3cd6b184551c..e9c8b032c72c 100644 --- a/drivers/usb/dwc3/dwc3-rtk.c +++ b/drivers/usb/dwc3/dwc3-rtk.c @@ -6,6 +6,7 @@ * */ +#include <linux/cleanup.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/platform_device.h> @@ -173,23 +174,20 @@ static const char *const speed_names[] = { static enum usb_device_speed __get_dwc3_maximum_speed(struct device_node *np) { - struct device_node *dwc3_np; const char *maximum_speed; int ret; - dwc3_np = of_get_compatible_child(np, "snps,dwc3"); + struct device_node *dwc3_np __free(device_node) = of_get_compatible_child(np, + "snps,dwc3"); if (!dwc3_np) return USB_SPEED_UNKNOWN; ret = of_property_read_string(dwc3_np, "maximum-speed", &maximum_speed); if (ret < 0) - goto out; + return USB_SPEED_UNKNOWN; ret = match_string(speed_names, ARRAY_SIZE(speed_names), maximum_speed); -out: - of_node_put(dwc3_np); - return (ret < 0) ? USB_SPEED_UNKNOWN : ret; } @@ -276,7 +274,6 @@ static int dwc3_rtk_probe_dwc3_core(struct dwc3_rtk *rtk) struct device_node *node = dev->of_node; struct platform_device *dwc3_pdev; struct device *dwc3_dev; - struct device_node *dwc3_node; enum usb_dr_mode dr_mode; int ret = 0; @@ -290,7 +287,8 @@ static int dwc3_rtk_probe_dwc3_core(struct dwc3_rtk *rtk) return ret; } - dwc3_node = of_get_compatible_child(node, "snps,dwc3"); + struct device_node *dwc3_node __free(device_node) = of_get_compatible_child(node, + "snps,dwc3"); if (!dwc3_node) { dev_err(dev, "failed to find dwc3 core node\n"); ret = -ENODEV; @@ -301,7 +299,7 @@ static int dwc3_rtk_probe_dwc3_core(struct dwc3_rtk *rtk) if (!dwc3_pdev) { dev_err(dev, "failed to find dwc3 core platform_device\n"); ret = -ENODEV; - goto err_node_put; + goto depopulate; } dwc3_dev = &dwc3_pdev->dev; @@ -343,14 +341,11 @@ static int dwc3_rtk_probe_dwc3_core(struct dwc3_rtk *rtk) switch_usb2_role(rtk, rtk->cur_role); platform_device_put(dwc3_pdev); - of_node_put(dwc3_node); return 0; err_pdev_put: platform_device_put(dwc3_pdev); -err_node_put: - of_node_put(dwc3_node); depopulate: of_platform_depopulate(dev); @@ -363,30 +358,18 @@ static int dwc3_rtk_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *res; void __iomem *regs; - int ret = 0; rtk = devm_kzalloc(dev, sizeof(*rtk), GFP_KERNEL); - if (!rtk) { - ret = -ENOMEM; - goto out; - } + if (!rtk) + return -ENOMEM; platform_set_drvdata(pdev, rtk); rtk->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing memory resource\n"); - ret = -ENODEV; - goto out; - } - - regs = devm_ioremap_resource(dev, res); - if (IS_ERR(regs)) { - ret = PTR_ERR(regs); - goto out; - } + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(regs)) + return PTR_ERR(regs); rtk->regs = regs; rtk->regs_size = resource_size(res); @@ -394,16 +377,11 @@ static int dwc3_rtk_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) { rtk->pm_base = devm_ioremap_resource(dev, res); - if (IS_ERR(rtk->pm_base)) { - ret = PTR_ERR(rtk->pm_base); - goto out; - } + if (IS_ERR(rtk->pm_base)) + return PTR_ERR(rtk->pm_base); } - ret = dwc3_rtk_probe_dwc3_core(rtk); - -out: - return ret; + return dwc3_rtk_probe_dwc3_core(rtk); } static void dwc3_rtk_remove(struct platform_device *pdev) diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index 211360eee95a..2841021f3557 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -14,6 +14,7 @@ * Inspired by dwc3-omap.c and dwc3-exynos.c. */ +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -197,7 +198,7 @@ static int st_dwc3_probe(struct platform_device *pdev) struct st_dwc3 *dwc3_data; struct resource *res; struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node, *child; + struct device_node *node = dev->of_node; struct platform_device *child_pdev; struct regmap *regmap; int ret; @@ -219,23 +220,26 @@ static int st_dwc3_probe(struct platform_device *pdev) dwc3_data->regmap = regmap; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "syscfg-reg"); - if (!res) { - ret = -ENXIO; - goto undo_platform_dev_alloc; - } + if (!res) + return -ENXIO; dwc3_data->syscfg_reg_off = res->start; - dev_vdbg(&pdev->dev, "glue-logic addr 0x%pK, syscfg-reg offset 0x%x\n", + dev_vdbg(dev, "glue-logic addr 0x%pK, syscfg-reg offset 0x%x\n", dwc3_data->glue_base, dwc3_data->syscfg_reg_off); + struct device_node *child __free(device_node) = of_get_compatible_child(node, + "snps,dwc3"); + if (!child) { + dev_err(dev, "failed to find dwc3 core node\n"); + return -ENODEV; + } + dwc3_data->rstc_pwrdn = devm_reset_control_get_exclusive(dev, "powerdown"); - if (IS_ERR(dwc3_data->rstc_pwrdn)) { - dev_err(&pdev->dev, "could not get power controller\n"); - ret = PTR_ERR(dwc3_data->rstc_pwrdn); - goto undo_platform_dev_alloc; - } + if (IS_ERR(dwc3_data->rstc_pwrdn)) + return dev_err_probe(dev, PTR_ERR(dwc3_data->rstc_pwrdn), + "could not get power controller\n"); /* Manage PowerDown */ reset_control_deassert(dwc3_data->rstc_pwrdn); @@ -243,37 +247,29 @@ static int st_dwc3_probe(struct platform_device *pdev) dwc3_data->rstc_rst = devm_reset_control_get_shared(dev, "softreset"); if (IS_ERR(dwc3_data->rstc_rst)) { - dev_err(&pdev->dev, "could not get reset controller\n"); - ret = PTR_ERR(dwc3_data->rstc_rst); + ret = dev_err_probe(dev, PTR_ERR(dwc3_data->rstc_rst), + "could not get reset controller\n"); goto undo_powerdown; } /* Manage SoftReset */ reset_control_deassert(dwc3_data->rstc_rst); - child = of_get_compatible_child(node, "snps,dwc3"); - if (!child) { - dev_err(&pdev->dev, "failed to find dwc3 core node\n"); - ret = -ENODEV; - goto err_node_put; - } - /* Allocate and initialize the core */ ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { dev_err(dev, "failed to add dwc3 core\n"); - goto err_node_put; + goto undo_softreset; } child_pdev = of_find_device_by_node(child); if (!child_pdev) { dev_err(dev, "failed to find dwc3 core device\n"); ret = -ENODEV; - goto err_node_put; + goto depopulate; } dwc3_data->dr_mode = usb_get_dr_mode(&child_pdev->dev); - of_node_put(child); platform_device_put(child_pdev); /* @@ -285,7 +281,7 @@ static int st_dwc3_probe(struct platform_device *pdev) ret = st_dwc3_drd_init(dwc3_data); if (ret) { dev_err(dev, "drd initialisation failed\n"); - goto undo_softreset; + goto depopulate; } /* ST glue logic init */ @@ -294,14 +290,12 @@ static int st_dwc3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dwc3_data); return 0; -err_node_put: - of_node_put(child); +depopulate: + of_platform_depopulate(dev); undo_softreset: reset_control_assert(dwc3_data->rstc_rst); undo_powerdown: reset_control_assert(dwc3_data->rstc_pwrdn); -undo_platform_dev_alloc: - platform_device_put(pdev); return ret; } diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c index bb4d894c16e9..b5e5be424ce9 100644 --- a/drivers/usb/dwc3/dwc3-xilinx.c +++ b/drivers/usb/dwc3/dwc3-xilinx.c @@ -285,11 +285,8 @@ static int dwc3_xlnx_probe(struct platform_device *pdev) return -ENOMEM; regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(regs)) { - ret = PTR_ERR(regs); - dev_err_probe(dev, ret, "failed to map registers\n"); - return ret; - } + if (IS_ERR(regs)) + return dev_err_probe(dev, PTR_ERR(regs), "failed to map registers\n"); match = of_match_node(dwc3_xlnx_of_match, pdev->dev.of_node); @@ -327,9 +324,14 @@ static int dwc3_xlnx_probe(struct platform_device *pdev) goto err_pm_set_suspended; pm_suspend_ignore_children(dev, false); - return pm_runtime_resume_and_get(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + goto err_pm_set_suspended; + + return 0; err_pm_set_suspended: + of_platform_depopulate(dev); pm_runtime_set_suspended(dev); err_clk_put: diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index d96ffbe52039..c9533a99e47c 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -232,7 +232,8 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) /* stall is always issued on EP0 */ dep = dwc->eps[0]; __dwc3_gadget_ep_set_halt(dep, 1, false); - dep->flags = DWC3_EP_ENABLED; + dep->flags &= DWC3_EP_RESOURCE_ALLOCATED; + dep->flags |= DWC3_EP_ENABLED; dwc->delayed_status = false; if (!list_empty(&dep->pending_list)) { diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 89fc690fdf34..291bc549935b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -287,6 +287,23 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async); * * Caller should handle locking. This function will issue @cmd with given * @params to @dep and wait for its completion. + * + * According to the programming guide, if the link state is in L1/L2/U3, + * then sending the Start Transfer command may not complete. The + * programming guide suggested to bring the link state back to ON/U0 by + * performing remote wakeup prior to sending the command. However, don't + * initiate remote wakeup when the user/function does not send wakeup + * request via wakeup ops. Send the command when it's allowed. + * + * Notes: + * For L1 link state, issuing a command requires the clearing of + * GUSB2PHYCFG.SUSPENDUSB2, which turns on the signal required to complete + * the given command (usually within 50us). This should happen within the + * command timeout set by driver. No additional step is needed. + * + * For L2 or U3 link state, the gadget is in USB suspend. Care should be + * taken when sending Start Transfer command to ensure that it's done after + * USB resume. */ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, struct dwc3_gadget_ep_cmd_params *params) @@ -327,30 +344,6 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); } - if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { - int link_state; - - /* - * Initiate remote wakeup if the link state is in U3 when - * operating in SS/SSP or L1/L2 when operating in HS/FS. If the - * link state is in U1/U2, no remote wakeup is needed. The Start - * Transfer command will initiate the link recovery. - */ - link_state = dwc3_gadget_get_link_state(dwc); - switch (link_state) { - case DWC3_LINK_STATE_U2: - if (dwc->gadget->speed >= USB_SPEED_SUPER) - break; - - fallthrough; - case DWC3_LINK_STATE_U3: - ret = __dwc3_gadget_wakeup(dwc, false); - dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n", - ret); - break; - } - } - /* * For some commands such as Update Transfer command, DEPCMDPARn * registers are reserved. Since the driver often sends Update Transfer diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 0e7c1e947c0a..c82a6a0fba93 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -6,13 +6,13 @@ #include <linux/kstrtox.h> #include <linux/nls.h> #include <linux/usb/composite.h> +#include <linux/usb/func_utils.h> #include <linux/usb/gadget_configfs.h> #include <linux/usb/webusb.h> #include "configfs.h" -#include "u_f.h" #include "u_os_desc.h" -int check_user_usb_string(const char *name, +static int check_user_usb_string(const char *name, struct usb_gadget_strings *stringtab_dev) { u16 num; @@ -902,7 +902,7 @@ static struct configfs_group_operations gadget_language_langid_group_ops = { .drop_item = gadget_language_string_drop, }; -static struct config_item_type gadget_language_type = { +static const struct config_item_type gadget_language_type = { .ct_item_ops = &gadget_language_langid_item_ops, .ct_group_ops = &gadget_language_langid_group_ops, .ct_attrs = gadget_language_langid_attrs, @@ -961,7 +961,7 @@ static struct configfs_group_operations gadget_language_group_ops = { .drop_item = &gadget_language_drop, }; -static struct config_item_type gadget_language_strings_type = { +static const struct config_item_type gadget_language_strings_type = { .ct_group_ops = &gadget_language_group_ops, .ct_owner = THIS_MODULE, }; @@ -1106,7 +1106,7 @@ static struct configfs_attribute *webusb_attrs[] = { NULL, }; -static struct config_item_type webusb_type = { +static const struct config_item_type webusb_type = { .ct_attrs = webusb_attrs, .ct_owner = THIS_MODULE, }; @@ -1263,7 +1263,7 @@ static struct configfs_item_operations os_desc_ops = { .drop_link = os_desc_unlink, }; -static struct config_item_type os_desc_type = { +static const struct config_item_type os_desc_type = { .ct_item_ops = &os_desc_ops, .ct_attrs = os_desc_attrs, .ct_owner = THIS_MODULE, diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c index 724b2631f249..7061720b9732 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -41,6 +41,7 @@ struct f_acm { struct gserial port; u8 ctrl_id, data_id; u8 port_num; + u8 bInterfaceProtocol; u8 pending; @@ -89,7 +90,7 @@ acm_iad_descriptor = { .bInterfaceCount = 2, // control + data .bFunctionClass = USB_CLASS_COMM, .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, - .bFunctionProtocol = USB_CDC_ACM_PROTO_AT_V25TER, + /* .bFunctionProtocol = DYNAMIC */ /* .iFunction = DYNAMIC */ }; @@ -101,7 +102,7 @@ static struct usb_interface_descriptor acm_control_interface_desc = { .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, + /* .bInterfaceProtocol = DYNAMIC */ /* .iInterface = DYNAMIC */ }; @@ -663,6 +664,9 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) goto fail; acm->notify = ep; + acm_iad_descriptor.bFunctionProtocol = acm->bInterfaceProtocol; + acm_control_interface_desc.bInterfaceProtocol = acm->bInterfaceProtocol; + /* allocate notification */ acm->notify_req = gs_alloc_req(ep, sizeof(struct usb_cdc_notification) + 2, @@ -719,8 +723,14 @@ static void acm_unbind(struct usb_configuration *c, struct usb_function *f) static void acm_free_func(struct usb_function *f) { struct f_acm *acm = func_to_acm(f); + struct f_serial_opts *opts; + + opts = container_of(f->fi, struct f_serial_opts, func_inst); kfree(acm); + mutex_lock(&opts->lock); + opts->instances--; + mutex_unlock(&opts->lock); } static void acm_resume(struct usb_function *f) @@ -761,7 +771,11 @@ static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) acm->port.func.disable = acm_disable; opts = container_of(fi, struct f_serial_opts, func_inst); + mutex_lock(&opts->lock); acm->port_num = opts->port_num; + acm->bInterfaceProtocol = opts->protocol; + opts->instances++; + mutex_unlock(&opts->lock); acm->port.func.unbind = acm_unbind; acm->port.func.free_func = acm_free_func; acm->port.func.resume = acm_resume; @@ -812,11 +826,42 @@ static ssize_t f_acm_port_num_show(struct config_item *item, char *page) CONFIGFS_ATTR_RO(f_acm_, port_num); +static ssize_t f_acm_protocol_show(struct config_item *item, char *page) +{ + return sprintf(page, "%u\n", to_f_serial_opts(item)->protocol); +} + +static ssize_t f_acm_protocol_store(struct config_item *item, + const char *page, size_t count) +{ + struct f_serial_opts *opts = to_f_serial_opts(item); + int ret; + + mutex_lock(&opts->lock); + + if (opts->instances) { + ret = -EBUSY; + goto out; + } + + ret = kstrtou8(page, 0, &opts->protocol); + if (ret) + goto out; + ret = count; + +out: + mutex_unlock(&opts->lock); + return ret; +} + +CONFIGFS_ATTR(f_acm_, protocol); + static struct configfs_attribute *acm_attrs[] = { #ifdef CONFIG_U_SERIAL_CONSOLE &f_acm_attr_console, #endif &f_acm_attr_port_num, + &f_acm_attr_protocol, NULL, }; @@ -832,6 +877,7 @@ static void acm_free_instance(struct usb_function_instance *fi) opts = container_of(fi, struct f_serial_opts, func_inst); gserial_free_line(opts->port_num); + mutex_destroy(&opts->lock); kfree(opts); } @@ -843,7 +889,9 @@ static struct usb_function_instance *acm_alloc_instance(void) opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); + opts->protocol = USB_CDC_ACM_PROTO_AT_V25TER; opts->func_inst.free_func_inst = acm_free_instance; + mutex_init(&opts->lock); ret = gserial_alloc_line(&opts->port_num); if (ret) { kfree(opts); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index e0ceaa721949..05b52e61a66f 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -33,6 +33,7 @@ #include <linux/usb/ccid.h> #include <linux/usb/composite.h> #include <linux/usb/functionfs.h> +#include <linux/usb/func_utils.h> #include <linux/aio.h> #include <linux/kthread.h> @@ -40,7 +41,6 @@ #include <linux/eventfd.h> #include "u_fs.h" -#include "u_f.h" #include "u_os_desc.h" #include "configfs.h" @@ -2478,7 +2478,7 @@ typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity, static int __must_check ffs_do_single_desc(char *data, unsigned len, ffs_entity_callback entity, - void *priv, int *current_class) + void *priv, int *current_class, int *current_subclass) { struct usb_descriptor_header *_ds = (void *)data; u8 length; @@ -2535,6 +2535,7 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, if (ds->iInterface) __entity(STRING, ds->iInterface); *current_class = ds->bInterfaceClass; + *current_subclass = ds->bInterfaceSubClass; } break; @@ -2559,6 +2560,12 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, if (length != sizeof(struct ccid_descriptor)) goto inv_length; break; + } else if (*current_class == USB_CLASS_APP_SPEC && + *current_subclass == USB_SUBCLASS_DFU) { + pr_vdebug("dfu functional descriptor\n"); + if (length != sizeof(struct usb_dfu_functional_descriptor)) + goto inv_length; + break; } else { pr_vdebug("unknown descriptor: %d for class %d\n", _ds->bDescriptorType, *current_class); @@ -2621,6 +2628,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, const unsigned _len = len; unsigned long num = 0; int current_class = -1; + int current_subclass = -1; for (;;) { int ret; @@ -2640,7 +2648,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, return _len - len; ret = ffs_do_single_desc(data, len, entity, priv, - ¤t_class); + ¤t_class, ¤t_subclass); if (ret < 0) { pr_debug("%s returns %d\n", __func__, ret); return ret; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 93dae017ae45..740311c4fa24 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -15,13 +15,21 @@ #include <linux/uaccess.h> #include <linux/wait.h> #include <linux/sched.h> +#include <linux/workqueue.h> +#include <linux/usb/func_utils.h> #include <linux/usb/g_hid.h> +#include <uapi/linux/usb/g_hid.h> -#include "u_f.h" #include "u_hid.h" #define HIDG_MINORS 4 +/* + * Most operating systems seem to allow for 5000ms timeout, we will allow + * userspace half that time to respond before we return an empty report. + */ +#define GET_REPORT_TIMEOUT_MS 2500 + static int major, minors; static const struct class hidg_class = { @@ -31,6 +39,11 @@ static const struct class hidg_class = { static DEFINE_IDA(hidg_ida); static DEFINE_MUTEX(hidg_ida_lock); /* protects access to hidg_ida */ +struct report_entry { + struct usb_hidg_report report_data; + struct list_head node; +}; + /*-------------------------------------------------------------------------*/ /* HID gadget struct */ @@ -75,6 +88,19 @@ struct f_hidg { wait_queue_head_t write_queue; struct usb_request *req; + /* get report */ + struct usb_request *get_req; + struct usb_hidg_report get_report; + bool get_report_returned; + int get_report_req_report_id; + int get_report_req_report_length; + spinlock_t get_report_spinlock; + wait_queue_head_t get_queue; /* Waiting for userspace response */ + wait_queue_head_t get_id_queue; /* Get ID came in */ + struct work_struct work; + struct workqueue_struct *workqueue; + struct list_head report_list; + struct device dev; struct cdev cdev; struct usb_function func; @@ -524,6 +550,174 @@ release_write_pending: return status; } +static struct report_entry *f_hidg_search_for_report(struct f_hidg *hidg, u8 report_id) +{ + struct list_head *ptr; + struct report_entry *entry; + + list_for_each(ptr, &hidg->report_list) { + entry = list_entry(ptr, struct report_entry, node); + if (entry->report_data.report_id == report_id) + return entry; + } + + return NULL; +} + +static void get_report_workqueue_handler(struct work_struct *work) +{ + struct f_hidg *hidg = container_of(work, struct f_hidg, work); + struct usb_composite_dev *cdev = hidg->func.config->cdev; + struct usb_request *req; + struct report_entry *ptr; + unsigned long flags; + + int status = 0; + + spin_lock_irqsave(&hidg->get_report_spinlock, flags); + req = hidg->get_req; + if (!req) { + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + return; + } + + req->zero = 0; + req->length = min_t(unsigned int, min_t(unsigned int, hidg->get_report_req_report_length, + hidg->report_length), + MAX_REPORT_LENGTH); + + /* Check if there is a response available for immediate response */ + ptr = f_hidg_search_for_report(hidg, hidg->get_report_req_report_id); + if (ptr && !ptr->report_data.userspace_req) { + /* Report exists in list and it is to be used for immediate response */ + req->buf = ptr->report_data.data; + status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + hidg->get_report_returned = true; + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + } else { + /* + * Report does not exist in list or should not be immediately sent + * i.e. give userspace time to respond + */ + hidg->get_report_returned = false; + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + wake_up(&hidg->get_id_queue); +#define GET_REPORT_COND (!hidg->get_report_returned) + /* Wait until userspace has responded or timeout */ + status = wait_event_interruptible_timeout(hidg->get_queue, !GET_REPORT_COND, + msecs_to_jiffies(GET_REPORT_TIMEOUT_MS)); + spin_lock_irqsave(&hidg->get_report_spinlock, flags); + req = hidg->get_req; + if (!req) { + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + return; + } + if (status == 0 && !hidg->get_report_returned) { + /* GET_REPORT request was not serviced by userspace within timeout period */ + VDBG(cdev, "get_report : userspace timeout.\n"); + hidg->get_report_returned = true; + } + + /* Search again for report ID in list and respond to GET_REPORT request */ + ptr = f_hidg_search_for_report(hidg, hidg->get_report_req_report_id); + if (ptr) { + /* + * Either get an updated response just serviced by userspace + * or send the latest response in the list + */ + req->buf = ptr->report_data.data; + } else { + /* If there are no prevoiusly sent reports send empty report */ + req->buf = hidg->get_report.data; + memset(req->buf, 0x0, req->length); + } + + status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + } + + if (status < 0) + VDBG(cdev, "usb_ep_queue error on ep0 responding to GET_REPORT\n"); +} + +static int f_hidg_get_report_id(struct file *file, __u8 __user *buffer) +{ + struct f_hidg *hidg = file->private_data; + int ret = 0; + + ret = put_user(hidg->get_report_req_report_id, buffer); + + return ret; +} + +static int f_hidg_get_report(struct file *file, struct usb_hidg_report __user *buffer) +{ + struct f_hidg *hidg = file->private_data; + struct usb_composite_dev *cdev = hidg->func.config->cdev; + unsigned long flags; + struct report_entry *entry; + struct report_entry *ptr; + __u8 report_id; + + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + if (copy_from_user(&entry->report_data, buffer, + sizeof(struct usb_hidg_report))) { + ERROR(cdev, "copy_from_user error\n"); + kfree(entry); + return -EINVAL; + } + + report_id = entry->report_data.report_id; + + spin_lock_irqsave(&hidg->get_report_spinlock, flags); + ptr = f_hidg_search_for_report(hidg, report_id); + + if (ptr) { + /* Report already exists in list - update it */ + if (copy_from_user(&ptr->report_data, buffer, + sizeof(struct usb_hidg_report))) { + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + ERROR(cdev, "copy_from_user error\n"); + kfree(entry); + return -EINVAL; + } + kfree(entry); + } else { + /* Report does not exist in list - add it */ + list_add_tail(&entry->node, &hidg->report_list); + } + + /* If there is no response pending then do nothing further */ + if (hidg->get_report_returned) { + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + return 0; + } + + /* If this userspace response serves the current pending report */ + if (hidg->get_report_req_report_id == report_id) { + hidg->get_report_returned = true; + wake_up(&hidg->get_queue); + } + + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + return 0; +} + +static long f_hidg_ioctl(struct file *file, unsigned int code, unsigned long arg) +{ + switch (code) { + case GADGET_HID_READ_GET_REPORT_ID: + return f_hidg_get_report_id(file, (__u8 __user *)arg); + case GADGET_HID_WRITE_GET_REPORT: + return f_hidg_get_report(file, (struct usb_hidg_report __user *)arg); + default: + return -ENOTTY; + } +} + static __poll_t f_hidg_poll(struct file *file, poll_table *wait) { struct f_hidg *hidg = file->private_data; @@ -531,6 +725,8 @@ static __poll_t f_hidg_poll(struct file *file, poll_table *wait) poll_wait(file, &hidg->read_queue, wait); poll_wait(file, &hidg->write_queue, wait); + poll_wait(file, &hidg->get_queue, wait); + poll_wait(file, &hidg->get_id_queue, wait); if (WRITE_COND) ret |= EPOLLOUT | EPOLLWRNORM; @@ -543,12 +739,16 @@ static __poll_t f_hidg_poll(struct file *file, poll_table *wait) ret |= EPOLLIN | EPOLLRDNORM; } + if (GET_REPORT_COND) + ret |= EPOLLPRI; + return ret; } #undef WRITE_COND #undef READ_COND_SSREPORT #undef READ_COND_INTOUT +#undef GET_REPORT_COND static int f_hidg_release(struct inode *inode, struct file *fd) { @@ -641,6 +841,10 @@ static void hidg_ssreport_complete(struct usb_ep *ep, struct usb_request *req) wake_up(&hidg->read_queue); } +static void hidg_get_report_complete(struct usb_ep *ep, struct usb_request *req) +{ +} + static int hidg_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { @@ -649,6 +853,7 @@ static int hidg_setup(struct usb_function *f, struct usb_request *req = cdev->req; int status = 0; __u16 value, length; + unsigned long flags; value = __le16_to_cpu(ctrl->wValue); length = __le16_to_cpu(ctrl->wLength); @@ -660,14 +865,20 @@ static int hidg_setup(struct usb_function *f, switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_GET_REPORT): - VDBG(cdev, "get_report\n"); + VDBG(cdev, "get_report | wLength=%d\n", ctrl->wLength); - /* send an empty report */ - length = min_t(unsigned, length, hidg->report_length); - memset(req->buf, 0x0, length); + /* + * Update GET_REPORT ID so that an ioctl can be used to determine what + * GET_REPORT the request was actually for. + */ + spin_lock_irqsave(&hidg->get_report_spinlock, flags); + hidg->get_report_req_report_id = value & 0xff; + hidg->get_report_req_report_length = length; + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); - goto respond; - break; + queue_work(hidg->workqueue, &hidg->work); + + return status; case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_GET_PROTOCOL): @@ -793,6 +1004,14 @@ static void hidg_disable(struct usb_function *f) spin_unlock_irqrestore(&hidg->read_spinlock, flags); } + spin_lock_irqsave(&hidg->get_report_spinlock, flags); + if (!hidg->get_report_returned) { + usb_ep_free_request(f->config->cdev->gadget->ep0, hidg->get_req); + hidg->get_req = NULL; + hidg->get_report_returned = true; + } + spin_unlock_irqrestore(&hidg->get_report_spinlock, flags); + spin_lock_irqsave(&hidg->write_spinlock, flags); if (!hidg->write_pending) { free_ep_req(hidg->in_ep, hidg->req); @@ -902,6 +1121,14 @@ fail: return status; } +#ifdef CONFIG_COMPAT +static long f_hidg_compat_ioctl(struct file *file, unsigned int code, + unsigned long value) +{ + return f_hidg_ioctl(file, code, value); +} +#endif + static const struct file_operations f_hidg_fops = { .owner = THIS_MODULE, .open = f_hidg_open, @@ -909,6 +1136,10 @@ static const struct file_operations f_hidg_fops = { .write = f_hidg_write, .read = f_hidg_read, .poll = f_hidg_poll, + .unlocked_ioctl = f_hidg_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = f_hidg_compat_ioctl, +#endif .llseek = noop_llseek, }; @@ -919,6 +1150,15 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) struct usb_string *us; int status; + hidg->get_req = usb_ep_alloc_request(c->cdev->gadget->ep0, GFP_ATOMIC); + if (!hidg->get_req) + return -ENOMEM; + + hidg->get_req->zero = 0; + hidg->get_req->complete = hidg_get_report_complete; + hidg->get_req->context = hidg; + hidg->get_report_returned = true; + /* maybe allocate device-global string IDs, and patch descriptors */ us = usb_gstrings_attach(c->cdev, ct_func_strings, ARRAY_SIZE(ct_func_string_defs)); @@ -1004,9 +1244,24 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg->write_pending = 1; hidg->req = NULL; spin_lock_init(&hidg->read_spinlock); + spin_lock_init(&hidg->get_report_spinlock); init_waitqueue_head(&hidg->write_queue); init_waitqueue_head(&hidg->read_queue); + init_waitqueue_head(&hidg->get_queue); + init_waitqueue_head(&hidg->get_id_queue); INIT_LIST_HEAD(&hidg->completed_out_req); + INIT_LIST_HEAD(&hidg->report_list); + + INIT_WORK(&hidg->work, get_report_workqueue_handler); + hidg->workqueue = alloc_workqueue("report_work", + WQ_FREEZABLE | + WQ_MEM_RECLAIM, + 1); + + if (!hidg->workqueue) { + status = -ENOMEM; + goto fail; + } /* create char device */ cdev_init(&hidg->cdev, &f_hidg_fops); @@ -1016,12 +1271,16 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail_free_descs: + destroy_workqueue(hidg->workqueue); usb_free_all_descriptors(f); fail: ERROR(f->config->cdev, "hidg_bind FAILED\n"); if (hidg->req != NULL) free_ep_req(hidg->in_ep, hidg->req); + usb_ep_free_request(c->cdev->gadget->ep0, hidg->get_req); + hidg->get_req = NULL; + return status; } @@ -1256,7 +1515,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) struct f_hidg *hidg = func_to_hidg(f); cdev_device_del(&hidg->cdev, &hidg->dev); - + destroy_workqueue(hidg->workqueue); usb_free_all_descriptors(f); } diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c index 979b028edb99..49b009a7d5d7 100644 --- a/drivers/usb/gadget/function/f_loopback.c +++ b/drivers/usb/gadget/function/f_loopback.c @@ -14,9 +14,9 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/usb/composite.h> +#include <linux/usb/func_utils.h> #include "g_zero.h" -#include "u_f.h" /* * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index cfd712fd7452..e11d8c0edf06 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -3050,7 +3050,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) if (!common->thread_task) { common->state = FSG_STATE_NORMAL; common->thread_task = - kthread_create(fsg_main_thread, common, "file-storage"); + kthread_run(fsg_main_thread, common, "file-storage"); if (IS_ERR(common->thread_task)) { ret = PTR_ERR(common->thread_task); common->thread_task = NULL; @@ -3059,7 +3059,6 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) } DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); - wake_up_process(common->thread_task); } fsg->gadget = gadget; diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 67052a664e74..1067847cc079 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -30,11 +30,11 @@ #include <sound/rawmidi.h> #include <linux/usb/ch9.h> +#include <linux/usb/func_utils.h> #include <linux/usb/gadget.h> #include <linux/usb/audio.h> #include <linux/usb/midi.h> -#include "u_f.h" #include "u_midi.h" MODULE_AUTHOR("Ben Williamson"); diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c index 3f63253ad3e0..8285df9ed6fd 100644 --- a/drivers/usb/gadget/function/f_midi2.c +++ b/drivers/usb/gadget/function/f_midi2.c @@ -15,11 +15,11 @@ #include <sound/ump_convert.h> #include <linux/usb/ch9.h> +#include <linux/usb/func_utils.h> #include <linux/usb/gadget.h> #include <linux/usb/audio.h> #include <linux/usb/midi-v2.h> -#include "u_f.h" #include "u_midi2.h" struct f_midi2; diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index 6f3702210450..ec5fd25020fd 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -13,10 +13,10 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/usb/composite.h> +#include <linux/usb/func_utils.h> #include <linux/err.h> #include "g_zero.h" -#include "u_f.h" /* * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 2b9fb4daa806..c87e74afc881 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -377,24 +377,10 @@ enum { STR_AS_OUT_IF_ALT1, STR_AS_IN_IF_ALT0, STR_AS_IN_IF_ALT1, + NUM_STR_DESCRIPTORS, }; -static struct usb_string strings_uac1[] = { - /* [STR_AC_IF].s = DYNAMIC, */ - [STR_USB_OUT_IT].s = "Playback Input terminal", - [STR_USB_OUT_IT_CH_NAMES].s = "Playback Channels", - [STR_IO_OUT_OT].s = "Playback Output terminal", - [STR_IO_IN_IT].s = "Capture Input terminal", - [STR_IO_IN_IT_CH_NAMES].s = "Capture Channels", - [STR_USB_IN_OT].s = "Capture Output terminal", - [STR_FU_IN].s = "Capture Volume", - [STR_FU_OUT].s = "Playback Volume", - [STR_AS_OUT_IF_ALT0].s = "Playback Inactive", - [STR_AS_OUT_IF_ALT1].s = "Playback Active", - [STR_AS_IN_IF_ALT0].s = "Capture Inactive", - [STR_AS_IN_IF_ALT1].s = "Capture Active", - { }, -}; +static struct usb_string strings_uac1[NUM_STR_DESCRIPTORS + 1] = {}; static struct usb_gadget_strings str_uac1 = { .language = 0x0409, /* en-us */ @@ -1265,6 +1251,20 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) strings_uac1[STR_AC_IF].s = audio_opts->function_name; + strings_uac1[STR_USB_OUT_IT].s = audio_opts->c_it_name; + strings_uac1[STR_USB_OUT_IT_CH_NAMES].s = audio_opts->c_it_ch_name; + strings_uac1[STR_IO_OUT_OT].s = audio_opts->c_ot_name; + strings_uac1[STR_FU_OUT].s = audio_opts->c_fu_vol_name; + strings_uac1[STR_AS_OUT_IF_ALT0].s = "Playback Inactive"; + strings_uac1[STR_AS_OUT_IF_ALT1].s = "Playback Active"; + + strings_uac1[STR_IO_IN_IT].s = audio_opts->p_it_name; + strings_uac1[STR_IO_IN_IT_CH_NAMES].s = audio_opts->p_it_ch_name; + strings_uac1[STR_USB_IN_OT].s = audio_opts->p_ot_name; + strings_uac1[STR_FU_IN].s = audio_opts->p_fu_vol_name; + strings_uac1[STR_AS_IN_IF_ALT0].s = "Capture Inactive"; + strings_uac1[STR_AS_IN_IF_ALT1].s = "Capture Active"; + us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1)); if (IS_ERR(us)) return PTR_ERR(us); @@ -1681,8 +1681,19 @@ UAC1_ATTRIBUTE(bool, c_volume_present); UAC1_ATTRIBUTE(s16, c_volume_min); UAC1_ATTRIBUTE(s16, c_volume_max); UAC1_ATTRIBUTE(s16, c_volume_res); + UAC1_ATTRIBUTE_STRING(function_name); +UAC1_ATTRIBUTE_STRING(p_it_name); +UAC1_ATTRIBUTE_STRING(p_it_ch_name); +UAC1_ATTRIBUTE_STRING(p_ot_name); +UAC1_ATTRIBUTE_STRING(p_fu_vol_name); + +UAC1_ATTRIBUTE_STRING(c_it_name); +UAC1_ATTRIBUTE_STRING(c_it_ch_name); +UAC1_ATTRIBUTE_STRING(c_ot_name); +UAC1_ATTRIBUTE_STRING(c_fu_vol_name); + static struct configfs_attribute *f_uac1_attrs[] = { &f_uac1_opts_attr_c_chmask, &f_uac1_opts_attr_c_srate, @@ -1706,6 +1717,16 @@ static struct configfs_attribute *f_uac1_attrs[] = { &f_uac1_opts_attr_function_name, + &f_uac1_opts_attr_p_it_name, + &f_uac1_opts_attr_p_it_ch_name, + &f_uac1_opts_attr_p_ot_name, + &f_uac1_opts_attr_p_fu_vol_name, + + &f_uac1_opts_attr_c_it_name, + &f_uac1_opts_attr_c_it_ch_name, + &f_uac1_opts_attr_c_ot_name, + &f_uac1_opts_attr_c_fu_vol_name, + NULL, }; @@ -1760,6 +1781,16 @@ static struct usb_function_instance *f_audio_alloc_inst(void) scnprintf(opts->function_name, sizeof(opts->function_name), "AC Interface"); + scnprintf(opts->p_it_name, sizeof(opts->p_it_name), "Capture Input terminal"); + scnprintf(opts->p_it_ch_name, sizeof(opts->p_it_ch_name), "Capture Channels"); + scnprintf(opts->p_ot_name, sizeof(opts->p_ot_name), "Capture Output terminal"); + scnprintf(opts->p_fu_vol_name, sizeof(opts->p_fu_vol_name), "Capture Volume"); + + scnprintf(opts->c_it_name, sizeof(opts->c_it_name), "Playback Input terminal"); + scnprintf(opts->c_it_ch_name, sizeof(opts->c_it_ch_name), "Playback Channels"); + scnprintf(opts->c_ot_name, sizeof(opts->c_ot_name), "Playback Output terminal"); + scnprintf(opts->c_fu_vol_name, sizeof(opts->c_fu_vol_name), "Playback Volume"); + return &opts->func_inst; } diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 2d6d3286ffde..1cdda44455b3 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -95,7 +95,9 @@ enum { STR_CLKSRC_IN, STR_CLKSRC_OUT, STR_USB_IT, + STR_USB_IT_CH, STR_IO_IT, + STR_IO_IT_CH, STR_USB_OT, STR_IO_OT, STR_FU_IN, @@ -104,25 +106,10 @@ enum { STR_AS_OUT_ALT1, STR_AS_IN_ALT0, STR_AS_IN_ALT1, + NUM_STR_DESCRIPTORS, }; -static struct usb_string strings_fn[] = { - /* [STR_ASSOC].s = DYNAMIC, */ - [STR_IF_CTRL].s = "Topology Control", - [STR_CLKSRC_IN].s = "Input Clock", - [STR_CLKSRC_OUT].s = "Output Clock", - [STR_USB_IT].s = "USBH Out", - [STR_IO_IT].s = "USBD Out", - [STR_USB_OT].s = "USBH In", - [STR_IO_OT].s = "USBD In", - [STR_FU_IN].s = "Capture Volume", - [STR_FU_OUT].s = "Playback Volume", - [STR_AS_OUT_ALT0].s = "Playback Inactive", - [STR_AS_OUT_ALT1].s = "Playback Active", - [STR_AS_IN_ALT0].s = "Capture Inactive", - [STR_AS_IN_ALT1].s = "Capture Active", - { }, -}; +static struct usb_string strings_fn[NUM_STR_DESCRIPTORS + 1] = {}; static const char *const speed_names[] = { [USB_SPEED_UNKNOWN] = "UNKNOWN", @@ -1049,6 +1036,23 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) return ret; strings_fn[STR_ASSOC].s = uac2_opts->function_name; + strings_fn[STR_IF_CTRL].s = uac2_opts->if_ctrl_name; + strings_fn[STR_CLKSRC_IN].s = uac2_opts->clksrc_in_name; + strings_fn[STR_CLKSRC_OUT].s = uac2_opts->clksrc_out_name; + + strings_fn[STR_USB_IT].s = uac2_opts->c_it_name; + strings_fn[STR_USB_IT_CH].s = uac2_opts->c_it_ch_name; + strings_fn[STR_IO_OT].s = uac2_opts->c_ot_name; + strings_fn[STR_FU_OUT].s = uac2_opts->c_fu_vol_name; + strings_fn[STR_AS_OUT_ALT0].s = "Playback Inactive"; + strings_fn[STR_AS_OUT_ALT1].s = "Playback Active"; + + strings_fn[STR_IO_IT].s = uac2_opts->p_it_name; + strings_fn[STR_IO_IT_CH].s = uac2_opts->p_it_ch_name; + strings_fn[STR_USB_OT].s = uac2_opts->p_ot_name; + strings_fn[STR_FU_IN].s = uac2_opts->p_fu_vol_name; + strings_fn[STR_AS_IN_ALT0].s = "Capture Inactive"; + strings_fn[STR_AS_IN_ALT1].s = "Capture Active"; us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn)); if (IS_ERR(us)) @@ -1072,7 +1076,9 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) in_clk_src_desc.iClockSource = us[STR_CLKSRC_IN].id; out_clk_src_desc.iClockSource = us[STR_CLKSRC_OUT].id; usb_out_it_desc.iTerminal = us[STR_USB_IT].id; + usb_out_it_desc.iChannelNames = us[STR_USB_IT_CH].id; io_in_it_desc.iTerminal = us[STR_IO_IT].id; + io_in_it_desc.iChannelNames = us[STR_IO_IT_CH].id; usb_in_ot_desc.iTerminal = us[STR_USB_OT].id; io_out_ot_desc.iTerminal = us[STR_IO_OT].id; std_as_out_if0_desc.iInterface = us[STR_AS_OUT_ALT0].id; @@ -2100,10 +2106,24 @@ UAC2_ATTRIBUTE(s16, c_volume_max); UAC2_ATTRIBUTE(s16, c_volume_res); UAC2_ATTRIBUTE(u32, fb_max); UAC2_ATTRIBUTE_STRING(function_name); +UAC2_ATTRIBUTE_STRING(if_ctrl_name); +UAC2_ATTRIBUTE_STRING(clksrc_in_name); +UAC2_ATTRIBUTE_STRING(clksrc_out_name); + +UAC2_ATTRIBUTE_STRING(p_it_name); +UAC2_ATTRIBUTE_STRING(p_it_ch_name); +UAC2_ATTRIBUTE_STRING(p_ot_name); +UAC2_ATTRIBUTE_STRING(p_fu_vol_name); + +UAC2_ATTRIBUTE_STRING(c_it_name); +UAC2_ATTRIBUTE_STRING(c_it_ch_name); +UAC2_ATTRIBUTE_STRING(c_ot_name); +UAC2_ATTRIBUTE_STRING(c_fu_vol_name); UAC2_ATTRIBUTE(s16, p_terminal_type); UAC2_ATTRIBUTE(s16, c_terminal_type); + static struct configfs_attribute *f_uac2_attrs[] = { &f_uac2_opts_attr_p_chmask, &f_uac2_opts_attr_p_srate, @@ -2130,6 +2150,19 @@ static struct configfs_attribute *f_uac2_attrs[] = { &f_uac2_opts_attr_c_volume_res, &f_uac2_opts_attr_function_name, + &f_uac2_opts_attr_if_ctrl_name, + &f_uac2_opts_attr_clksrc_in_name, + &f_uac2_opts_attr_clksrc_out_name, + + &f_uac2_opts_attr_p_it_name, + &f_uac2_opts_attr_p_it_ch_name, + &f_uac2_opts_attr_p_ot_name, + &f_uac2_opts_attr_p_fu_vol_name, + + &f_uac2_opts_attr_c_it_name, + &f_uac2_opts_attr_c_it_ch_name, + &f_uac2_opts_attr_c_ot_name, + &f_uac2_opts_attr_c_fu_vol_name, &f_uac2_opts_attr_p_terminal_type, &f_uac2_opts_attr_c_terminal_type, @@ -2191,6 +2224,19 @@ static struct usb_function_instance *afunc_alloc_inst(void) opts->fb_max = FBACK_FAST_MAX; scnprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink"); + scnprintf(opts->if_ctrl_name, sizeof(opts->if_ctrl_name), "Topology Control"); + scnprintf(opts->clksrc_in_name, sizeof(opts->clksrc_in_name), "Input Clock"); + scnprintf(opts->clksrc_out_name, sizeof(opts->clksrc_out_name), "Output Clock"); + + scnprintf(opts->p_it_name, sizeof(opts->p_it_name), "USBD Out"); + scnprintf(opts->p_it_ch_name, sizeof(opts->p_it_ch_name), "Capture Channels"); + scnprintf(opts->p_ot_name, sizeof(opts->p_ot_name), "USBH In"); + scnprintf(opts->p_fu_vol_name, sizeof(opts->p_fu_vol_name), "Capture Volume"); + + scnprintf(opts->c_it_name, sizeof(opts->c_it_name), "USBH Out"); + scnprintf(opts->c_it_ch_name, sizeof(opts->c_it_ch_name), "Playback Channels"); + scnprintf(opts->c_ot_name, sizeof(opts->c_ot_name), "USBD In"); + scnprintf(opts->c_fu_vol_name, sizeof(opts->c_fu_vol_name), "Playback Volume"); opts->p_terminal_type = UAC2_DEF_P_TERM_TYPE; opts->c_terminal_type = UAC2_DEF_C_TERM_TYPE; diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 24299576972f..ca8dbec65f73 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -1140,35 +1140,35 @@ static int u_audio_rate_get(struct snd_kcontrol *kcontrol, } static struct snd_kcontrol_new u_audio_controls[] = { - [UAC_FBACK_CTRL] { + [UAC_FBACK_CTRL] = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "Capture Pitch 1000000", .info = u_audio_pitch_info, .get = u_audio_pitch_get, .put = u_audio_pitch_put, }, - [UAC_P_PITCH_CTRL] { + [UAC_P_PITCH_CTRL] = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "Playback Pitch 1000000", .info = u_audio_pitch_info, .get = u_audio_pitch_get, .put = u_audio_pitch_put, }, - [UAC_MUTE_CTRL] { + [UAC_MUTE_CTRL] = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "", /* will be filled later */ .info = u_audio_mute_info, .get = u_audio_mute_get, .put = u_audio_mute_put, }, - [UAC_VOLUME_CTRL] { + [UAC_VOLUME_CTRL] = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "", /* will be filled later */ .info = u_audio_volume_info, .get = u_audio_volume_get, .put = u_audio_volume_put, }, - [UAC_RATE_CTRL] { + [UAC_RATE_CTRL] = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "", /* will be filled later */ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index b394105e55d6..0a8c05b2746b 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -28,6 +28,7 @@ #include <linux/kthread.h> #include <linux/workqueue.h> #include <linux/kfifo.h> +#include <linux/serial.h> #include "u_serial.h" @@ -126,6 +127,7 @@ struct gs_port { wait_queue_head_t close_wait; bool suspended; /* port suspended */ bool start_delayed; /* delay start when suspended */ + struct async_icount icount; /* REVISIT this state ... */ struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ @@ -257,6 +259,7 @@ __acquires(&port->port_lock) break; } do_tty_wake = true; + port->icount.tx += len; req->length = len; list_del(&req->list); @@ -408,6 +411,7 @@ static void gs_rx_push(struct work_struct *work) size -= n; } + port->icount.rx += size; count = tty_insert_flip_string(&port->port, packet, size); if (count) @@ -851,6 +855,23 @@ static int gs_break_ctl(struct tty_struct *tty, int duration) return status; } +static int gs_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct gs_port *port = tty->driver_data; + struct async_icount cnow; + unsigned long flags; + + spin_lock_irqsave(&port->port_lock, flags); + cnow = port->icount; + spin_unlock_irqrestore(&port->port_lock, flags); + + icount->rx = cnow.rx; + icount->tx = cnow.tx; + + return 0; +} + static const struct tty_operations gs_tty_ops = { .open = gs_open, .close = gs_close, @@ -861,6 +882,7 @@ static const struct tty_operations gs_tty_ops = { .chars_in_buffer = gs_chars_in_buffer, .unthrottle = gs_unthrottle, .break_ctl = gs_break_ctl, + .get_icount = gs_get_icount, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h index 901d99310bc4..e1274338ea61 100644 --- a/drivers/usb/gadget/function/u_serial.h +++ b/drivers/usb/gadget/function/u_serial.h @@ -17,6 +17,10 @@ struct f_serial_opts { struct usb_function_instance func_inst; u8 port_num; + u8 protocol; + + struct mutex lock; /* protect instances */ + int instances; }; /* diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h index f7a616760e31..feb6eb76462f 100644 --- a/drivers/usb/gadget/function/u_uac1.h +++ b/drivers/usb/gadget/function/u_uac1.h @@ -52,7 +52,17 @@ struct f_uac1_opts { int req_number; unsigned bound:1; - char function_name[32]; + char function_name[USB_MAX_STRING_LEN]; + + char p_it_name[USB_MAX_STRING_LEN]; + char p_it_ch_name[USB_MAX_STRING_LEN]; + char p_ot_name[USB_MAX_STRING_LEN]; + char p_fu_vol_name[USB_MAX_STRING_LEN]; + + char c_it_name[USB_MAX_STRING_LEN]; + char c_it_ch_name[USB_MAX_STRING_LEN]; + char c_ot_name[USB_MAX_STRING_LEN]; + char c_fu_vol_name[USB_MAX_STRING_LEN]; struct mutex lock; int refcnt; diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h index 5e81bdd6c5fb..0df808289ded 100644 --- a/drivers/usb/gadget/function/u_uac2.h +++ b/drivers/usb/gadget/function/u_uac2.h @@ -68,7 +68,20 @@ struct f_uac2_opts { int fb_max; bool bound; - char function_name[32]; + char function_name[USB_MAX_STRING_LEN]; + char if_ctrl_name[USB_MAX_STRING_LEN]; + char clksrc_in_name[USB_MAX_STRING_LEN]; + char clksrc_out_name[USB_MAX_STRING_LEN]; + + char p_it_name[USB_MAX_STRING_LEN]; + char p_it_ch_name[USB_MAX_STRING_LEN]; + char p_ot_name[USB_MAX_STRING_LEN]; + char p_fu_vol_name[USB_MAX_STRING_LEN]; + + char c_it_name[USB_MAX_STRING_LEN]; + char c_it_ch_name[USB_MAX_STRING_LEN]; + char c_ot_name[USB_MAX_STRING_LEN]; + char c_fu_vol_name[USB_MAX_STRING_LEN]; s16 p_terminal_type; s16 c_terminal_type; diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index a024aecb76dc..de1736f834e6 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -121,6 +121,9 @@ static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc, list_for_each_entry(format, &uvc->header->formats, entry) { const struct uvc_format_desc *fmtdesc = to_uvc_format(format->fmt); + if (IS_ERR(fmtdesc)) + continue; + if (fmtdesc->fcc == pixelformat) { uformat = format->fmt; break; @@ -240,6 +243,7 @@ uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt) struct uvc_video *video = &uvc->video; struct uvcg_format *uformat; struct uvcg_frame *uframe; + const struct uvc_format_desc *fmtdesc; u8 *fcc; if (fmt->type != video->queue.queue.type) @@ -277,7 +281,10 @@ uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt) fmt->fmt.pix.height = uframe->frame.w_height; fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe); fmt->fmt.pix.sizeimage = uvc_get_frame_size(uformat, uframe); - fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc; + fmtdesc = to_uvc_format(uformat); + if (IS_ERR(fmtdesc)) + return PTR_ERR(fmtdesc); + fmt->fmt.pix.pixelformat = fmtdesc->fcc; } fmt->fmt.pix.field = V4L2_FIELD_NONE; fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; @@ -389,6 +396,9 @@ uvc_v4l2_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) return -EINVAL; fmtdesc = to_uvc_format(uformat); + if (IS_ERR(fmtdesc)) + return PTR_ERR(fmtdesc); + f->pixelformat = fmtdesc->fcc; return 0; diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index d41f5f31dadd..a9edd60fbbf7 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -753,6 +753,7 @@ int uvcg_video_enable(struct uvc_video *video) video->req_int_count = 0; uvc_video_ep_queue_initial_requests(video); + queue_work(video->async_wq, &video->pump); return ret; } diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index 6aea1ecb3999..115d219c9c00 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -8,8 +8,8 @@ * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> */ -#include "u_f.h" #include <linux/usb/ch9.h> +#include <linux/usb/func_utils.h> struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len) { diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h deleted file mode 100644 index e313c3b8dcb1..000000000000 --- a/drivers/usb/gadget/u_f.h +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * u_f.h - * - * Utility definitions for USB functions - * - * Copyright (c) 2013 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> - */ - -#ifndef __U_F_H__ -#define __U_F_H__ - -#include <linux/usb/gadget.h> -#include <linux/overflow.h> - -/* Variable Length Array Macros **********************************************/ -#define vla_group(groupname) size_t groupname##__next = 0 -#define vla_group_size(groupname) groupname##__next - -#define vla_item(groupname, type, name, n) \ - size_t groupname##_##name##__offset = ({ \ - size_t offset = 0; \ - if (groupname##__next != SIZE_MAX) { \ - size_t align_mask = __alignof__(type) - 1; \ - size_t size = array_size(n, sizeof(type)); \ - offset = (groupname##__next + align_mask) & \ - ~align_mask; \ - if (check_add_overflow(offset, size, \ - &groupname##__next)) { \ - groupname##__next = SIZE_MAX; \ - offset = 0; \ - } \ - } \ - offset; \ - }) - -#define vla_item_with_sz(groupname, type, name, n) \ - size_t groupname##_##name##__sz = array_size(n, sizeof(type)); \ - size_t groupname##_##name##__offset = ({ \ - size_t offset = 0; \ - if (groupname##__next != SIZE_MAX) { \ - size_t align_mask = __alignof__(type) - 1; \ - offset = (groupname##__next + align_mask) & \ - ~align_mask; \ - if (check_add_overflow(offset, groupname##_##name##__sz,\ - &groupname##__next)) { \ - groupname##__next = SIZE_MAX; \ - offset = 0; \ - } \ - } \ - offset; \ - }) - -#define vla_ptr(ptr, groupname, name) \ - ((void *) ((char *)ptr + groupname##_##name##__offset)) - -struct usb_ep; -struct usb_request; - -/** - * alloc_ep_req - returns a usb_request allocated by the gadget driver and - * allocates the request's buffer. - * - * @ep: the endpoint to allocate a usb_request - * @len: usb_requests's buffer suggested size - * - * In case @ep direction is OUT, the @len will be aligned to ep's - * wMaxPacketSize. In order to avoid memory leaks or drops, *always* use - * usb_requests's length (req->length) to refer to the allocated buffer size. - * Requests allocated via alloc_ep_req() *must* be freed by free_ep_req(). - */ -struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len); - -/* Frees a usb_request previously allocated by alloc_ep_req() */ -static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - WARN_ON(req->buf == NULL); - kfree(req->buf); - req->buf = NULL; - usb_ep_free_request(ep, req); -} - -#endif /* __U_F_H__ */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index 35a652807fca..5149e2b7f050 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -639,6 +639,7 @@ static const struct of_device_id bdc_of_match[] = { { .compatible = "brcm,bdc" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, bdc_of_match); static struct platform_driver bdc_driver = { .driver = { diff --git a/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c b/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c index 0eed0e03842c..62fce42ef2da 100644 --- a/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c +++ b/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c @@ -2033,8 +2033,8 @@ static void cdns2_quiesce(struct cdns2_device *pdev) set_reg_bit_8(&pdev->usb_regs->usbcs, USBCS_DISCON); /* Disable interrupt. */ - writeb(0, &pdev->interrupt_regs->extien), - writeb(0, &pdev->interrupt_regs->usbien), + writeb(0, &pdev->interrupt_regs->extien); + writeb(0, &pdev->interrupt_regs->usbien); writew(0, &pdev->adma_regs->ep_ien); /* Clear interrupt line. */ @@ -2251,7 +2251,6 @@ static int cdns2_gadget_start(struct cdns2_device *pdev) { u32 max_speed; void *buf; - int val; int ret; pdev->usb_regs = pdev->regs; @@ -2261,14 +2260,9 @@ static int cdns2_gadget_start(struct cdns2_device *pdev) pdev->adma_regs = pdev->regs + CDNS2_ADMA_REGS_OFFSET; /* Reset controller. */ - set_reg_bit_8(&pdev->usb_regs->cpuctrl, CPUCTRL_SW_RST); - - ret = readl_poll_timeout_atomic(&pdev->usb_regs->cpuctrl, val, - !(val & CPUCTRL_SW_RST), 1, 10000); - if (ret) { - dev_err(pdev->dev, "Error: reset controller timeout\n"); - return -EINVAL; - } + writeb(CPUCTRL_SW_RST | CPUCTRL_UPCLK | CPUCTRL_WUEN, + &pdev->usb_regs->cpuctrl); + usleep_range(5, 10); usb_initialize_gadget(pdev->dev, &pdev->gadget, NULL); diff --git a/drivers/usb/gadget/udc/cdns2/cdns2-gadget.h b/drivers/usb/gadget/udc/cdns2/cdns2-gadget.h index 71e2f62d653a..b5d5ec12e986 100644 --- a/drivers/usb/gadget/udc/cdns2/cdns2-gadget.h +++ b/drivers/usb/gadget/udc/cdns2/cdns2-gadget.h @@ -292,8 +292,17 @@ struct cdns2_usb_regs { #define SPEEDCTRL_HSDISABLE BIT(7) /* CPUCTRL- bitmasks. */ +/* UP clock enable */ +#define CPUCTRL_UPCLK BIT(0) /* Controller reset bit. */ #define CPUCTRL_SW_RST BIT(1) +/** + * If the wuen bit is ‘1’, the upclken is automatically set to ‘1’ after + * detecting rising edge of wuintereq interrupt. If the wuen bit is ‘0’, + * the wuintereq interrupt is ignored. + */ +#define CPUCTRL_WUEN BIT(7) + /** * struct cdns2_adma_regs - ADMA controller registers. diff --git a/drivers/usb/gadget/udc/cdns2/cdns2-pci.c b/drivers/usb/gadget/udc/cdns2/cdns2-pci.c index 50c3d0974d9b..b1a8f772467c 100644 --- a/drivers/usb/gadget/udc/cdns2/cdns2-pci.c +++ b/drivers/usb/gadget/udc/cdns2/cdns2-pci.c @@ -15,8 +15,7 @@ #include "cdns2-gadget.h" #define PCI_DRIVER_NAME "cdns-pci-usbhs" -#define CDNS_VENDOR_ID 0x17cd -#define CDNS_DEVICE_ID 0x0120 +#define PCI_DEVICE_ID_CDNS_USB2 0x0120 #define PCI_BAR_DEV 0 #define PCI_DEV_FN_DEVICE 0 @@ -114,8 +113,8 @@ static const struct dev_pm_ops cdns2_pci_pm_ops = { }; static const struct pci_device_id cdns2_pci_ids[] = { - { PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_SERIAL_USB_DEVICE, PCI_ANY_ID }, + { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USB2), + .class = PCI_CLASS_SERIAL_USB_DEVICE }, { 0, } }; diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index f37b0d8386c1..ff7bee78bcc4 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1304,7 +1304,8 @@ static int dummy_urb_enqueue( /* kick the scheduler, it'll do the rest */ if (!hrtimer_active(&dum_hcd->timer)) - hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL); + hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), + HRTIMER_MODE_REL_SOFT); done: spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); @@ -1325,7 +1326,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) rc = usb_hcd_check_unlink_urb(hcd, urb, status); if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum_hcd->urbp_list)) - hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL); + hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL_SOFT); spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); return rc; @@ -1995,7 +1996,8 @@ return_urb: dum_hcd->udev = NULL; } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { /* want a 1 msec delay here */ - hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL); + hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), + HRTIMER_MODE_REL_SOFT); } spin_unlock_irqrestore(&dum->lock, flags); @@ -2389,7 +2391,7 @@ static int dummy_bus_resume(struct usb_hcd *hcd) dum_hcd->rh_state = DUMMY_RH_RUNNING; set_link_state(dum_hcd); if (!list_empty(&dum_hcd->urbp_list)) - hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL); + hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL_SOFT); hcd->state = HC_STATE_RUNNING; } spin_unlock_irq(&dum_hcd->dum->lock); @@ -2467,7 +2469,7 @@ static DEVICE_ATTR_RO(urbs); static int dummy_start_ss(struct dummy_hcd *dum_hcd) { - hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); dum_hcd->timer.function = dummy_timer; dum_hcd->rh_state = DUMMY_RH_RUNNING; dum_hcd->stream_en_ep = 0; @@ -2497,7 +2499,7 @@ static int dummy_start(struct usb_hcd *hcd) return dummy_start_ss(dum_hcd); spin_lock_init(&dum_hcd->dum->lock); - hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); dum_hcd->timer.function = dummy_timer; dum_hcd->rh_state = DUMMY_RH_RUNNING; diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index d5f29f8fe481..3bfd889ed56a 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -1487,31 +1487,29 @@ static int udc_ep0_out_req(struct lpc32xx_udc *udc) req = list_entry(ep0->queue.next, struct lpc32xx_request, queue); - if (req) { - if (req->req.length == 0) { - /* Just dequeue request */ - done(ep0, req, 0); - udc->ep0state = WAIT_FOR_SETUP; - return 1; - } + if (req->req.length == 0) { + /* Just dequeue request */ + done(ep0, req, 0); + udc->ep0state = WAIT_FOR_SETUP; + return 1; + } - /* Get data from FIFO */ - bufferspace = req->req.length - req->req.actual; - if (bufferspace > ep0->ep.maxpacket) - bufferspace = ep0->ep.maxpacket; + /* Get data from FIFO */ + bufferspace = req->req.length - req->req.actual; + if (bufferspace > ep0->ep.maxpacket) + bufferspace = ep0->ep.maxpacket; - /* Copy data to buffer */ - prefetchw(req->req.buf + req->req.actual); - tr = udc_read_hwep(udc, EP_OUT, req->req.buf + req->req.actual, - bufferspace); - req->req.actual += bufferspace; + /* Copy data to buffer */ + prefetchw(req->req.buf + req->req.actual); + tr = udc_read_hwep(udc, EP_OUT, req->req.buf + req->req.actual, + bufferspace); + req->req.actual += bufferspace; - if (tr < ep0->ep.maxpacket) { - /* This is the last packet */ - done(ep0, req, 0); - udc->ep0state = WAIT_FOR_SETUP; - return 1; - } + if (tr < ep0->ep.maxpacket) { + /* This is the last packet */ + done(ep0, req, 0); + udc->ep0state = WAIT_FOR_SETUP; + return 1; } return 0; @@ -1962,18 +1960,17 @@ static void udc_handle_eps(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) /* If there isn't a request waiting, something went wrong */ req = list_entry(ep->queue.next, struct lpc32xx_request, queue); - if (req) { - done(ep, req, 0); - /* Start another request if ready */ - if (!list_empty(&ep->queue)) { - if (ep->is_in) - udc_ep_in_req_dma(udc, ep); - else - udc_ep_out_req_dma(udc, ep); - } else - ep->req_pending = 0; - } + done(ep, req, 0); + + /* Start another request if ready */ + if (!list_empty(&ep->queue)) { + if (ep->is_in) + udc_ep_in_req_dma(udc, ep); + else + udc_ep_out_req_dma(udc, ep); + } else + ep->req_pending = 0; } @@ -1989,10 +1986,6 @@ static void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) #endif req = list_entry(ep->queue.next, struct lpc32xx_request, queue); - if (!req) { - ep_err(ep, "DMA interrupt on no req!\n"); - return; - } dd = req->dd_desc_ptr; /* DMA descriptor should always be retired for this call */ diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 74590f93ea61..ebc45565c33e 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -947,7 +947,7 @@ static int xudc_ep_disable(struct usb_ep *_ep) ep->desc = NULL; ep->ep_usb.desc = NULL; - dev_dbg(udc->dev, "USB Ep %d disable\n ", ep->epnumber); + dev_dbg(udc->dev, "USB Ep %d disable\n", ep->epnumber); /* Disable the endpoint.*/ epcfg = udc->read_fn(udc->addr + ep->offset); epcfg &= ~XUSB_EP_CFG_VALID_MASK; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 4448d0ab06f0..d011d6c753ed 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -40,11 +40,11 @@ config USB_XHCI_DBGCAP config USB_XHCI_PCI tristate depends on USB_PCI - depends on USB_XHCI_PCI_RENESAS || !USB_XHCI_PCI_RENESAS default y config USB_XHCI_PCI_RENESAS tristate "Support for additional Renesas xHCI controller with firmware" + depends on USB_XHCI_PCI help Say 'Y' to enable the support for the Renesas xHCI controller with firmware. Make sure you have the firmware for the device and diff --git a/drivers/usb/host/ehci-brcm.c b/drivers/usb/host/ehci-brcm.c index 77e42c739c58..68cad0620f1a 100644 --- a/drivers/usb/host/ehci-brcm.c +++ b/drivers/usb/host/ehci-brcm.c @@ -246,6 +246,7 @@ static const struct of_device_id brcm_ehci_of_match[] = { { .compatible = "brcm,bcm7445-ehci", }, {} }; +MODULE_DEVICE_TABLE(of, brcm_ehci_of_match); static struct platform_driver ehci_brcm_driver = { .probe = ehci_brcm_probe, diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index f40bc2a7a124..e3a961d3f5fc 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -48,7 +48,6 @@ struct exynos_ehci_hcd { static int exynos_ehci_get_phy(struct device *dev, struct exynos_ehci_hcd *exynos_ehci) { - struct device_node *child; struct phy *phy; int phy_number, num_phys; int ret; @@ -66,26 +65,22 @@ static int exynos_ehci_get_phy(struct device *dev, return 0; /* Get PHYs using legacy bindings */ - for_each_available_child_of_node(dev->of_node, child) { + for_each_available_child_of_node_scoped(dev->of_node, child) { ret = of_property_read_u32(child, "reg", &phy_number); if (ret) { dev_err(dev, "Failed to parse device tree\n"); - of_node_put(child); return ret; } if (phy_number >= PHY_NUMBER) { dev_err(dev, "Invalid number of PHYs\n"); - of_node_put(child); return -EINVAL; } phy = devm_of_phy_optional_get(dev, child, NULL); exynos_ehci->phy[phy_number] = phy; - if (IS_ERR(phy)) { - of_node_put(child); + if (IS_ERR(phy)) return PTR_ERR(phy); - } } exynos_ehci->legacy_phy = true; diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index bfa2eba4e3a7..1379e03644b2 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -37,7 +37,6 @@ struct exynos_ohci_hcd { static int exynos_ohci_get_phy(struct device *dev, struct exynos_ohci_hcd *exynos_ohci) { - struct device_node *child; struct phy *phy; int phy_number, num_phys; int ret; @@ -55,26 +54,22 @@ static int exynos_ohci_get_phy(struct device *dev, return 0; /* Get PHYs using legacy bindings */ - for_each_available_child_of_node(dev->of_node, child) { + for_each_available_child_of_node_scoped(dev->of_node, child) { ret = of_property_read_u32(child, "reg", &phy_number); if (ret) { dev_err(dev, "Failed to parse device tree\n"); - of_node_put(child); return ret; } if (phy_number >= PHY_NUMBER) { dev_err(dev, "Invalid number of PHYs\n"); - of_node_put(child); return -EINVAL; } phy = devm_of_phy_optional_get(dev, child, NULL); exynos_ohci->phy[phy_number] = phy; - if (IS_ERR(phy)) { - of_node_put(child); + if (IS_ERR(phy)) return PTR_ERR(phy); - } } exynos_ohci->legacy_phy = true; diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 8264c454f6bd..5b775e1ea527 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -51,8 +51,6 @@ static struct hc_driver __read_mostly ohci_nxp_hc_driver; static struct i2c_client *isp1301_i2c_client; -static struct clk *usb_host_clk; - static void isp1301_configure_lpc32xx(void) { /* LPC32XX only supports DAT_SE0 USB mode */ @@ -155,6 +153,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) struct resource *res; int ret = 0, irq; struct device_node *isp1301_node; + struct clk *usb_host_clk; if (pdev->dev.of_node) { isp1301_node = of_parse_phandle(pdev->dev.of_node, @@ -180,26 +179,20 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) } /* Enable USB host clock */ - usb_host_clk = devm_clk_get(&pdev->dev, NULL); + usb_host_clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(usb_host_clk)) { - dev_err(&pdev->dev, "failed to acquire USB OHCI clock\n"); + dev_err(&pdev->dev, "failed to acquire and start USB OHCI clock\n"); ret = PTR_ERR(usb_host_clk); goto fail_disable; } - ret = clk_prepare_enable(usb_host_clk); - if (ret < 0) { - dev_err(&pdev->dev, "failed to start USB OHCI clock\n"); - goto fail_disable; - } - isp1301_configure(); hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Failed to allocate HC buffer\n"); ret = -ENOMEM; - goto fail_hcd; + goto fail_disable; } hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); @@ -229,8 +222,6 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) ohci_nxp_stop_hc(); fail_resource: usb_put_hcd(hcd); -fail_hcd: - clk_disable_unprepare(usb_host_clk); fail_disable: isp1301_i2c_client = NULL; return ret; @@ -243,7 +234,6 @@ static void ohci_hcd_nxp_remove(struct platform_device *pdev) usb_remove_hcd(hcd); ohci_nxp_stop_hc(); usb_put_hcd(hcd); - clk_disable_unprepare(usb_host_clk); isp1301_i2c_client = NULL; } diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index f64bfe5f4d4d..a6be061f8653 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -204,10 +204,6 @@ static const struct of_device_id ohci_hcd_ppc_of_match[] = { #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE { .name = "usb", - .compatible = "ohci-littledian", - }, - { - .name = "usb", .compatible = "ohci-le", }, #endif diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 9f4bf8c5f8a5..6576515a29cd 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -297,9 +297,9 @@ static void put_child_connect_map(struct r8a66597 *r8a66597, int address) static void set_pipe_reg_addr(struct r8a66597_pipe *pipe, u8 dma_ch) { u16 pipenum = pipe->info.pipenum; - const unsigned long fifoaddr[] = {D0FIFO, D1FIFO, CFIFO}; - const unsigned long fifosel[] = {D0FIFOSEL, D1FIFOSEL, CFIFOSEL}; - const unsigned long fifoctr[] = {D0FIFOCTR, D1FIFOCTR, CFIFOCTR}; + static const unsigned long fifoaddr[] = {D0FIFO, D1FIFO, CFIFO}; + static const unsigned long fifosel[] = {D0FIFOSEL, D1FIFOSEL, CFIFOSEL}; + static const unsigned long fifoctr[] = {D0FIFOCTR, D1FIFOCTR, CFIFOCTR}; if (dma_ch > R8A66597_PIPE_NO_DMA) /* dma fifo not use? */ dma_ch = R8A66597_PIPE_NO_DMA; diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 161c09953c4e..241d7aa1fbc2 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -173,16 +173,18 @@ static void xhci_dbc_giveback(struct dbc_request *req, int status) spin_lock(&dbc->lock); } -static void xhci_dbc_flush_single_request(struct dbc_request *req) +static void trb_to_noop(union xhci_trb *trb) { - union xhci_trb *trb = req->trb; - trb->generic.field[0] = 0; trb->generic.field[1] = 0; trb->generic.field[2] = 0; trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE); trb->generic.field[3] |= cpu_to_le32(TRB_TYPE(TRB_TR_NOOP)); +} +static void xhci_dbc_flush_single_request(struct dbc_request *req) +{ + trb_to_noop(req->trb); xhci_dbc_giveback(req, -ESHUTDOWN); } @@ -649,7 +651,6 @@ static void xhci_dbc_stop(struct xhci_dbc *dbc) case DS_DISABLED: return; case DS_CONFIGURED: - case DS_STALLED: if (dbc->driver->disconnect) dbc->driver->disconnect(dbc); break; @@ -670,6 +671,23 @@ static void xhci_dbc_stop(struct xhci_dbc *dbc) } static void +handle_ep_halt_changes(struct xhci_dbc *dbc, struct dbc_ep *dep, bool halted) +{ + if (halted) { + dev_info(dbc->dev, "DbC Endpoint halted\n"); + dep->halted = 1; + + } else if (dep->halted) { + dev_info(dbc->dev, "DbC Endpoint halt cleared\n"); + dep->halted = 0; + + if (!list_empty(&dep->list_pending)) + writel(DBC_DOOR_BELL_TARGET(dep->direction), + &dbc->regs->doorbell); + } +} + +static void dbc_handle_port_status(struct xhci_dbc *dbc, union xhci_trb *event) { u32 portsc; @@ -697,6 +715,7 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event) struct xhci_ring *ring; int ep_id; int status; + struct xhci_ep_ctx *ep_ctx; u32 comp_code; size_t remain_length; struct dbc_request *req = NULL, *r; @@ -706,8 +725,30 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event) ep_id = TRB_TO_EP_ID(le32_to_cpu(event->generic.field[3])); dep = (ep_id == EPID_OUT) ? get_out_ep(dbc) : get_in_ep(dbc); + ep_ctx = (ep_id == EPID_OUT) ? + dbc_bulkout_ctx(dbc) : dbc_bulkin_ctx(dbc); ring = dep->ring; + /* Match the pending request: */ + list_for_each_entry(r, &dep->list_pending, list_pending) { + if (r->trb_dma == event->trans_event.buffer) { + req = r; + break; + } + if (r->status == -COMP_STALL_ERROR) { + dev_warn(dbc->dev, "Give back stale stalled req\n"); + ring->num_trbs_free++; + xhci_dbc_giveback(r, 0); + } + } + + if (!req) { + dev_warn(dbc->dev, "no matched request\n"); + return; + } + + trace_xhci_dbc_handle_transfer(ring, &req->trb->generic); + switch (comp_code) { case COMP_SUCCESS: remain_length = 0; @@ -718,31 +759,49 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event) case COMP_TRB_ERROR: case COMP_BABBLE_DETECTED_ERROR: case COMP_USB_TRANSACTION_ERROR: - case COMP_STALL_ERROR: dev_warn(dbc->dev, "tx error %d detected\n", comp_code); status = -comp_code; break; + case COMP_STALL_ERROR: + dev_warn(dbc->dev, "Stall error at bulk TRB %llx, remaining %zu, ep deq %llx\n", + event->trans_event.buffer, remain_length, ep_ctx->deq); + status = 0; + dep->halted = 1; + + /* + * xHC DbC may trigger a STALL bulk xfer event when host sends a + * ClearFeature(ENDPOINT_HALT) request even if there wasn't an + * active bulk transfer. + * + * Don't give back this transfer request as hardware will later + * start processing TRBs starting from this 'STALLED' TRB, + * causing TRBs and requests to be out of sync. + * + * If STALL event shows some bytes were transferred then assume + * it's an actual transfer issue and give back the request. + * In this case mark the TRB as No-Op to avoid hw from using the + * TRB again. + */ + + if ((ep_ctx->deq & ~TRB_CYCLE) == event->trans_event.buffer) { + dev_dbg(dbc->dev, "Ep stopped on Stalled TRB\n"); + if (remain_length == req->length) { + dev_dbg(dbc->dev, "Spurious stall event, keep req\n"); + req->status = -COMP_STALL_ERROR; + req->actual = 0; + return; + } + dev_dbg(dbc->dev, "Give back stalled req, but turn TRB to No-op\n"); + trb_to_noop(req->trb); + } + break; + default: dev_err(dbc->dev, "unknown tx error %d\n", comp_code); status = -comp_code; break; } - /* Match the pending request: */ - list_for_each_entry(r, &dep->list_pending, list_pending) { - if (r->trb_dma == event->trans_event.buffer) { - req = r; - break; - } - } - - if (!req) { - dev_warn(dbc->dev, "no matched request\n"); - return; - } - - trace_xhci_dbc_handle_transfer(ring, &req->trb->generic); - ring->num_trbs_free++; req->actual = req->length - remain_length; xhci_dbc_giveback(req, status); @@ -762,7 +821,6 @@ static void inc_evt_deq(struct xhci_ring *ring) static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) { dma_addr_t deq; - struct dbc_ep *dep; union xhci_trb *evt; u32 ctrl, portsc; bool update_erdp = false; @@ -814,43 +872,17 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) return EVT_DISC; } - /* Handle endpoint stall event: */ + /* Check and handle changes in endpoint halt status */ ctrl = readl(&dbc->regs->control); - if ((ctrl & DBC_CTRL_HALT_IN_TR) || - (ctrl & DBC_CTRL_HALT_OUT_TR)) { - dev_info(dbc->dev, "DbC Endpoint stall\n"); - dbc->state = DS_STALLED; - - if (ctrl & DBC_CTRL_HALT_IN_TR) { - dep = get_in_ep(dbc); - xhci_dbc_flush_endpoint_requests(dep); - } - - if (ctrl & DBC_CTRL_HALT_OUT_TR) { - dep = get_out_ep(dbc); - xhci_dbc_flush_endpoint_requests(dep); - } - - return EVT_DONE; - } + handle_ep_halt_changes(dbc, get_in_ep(dbc), ctrl & DBC_CTRL_HALT_IN_TR); + handle_ep_halt_changes(dbc, get_out_ep(dbc), ctrl & DBC_CTRL_HALT_OUT_TR); /* Clear DbC run change bit: */ if (ctrl & DBC_CTRL_DBC_RUN_CHANGE) { writel(ctrl, &dbc->regs->control); ctrl = readl(&dbc->regs->control); } - break; - case DS_STALLED: - ctrl = readl(&dbc->regs->control); - if (!(ctrl & DBC_CTRL_HALT_IN_TR) && - !(ctrl & DBC_CTRL_HALT_OUT_TR) && - (ctrl & DBC_CTRL_DBC_RUN)) { - dbc->state = DS_CONFIGURED; - break; - } - - return EVT_DONE; default: dev_err(dbc->dev, "Unknown DbC state %d\n", dbc->state); break; @@ -939,7 +971,6 @@ static const char * const dbc_state_strings[DS_MAX] = { [DS_ENABLED] = "enabled", [DS_CONNECTED] = "connected", [DS_CONFIGURED] = "configured", - [DS_STALLED] = "stalled", }; static ssize_t dbc_show(struct device *dev, diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h index eab59d921e22..8ec813b6e9fd 100644 --- a/drivers/usb/host/xhci-dbgcap.h +++ b/drivers/usb/host/xhci-dbgcap.h @@ -81,7 +81,6 @@ enum dbc_state { DS_ENABLED, DS_CONNECTED, DS_CONFIGURED, - DS_STALLED, DS_MAX }; @@ -90,6 +89,7 @@ struct dbc_ep { struct list_head list_pending; struct xhci_ring *ring; unsigned int direction:1; + unsigned int halted:1; }; #define DBC_QUEUE_SIZE 16 diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index 881f5a7e6e0e..b8e78867e25a 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -333,7 +333,7 @@ static void dbc_rx_push(struct tasklet_struct *t) port->n_read = 0; } - list_move(&req->list_pool, &port->read_pool); + list_move_tail(&req->list_pool, &port->read_pool); } if (do_push) diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index 96eb36a58738..67ecf7320c62 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -42,6 +42,7 @@ #define XHCI_EXT_CAPS_DEBUG 10 /* Vendor caps */ #define XHCI_EXT_CAPS_VENDOR_INTEL 192 +#define XHCI_EXT_CAPS_INTEL_SPR_SHADOW 206 /* USB Legacy Support Capability - section 7.1.1 */ #define XHCI_HC_BIOS_OWNED (1 << 16) #define XHCI_HC_OS_OWNED (1 << 24) @@ -64,6 +65,10 @@ #define XHCI_HLC (1 << 19) #define XHCI_BLC (1 << 20) +/* Intel SPR shadow capability */ +#define XHCI_INTEL_SPR_ESS_PORT_OFFSET 0x8ac4 /* SuperSpeed port control */ +#define XHCI_INTEL_SPR_TUNEN BIT(4) /* Tunnel mode enabled */ + /* command register values to disable interrupts and halt the HC */ /* start/stop HC execution - do not write unless HC is halted*/ #define XHCI_CMD_RUN (1 << 0) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 61f083de6e19..d27c30ac17fd 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -752,6 +752,42 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci) return xhci_reset(xhci, XHCI_RESET_SHORT_USEC); } +/** + * xhci_port_is_tunneled() - Check if USB3 connection is tunneled over USB4 + * @xhci: xhci host controller + * @port: USB3 port to be checked. + * + * Some hosts can detect if a USB3 connection is native USB3 or tunneled over + * USB4. Intel hosts expose this via vendor specific extended capability 206 + * eSS PORT registers TUNEN (tunnel enabled) bit. + * + * A USB3 device must be connected to the port to detect the tunnel. + * + * Return: link tunnel mode enum, USB_LINK_UNKNOWN if host is incapable of + * detecting USB3 over USB4 tunnels. USB_LINK_NATIVE or USB_LINK_TUNNELED + * otherwise. + */ +enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci, + struct xhci_port *port) +{ + void __iomem *base; + u32 offset; + + base = &xhci->cap_regs->hc_capbase; + offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW); + + if (offset && offset <= XHCI_INTEL_SPR_ESS_PORT_OFFSET) { + offset = XHCI_INTEL_SPR_ESS_PORT_OFFSET + port->hcd_portnum * 0x20; + + if (readl(base + offset) & XHCI_INTEL_SPR_TUNEN) + return USB_LINK_TUNNELED; + else + return USB_LINK_NATIVE; + } + + return USB_LINK_UNKNOWN; +} + void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port, u32 link_state) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 937ce5fd5809..d2900197a49e 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2332,7 +2332,8 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, } struct xhci_interrupter * -xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs) +xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, + u32 imod_interval) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_interrupter *ir; @@ -2365,6 +2366,11 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs) return NULL; } + err = xhci_set_interrupter_moderation(ir, imod_interval); + if (err) + xhci_warn(xhci, "Failed to set interrupter %d moderation to %uns\n", + i, imod_interval); + xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n", i, xhci->max_interrupters); diff --git a/drivers/usb/host/xhci-pci-renesas.c b/drivers/usb/host/xhci-pci-renesas.c index 247cc7c2ce70..30cc5a1380a5 100644 --- a/drivers/usb/host/xhci-pci-renesas.c +++ b/drivers/usb/host/xhci-pci-renesas.c @@ -50,6 +50,8 @@ #define RENESAS_RETRY 10000 #define RENESAS_DELAY 10 +#define RENESAS_FW_NAME "renesas_usb_fw.mem" + static int renesas_fw_download_image(struct pci_dev *dev, const u32 *fw, size_t step, bool rom) { @@ -573,12 +575,10 @@ exit: return err; } -int renesas_xhci_check_request_fw(struct pci_dev *pdev, - const struct pci_device_id *id) +static int renesas_xhci_check_request_fw(struct pci_dev *pdev, + const struct pci_device_id *id) { - struct xhci_driver_data *driver_data = - (struct xhci_driver_data *)id->driver_data; - const char *fw_name = driver_data->firmware; + const char fw_name[] = RENESAS_FW_NAME; const struct firmware *fw; bool has_rom; int err; @@ -625,7 +625,41 @@ exit: release_firmware(fw); return err; } -EXPORT_SYMBOL_GPL(renesas_xhci_check_request_fw); -MODULE_DESCRIPTION("Support for Renesas xHCI controller with firmware"); +static int +xhci_pci_renesas_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int retval; + + retval = renesas_xhci_check_request_fw(dev, id); + if (retval) + return retval; + + return xhci_pci_common_probe(dev, id); +} + +static const struct pci_device_id pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014) }, + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015) }, + { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +static struct pci_driver xhci_renesas_pci_driver = { + .name = "xhci-pci-renesas", + .id_table = pci_ids, + + .probe = xhci_pci_renesas_probe, + .remove = xhci_pci_remove, + + .shutdown = usb_hcd_pci_shutdown, + .driver = { + .pm = pm_ptr(&usb_hcd_pci_pm_ops), + }, +}; +module_pci_driver(xhci_renesas_pci_driver); + +MODULE_DESCRIPTION("Renesas xHCI PCI Host Controller Driver"); +MODULE_FIRMWARE(RENESAS_FW_NAME); +MODULE_IMPORT_NS(xhci); MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index dc1e345ab67e..91dccd25a551 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -55,6 +55,9 @@ #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed +#define PCI_VENDOR_ID_PHYTIUM 0x1db7 +#define PCI_DEVICE_ID_PHYTIUM_XHCI 0xdc27 + /* Thunderbolt */ #define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI 0x15b5 @@ -78,6 +81,9 @@ #define PCI_DEVICE_ID_ASMEDIA_2142_XHCI 0x2142 #define PCI_DEVICE_ID_ASMEDIA_3242_XHCI 0x3242 +#define PCI_DEVICE_ID_CADENCE 0x17CD +#define PCI_DEVICE_ID_CADENCE_SSP 0x0200 + static const char hcd_name[] = "xhci_hcd"; static struct hc_driver __read_mostly xhci_pci_hc_driver; @@ -93,6 +99,10 @@ static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { .update_hub_device = xhci_pci_update_hub_device, }; +/* + * Primary Legacy and MSI IRQ are synced in suspend_common(). + * All MSI-X IRQs and secondary MSI IRQs should be synced here. + */ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) { struct usb_hcd *hcd = xhci_to_hcd(xhci); @@ -105,13 +115,12 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) } } -/* Free any IRQs and disable MSI-X */ +/* Legacy IRQ is freed by usb_remove_hcd() or usb_hcd_pci_shutdown() */ static void xhci_cleanup_msix(struct xhci_hcd *xhci) { struct usb_hcd *hcd = xhci_to_hcd(xhci); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - /* return if using legacy interrupt */ if (hcd->irq > 0) return; @@ -235,15 +244,6 @@ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(dev); - struct xhci_driver_data *driver_data; - const struct pci_device_id *id; - - id = pci_match_id(to_pci_driver(pdev->dev.driver)->id_table, pdev); - - if (id && id->driver_data) { - driver_data = (struct xhci_driver_data *)id->driver_data; - xhci->quirks |= driver_data->quirks; - } /* Look for vendor-specific quirks */ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && @@ -416,6 +416,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; + if (pdev->vendor == PCI_VENDOR_ID_PHYTIUM && + pdev->device == PCI_DEVICE_ID_PHYTIUM_XHCI) + xhci->quirks |= XHCI_RESET_ON_RESUME; + /* See https://bugzilla.kernel.org/show_bug.cgi?id=79511 */ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3432) @@ -473,6 +477,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH; } + if (pdev->vendor == PCI_DEVICE_ID_CADENCE && + pdev->device == PCI_DEVICE_ID_CADENCE_SSP) + xhci->quirks |= XHCI_CDNS_SCTX_QUIRK; + /* xHC spec requires PCI devices to support D3hot and D3cold */ if (xhci->hci_version >= 0x120) xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; @@ -534,10 +542,9 @@ static int xhci_pci_setup(struct usb_hcd *hcd) struct xhci_hcd *xhci; struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int retval; + u8 sbrn; xhci = hcd_to_xhci(hcd); - if (!xhci->sbrn) - pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); /* imod_interval is the interrupt moderation value in nanoseconds. */ xhci->imod_interval = 40000; @@ -552,7 +559,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd) if (xhci->quirks & XHCI_PME_STUCK_QUIRK) xhci_pme_acpi_rtd3_enable(pdev); - xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); + pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &sbrn); + xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int)sbrn); /* Find any debug ports */ return xhci_pci_reinit(xhci, pdev); @@ -572,21 +580,13 @@ static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hd * We need to register our own PCI probe function (instead of the USB core's * function) in order to create a second roothub under xHCI. */ -static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; struct xhci_hcd *xhci; struct usb_hcd *hcd; - struct xhci_driver_data *driver_data; struct reset_control *reset; - driver_data = (struct xhci_driver_data *)id->driver_data; - if (driver_data && driver_data->quirks & XHCI_RENESAS_FW_QUIRK) { - retval = renesas_xhci_check_request_fw(dev, id); - if (retval) - return retval; - } - reset = devm_reset_control_get_optional_exclusive(&dev->dev, NULL); if (IS_ERR(reset)) return PTR_ERR(reset); @@ -651,12 +651,30 @@ put_runtime_pm: pm_runtime_put_noidle(&dev->dev); return retval; } +EXPORT_SYMBOL_NS_GPL(xhci_pci_common_probe, xhci); -static void xhci_pci_remove(struct pci_dev *dev) +static const struct pci_device_id pci_ids_reject[] = { + /* handled by xhci-pci-renesas */ + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014) }, + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015) }, + { /* end: all zeroes */ } +}; + +static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + if (pci_match_id(pci_ids_reject, dev)) + return -ENODEV; + + return xhci_pci_common_probe(dev, id); +} + +void xhci_pci_remove(struct pci_dev *dev) { struct xhci_hcd *xhci; + bool set_power_d3; xhci = hcd_to_xhci(pci_get_drvdata(dev)); + set_power_d3 = xhci->quirks & XHCI_SPURIOUS_WAKEUP; xhci->xhc_state |= XHCI_STATE_REMOVING; @@ -669,12 +687,13 @@ static void xhci_pci_remove(struct pci_dev *dev) xhci->shared_hcd = NULL; } + usb_hcd_pci_remove(dev); + /* Workaround for spurious wakeups at shutdown with HSW */ - if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) + if (set_power_d3) pci_set_power_state(dev, PCI_D3hot); - - usb_hcd_pci_remove(dev); } +EXPORT_SYMBOL_NS_GPL(xhci_pci_remove, xhci); /* * In some Intel xHCI controllers, in order to get D3 working, @@ -783,7 +802,6 @@ static int xhci_pci_resume(struct usb_hcd *hcd, pm_message_t msg) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int retval = 0; reset_control_reset(xhci->reset); @@ -814,8 +832,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, pm_message_t msg) if (xhci->quirks & XHCI_PME_STUCK_QUIRK) xhci_pme_quirk(hcd); - retval = xhci_resume(xhci, msg); - return retval; + return xhci_resume(xhci, msg); } static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup) @@ -882,19 +899,8 @@ static void xhci_pci_shutdown(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -static const struct xhci_driver_data reneses_data = { - .quirks = XHCI_RENESAS_FW_QUIRK, - .firmware = "renesas_usb_fw.mem", -}; - /* PCI driver selection metadata; PCI hotplugging uses this */ static const struct pci_device_id pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014), - .driver_data = (unsigned long)&reneses_data, - }, - { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015), - .driver_data = (unsigned long)&reneses_data, - }, /* handle any USB 3.0 xHCI controller */ { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0), }, @@ -902,14 +908,6 @@ static const struct pci_device_id pci_ids[] = { }; MODULE_DEVICE_TABLE(pci, pci_ids); -/* - * Without CONFIG_USB_XHCI_PCI_RENESAS renesas_xhci_check_request_fw() won't - * load firmware, so don't encumber the xhci-pci driver with it. - */ -#if IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS) -MODULE_FIRMWARE("renesas_usb_fw.mem"); -#endif - /* pci driver glue; this is a "new style" PCI driver module */ static struct pci_driver xhci_pci_driver = { .name = hcd_name, diff --git a/drivers/usb/host/xhci-pci.h b/drivers/usb/host/xhci-pci.h index cb9a8f331a44..e87c7d9d76b8 100644 --- a/drivers/usb/host/xhci-pci.h +++ b/drivers/usb/host/xhci-pci.h @@ -4,22 +4,7 @@ #ifndef XHCI_PCI_H #define XHCI_PCI_H -#if IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS) -int renesas_xhci_check_request_fw(struct pci_dev *dev, - const struct pci_device_id *id); - -#else -static int renesas_xhci_check_request_fw(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return 0; -} - -#endif - -struct xhci_driver_data { - u64 quirks; - const char *firmware; -}; +int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id); +void xhci_pci_remove(struct pci_dev *dev); #endif diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 31bdfa52eeb2..ecaa75718e59 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -259,6 +259,12 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s if (device_property_read_bool(tmpdev, "write-64-hi-lo-quirk")) xhci->quirks |= XHCI_WRITE_64_HI_LO; + if (device_property_read_bool(tmpdev, "xhci-missing-cas-quirk")) + xhci->quirks |= XHCI_MISSING_CAS; + + if (device_property_read_bool(tmpdev, "xhci-skip-phy-init-quirk")) + xhci->quirks |= XHCI_SKIP_PHY_INIT; + device_property_read_u32(tmpdev, "imod-interval-ns", &xhci->imod_interval); } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 4ea2c3e072a9..4d664ba53fe9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1399,6 +1399,20 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, struct xhci_stream_ctx *ctx = &ep->stream_info->stream_ctx_array[stream_id]; deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK; + + /* + * Cadence xHCI controllers store some endpoint state + * information within Rsvd0 fields of Stream Endpoint + * context. This field is not cleared during Set TR + * Dequeue Pointer command which causes XDMA to skip + * over transfer ring and leads to data loss on stream + * pipe. + * To fix this issue driver must clear Rsvd0 field. + */ + if (xhci->quirks & XHCI_CDNS_SCTX_QUIRK) { + ctx->reserved[0] = 0; + ctx->reserved[1] = 0; + } } else { deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; } @@ -2521,9 +2535,6 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, td->status = 0; break; case COMP_SHORT_PACKET: - xhci_dbg(xhci, "ep %#x - asked for %d bytes, %d bytes untransferred\n", - td->urb->ep->desc.bEndpointAddress, - requested, remaining); td->status = 0; break; case COMP_STOPPED_SHORT_PACKET: @@ -2764,35 +2775,25 @@ static int handle_tx_event(struct xhci_hcd *xhci, return 0; } - do { - /* This TRB should be in the TD at the head of this ring's - * TD list. + if (list_empty(&ep_ring->td_list)) { + /* + * Don't print wanings if ring is empty due to a stopped endpoint generating an + * extra completion event if the device was suspended. Or, a event for the last TRB + * of a short TD we already got a short event for. The short TD is already removed + * from the TD list. */ - if (list_empty(&ep_ring->td_list)) { - /* - * Don't print wanings if it's due to a stopped endpoint - * generating an extra completion event if the device - * was suspended. Or, a event for the last TRB of a - * short TD we already got a short event for. - * The short TD is already removed from the TD list. - */ - - if (!(trb_comp_code == COMP_STOPPED || - trb_comp_code == COMP_STOPPED_LENGTH_INVALID || - ep_ring->last_td_was_short)) { - xhci_warn(xhci, "WARN Event TRB for slot %u ep %d with no TDs queued?\n", - slot_id, ep_index); - } - if (ep->skip) { - ep->skip = false; - xhci_dbg(xhci, "td_list is empty while skip flag set. Clear skip flag for slot %u ep %u.\n", - slot_id, ep_index); - } - - td = NULL; - goto check_endpoint_halted; + if (trb_comp_code != COMP_STOPPED && + trb_comp_code != COMP_STOPPED_LENGTH_INVALID && + !ep_ring->last_td_was_short) { + xhci_warn(xhci, "Event TRB for slot %u ep %u with no TDs queued\n", + slot_id, ep_index); } + ep->skip = false; + goto check_endpoint_halted; + } + + do { td = list_first_entry(&ep_ring->td_list, struct xhci_td, td_list); @@ -2803,7 +2804,14 @@ static int handle_tx_event(struct xhci_hcd *xhci, if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) { skip_isoc_td(xhci, td, ep, status); - continue; + if (!list_empty(&ep_ring->td_list)) + continue; + + xhci_dbg(xhci, "All TDs skipped for slot %u ep %u. Clear skip flag.\n", + slot_id, ep_index); + ep->skip = false; + td = NULL; + goto check_endpoint_halted; } /* @@ -3941,10 +3949,6 @@ static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci, start_frame_id = (start_frame_id >> 3) & 0x7ff; end_frame_id = (end_frame_id >> 3) & 0x7ff; - xhci_dbg(xhci, "%s: index %d, reg 0x%x start_frame_id 0x%x, end_frame_id 0x%x, start_frame 0x%x\n", - __func__, index, readl(&xhci->run_regs->microframe_index), - start_frame_id, end_frame_id, start_frame); - if (start_frame_id < end_frame_id) { if (start_frame > end_frame_id || start_frame < start_frame_id) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index efdf4c228b8c..899c0effb5d3 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -347,8 +347,8 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) } /* interrupt moderation interval imod_interval in nanoseconds */ -static int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, - u32 imod_interval) +int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, + u32 imod_interval) { u32 imod; @@ -4525,6 +4525,20 @@ static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) struct xhci_port *port; u32 capability; + /* Check if USB3 device at root port is tunneled over USB4 */ + if (hcd->speed >= HCD_USB3 && !udev->parent->parent) { + port = xhci->usb3_rhub.ports[udev->portnum - 1]; + + udev->tunnel_mode = xhci_port_is_tunneled(xhci, port); + if (udev->tunnel_mode == USB_LINK_UNKNOWN) + dev_dbg(&udev->dev, "link tunnel state unknown\n"); + else if (udev->tunnel_mode == USB_LINK_TUNNELED) + dev_dbg(&udev->dev, "tunneled over USB4 link\n"); + else if (udev->tunnel_mode == USB_LINK_NATIVE) + dev_dbg(&udev->dev, "native USB 3.x link\n"); + return 0; + } + if (hcd->speed >= HCD_USB3 || !udev->lpm_capable || !xhci->hw_lpm_support) return 0; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ebd0afd59a60..620502de971a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1498,15 +1498,10 @@ struct xhci_hcd { spinlock_t lock; /* packed release number */ - u8 sbrn; u16 hci_version; - u8 max_slots; u16 max_interrupters; - u8 max_ports; - u8 isoc_threshold; /* imod_interval in ns (I * 250ns) */ u32 imod_interval; - int event_ring_max; /* 4KB min, 128MB max */ int page_size; /* Valid values are 12 to 20, inclusive */ @@ -1616,7 +1611,7 @@ struct xhci_hcd { #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35) -#define XHCI_RENESAS_FW_QUIRK BIT_ULL(36) +/* Reserved. It was XHCI_RENESAS_FW_QUIRK */ #define XHCI_SKIP_PHY_INIT BIT_ULL(37) #define XHCI_DISABLE_SPARSE BIT_ULL(38) #define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39) @@ -1628,6 +1623,7 @@ struct xhci_hcd { #define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45) #define XHCI_ZHAOXIN_HOST BIT_ULL(46) #define XHCI_WRITE_64_HI_LO BIT_ULL(47) +#define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48) unsigned int num_active_eps; unsigned int limit_active_eps; @@ -1831,7 +1827,8 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, void xhci_free_container_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); struct xhci_interrupter * -xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs); +xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs, + u32 imod_interval); void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir); @@ -1871,6 +1868,8 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags); +int xhci_set_interrupter_moderation(struct xhci_interrupter *ir, + u32 imod_interval); /* xHCI ring, segment, TRB, and TD functions */ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); @@ -1904,10 +1903,6 @@ int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd, enum xhci_ep_reset_type reset_type); int xhci_queue_reset_device(struct xhci_hcd *xhci, struct xhci_command *cmd, u32 slot_id); -void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int slot_id, - unsigned int ep_index, unsigned int stream_id, - struct xhci_td *td); -void xhci_stop_endpoint_command_watchdog(struct timer_list *t); void xhci_handle_command_timeout(struct work_struct *work); void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, @@ -1929,7 +1924,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1); struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd); - +enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci, + struct xhci_port *port); void xhci_hc_died(struct xhci_hcd *xhci); #ifdef CONFIG_PM diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index c8098e9b432e..62b5a30edc42 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -107,7 +107,12 @@ static void appledisplay_complete(struct urb *urb) case ACD_BTN_BRIGHT_UP: case ACD_BTN_BRIGHT_DOWN: pdata->button_pressed = 1; - schedule_delayed_work(&pdata->work, 0); + /* + * there is a window during which no device + * is registered + */ + if (pdata->bd ) + schedule_delayed_work(&pdata->work, 0); break; case ACD_BTN_NONE: default: @@ -202,6 +207,7 @@ static int appledisplay_probe(struct usb_interface *iface, const struct usb_device_id *id) { struct backlight_properties props; + struct backlight_device *backlight; struct appledisplay *pdata; struct usb_device *udev = interface_to_usbdev(iface); struct usb_endpoint_descriptor *endpoint; @@ -272,13 +278,14 @@ static int appledisplay_probe(struct usb_interface *iface, memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = 0xff; - pdata->bd = backlight_device_register(bl_name, NULL, pdata, + backlight = backlight_device_register(bl_name, NULL, pdata, &appledisplay_bl_data, &props); - if (IS_ERR(pdata->bd)) { + if (IS_ERR(backlight)) { dev_err(&iface->dev, "Backlight registration failed\n"); - retval = PTR_ERR(pdata->bd); + retval = PTR_ERR(backlight); goto error; } + pdata->bd = backlight; /* Try to get brightness */ brightness = appledisplay_bl_get_brightness(pdata->bd); diff --git a/drivers/usb/misc/brcmstb-usb-pinmap.c b/drivers/usb/misc/brcmstb-usb-pinmap.c index 2b2019c19cde..1ce885e4184c 100644 --- a/drivers/usb/misc/brcmstb-usb-pinmap.c +++ b/drivers/usb/misc/brcmstb-usb-pinmap.c @@ -335,6 +335,7 @@ static const struct of_device_id brcmstb_usb_pinmap_of_match[] = { { .compatible = "brcm,usb-pinmap" }, { }, }; +MODULE_DEVICE_TABLE(of, brcmstb_usb_pinmap_of_match); static struct platform_driver brcmstb_usb_pinmap_driver = { .driver = { diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index cecd7693b741..75f5a740cba3 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -88,6 +88,9 @@ static int vendor_command(struct cypress *dev, unsigned char request, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, address, data, iobuf, CYPRESS_MAX_REQSIZE, USB_CTRL_GET_TIMEOUT); + /* we must not process garbage */ + if (retval < 2) + goto err_buf; /* store returned data (more READs to be added) */ switch (request) { @@ -107,6 +110,7 @@ static int vendor_command(struct cypress *dev, unsigned char request, break; } +err_buf: kfree(iobuf); error: return retval; diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c index 56710e6b1653..560591e02d6a 100644 --- a/drivers/usb/misc/onboard_usb_dev.c +++ b/drivers/usb/misc/onboard_usb_dev.c @@ -11,6 +11,7 @@ #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/init.h> +#include <linux/i2c.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> @@ -29,6 +30,17 @@ #include "onboard_usb_dev.h" +/* USB5744 register offset and mask */ +#define USB5744_CMD_ATTACH 0xAA +#define USB5744_CMD_ATTACH_LSB 0x56 +#define USB5744_CMD_CREG_ACCESS 0x99 +#define USB5744_CMD_CREG_ACCESS_LSB 0x37 +#define USB5744_CREG_MEM_ADDR 0x00 +#define USB5744_CREG_WRITE 0x00 +#define USB5744_CREG_RUNTIMEFLAGS2 0x41 +#define USB5744_CREG_RUNTIMEFLAGS2_LSB 0x1D +#define USB5744_CREG_BYPASS_UDC_SUSPEND BIT(3) + static void onboard_dev_attach_usb_driver(struct work_struct *work); static struct usb_device_driver onboard_dev_usbdev_driver; @@ -98,6 +110,7 @@ static int onboard_dev_power_on(struct onboard_dev *onboard_dev) fsleep(onboard_dev->pdata->reset_us); gpiod_set_value_cansleep(onboard_dev->reset_gpio, 0); + fsleep(onboard_dev->pdata->power_on_delay_us); onboard_dev->is_powered_on = true; @@ -296,10 +309,50 @@ static void onboard_dev_attach_usb_driver(struct work_struct *work) pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err)); } +static int onboard_dev_5744_i2c_init(struct i2c_client *client) +{ +#if IS_ENABLED(CONFIG_I2C) + struct device *dev = &client->dev; + int ret; + + /* + * Set BYPASS_UDC_SUSPEND bit to ensure MCU is always enabled + * and ready to respond to SMBus runtime commands. + * The command writes 5 bytes to memory and single data byte in + * configuration register. + */ + char wr_buf[7] = {USB5744_CREG_MEM_ADDR, 5, + USB5744_CREG_WRITE, 1, + USB5744_CREG_RUNTIMEFLAGS2, + USB5744_CREG_RUNTIMEFLAGS2_LSB, + USB5744_CREG_BYPASS_UDC_SUSPEND}; + + ret = i2c_smbus_write_block_data(client, 0, sizeof(wr_buf), wr_buf); + if (ret) + return dev_err_probe(dev, ret, "BYPASS_UDC_SUSPEND bit configuration failed\n"); + + ret = i2c_smbus_write_word_data(client, USB5744_CMD_CREG_ACCESS, + USB5744_CMD_CREG_ACCESS_LSB); + if (ret) + return dev_err_probe(dev, ret, "Configuration Register Access Command failed\n"); + + /* Send SMBus command to boot hub. */ + ret = i2c_smbus_write_word_data(client, USB5744_CMD_ATTACH, + USB5744_CMD_ATTACH_LSB); + if (ret < 0) + return dev_err_probe(dev, ret, "USB Attach with SMBus command failed\n"); + + return ret; +#else + return -ENODEV; +#endif +} + static int onboard_dev_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct onboard_dev *onboard_dev; + struct device_node *i2c_node; int err; onboard_dev = devm_kzalloc(dev, sizeof(*onboard_dev), GFP_KERNEL); @@ -339,6 +392,27 @@ static int onboard_dev_probe(struct platform_device *pdev) if (err) return err; + i2c_node = of_parse_phandle(pdev->dev.of_node, "i2c-bus", 0); + if (i2c_node) { + struct i2c_client *client; + + client = of_find_i2c_device_by_node(i2c_node); + of_node_put(i2c_node); + + if (!client) { + err = -EPROBE_DEFER; + goto err_power_off; + } + + if (of_device_is_compatible(pdev->dev.of_node, "usb424,2744") || + of_device_is_compatible(pdev->dev.of_node, "usb424,5744")) + err = onboard_dev_5744_i2c_init(client); + + put_device(&client->dev); + if (err < 0) + goto err_power_off; + } + /* * The USB driver might have been detached from the USB devices by * onboard_dev_remove() (e.g. through an 'unbind' by userspace), @@ -350,6 +424,10 @@ static int onboard_dev_probe(struct platform_device *pdev) schedule_work(&attach_usb_driver_work); return 0; + +err_power_off: + onboard_dev_power_off(onboard_dev); + return err; } static void onboard_dev_remove(struct platform_device *pdev) diff --git a/drivers/usb/misc/onboard_usb_dev.h b/drivers/usb/misc/onboard_usb_dev.h index fbba549c0f47..317b3eb99c02 100644 --- a/drivers/usb/misc/onboard_usb_dev.h +++ b/drivers/usb/misc/onboard_usb_dev.h @@ -10,6 +10,7 @@ struct onboard_dev_pdata { unsigned long reset_us; /* reset pulse width in us */ + unsigned long power_on_delay_us; /* power on delay in us */ unsigned int num_supplies; /* number of supplies */ const char * const supply_names[MAX_SUPPLIES]; bool is_hub; @@ -24,6 +25,7 @@ static const struct onboard_dev_pdata microchip_usb424_data = { static const struct onboard_dev_pdata microchip_usb5744_data = { .reset_us = 0, + .power_on_delay_us = 10000, .num_supplies = 2, .supply_names = { "vdd", "vdd2" }, .is_hub = true, diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c index 26e9b8749d8a..19906301a4eb 100644 --- a/drivers/usb/misc/qcom_eud.c +++ b/drivers/usb/misc/qcom_eud.c @@ -232,7 +232,7 @@ static void eud_remove(struct platform_device *pdev) } static const struct of_device_id eud_dt_match[] = { - { .compatible = "qcom,sc7280-eud" }, + { .compatible = "qcom,eud" }, { } }; MODULE_DEVICE_TABLE(of, eud_dt_match); diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 4745a320eae4..4a9859e03f6b 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -404,7 +404,6 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, struct usb_yurex *dev; int len = 0; char in_buffer[MAX_S64_STRLEN]; - unsigned long flags; dev = file->private_data; @@ -419,9 +418,9 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, return -EIO; } - spin_lock_irqsave(&dev->lock, flags); + spin_lock_irq(&dev->lock); scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu); - spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock_irq(&dev->lock); mutex_unlock(&dev->io_mutex); return simple_read_from_buffer(buffer, count, ppos, in_buffer, len); @@ -511,8 +510,11 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, __func__, retval); goto error; } - if (set && timeout) + if (set && timeout) { + spin_lock_irq(&dev->lock); dev->bbu = c2; + spin_unlock_irq(&dev->lock); + } return timeout ? count : -EIO; error: diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c index 0a35aab3ab81..63c86c046b98 100644 --- a/drivers/usb/musb/mediatek.c +++ b/drivers/usb/musb/mediatek.c @@ -416,10 +416,9 @@ static int mtk_musb_probe(struct platform_device *pdev) return -ENOMEM; ret = of_platform_populate(np, NULL, NULL, dev); - if (ret) { - dev_err(dev, "failed to create child devices at %p\n", np); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "failed to create child devices at %p\n", np); ret = mtk_musb_clks_get(glue); if (ret) @@ -448,23 +447,19 @@ static int mtk_musb_probe(struct platform_device *pdev) glue->role = USB_ROLE_NONE; break; default: - dev_err(&pdev->dev, "Error 'dr_mode' property\n"); - return -EINVAL; + return dev_err_probe(&pdev->dev, -EINVAL, + "Error 'dr_mode' property\n"); } glue->phy = devm_of_phy_get_by_index(dev, np, 0); - if (IS_ERR(glue->phy)) { - dev_err(dev, "fail to getting phy %ld\n", - PTR_ERR(glue->phy)); - return PTR_ERR(glue->phy); - } + if (IS_ERR(glue->phy)) + return dev_err_probe(dev, PTR_ERR(glue->phy), + "fail to getting phy\n"); glue->usb_phy = usb_phy_generic_register(); - if (IS_ERR(glue->usb_phy)) { - dev_err(dev, "fail to registering usb-phy %ld\n", - PTR_ERR(glue->usb_phy)); - return PTR_ERR(glue->usb_phy); - } + if (IS_ERR(glue->usb_phy)) + return dev_err_probe(dev, PTR_ERR(glue->usb_phy), + "fail to registering usb-phy\n"); glue->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); if (IS_ERR(glue->xceiv)) { diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c index 29c7e5cdb230..00e13214aa76 100644 --- a/drivers/usb/musb/mpfs.c +++ b/drivers/usb/musb/mpfs.c @@ -49,30 +49,6 @@ static const struct musb_hdrc_config mpfs_musb_hdrc_config = { .ram_bits = MPFS_MUSB_RAM_BITS, }; -static irqreturn_t mpfs_musb_interrupt(int irq, void *__hci) -{ - unsigned long flags; - irqreturn_t ret = IRQ_NONE; - struct musb *musb = __hci; - - spin_lock_irqsave(&musb->lock, flags); - - musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); - musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); - musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); - - if (musb->int_usb || musb->int_tx || musb->int_rx) { - musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); - musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); - musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); - ret = musb_interrupt(musb); - } - - spin_unlock_irqrestore(&musb->lock, flags); - - return ret; -} - static void mpfs_musb_set_vbus(struct musb *musb, int is_on) { u8 devctl; @@ -111,6 +87,129 @@ static void mpfs_musb_set_vbus(struct musb *musb, int is_on) musb_readb(musb->mregs, MUSB_DEVCTL)); } +#define POLL_SECONDS 2 + +static void otg_timer(struct timer_list *t) +{ + struct musb *musb = from_timer(musb, t, dev_timer); + void __iomem *mregs = musb->mregs; + u8 devctl; + unsigned long flags; + + /* + * We poll because PolarFire SoC won't expose several OTG-critical + * status change events (from the transceiver) otherwise. + */ + devctl = musb_readb(mregs, MUSB_DEVCTL); + dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, + usb_otg_state_string(musb->xceiv->otg->state)); + + spin_lock_irqsave(&musb->lock, flags); + switch (musb->xceiv->otg->state) { + case OTG_STATE_A_WAIT_BCON: + devctl &= ~MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + if (devctl & MUSB_DEVCTL_BDEVICE) { + musb->xceiv->otg->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + mod_timer(&musb->dev_timer, jiffies + POLL_SECONDS * HZ); + } else { + musb->xceiv->otg->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + } + break; + case OTG_STATE_A_WAIT_VFALL: + if (devctl & MUSB_DEVCTL_VBUS) { + mod_timer(&musb->dev_timer, jiffies + POLL_SECONDS * HZ); + break; + } + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; + break; + case OTG_STATE_B_IDLE: + /* + * There's no ID-changed IRQ, so we have no good way to tell + * when to switch to the A-Default state machine (by setting + * the DEVCTL.Session bit). + * + * Workaround: whenever we're in B_IDLE, try setting the + * session flag every few seconds. If it works, ID was + * grounded and we're now in the A-Default state machine. + * + * NOTE: setting the session flag is _supposed_ to trigger + * SRP but clearly it doesn't. + */ + musb_writeb(mregs, MUSB_DEVCTL, devctl | MUSB_DEVCTL_SESSION); + devctl = musb_readb(mregs, MUSB_DEVCTL); + if (devctl & MUSB_DEVCTL_BDEVICE) + mod_timer(&musb->dev_timer, jiffies + POLL_SECONDS * HZ); + else + musb->xceiv->otg->state = OTG_STATE_A_IDLE; + break; + default: + break; + } + spin_unlock_irqrestore(&musb->lock, flags); +} + +static void __maybe_unused mpfs_musb_try_idle(struct musb *musb, unsigned long timeout) +{ + static unsigned long last_timer; + + if (timeout == 0) + timeout = jiffies + msecs_to_jiffies(3); + + /* Never idle if active, or when VBUS timeout is not set as host */ + if (musb->is_active || (musb->a_wait_bcon == 0 && + musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)) { + dev_dbg(musb->controller, "%s active, deleting timer\n", + usb_otg_state_string(musb->xceiv->otg->state)); + del_timer(&musb->dev_timer); + last_timer = jiffies; + return; + } + + if (time_after(last_timer, timeout) && timer_pending(&musb->dev_timer)) { + dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n"); + return; + } + last_timer = timeout; + + dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", + usb_otg_state_string(musb->xceiv->otg->state), + jiffies_to_msecs(timeout - jiffies)); + mod_timer(&musb->dev_timer, timeout); +} + +static irqreturn_t mpfs_musb_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + if (musb->int_usb || musb->int_tx || musb->int_rx) { + musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); + musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); + musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); + ret = musb_interrupt(musb); + } + + /* Poll for ID change */ + if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) + mod_timer(&musb->dev_timer, jiffies + POLL_SECONDS * HZ); + + spin_unlock_irqrestore(&musb->lock, flags); + + return ret; +} + static int mpfs_musb_init(struct musb *musb) { struct device *dev = musb->controller; @@ -121,6 +220,8 @@ static int mpfs_musb_init(struct musb *musb) return PTR_ERR(musb->xceiv); } + timer_setup(&musb->dev_timer, otg_timer, 0); + musb->dyn_fifo = true; musb->isr = mpfs_musb_interrupt; @@ -129,14 +230,25 @@ static int mpfs_musb_init(struct musb *musb) return 0; } +static int mpfs_musb_exit(struct musb *musb) +{ + del_timer_sync(&musb->dev_timer); + + return 0; +} + static const struct musb_platform_ops mpfs_ops = { .quirks = MUSB_DMA_INVENTRA, .init = mpfs_musb_init, + .exit = mpfs_musb_exit, .fifo_mode = 2, #ifdef CONFIG_USB_INVENTRA_DMA .dma_init = musbhs_dma_controller_create, .dma_exit = musbhs_dma_controller_destroy, #endif +#ifndef CONFIG_USB_MUSB_HOST + .try_idle = mpfs_musb_try_idle, +#endif .set_vbus = mpfs_musb_set_vbus }; diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 817c242a76ca..5428b2b67de1 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -374,6 +374,7 @@ static const struct of_device_id gpio_vbus_of_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, gpio_vbus_of_match); static struct platform_driver gpio_vbus_driver = { .driver = { diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 920a32cd094d..cc4156c1b148 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -18,6 +18,7 @@ #include <linux/regmap.h> #include <linux/mfd/syscon.h> #include <linux/iopoll.h> +#include <linux/regulator/consumer.h> #define DRIVER_NAME "mxs_phy" @@ -70,6 +71,9 @@ #define BM_USBPHY_PLL_EN_USB_CLKS BIT(6) /* Anatop Registers */ +#define ANADIG_REG_1P1_SET 0x114 +#define ANADIG_REG_1P1_CLR 0x118 + #define ANADIG_ANA_MISC0 0x150 #define ANADIG_ANA_MISC0_SET 0x154 #define ANADIG_ANA_MISC0_CLR 0x158 @@ -117,6 +121,14 @@ #define BM_ANADIG_USB2_MISC_RX_VPIN_FS BIT(29) #define BM_ANADIG_USB2_MISC_RX_VMIN_FS BIT(28) +/* System Integration Module (SIM) Registers */ +#define SIM_GPR1 0x30 + +#define USB_PHY_VLLS_WAKEUP_EN BIT(0) + +#define BM_ANADIG_REG_1P1_ENABLE_WEAK_LINREG BIT(18) +#define BM_ANADIG_REG_1P1_TRACK_VDD_SOC_CAP BIT(19) + #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) /* Do disconnection between PHY and controller without vbus */ @@ -149,6 +161,15 @@ #define MXS_PHY_TX_D_CAL_MIN 79 #define MXS_PHY_TX_D_CAL_MAX 119 +/* + * At imx6q/6sl/6sx, the PHY2's clock is controlled by hardware directly, + * eg, according to PHY's suspend status. In these PHYs, we only need to + * open the clock at the initialization and close it at its shutdown routine. + * These PHYs can send resume signal without software interfere if not + * gate clock. + */ +#define MXS_PHY_HARDWARE_CONTROL_PHY2_CLK BIT(4) + struct mxs_phy_data { unsigned int flags; }; @@ -160,12 +181,14 @@ static const struct mxs_phy_data imx23_phy_data = { static const struct mxs_phy_data imx6q_phy_data = { .flags = MXS_PHY_SENDING_SOF_TOO_FAST | MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS | - MXS_PHY_NEED_IP_FIX, + MXS_PHY_NEED_IP_FIX | + MXS_PHY_HARDWARE_CONTROL_PHY2_CLK, }; static const struct mxs_phy_data imx6sl_phy_data = { .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS | - MXS_PHY_NEED_IP_FIX, + MXS_PHY_NEED_IP_FIX | + MXS_PHY_HARDWARE_CONTROL_PHY2_CLK, }; static const struct mxs_phy_data vf610_phy_data = { @@ -174,11 +197,13 @@ static const struct mxs_phy_data vf610_phy_data = { }; static const struct mxs_phy_data imx6sx_phy_data = { - .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS, + .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS | + MXS_PHY_HARDWARE_CONTROL_PHY2_CLK, }; static const struct mxs_phy_data imx6ul_phy_data = { - .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS, + .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS | + MXS_PHY_HARDWARE_CONTROL_PHY2_CLK, }; static const struct mxs_phy_data imx7ulp_phy_data = { @@ -201,9 +226,11 @@ struct mxs_phy { struct clk *clk; const struct mxs_phy_data *data; struct regmap *regmap_anatop; + struct regmap *regmap_sim; int port_id; u32 tx_reg_set; u32 tx_reg_mask; + struct regulator *phy_3p0; }; static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy) @@ -221,6 +248,11 @@ static inline bool is_imx7ulp_phy(struct mxs_phy *mxs_phy) return mxs_phy->data == &imx7ulp_phy_data; } +static inline bool is_imx6ul_phy(struct mxs_phy *mxs_phy) +{ + return mxs_phy->data == &imx6ul_phy_data; +} + /* * PHY needs some 32K cycles to switch from 32K clock to * bus (such as AHB/AXI, etc) clock. @@ -288,6 +320,16 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) if (ret) goto disable_pll; + if (mxs_phy->phy_3p0) { + ret = regulator_enable(mxs_phy->phy_3p0); + if (ret) { + dev_err(mxs_phy->phy.dev, + "Failed to enable 3p0 regulator, ret=%d\n", + ret); + return ret; + } + } + /* Power up the PHY */ writel(0, base + HW_USBPHY_PWD); @@ -448,6 +490,9 @@ static void mxs_phy_shutdown(struct usb_phy *phy) if (is_imx7ulp_phy(mxs_phy)) mxs_phy_pll_enable(phy->io_priv, false); + if (mxs_phy->phy_3p0) + regulator_disable(mxs_phy->phy_3p0); + clk_disable_unprepare(mxs_phy->clk); } @@ -503,12 +548,19 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend) } writel(BM_USBPHY_CTRL_CLKGATE, x->io_priv + HW_USBPHY_CTRL_SET); - clk_disable_unprepare(mxs_phy->clk); + if (!(mxs_phy->port_id == 1 && + (mxs_phy->data->flags & + MXS_PHY_HARDWARE_CONTROL_PHY2_CLK))) + clk_disable_unprepare(mxs_phy->clk); } else { mxs_phy_clock_switch_delay(); - ret = clk_prepare_enable(mxs_phy->clk); - if (ret) - return ret; + if (!(mxs_phy->port_id == 1 && + (mxs_phy->data->flags & + MXS_PHY_HARDWARE_CONTROL_PHY2_CLK))) { + ret = clk_prepare_enable(mxs_phy->clk); + if (ret) + return ret; + } writel(BM_USBPHY_CTRL_CLKGATE, x->io_priv + HW_USBPHY_CTRL_CLR); writel(0, x->io_priv + HW_USBPHY_PWD); @@ -738,6 +790,17 @@ static int mxs_phy_probe(struct platform_device *pdev) } } + /* Currently, only imx7ulp has SIM module */ + if (of_get_property(np, "nxp,sim", NULL)) { + mxs_phy->regmap_sim = syscon_regmap_lookup_by_phandle + (np, "nxp,sim"); + if (IS_ERR(mxs_phy->regmap_sim)) { + dev_dbg(&pdev->dev, + "failed to find regmap for sim\n"); + return PTR_ERR(mxs_phy->regmap_sim); + } + } + /* Precompute which bits of the TX register are to be updated, if any */ if (!of_property_read_u32(np, "fsl,tx-cal-45-dn-ohms", &val) && val >= MXS_PHY_TX_CAL45_MIN && val <= MXS_PHY_TX_CAL45_MAX) { @@ -789,6 +852,17 @@ static int mxs_phy_probe(struct platform_device *pdev) mxs_phy->clk = clk; mxs_phy->data = of_device_get_match_data(&pdev->dev); + mxs_phy->phy_3p0 = devm_regulator_get(&pdev->dev, "phy-3p0"); + if (PTR_ERR(mxs_phy->phy_3p0) == -ENODEV) + /* not exist */ + mxs_phy->phy_3p0 = NULL; + else if (IS_ERR(mxs_phy->phy_3p0)) + return dev_err_probe(&pdev->dev, PTR_ERR(mxs_phy->phy_3p0), + "Getting regulator error\n"); + + if (mxs_phy->phy_3p0) + regulator_set_voltage(mxs_phy->phy_3p0, 3200000, 3200000); + platform_set_drvdata(pdev, mxs_phy); device_set_wakeup_capable(&pdev->dev, true); @@ -804,28 +878,58 @@ static void mxs_phy_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP +static void mxs_phy_wakeup_enable(struct mxs_phy *mxs_phy, bool on) +{ + u32 mask = USB_PHY_VLLS_WAKEUP_EN; + + /* If the SoCs don't have SIM, quit */ + if (!mxs_phy->regmap_sim) + return; + + if (on) { + regmap_update_bits(mxs_phy->regmap_sim, SIM_GPR1, mask, mask); + udelay(500); + } else { + regmap_update_bits(mxs_phy->regmap_sim, SIM_GPR1, mask, 0); + } +} + static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on) { - unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR; + unsigned int reg; + u32 value; /* If the SoCs don't have anatop, quit */ if (!mxs_phy->regmap_anatop) return; - if (is_imx6q_phy(mxs_phy)) + if (is_imx6q_phy(mxs_phy)) { + reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR; regmap_write(mxs_phy->regmap_anatop, reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG); - else if (is_imx6sl_phy(mxs_phy)) + } else if (is_imx6sl_phy(mxs_phy)) { + reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR; regmap_write(mxs_phy->regmap_anatop, reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL); + } else if (is_imx6ul_phy(mxs_phy)) { + reg = on ? ANADIG_REG_1P1_SET : ANADIG_REG_1P1_CLR; + value = BM_ANADIG_REG_1P1_ENABLE_WEAK_LINREG | + BM_ANADIG_REG_1P1_TRACK_VDD_SOC_CAP; + if (mxs_phy_get_vbus_status(mxs_phy) && on) + regmap_write(mxs_phy->regmap_anatop, reg, value); + else if (!on) + regmap_write(mxs_phy->regmap_anatop, reg, value); + } } static int mxs_phy_system_suspend(struct device *dev) { struct mxs_phy *mxs_phy = dev_get_drvdata(dev); - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev)) { mxs_phy_enable_ldo_in_suspend(mxs_phy, true); + mxs_phy_wakeup_enable(mxs_phy, true); + } return 0; } @@ -834,8 +938,10 @@ static int mxs_phy_system_resume(struct device *dev) { struct mxs_phy *mxs_phy = dev_get_drvdata(dev); - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev)) { mxs_phy_enable_ldo_in_suspend(mxs_phy, false); + mxs_phy_wakeup_enable(mxs_phy, false); + } return 0; } diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index d7aa913ceb8a..c58a12c147f4 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -11,6 +11,7 @@ #include <linux/usb/role.h> #include <linux/property.h> #include <linux/device.h> +#include <linux/lockdep.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/slab.h> @@ -21,6 +22,7 @@ static const struct class role_class = { struct usb_role_switch { struct device dev; + struct lock_class_key key; struct mutex lock; /* device lock*/ struct module *module; /* the module this device depends on */ enum usb_role role; @@ -326,6 +328,8 @@ static void usb_role_switch_release(struct device *dev) { struct usb_role_switch *sw = to_role_switch(dev); + mutex_destroy(&sw->lock); + lockdep_unregister_key(&sw->key); kfree(sw); } @@ -364,7 +368,8 @@ usb_role_switch_register(struct device *parent, if (!sw) return ERR_PTR(-ENOMEM); - mutex_init(&sw->lock); + lockdep_register_key(&sw->key); + mutex_init_with_key(&sw->lock, &sw->key); sw->allow_userspace_control = desc->allow_userspace_control; sw->usb2_port = desc->usb2_port; diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index a1df686c3066..aa517242d060 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -138,7 +138,6 @@ static void aircable_process_read_urb(struct urb *urb) static struct usb_serial_driver aircable_device = { .driver = { - .owner = THIS_MODULE, .name = "aircable", }, .id_table = id_table, diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 67a07cc007f0..800b04fe37fa 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -599,7 +599,6 @@ static void ark3116_process_read_urb(struct urb *urb) static struct usb_serial_driver ark3116_device = { .driver = { - .owner = THIS_MODULE, .name = "ark3116", }, .id_table = id_table, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index cf47ee4ae5d3..44f5b58beec9 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -66,7 +66,6 @@ MODULE_DEVICE_TABLE(usb, id_table); /* All of the device info needed for the serial converters */ static struct usb_serial_driver belkin_device = { .driver = { - .owner = THIS_MODULE, .name = "belkin", }, .description = "Belkin / Peracom / GoHubs USB Serial Adapter", diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 0870c6533f80..02945ccf531d 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -837,7 +837,6 @@ static int ch341_reset_resume(struct usb_serial *serial) static struct usb_serial_driver ch341_device = { .driver = { - .owner = THIS_MODULE, .name = "ch341-uart", }, .id_table = id_table, diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 21fd26609252..c24101f0a07a 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -299,7 +299,6 @@ struct cp210x_port_private { static struct usb_serial_driver cp210x_device = { .driver = { - .owner = THIS_MODULE, .name = "cp210x", }, .id_table = id_table, diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 51e5aac3bf4c..76dd8e7453b5 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -67,7 +67,6 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver cyberjack_device = { .driver = { - .owner = THIS_MODULE, .name = "cyberjack", }, .description = "Reiner SCT Cyberjack USB card reader", diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 1e0c028c5ec9..ce9134bb30f3 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -139,7 +139,6 @@ static void cypress_write_int_callback(struct urb *urb); static struct usb_serial_driver cypress_earthmate_device = { .driver = { - .owner = THIS_MODULE, .name = "earthmate", }, .description = "DeLorme Earthmate USB", @@ -166,7 +165,6 @@ static struct usb_serial_driver cypress_earthmate_device = { static struct usb_serial_driver cypress_hidcom_device = { .driver = { - .owner = THIS_MODULE, .name = "cyphidcom", }, .description = "HID->COM RS232 Adapter", @@ -192,7 +190,6 @@ static struct usb_serial_driver cypress_hidcom_device = { static struct usb_serial_driver cypress_ca42v2_device = { .driver = { - .owner = THIS_MODULE, .name = "nokiaca42v2", }, .description = "Nokia CA-42 V2 Adapter", diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index d1dea3850576..a06485965412 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -262,7 +262,6 @@ MODULE_DEVICE_TABLE(usb, id_table_combined); static struct usb_serial_driver digi_acceleport_2_device = { .driver = { - .owner = THIS_MODULE, .name = "digi_2", }, .description = "Digi 2 port USB adapter", @@ -293,7 +292,6 @@ static struct usb_serial_driver digi_acceleport_2_device = { static struct usb_serial_driver digi_acceleport_4_device = { .driver = { - .owner = THIS_MODULE, .name = "digi_4", }, .description = "Digi 4 port USB adapter", diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 405e835e93dd..aedcf7ebd269 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -43,7 +43,6 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver empeg_device = { .driver = { - .owner = THIS_MODULE, .name = "empeg", }, .id_table = id_table, diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 5f7a46bcace6..530b77fc2f78 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -967,7 +967,6 @@ static int f81232_resume(struct usb_serial *serial) static struct usb_serial_driver f81232_device = { .driver = { - .owner = THIS_MODULE, .name = "f81232", }, .id_table = f81232_id_table, @@ -994,7 +993,6 @@ static struct usb_serial_driver f81232_device = { static struct usb_serial_driver f81534a_device = { .driver = { - .owner = THIS_MODULE, .name = "f81534a", }, .id_table = f81534a_id_table, diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index ef126cd3d94f..685930ac8383 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -1538,7 +1538,6 @@ static int f81534_resume(struct usb_serial *serial) static struct usb_serial_driver f81534_device = { .driver = { - .owner = THIS_MODULE, .name = "f81534", }, .description = DRIVER_DESC, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 76a04ab41100..c6f17d732b95 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2871,7 +2871,6 @@ static int ftdi_ioctl(struct tty_struct *tty, static struct usb_serial_driver ftdi_device = { .driver = { - .owner = THIS_MODULE, .name = "ftdi_sio", .dev_groups = ftdi_groups, }, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 6d6ec7eed87c..b97ba8ed6801 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1412,7 +1412,6 @@ static void garmin_port_remove(struct usb_serial_port *port) /* All of the device info needed */ static struct usb_serial_driver garmin_device = { .driver = { - .owner = THIS_MODULE, .name = "garmin_gps", }, .description = "Garmin GPS usb/tty", diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 15b6dee3a8e5..757f0a586ddb 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -63,7 +63,6 @@ static int usb_serial_generic_calc_num_ports(struct usb_serial *serial, static struct usb_serial_driver usb_serial_generic_device = { .driver = { - .owner = THIS_MODULE, .name = "generic", }, .id_table = generic_device_ids, diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index abe4bbb0ac65..c7d6b5e3f898 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2978,7 +2978,6 @@ static void edge_port_remove(struct usb_serial_port *port) static struct usb_serial_driver edgeport_2port_device = { .driver = { - .owner = THIS_MODULE, .name = "edgeport_2", }, .description = "Edgeport 2 port adapter", @@ -3013,7 +3012,6 @@ static struct usb_serial_driver edgeport_2port_device = { static struct usb_serial_driver edgeport_4port_device = { .driver = { - .owner = THIS_MODULE, .name = "edgeport_4", }, .description = "Edgeport 4 port adapter", @@ -3048,7 +3046,6 @@ static struct usb_serial_driver edgeport_4port_device = { static struct usb_serial_driver edgeport_8port_device = { .driver = { - .owner = THIS_MODULE, .name = "edgeport_8", }, .description = "Edgeport 8 port adapter", @@ -3083,7 +3080,6 @@ static struct usb_serial_driver edgeport_8port_device = { static struct usb_serial_driver epic_device = { .driver = { - .owner = THIS_MODULE, .name = "epic", }, .description = "EPiC device", diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 7a3a6e539456..7d0584b2a234 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2670,7 +2670,6 @@ static int edge_resume(struct usb_serial *serial) static struct usb_serial_driver edgeport_1port_device = { .driver = { - .owner = THIS_MODULE, .name = "edgeport_ti_1", }, .description = "Edgeport TI 1 port adapter", @@ -2708,7 +2707,6 @@ static struct usb_serial_driver edgeport_1port_device = { static struct usb_serial_driver edgeport_2port_device = { .driver = { - .owner = THIS_MODULE, .name = "edgeport_ti_2", }, .description = "Edgeport TI 2 port adapter", diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index e11441bac44f..3c6a9b9b9c2b 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -496,7 +496,6 @@ MODULE_DEVICE_TABLE(usb, ipaq_id_table); /* All of the device info needed for the Compaq iPAQ */ static struct usb_serial_driver ipaq_device = { .driver = { - .owner = THIS_MODULE, .name = "ipaq", }, .description = "PocketPC PDA", diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index d04c7cc5c1c2..b1e672c2f423 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -285,7 +285,6 @@ static void ipw_close(struct usb_serial_port *port) static struct usb_serial_driver ipw_device = { .driver = { - .owner = THIS_MODULE, .name = "ipw", }, .description = "IPWireless converter", diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 82f108134e6f..a106b71e698f 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -71,7 +71,6 @@ MODULE_DEVICE_TABLE(usb, ir_id_table); static struct usb_serial_driver ir_device = { .driver = { - .owner = THIS_MODULE, .name = "ir-usb", }, .description = "IR Dongle", diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 77cba71bcccb..c21dcc9b6f05 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -1157,7 +1157,6 @@ static int iuu_remove_sysfs_attrs(struct usb_serial_port *port) static struct usb_serial_driver iuu_device = { .driver = { - .owner = THIS_MODULE, .name = "iuu_phoenix", }, .id_table = id_table, diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 0a783985197c..9129e0282c24 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -3001,7 +3001,6 @@ static void keyspan_port_remove(struct usb_serial_port *port) /* Structs for the devices, pre and post renumeration. */ static struct usb_serial_driver keyspan_pre_device = { .driver = { - .owner = THIS_MODULE, .name = "keyspan_no_firm", }, .description = "Keyspan - (without firmware)", @@ -3012,7 +3011,6 @@ static struct usb_serial_driver keyspan_pre_device = { static struct usb_serial_driver keyspan_1port_device = { .driver = { - .owner = THIS_MODULE, .name = "keyspan_1", }, .description = "Keyspan 1 port adapter", @@ -3036,7 +3034,6 @@ static struct usb_serial_driver keyspan_1port_device = { static struct usb_serial_driver keyspan_2port_device = { .driver = { - .owner = THIS_MODULE, .name = "keyspan_2", }, .description = "Keyspan 2 port adapter", @@ -3060,7 +3057,6 @@ static struct usb_serial_driver keyspan_2port_device = { static struct usb_serial_driver keyspan_4port_device = { .driver = { - .owner = THIS_MODULE, .name = "keyspan_4", }, .description = "Keyspan 4 port adapter", diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 0eef358b314a..e98b479593d3 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -676,7 +676,6 @@ static void keyspan_pda_port_remove(struct usb_serial_port *port) static struct usb_serial_driver keyspan_pda_fake_device = { .driver = { - .owner = THIS_MODULE, .name = "keyspan_pda_pre", }, .description = "Keyspan PDA - (prerenumeration)", @@ -687,7 +686,6 @@ static struct usb_serial_driver keyspan_pda_fake_device = { static struct usb_serial_driver keyspan_pda_device = { .driver = { - .owner = THIS_MODULE, .name = "keyspan_pda", }, .description = "Keyspan PDA", diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 394b3189e003..a2c0bebc041f 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -75,7 +75,6 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver kl5kusb105d_device = { .driver = { - .owner = THIS_MODULE, .name = "kl5kusb105d", }, .description = "KL5KUSB105D / PalmConnect", diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 5e775f68fcb8..464433be2034 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -77,7 +77,6 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver kobil_device = { .driver = { - .owner = THIS_MODULE, .name = "kobil", }, .description = "KOBIL USB smart card terminal", @@ -156,8 +155,7 @@ static void kobil_init_termios(struct tty_struct *tty) { /* Default to echo off and other sane device settings */ tty->termios.c_lflag = 0; - tty->termios.c_iflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); - tty->termios.c_iflag |= IGNBRK | IGNPAR | IXOFF; + tty->termios.c_iflag = IGNBRK | IGNPAR | IXOFF; /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */ tty->termios.c_oflag &= ~ONLCR; } diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 6570c8817a80..e5a139ed5d90 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -69,7 +69,6 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver mct_u232_device = { .driver = { - .owner = THIS_MODULE, .name = "mct_u232", }, .description = "MCT U232", diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 30ab565e0738..028878292901 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -341,7 +341,6 @@ static void metrousb_unthrottle(struct tty_struct *tty) static struct usb_serial_driver metrousb_device = { .driver = { - .owner = THIS_MODULE, .name = "metro-usb", }, .description = "Metrologic USB to Serial", diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 23544074eb1c..e59bfa7c8030 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1724,7 +1724,6 @@ static void mos7720_port_remove(struct usb_serial_port *port) static struct usb_serial_driver moschip7720_2port_driver = { .driver = { - .owner = THIS_MODULE, .name = "moschip7720", }, .description = "Moschip 2 port adapter", diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 85697466b147..ca3da79afd23 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1782,7 +1782,6 @@ static int mos7840_resume(struct usb_serial *serial) static struct usb_serial_driver moschip7840_4port_device = { .driver = { - .owner = THIS_MODULE, .name = "mos7840", }, .description = DRIVER_DESC, diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index 942cb0153423..57e4f2b215d8 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -1278,7 +1278,6 @@ static int mxuport_resume(struct usb_serial *serial) static struct usb_serial_driver mxuport_device = { .driver = { - .owner = THIS_MODULE, .name = "mxuport", }, .description = "MOXA UPort", diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 82791fd67c46..4d57a5902292 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -95,7 +95,6 @@ static int navman_write(struct tty_struct *tty, struct usb_serial_port *port, static struct usb_serial_driver navman_device = { .driver = { - .owner = THIS_MODULE, .name = "navman", }, .id_table = id_table, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 41f1b872d277..397ebd5a3e74 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -49,7 +49,6 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver zyxel_omninet_device = { .driver = { - .owner = THIS_MODULE, .name = "omninet", }, .description = "ZyXEL - omni.net usb", diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index e31a6d77da3a..1ee84ccc4bbd 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -375,7 +375,6 @@ static void opticon_port_remove(struct usb_serial_port *port) static struct usb_serial_driver opticon_device = { .driver = { - .owner = THIS_MODULE, .name = "opticon", }, .id_table = id_table, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 311040f9b935..eb0731992ca9 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -619,6 +619,8 @@ static void option_instat_callback(struct urb *urb); /* MeiG Smart Technology products */ #define MEIGSMART_VENDOR_ID 0x2dee +/* MeiG Smart SRM825L based on Qualcomm 315 */ +#define MEIGSMART_PRODUCT_SRM825L 0x4d22 /* MeiG Smart SLM320 based on UNISOC UIS8910 */ #define MEIGSMART_PRODUCT_SLM320 0x4d41 @@ -2366,6 +2368,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM320, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x60) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); @@ -2376,7 +2381,6 @@ MODULE_DEVICE_TABLE(usb, option_ids); static struct usb_serial_driver option_1port_device = { .driver = { - .owner = THIS_MODULE, .name = "option1", }, .description = "GSM modem (1-port)", diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index fa07f6ff9ecc..24068368892c 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -138,7 +138,6 @@ static void oti6858_port_remove(struct usb_serial_port *port); /* device info */ static struct usb_serial_driver oti6858_device = { .driver = { - .owner = THIS_MODULE, .name = "oti6858", }, .id_table = id_table, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index d93f5d584557..ab48f8875249 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -118,6 +118,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_PRODUCT_ID) }, + { USB_DEVICE(MACROSILICON_VENDOR_ID, MACROSILICON_MS3020_PRODUCT_ID) }, { } /* Terminating entry */ }; @@ -1234,7 +1235,6 @@ static void pl2303_process_read_urb(struct urb *urb) static struct usb_serial_driver pl2303_device = { .driver = { - .owner = THIS_MODULE, .name = "pl2303", }, .id_table = id_table, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 732f9b13ad5d..d60eda7f6eda 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -171,3 +171,7 @@ /* Allied Telesis VT-Kit3 */ #define AT_VENDOR_ID 0x0caa #define AT_VTKIT3_PRODUCT_ID 0x3001 + +/* Macrosilicon MS3020 */ +#define MACROSILICON_VENDOR_ID 0x345f +#define MACROSILICON_MS3020_PRODUCT_ID 0x3020 diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index 015bb7c5d19d..485ec5b07122 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -72,7 +72,6 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver qcaux_device = { .driver = { - .owner = THIS_MODULE, .name = "qcaux", }, .id_table = id_table, diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 703a9c563557..c7de9585feb2 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -454,7 +454,6 @@ static void qc_release(struct usb_serial *serial) static struct usb_serial_driver qcdevice = { .driver = { - .owner = THIS_MODULE, .name = "qcserial", }, .description = "Qualcomm USB modem", diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 821f25e52ec2..4167a45d1be3 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -924,7 +924,6 @@ write_out: static struct usb_serial_driver qt2_device = { .driver = { - .owner = THIS_MODULE, .name = "quatech-serial", }, .description = DRIVER_DESC, diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 6accbecb6318..238b54993446 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -284,7 +284,6 @@ static int safe_startup(struct usb_serial *serial) static struct usb_serial_driver safe_device = { .driver = { - .owner = THIS_MODULE, .name = "safe_serial", }, .id_table = id_table, diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 353b2549eaa8..64a2e0bb5723 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -1021,7 +1021,6 @@ static int sierra_resume(struct usb_serial *serial) static struct usb_serial_driver sierra_device = { .driver = { - .owner = THIS_MODULE, .name = "sierra", }, .description = "Sierra USB modem", diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 6b294bf8bc43..11077beb7232 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -452,7 +452,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty) static struct usb_serial_driver spcp8x5_device = { .driver = { - .owner = THIS_MODULE, .name = "SPCP8x5", }, .id_table = id_table, diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 1e1888b66305..df21009bdf42 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -500,7 +500,6 @@ static void ssu100_process_read_urb(struct urb *urb) static struct usb_serial_driver ssu100_device = { .driver = { - .owner = THIS_MODULE, .name = "ssu100", }, .description = DRIVER_DESC, diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 9aabb087f733..58962bcbf9ba 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -169,7 +169,6 @@ static void symbol_port_remove(struct usb_serial_port *port) static struct usb_serial_driver symbol_device = { .driver = { - .owner = THIS_MODULE, .name = "symbol", }, .id_table = id_table, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 0fba25abf671..a0c244bc77c0 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -417,7 +417,6 @@ static const struct usb_device_id ti_id_table_combined[] = { static struct usb_serial_driver ti_1port_device = { .driver = { - .owner = THIS_MODULE, .name = "ti_usb_3410_5052_1", }, .description = "TI USB 3410 1 port adapter", @@ -450,7 +449,6 @@ static struct usb_serial_driver ti_1port_device = { static struct usb_serial_driver ti_2port_device = { .driver = { - .owner = THIS_MODULE, .name = "ti_usb_3410_5052_2", }, .description = "TI USB 5052 2 port adapter", diff --git a/drivers/usb/serial/upd78f0730.c b/drivers/usb/serial/upd78f0730.c index 46952182e04f..15a17bf111f1 100644 --- a/drivers/usb/serial/upd78f0730.c +++ b/drivers/usb/serial/upd78f0730.c @@ -407,7 +407,6 @@ static void upd78f0730_close(struct usb_serial_port *port) static struct usb_serial_driver upd78f0730_device = { .driver = { - .owner = THIS_MODULE, .name = "upd78f0730", }, .id_table = id_table, diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 82f4f0b992aa..2c12449ff60c 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -24,7 +24,6 @@ static const struct usb_device_id vendor##_id_table[] = { \ }; \ static struct usb_serial_driver vendor##_device = { \ .driver = { \ - .owner = THIS_MODULE, \ .name = #vendor, \ }, \ .id_table = vendor##_id_table, \ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index f1e91eb7f8a4..df6a2ae0bf42 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1459,17 +1459,18 @@ static void usb_serial_deregister(struct usb_serial_driver *device) } /** - * usb_serial_register_drivers - register drivers for a usb-serial module + * __usb_serial_register_drivers - register drivers for a usb-serial module * @serial_drivers: NULL-terminated array of pointers to drivers to be registered + * @owner: owning module * @name: name of the usb_driver for this set of @serial_drivers * @id_table: list of all devices this @serial_drivers set binds to * * Registers all the drivers in the @serial_drivers array, and dynamically * creates a struct usb_driver with the name @name and id_table of @id_table. */ -int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[], - const char *name, - const struct usb_device_id *id_table) +int __usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[], + struct module *owner, const char *name, + const struct usb_device_id *id_table) { int rc; struct usb_driver *udriver; @@ -1514,6 +1515,7 @@ int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[] for (sd = serial_drivers; *sd; ++sd) { (*sd)->usb_driver = udriver; + (*sd)->driver.owner = owner; rc = usb_serial_register(*sd); if (rc) goto err_deregister_drivers; @@ -1532,7 +1534,7 @@ err_free_driver: kfree(udriver); return rc; } -EXPORT_SYMBOL_GPL(usb_serial_register_drivers); +EXPORT_SYMBOL_GPL(__usb_serial_register_drivers); /** * usb_serial_deregister_drivers - deregister drivers for a usb-serial module diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index 61a8425b7762..ec9fff794b36 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -83,7 +83,6 @@ static void usb_debug_init_termios(struct tty_struct *tty) static struct usb_serial_driver debug_device = { .driver = { - .owner = THIS_MODULE, .name = "debug", }, .id_table = id_table, @@ -96,7 +95,6 @@ static struct usb_serial_driver debug_device = { static struct usb_serial_driver dbc_device = { .driver = { - .owner = THIS_MODULE, .name = "xhci_dbc", }, .id_table = dbc_id_table, diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 4412834db21c..062a38fe0c1c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -161,7 +161,6 @@ MODULE_DEVICE_TABLE(usb, id_table_combined); and Palm 4.0 devices */ static struct usb_serial_driver handspring_device = { .driver = { - .owner = THIS_MODULE, .name = "visor", }, .description = "Handspring Visor / Palm OS", @@ -180,7 +179,6 @@ static struct usb_serial_driver handspring_device = { /* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */ static struct usb_serial_driver clie_5_device = { .driver = { - .owner = THIS_MODULE, .name = "clie_5", }, .description = "Sony Clie 5.0", @@ -200,7 +198,6 @@ static struct usb_serial_driver clie_5_device = { /* device info for the Sony Clie OS version 3.5 */ static struct usb_serial_driver clie_3_5_device = { .driver = { - .owner = THIS_MODULE, .name = "clie_3.5", }, .description = "Sony Clie 3.5", diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index ca48e90a8e81..009faeb2ef55 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -91,7 +91,6 @@ static int whiteheat_break_ctl(struct tty_struct *tty, int break_state); static struct usb_serial_driver whiteheat_fake_device = { .driver = { - .owner = THIS_MODULE, .name = "whiteheatnofirm", }, .description = "Connect Tech - WhiteHEAT - (prerenumeration)", @@ -103,7 +102,6 @@ static struct usb_serial_driver whiteheat_fake_device = { static struct usb_serial_driver whiteheat_device = { .driver = { - .owner = THIS_MODULE, .name = "whiteheat", }, .description = "Connect Tech - WhiteHEAT", diff --git a/drivers/usb/serial/wishbone-serial.c b/drivers/usb/serial/wishbone-serial.c index ff4092f9b33c..670d573f6b63 100644 --- a/drivers/usb/serial/wishbone-serial.c +++ b/drivers/usb/serial/wishbone-serial.c @@ -70,7 +70,6 @@ static void wishbone_serial_close(struct usb_serial_port *port) static struct usb_serial_driver wishbone_serial_device = { .driver = { - .owner = THIS_MODULE, .name = "wishbone_serial", }, .id_table = id_table, diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 1d9a12628f81..4186e791b384 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -1082,7 +1082,6 @@ MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver xr_device = { .driver = { - .owner = THIS_MODULE, .name = "xr_serial", }, .id_table = id_table, diff --git a/drivers/usb/serial/xsens_mt.c b/drivers/usb/serial/xsens_mt.c index cf262c9a9638..382b3698c1d5 100644 --- a/drivers/usb/serial/xsens_mt.c +++ b/drivers/usb/serial/xsens_mt.c @@ -49,7 +49,6 @@ static int xsens_mt_probe(struct usb_serial *serial, static struct usb_serial_driver xsens_mt_device = { .driver = { - .owner = THIS_MODULE, .name = "xsens_mt", }, .id_table = id_table, diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index 40d34cc28344..a9d3c58ce7d9 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -132,7 +132,7 @@ static int init_alauda(struct us_data *us); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id alauda_usb_ids[] = { +static const struct usb_device_id alauda_usb_ids[] = { # include "unusual_alauda.h" { } /* Terminating entry */ }; @@ -154,7 +154,7 @@ MODULE_DEVICE_TABLE(usb, alauda_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev alauda_unusual_dev_list[] = { +static const struct us_unusual_dev alauda_unusual_dev_list[] = { # include "unusual_alauda.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c index 98b3ec352a13..30dfd0082474 100644 --- a/drivers/usb/storage/cypress_atacb.c +++ b/drivers/usb/storage/cypress_atacb.c @@ -33,7 +33,7 @@ MODULE_IMPORT_NS(USB_STORAGE); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id cypress_usb_ids[] = { +static const struct usb_device_id cypress_usb_ids[] = { # include "unusual_cypress.h" { } /* Terminating entry */ }; @@ -55,7 +55,7 @@ MODULE_DEVICE_TABLE(usb, cypress_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev cypress_unusual_dev_list[] = { +static const struct us_unusual_dev cypress_unusual_dev_list[] = { # include "unusual_cypress.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index bcc4a2fad863..3ea5601d16b8 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -80,7 +80,7 @@ static int datafab_determine_lun(struct us_data *us, { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id datafab_usb_ids[] = { +static const struct usb_device_id datafab_usb_ids[] = { # include "unusual_datafab.h" { } /* Terminating entry */ }; @@ -102,7 +102,7 @@ MODULE_DEVICE_TABLE(usb, datafab_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev datafab_unusual_dev_list[] = { +static const struct us_unusual_dev datafab_unusual_dev_list[] = { # include "unusual_datafab.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 97c66c0d91f4..a4bfbecbf16c 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -43,7 +43,7 @@ MODULE_FIRMWARE(MS_RW_FIRMWARE); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags)} -static struct usb_device_id ene_ub6250_usb_ids[] = { +static const struct usb_device_id ene_ub6250_usb_ids[] = { # include "unusual_ene_ub6250.h" { } /* Terminating entry */ }; @@ -65,7 +65,7 @@ MODULE_DEVICE_TABLE(usb, ene_ub6250_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = { +static const struct us_unusual_dev ene_ub6250_unusual_dev_list[] = { # include "unusual_ene_ub6250.h" { } /* Terminating entry */ }; @@ -1484,7 +1484,7 @@ static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) { u32 bl_num; - u16 bl_len; + u32 bl_len; unsigned int offset = 0; unsigned char buf[8]; struct scatterlist *sg = NULL; diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index c3ce51c2dabd..cab27ba7a32a 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -119,7 +119,7 @@ static int init_freecom(struct us_data *us); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id freecom_usb_ids[] = { +static const struct usb_device_id freecom_usb_ids[] = { # include "unusual_freecom.h" { } /* Terminating entry */ }; @@ -141,7 +141,7 @@ MODULE_DEVICE_TABLE(usb, freecom_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev freecom_unusual_dev_list[] = { +static const struct us_unusual_dev freecom_unusual_dev_list[] = { # include "unusual_freecom.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 300aeef160e7..f2254eb3c0d7 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -67,7 +67,7 @@ static int isd200_Initialization(struct us_data *us); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id isd200_usb_ids[] = { +static const struct usb_device_id isd200_usb_ids[] = { # include "unusual_isd200.h" { } /* Terminating entry */ }; @@ -89,7 +89,7 @@ MODULE_DEVICE_TABLE(usb, isd200_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev isd200_unusual_dev_list[] = { +static const struct us_unusual_dev isd200_unusual_dev_list[] = { # include "unusual_isd200.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index 229bf0c1afc9..0e71a8f33c2b 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -62,7 +62,7 @@ MODULE_IMPORT_NS(USB_STORAGE); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id jumpshot_usb_ids[] = { +static const struct usb_device_id jumpshot_usb_ids[] = { # include "unusual_jumpshot.h" { } /* Terminating entry */ }; @@ -84,7 +84,7 @@ MODULE_DEVICE_TABLE(usb, jumpshot_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev jumpshot_unusual_dev_list[] = { +static const struct us_unusual_dev jumpshot_unusual_dev_list[] = { # include "unusual_jumpshot.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c index 38ddfedef629..d6a5e54f2ca8 100644 --- a/drivers/usb/storage/karma.c +++ b/drivers/usb/storage/karma.c @@ -51,7 +51,7 @@ static int rio_karma_init(struct us_data *us); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id karma_usb_ids[] = { +static const struct usb_device_id karma_usb_ids[] = { # include "unusual_karma.h" { } /* Terminating entry */ }; @@ -73,7 +73,7 @@ MODULE_DEVICE_TABLE(usb, karma_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev karma_unusual_dev_list[] = { +static const struct us_unusual_dev karma_unusual_dev_list[] = { # include "unusual_karma.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 01f3c2779ccf..f97cf6cadb8e 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -55,7 +55,7 @@ struct usb_onetouch { { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id onetouch_usb_ids[] = { +static const struct usb_device_id onetouch_usb_ids[] = { # include "unusual_onetouch.h" { } /* Terminating entry */ }; @@ -77,7 +77,7 @@ MODULE_DEVICE_TABLE(usb, onetouch_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev onetouch_unusual_dev_list[] = { +static const struct us_unusual_dev onetouch_unusual_dev_list[] = { # include "unusual_onetouch.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 51bcd4a43690..03d1b9c69ea1 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -63,7 +63,7 @@ static int usb_stor_sddr09_init(struct us_data *us); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id sddr09_usb_ids[] = { +static const struct usb_device_id sddr09_usb_ids[] = { # include "unusual_sddr09.h" { } /* Terminating entry */ }; @@ -85,7 +85,7 @@ MODULE_DEVICE_TABLE(usb, sddr09_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev sddr09_unusual_dev_list[] = { +static const struct us_unusual_dev sddr09_unusual_dev_list[] = { # include "unusual_sddr09.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index 0aa079405d23..b8227478a7ad 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -40,7 +40,7 @@ MODULE_IMPORT_NS(USB_STORAGE); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id sddr55_usb_ids[] = { +static const struct usb_device_id sddr55_usb_ids[] = { # include "unusual_sddr55.h" { } /* Terminating entry */ }; @@ -62,7 +62,7 @@ MODULE_DEVICE_TABLE(usb, sddr55_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev sddr55_unusual_dev_list[] = { +static const struct us_unusual_dev sddr55_unusual_dev_list[] = { # include "unusual_sddr55.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index f0d0ca37163d..e7c224b7c464 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -162,7 +162,7 @@ static int init_usbat_flash(struct us_data *us); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id usbat_usb_ids[] = { +static const struct usb_device_id usbat_usb_ids[] = { # include "unusual_usbat.h" { } /* Terminating entry */ }; @@ -184,7 +184,7 @@ MODULE_DEVICE_TABLE(usb, usbat_usb_ids); .initFunction = init_function, \ } -static struct us_unusual_dev usbat_unusual_dev_list[] = { +static const struct us_unusual_dev usbat_unusual_dev_list[] = { # include "unusual_usbat.h" { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index c223b4dc1b19..03043d567fa1 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -927,7 +927,7 @@ static const struct scsi_host_template uas_host_template = { { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags) } -static struct usb_device_id uas_usb_ids[] = { +static const struct usb_device_id uas_usb_ids[] = { # include "unusual_uas.h" { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) }, { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) }, diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index 5a5bf3532ad7..d1e7c487ddfb 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -6,6 +6,7 @@ * Copyright(c) 2022, Analogix Semiconductor. All rights reserved. * */ +#include <linux/bitfield.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -884,8 +885,8 @@ static void anx7411_chip_standby(struct anx7411_data *ctx) OCM_RESET); ret |= anx7411_reg_write(ctx->tcpc_client, ANALOG_CTRL_10, 0x80); /* Set TCPC to RD and DRP enable */ - cc1 = TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT; - cc2 = TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT; + cc1 = FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RD); + cc2 = FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RD); ret |= anx7411_reg_write(ctx->tcpc_client, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP | cc1 | cc2); @@ -1339,12 +1340,6 @@ static void anx7411_get_gpio_irq(struct anx7411_data *ctx) dev_err(dev, "failed to get GPIO IRQ\n"); } -static enum power_supply_usb_type anx7411_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_PPS, -}; - static enum power_supply_property anx7411_psy_props[] = { POWER_SUPPLY_PROP_USB_TYPE, POWER_SUPPLY_PROP_ONLINE, @@ -1422,8 +1417,9 @@ static int anx7411_psy_register(struct anx7411_data *ctx) psy_desc->name = psy_name; psy_desc->type = POWER_SUPPLY_TYPE_USB; - psy_desc->usb_types = anx7411_psy_usb_types; - psy_desc->num_usb_types = ARRAY_SIZE(anx7411_psy_usb_types); + psy_desc->usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); psy_desc->properties = anx7411_psy_props; psy_desc->num_properties = ARRAY_SIZE(anx7411_psy_props); @@ -1576,6 +1572,7 @@ static const struct of_device_id anx_match_table[] = { {.compatible = "analogix,anx7411",}, {}, }; +MODULE_DEVICE_TABLE(of, anx_match_table); static struct i2c_driver anx7411_driver = { .driver = { diff --git a/drivers/usb/typec/mux/fsa4480.c b/drivers/usb/typec/mux/fsa4480.c index cd235339834b..f71dba8bf07c 100644 --- a/drivers/usb/typec/mux/fsa4480.c +++ b/drivers/usb/typec/mux/fsa4480.c @@ -274,7 +274,7 @@ static int fsa4480_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n"); ret = regmap_read(fsa->regmap, FSA4480_DEVICE_ID, &val); - if (ret || !val) + if (ret) return dev_err_probe(dev, -ENODEV, "FSA4480 not found\n"); dev_dbg(dev, "Found FSA4480 v%lu.%lu (Vendor ID = %lu)\n", diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c index 56989a0d0f43..46b4c5c3a6be 100644 --- a/drivers/usb/typec/mux/intel_pmc_mux.c +++ b/drivers/usb/typec/mux/intel_pmc_mux.c @@ -8,6 +8,7 @@ #include <linux/acpi.h> #include <linux/module.h> +#include <linux/platform_data/x86/intel_scu_ipc.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/usb/pd.h> @@ -18,8 +19,6 @@ #include <linux/debugfs.h> #include <linux/usb.h> -#include <asm/intel_scu_ipc.h> - #define PMC_USBC_CMD 0xa7 /* Response status bits */ diff --git a/drivers/usb/typec/rt1719.c b/drivers/usb/typec/rt1719.c index be02d420920e..0b0c23a0b014 100644 --- a/drivers/usb/typec/rt1719.c +++ b/drivers/usb/typec/rt1719.c @@ -109,12 +109,6 @@ struct rt1719_data { u16 conn_stat; }; -static const enum power_supply_usb_type rt1719_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_PPS -}; - static const enum power_supply_property rt1719_psy_properties[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_USB_TYPE, @@ -572,8 +566,9 @@ static int devm_rt1719_psy_register(struct rt1719_data *data) data->psy_desc.name = psy_name; data->psy_desc.type = POWER_SUPPLY_TYPE_USB; - data->psy_desc.usb_types = rt1719_psy_usb_types; - data->psy_desc.num_usb_types = ARRAY_SIZE(rt1719_psy_usb_types); + data->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); data->psy_desc.properties = rt1719_psy_properties; data->psy_desc.num_properties = ARRAY_SIZE(rt1719_psy_properties); data->psy_desc.get_property = rt1719_psy_get_property; diff --git a/drivers/usb/typec/tcpm/maxim_contaminant.c b/drivers/usb/typec/tcpm/maxim_contaminant.c index f8504a90da26..22163d8f9eb0 100644 --- a/drivers/usb/typec/tcpm/maxim_contaminant.c +++ b/drivers/usb/typec/tcpm/maxim_contaminant.c @@ -5,6 +5,7 @@ * USB-C module to reduce wakeups due to contaminants. */ +#include <linux/bitfield.h> #include <linux/device.h> #include <linux/irqreturn.h> #include <linux/module.h> @@ -45,14 +46,9 @@ enum fladc_select { #define READ1_SLEEP_MS 10 #define READ2_SLEEP_MS 5 -#define STATUS_CHECK(reg, mask, val) (((reg) & (mask)) == (val)) - #define IS_CC_OPEN(cc_status) \ - (STATUS_CHECK((cc_status), TCPC_CC_STATUS_CC1_MASK << TCPC_CC_STATUS_CC1_SHIFT, \ - TCPC_CC_STATE_SRC_OPEN) && STATUS_CHECK((cc_status), \ - TCPC_CC_STATUS_CC2_MASK << \ - TCPC_CC_STATUS_CC2_SHIFT, \ - TCPC_CC_STATE_SRC_OPEN)) + (FIELD_GET(TCPC_CC_STATUS_CC1, cc_status) == TCPC_CC_STATE_SRC_OPEN \ + && FIELD_GET(TCPC_CC_STATUS_CC2, cc_status) == TCPC_CC_STATE_SRC_OPEN) static int max_contaminant_adc_to_mv(struct max_tcpci_chip *chip, enum fladc_select channel, bool ua_src, u8 fladc) @@ -80,8 +76,8 @@ static int max_contaminant_read_adc_mv(struct max_tcpci_chip *chip, enum fladc_s int ret; /* Channel & scale select */ - ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL_MASK, - channel << ADC_CHANNEL_OFFSET); + ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL, + FIELD_PREP(ADCINSEL, channel)); if (ret < 0) return ret; @@ -100,7 +96,8 @@ static int max_contaminant_read_adc_mv(struct max_tcpci_chip *chip, enum fladc_s if (ret < 0) return ret; - ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL_MASK, 0); + ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL, + FIELD_PREP(ADCINSEL, 0)); if (ret < 0) return ret; @@ -120,13 +117,14 @@ static int max_contaminant_read_resistance_kohm(struct max_tcpci_chip *chip, if (channel == CC1_SCALE1 || channel == CC2_SCALE1 || channel == CC1_SCALE2 || channel == CC2_SCALE2) { /* Enable 1uA current source */ - ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK, - ULTRA_LOW_POWER_MODE); + ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL, + FIELD_PREP(CCLPMODESEL, ULTRA_LOW_POWER_MODE)); if (ret < 0) return ret; /* Enable 1uA current source */ - ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, UA_1_SRC); + ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL, + FIELD_PREP(CCRPCTRL, UA_1_SRC)); if (ret < 0) return ret; @@ -180,7 +178,8 @@ static int max_contaminant_read_comparators(struct max_tcpci_chip *chip, u8 *ven int ret; /* Enable 80uA source */ - ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, UA_80_SRC); + ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL, + FIELD_PREP(CCRPCTRL, UA_80_SRC)); if (ret < 0) return ret; @@ -213,7 +212,8 @@ static int max_contaminant_read_comparators(struct max_tcpci_chip *chip, u8 *ven if (ret < 0) return ret; - ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, 0); + ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL, + FIELD_PREP(CCRPCTRL, 0)); if (ret < 0) return ret; @@ -284,10 +284,11 @@ static int max_contaminant_enable_dry_detection(struct max_tcpci_chip *chip) u8 temp; int ret; - ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL3, CCWTRDEB_MASK | CCWTRSEL_MASK - | WTRCYCLE_MASK, CCWTRDEB_1MS << CCWTRDEB_SHIFT | - CCWTRSEL_1V << CCWTRSEL_SHIFT | WTRCYCLE_4_8_S << - WTRCYCLE_SHIFT); + ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL3, + CCWTRDEB | CCWTRSEL | WTRCYCLE, + FIELD_PREP(CCWTRDEB, CCWTRDEB_1MS) + | FIELD_PREP(CCWTRSEL, CCWTRSEL_1V) + | FIELD_PREP(WTRCYCLE, WTRCYCLE_4_8_S)); if (ret < 0) return ret; @@ -302,8 +303,9 @@ static int max_contaminant_enable_dry_detection(struct max_tcpci_chip *chip) if (ret < 0) return ret; - ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK, - ULTRA_LOW_POWER_MODE); + ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL, + FIELD_PREP(CCLPMODESEL, + ULTRA_LOW_POWER_MODE)); if (ret < 0) return ret; ret = max_tcpci_read8(chip, TCPC_VENDOR_CC_CTRL2, &temp); @@ -322,11 +324,14 @@ static int max_contaminant_enable_dry_detection(struct max_tcpci_chip *chip) return 0; } -bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce) +bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce, + bool *cc_handled) { u8 cc_status, pwr_cntl; int ret; + *cc_handled = true; + ret = max_tcpci_read8(chip, TCPC_CC_STATUS, &cc_status); if (ret < 0) return false; @@ -368,9 +373,8 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect return true; } } - return false; } else if (chip->contaminant_state == DETECTED) { - if (STATUS_CHECK(cc_status, TCPC_CC_STATUS_TOGGLING, 0)) { + if (!(cc_status & TCPC_CC_STATUS_TOGGLING)) { chip->contaminant_state = max_contaminant_detect_contaminant(chip); if (chip->contaminant_state == DETECTED) { max_contaminant_enable_dry_detection(chip); @@ -379,6 +383,7 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect } } + *cc_handled = false; return false; } diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index 3e3dcb983dde..ed32583829be 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -5,6 +5,7 @@ * USB Type-C Port Controller Interface. */ +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> @@ -103,45 +104,45 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) switch (cc) { case TYPEC_CC_RA: - reg = (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC2_SHIFT); + reg = (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RA) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RA)); break; case TYPEC_CC_RD: - reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); + reg = (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RD) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RD)); break; case TYPEC_CC_RP_DEF: - reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) | - (TCPC_ROLE_CTRL_RP_VAL_DEF << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); + reg = (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RP) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RP) + | FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL, + TCPC_ROLE_CTRL_RP_VAL_DEF)); break; case TYPEC_CC_RP_1_5: - reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) | - (TCPC_ROLE_CTRL_RP_VAL_1_5 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); + reg = (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RP) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RP) + | FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL, + TCPC_ROLE_CTRL_RP_VAL_1_5)); break; case TYPEC_CC_RP_3_0: - reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) | - (TCPC_ROLE_CTRL_RP_VAL_3_0 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); + reg = (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RP) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RP) + | FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL, + TCPC_ROLE_CTRL_RP_VAL_3_0)); break; case TYPEC_CC_OPEN: default: - reg = (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT); + reg = (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_OPEN) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_OPEN)); break; } if (vconn_pres) { if (polarity == TYPEC_POLARITY_CC2) { - reg &= ~(TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT); - reg |= (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT); + reg &= ~TCPC_ROLE_CTRL_CC1; + reg |= FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_OPEN); } else { - reg &= ~(TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT); - reg |= (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT); + reg &= ~TCPC_ROLE_CTRL_CC2; + reg |= FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_OPEN); } } @@ -167,15 +168,11 @@ static int tcpci_apply_rc(struct tcpc_dev *tcpc, enum typec_cc_status cc, * 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)) + if (FIELD_GET(TCPC_ROLE_CTRL_CC2, reg) != FIELD_GET(TCPC_ROLE_CTRL_CC1, reg)) 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_CC2 : TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_OPEN); } @@ -200,25 +197,25 @@ static int tcpci_start_toggling(struct tcpc_dev *tcpc, switch (cc) { default: case TYPEC_CC_RP_DEF: - reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); + reg |= FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL, + TCPC_ROLE_CTRL_RP_VAL_DEF); break; case TYPEC_CC_RP_1_5: - reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); + reg |= FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL, + TCPC_ROLE_CTRL_RP_VAL_1_5); break; case TYPEC_CC_RP_3_0: - reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); + reg |= FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL, + TCPC_ROLE_CTRL_RP_VAL_3_0); break; } if (cc == TYPEC_CC_RD) - reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); + reg |= (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RD) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RD)); else - reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT); + reg |= (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RP) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RP)); ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); if (ret < 0) return ret; @@ -241,12 +238,10 @@ static int tcpci_get_cc(struct tcpc_dev *tcpc, if (ret < 0) return ret; - *cc1 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC1_SHIFT) & - TCPC_CC_STATUS_CC1_MASK, + *cc1 = tcpci_to_typec_cc(FIELD_GET(TCPC_CC_STATUS_CC1, reg), reg & TCPC_CC_STATUS_TERM || tcpc_presenting_rd(role_control, CC1)); - *cc2 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC2_SHIFT) & - TCPC_CC_STATUS_CC2_MASK, + *cc2 = tcpci_to_typec_cc(FIELD_GET(TCPC_CC_STATUS_CC2, reg), reg & TCPC_CC_STATUS_TERM || tcpc_presenting_rd(role_control, CC2)); @@ -282,28 +277,28 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc, reg = reg & ~TCPC_ROLE_CTRL_DRP; if (polarity == TYPEC_POLARITY_CC2) { - reg &= ~(TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT); + reg &= ~TCPC_ROLE_CTRL_CC2; /* Local port is source */ if (cc2 == TYPEC_CC_RD) /* Role control would have the Rp setting when DRP was enabled */ - reg |= TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT; + reg |= FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RP); else - reg |= TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT; + reg |= FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RD); } else { - reg &= ~(TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT); + reg &= ~TCPC_ROLE_CTRL_CC1; /* Local port is source */ if (cc1 == TYPEC_CC_RD) /* Role control would have the Rp setting when DRP was enabled */ - reg |= TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT; + reg |= FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RP); else - reg |= TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT; + reg |= FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RD); } } if (polarity == TYPEC_POLARITY_CC2) - reg |= TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT; + reg |= FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_OPEN); else - reg |= TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT; + reg |= FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_OPEN); ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); if (ret < 0) return ret; @@ -461,7 +456,7 @@ static int tcpci_set_roles(struct tcpc_dev *tcpc, bool attached, unsigned int reg; int ret; - reg = PD_REV20 << TCPC_MSG_HDR_INFO_REV_SHIFT; + reg = FIELD_PREP(TCPC_MSG_HDR_INFO_REV, PD_REV20); if (role == TYPEC_SOURCE) reg |= TCPC_MSG_HDR_INFO_PWR_ROLE; if (data == TYPEC_HOST) @@ -612,8 +607,11 @@ static int tcpci_pd_transmit(struct tcpc_dev *tcpc, enum tcpm_transmit_type type } /* nRetryCount is 3 in PD2.0 spec where 2 in PD3.0 spec */ - reg = ((negotiated_rev > PD_REV20 ? PD_RETRY_COUNT_3_0_OR_HIGHER : PD_RETRY_COUNT_DEFAULT) - << TCPC_TRANSMIT_RETRY_SHIFT) | (type << TCPC_TRANSMIT_TYPE_SHIFT); + reg = FIELD_PREP(TCPC_TRANSMIT_RETRY, + (negotiated_rev > PD_REV20 + ? PD_RETRY_COUNT_3_0_OR_HIGHER + : PD_RETRY_COUNT_DEFAULT)); + reg |= FIELD_PREP(TCPC_TRANSMIT_TYPE, type); ret = regmap_write(tcpci->regmap, TCPC_TRANSMIT, reg); if (ret < 0) return ret; @@ -709,10 +707,13 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci) { u16 status; int ret; + int irq_ret; unsigned int raw; tcpci_read16(tcpci, TCPC_ALERT, &status); + irq_ret = status & tcpci->alert_mask; +process_status: /* * Clear alert status for everything except RX_STATUS, which shouldn't * be cleared until we have successfully retrieved message. @@ -785,7 +786,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci) else if (status & TCPC_ALERT_TX_FAILED) tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED); - return IRQ_RETVAL(status & tcpci->alert_mask); + tcpci_read16(tcpci, TCPC_ALERT, &status); + + if (status & tcpci->alert_mask) + goto process_status; + + return IRQ_RETVAL(irq_ret); } EXPORT_SYMBOL_GPL(tcpci_irq); @@ -917,20 +923,22 @@ static int tcpci_probe(struct i2c_client *client) chip->data.set_orientation = err; - chip->tcpci = tcpci_register_port(&client->dev, &chip->data); - if (IS_ERR(chip->tcpci)) - return PTR_ERR(chip->tcpci); - err = devm_request_threaded_irq(&client->dev, client->irq, NULL, _tcpci_irq, - IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, + IRQF_SHARED | IRQF_ONESHOT, dev_name(&client->dev), chip); - if (err < 0) { - tcpci_unregister_port(chip->tcpci); + if (err < 0) return err; - } - return 0; + /* + * Disable irq while registering port. If irq is configured as an edge + * irq this allow to keep track and process the irq as soon as it is enabled. + */ + disable_irq(client->irq); + chip->tcpci = tcpci_register_port(&client->dev, &chip->data); + enable_irq(client->irq); + + return PTR_ERR_OR_ZERO(chip->tcpci); } static void tcpci_remove(struct i2c_client *client) diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.h b/drivers/usb/typec/tcpm/tcpci_maxim.h index 78ff3b73ee7e..76270d5c2838 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim.h +++ b/drivers/usb/typec/tcpm/tcpci_maxim.h @@ -20,28 +20,24 @@ #define SBUOVPDIS BIT(7) #define CCOVPDIS BIT(6) #define SBURPCTRL BIT(5) -#define CCLPMODESEL_MASK GENMASK(4, 3) -#define ULTRA_LOW_POWER_MODE BIT(3) -#define CCRPCTRL_MASK GENMASK(2, 0) +#define CCLPMODESEL GENMASK(4, 3) +#define ULTRA_LOW_POWER_MODE 1 +#define CCRPCTRL GENMASK(2, 0) #define UA_1_SRC 1 #define UA_80_SRC 3 #define TCPC_VENDOR_CC_CTRL3 0x8e -#define CCWTRDEB_MASK GENMASK(7, 6) -#define CCWTRDEB_SHIFT 6 +#define CCWTRDEB GENMASK(7, 6) #define CCWTRDEB_1MS 1 -#define CCWTRSEL_MASK GENMASK(5, 3) -#define CCWTRSEL_SHIFT 3 +#define CCWTRSEL GENMASK(5, 3) #define CCWTRSEL_1V 0x4 #define CCLADDERDIS BIT(2) -#define WTRCYCLE_MASK BIT(0) -#define WTRCYCLE_SHIFT 0 +#define WTRCYCLE GENMASK(0, 0) #define WTRCYCLE_2_4_S 0 #define WTRCYCLE_4_8_S 1 #define TCPC_VENDOR_ADC_CTRL1 0x91 -#define ADCINSEL_MASK GENMASK(7, 5) -#define ADC_CHANNEL_OFFSET 5 +#define ADCINSEL GENMASK(7, 5) #define ADCEN BIT(0) enum contamiant_state { @@ -85,6 +81,20 @@ static inline int max_tcpci_write8(struct max_tcpci_chip *chip, unsigned int reg return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8)); } -bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce); +/** + * max_contaminant_is_contaminant - Test if CC was toggled due to contaminant + * + * @chip: Handle to a struct max_tcpci_chip + * @disconnect_while_debounce: Whether the disconnect was detected when CC + * pins were debouncing + * @cc_handled: Returns whether or not update to CC status was handled here + * + * Determine if a contaminant was detected. + * + * Returns: true if a contaminant was detected, false otherwise. cc_handled + * is updated to reflect whether or not further CC handling is required. + */ +bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce, + bool *cc_handled); #endif // TCPCI_MAXIM_H_ diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c index 760e2f92b958..fd1b80593367 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c @@ -97,11 +97,13 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip) if (ret < 0) return; - alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED | - TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS | - TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS | - /* Enable Extended alert for detecting Fast Role Swap Signal */ - TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS | TCPC_ALERT_FAULT; + alert_mask = (TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | + TCPC_ALERT_TX_FAILED | TCPC_ALERT_RX_HARD_RST | + TCPC_ALERT_RX_STATUS | TCPC_ALERT_POWER_STATUS | + TCPC_ALERT_CC_STATUS | + TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS | + TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | + TCPC_ALERT_FAULT); ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask); if (ret < 0) { @@ -191,9 +193,8 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status) * Read complete, clear RX status alert bit. * Clear overflow as well if set. */ - ret = max_tcpci_write16(chip, TCPC_ALERT, status & TCPC_ALERT_RX_BUF_OVF ? - TCPC_ALERT_RX_STATUS | TCPC_ALERT_RX_BUF_OVF : - TCPC_ALERT_RX_STATUS); + ret = max_tcpci_write16(chip, TCPC_ALERT, + TCPC_ALERT_RX_STATUS | (status & TCPC_ALERT_RX_BUF_OVF)); if (ret < 0) return; @@ -295,9 +296,8 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status) * be cleared until we have successfully retrieved message. */ if (status & ~TCPC_ALERT_RX_STATUS) { - mask = status & TCPC_ALERT_RX_BUF_OVF ? - status & ~(TCPC_ALERT_RX_STATUS | TCPC_ALERT_RX_BUF_OVF) : - status & ~TCPC_ALERT_RX_STATUS; + mask = status & ~(TCPC_ALERT_RX_STATUS + | (status & TCPC_ALERT_RX_BUF_OVF)); ret = max_tcpci_write16(chip, TCPC_ALERT, mask); if (ret < 0) { dev_err(chip->dev, "ALERT clear failed\n"); @@ -357,12 +357,14 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status) tcpm_vbus_change(chip->port); if (status & TCPC_ALERT_CC_STATUS) { + bool cc_handled = false; + if (chip->contaminant_state == DETECTED || tcpm_port_is_toggling(chip->port)) { - if (!max_contaminant_is_contaminant(chip, false)) + if (!max_contaminant_is_contaminant(chip, false, &cc_handled)) tcpm_port_clean(chip->port); - } else { - tcpm_cc_change(chip->port); } + if (!cc_handled) + tcpm_cc_change(chip->port); } if (status & TCPC_ALERT_POWER_STATUS) @@ -397,7 +399,7 @@ static irqreturn_t max_tcpci_irq(int irq, void *dev_id) } while (status) { irq_return = _max_tcpci_irq(chip, status); - /* Do not return if the ALERT is already set. */ + /* Do not return if a (new) ALERT is set (again). */ ret = max_tcpci_read16(chip, TCPC_ALERT, &status); if (ret < 0) break; @@ -455,8 +457,9 @@ static int tcpci_init(struct tcpci *tcpci, struct tcpci_data *data) static void max_tcpci_check_contaminant(struct tcpci *tcpci, struct tcpci_data *tdata) { struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata); + bool cc_handled; - if (!max_contaminant_is_contaminant(chip, true)) + if (!max_contaminant_is_contaminant(chip, true, &cc_handled)) tcpm_port_clean(chip->port); } @@ -472,6 +475,11 @@ static bool max_tcpci_attempt_vconn_swap_discovery(struct tcpci *tcpci, struct t return true; } +static void max_tcpci_unregister_tcpci_port(void *tcpci) +{ + tcpci_unregister_port(tcpci); +} + static int max_tcpci_probe(struct i2c_client *client) { int ret; @@ -484,17 +492,17 @@ static int max_tcpci_probe(struct i2c_client *client) chip->client = client; chip->data.regmap = devm_regmap_init_i2c(client, &max_tcpci_regmap_config); - if (IS_ERR(chip->data.regmap)) { - dev_err(&client->dev, "Regmap init failed\n"); - return PTR_ERR(chip->data.regmap); - } + if (IS_ERR(chip->data.regmap)) + return dev_err_probe(&client->dev, PTR_ERR(chip->data.regmap), + "Regmap init failed\n"); chip->dev = &client->dev; i2c_set_clientdata(client, chip); ret = max_tcpci_read8(chip, TCPC_POWER_STATUS, &power_status); if (ret < 0) - return ret; + return dev_err_probe(&client->dev, ret, + "Failed to read TCPC_POWER_STATUS\n"); /* Chip level tcpci callbacks */ chip->data.set_vbus = max_tcpci_set_vbus; @@ -511,30 +519,25 @@ static int max_tcpci_probe(struct i2c_client *client) max_tcpci_init_regs(chip); chip->tcpci = tcpci_register_port(chip->dev, &chip->data); - if (IS_ERR(chip->tcpci)) { - dev_err(&client->dev, "TCPCI port registration failed\n"); - return PTR_ERR(chip->tcpci); - } + if (IS_ERR(chip->tcpci)) + return dev_err_probe(&client->dev, PTR_ERR(chip->tcpci), + "TCPCI port registration failed\n"); + + ret = devm_add_action_or_reset(&client->dev, + max_tcpci_unregister_tcpci_port, + chip->tcpci); + if (ret) + return ret; + chip->port = tcpci_get_tcpm_port(chip->tcpci); + ret = max_tcpci_init_alert(chip, client); if (ret < 0) - goto unreg_port; + return dev_err_probe(&client->dev, ret, + "IRQ initialization failed\n"); device_init_wakeup(chip->dev, true); return 0; - -unreg_port: - tcpci_unregister_port(chip->tcpci); - - return ret; -} - -static void max_tcpci_remove(struct i2c_client *client) -{ - struct max_tcpci_chip *chip = i2c_get_clientdata(client); - - if (!IS_ERR_OR_NULL(chip->tcpci)) - tcpci_unregister_port(chip->tcpci); } static const struct i2c_device_id max_tcpci_id[] = { @@ -557,7 +560,6 @@ static struct i2c_driver max_tcpci_i2c_driver = { .of_match_table = of_match_ptr(max_tcpci_of_match), }, .probe = max_tcpci_probe, - .remove = max_tcpci_remove, .id_table = max_tcpci_id, }; module_i2c_driver(max_tcpci_i2c_driver); diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index 67422d45eb54..64f6dd0dc660 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -5,6 +5,7 @@ * Richtek RT1711H Type-C Chip Driver */ +#include <linux/bitfield.h> #include <linux/bits.h> #include <linux/kernel.h> #include <linux/mod_devicetable.h> @@ -195,12 +196,10 @@ static inline int rt1711h_init_cc_params(struct rt1711h_chip *chip, u8 status) if (ret < 0) return ret; - cc1 = tcpci_to_typec_cc((status >> TCPC_CC_STATUS_CC1_SHIFT) & - TCPC_CC_STATUS_CC1_MASK, + cc1 = tcpci_to_typec_cc(FIELD_GET(TCPC_CC_STATUS_CC1, status), status & TCPC_CC_STATUS_TERM || tcpc_presenting_rd(role, CC1)); - cc2 = tcpci_to_typec_cc((status >> TCPC_CC_STATUS_CC2_SHIFT) & - TCPC_CC_STATUS_CC2_MASK, + cc2 = tcpci_to_typec_cc(FIELD_GET(TCPC_CC_STATUS_CC2, status), status & TCPC_CC_STATUS_TERM || tcpc_presenting_rd(role, CC2)); @@ -233,25 +232,25 @@ static int rt1711h_start_drp_toggling(struct tcpci *tcpci, switch (cc) { default: case TYPEC_CC_RP_DEF: - reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); + reg |= FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL, + TCPC_ROLE_CTRL_RP_VAL_DEF); break; case TYPEC_CC_RP_1_5: - reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); + reg |= FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL, + TCPC_ROLE_CTRL_RP_VAL_1_5); break; case TYPEC_CC_RP_3_0: - reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 << - TCPC_ROLE_CTRL_RP_VAL_SHIFT); + reg |= FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL, + TCPC_ROLE_CTRL_RP_VAL_3_0); break; } if (cc == TYPEC_CC_RD) - reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); + reg |= (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RD) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RD)); else - reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | - (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT); + reg |= (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RP) + | FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RP)); ret = rt1711h_write8(chip, TCPC_ROLE_CTRL, reg); if (ret < 0) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 4b02d6474259..fc619478200f 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -7483,12 +7483,6 @@ static int tcpm_psy_prop_writeable(struct power_supply *psy, } } -static enum power_supply_usb_type tcpm_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_PPS, -}; - static const char *tcpm_psy_name_prefix = "tcpm-source-psy-"; static int devm_tcpm_psy_register(struct tcpm_port *port) @@ -7509,8 +7503,9 @@ static int devm_tcpm_psy_register(struct tcpm_port *port) port_dev_name); port->psy_desc.name = psy_name; port->psy_desc.type = POWER_SUPPLY_TYPE_USB; - port->psy_desc.usb_types = tcpm_psy_usb_types; - port->psy_desc.num_usb_types = ARRAY_SIZE(tcpm_psy_usb_types); + port->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); port->psy_desc.properties = tcpm_psy_props; port->psy_desc.num_properties = ARRAY_SIZE(tcpm_psy_props); port->psy_desc.get_property = tcpm_psy_get_prop; diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index dd51a25480bf..7ee721a877c1 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -150,11 +150,6 @@ static enum power_supply_property tps6598x_psy_props[] = { POWER_SUPPLY_PROP_ONLINE, }; -static enum power_supply_usb_type tps6598x_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, -}; - static const char *tps6598x_psy_name_prefix = "tps6598x-source-psy-"; /* @@ -827,8 +822,8 @@ static int devm_tps6598_psy_register(struct tps6598x *tps) tps->psy_desc.name = psy_name; tps->psy_desc.type = POWER_SUPPLY_TYPE_USB; - tps->psy_desc.usb_types = tps6598x_psy_usb_types; - tps->psy_desc.num_usb_types = ARRAY_SIZE(tps6598x_psy_usb_types); + tps->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD); tps->psy_desc.properties = tps6598x_psy_props; tps->psy_desc.num_properties = ARRAY_SIZE(tps6598x_psy_props); tps->psy_desc.get_property = tps6598x_psy_get_prop; @@ -1465,8 +1460,9 @@ static void tps6598x_remove(struct i2c_client *client) if (!client->irq) cancel_delayed_work_sync(&tps->wq_poll); + else + devm_free_irq(tps->dev, client->irq, tps); - devm_free_irq(tps->dev, client->irq, tps); tps6598x_disconnect(tps, 0); typec_unregister_port(tps->port); usb_role_switch_put(tps->role_sw); diff --git a/drivers/usb/typec/ucsi/psy.c b/drivers/usb/typec/ucsi/psy.c index e623d80e177c..1c631c7855a9 100644 --- a/drivers/usb/typec/ucsi/psy.c +++ b/drivers/usb/typec/ucsi/psy.c @@ -254,12 +254,6 @@ static int ucsi_psy_get_prop(struct power_supply *psy, } } -static enum power_supply_usb_type ucsi_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_C, - POWER_SUPPLY_USB_TYPE_PD, - POWER_SUPPLY_USB_TYPE_PD_PPS, -}; - int ucsi_register_port_psy(struct ucsi_connector *con) { struct power_supply_config psy_cfg = {}; @@ -276,8 +270,9 @@ int ucsi_register_port_psy(struct ucsi_connector *con) con->psy_desc.name = psy_name; con->psy_desc.type = POWER_SUPPLY_TYPE_USB; - con->psy_desc.usb_types = ucsi_psy_usb_types; - con->psy_desc.num_usb_types = ARRAY_SIZE(ucsi_psy_usb_types); + con->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | + BIT(POWER_SUPPLY_USB_TYPE_PD) | + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); con->psy_desc.properties = ucsi_psy_props; con->psy_desc.num_properties = ARRAY_SIZE(ucsi_psy_props); con->psy_desc.get_property = ucsi_psy_get_prop; diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 4039851551c1..e0f3925e401b 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -38,6 +38,10 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci) { + /* Ignore bogus data in CCI if busy indicator is set. */ + if (cci & UCSI_CCI_BUSY) + return; + if (UCSI_CCI_CONNECTOR(cci)) ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci)); @@ -99,24 +103,18 @@ static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci, *cci = 0; - /* - * Below UCSI 2.0, MESSAGE_IN was limited to 16 bytes. Truncate the - * reads here. - */ - if (ucsi->version <= UCSI_VERSION_1_2) - size = clamp(size, 0, 16); + if (size > UCSI_MAX_DATA_LENGTH(ucsi)) + return -EINVAL; ret = ucsi->ops->sync_control(ucsi, command); - if (ret) - return ret; + if (ucsi->ops->read_cci(ucsi, cci)) + return -EIO; - ret = ucsi->ops->read_cci(ucsi, cci); + if (*cci & UCSI_CCI_BUSY) + return ucsi_run_command(ucsi, UCSI_CANCEL, cci, NULL, 0, false) ?: -EBUSY; if (ret) return ret; - if (*cci & UCSI_CCI_BUSY) - return -EBUSY; - if (!(*cci & UCSI_CCI_COMMAND_COMPLETE)) return -EIO; @@ -148,21 +146,10 @@ static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num) int ret; command = UCSI_GET_ERROR_STATUS | UCSI_CONNECTOR_NUMBER(connector_num); - ret = ucsi_run_command(ucsi, command, &cci, - &error, sizeof(error), false); - - if (cci & UCSI_CCI_BUSY) { - ret = ucsi_run_command(ucsi, UCSI_CANCEL, &cci, NULL, 0, false); - - return ret ? ret : -EBUSY; - } - + ret = ucsi_run_command(ucsi, command, &cci, &error, sizeof(error), false); if (ret < 0) return ret; - if (cci & UCSI_CCI_ERROR) - return -EIO; - switch (error) { case UCSI_ERROR_INCOMPATIBLE_PARTNER: return -EOPNOTSUPP; @@ -238,9 +225,8 @@ static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, mutex_lock(&ucsi->ppm_lock); ret = ucsi_run_command(ucsi, cmd, &cci, data, size, conn_ack); - if (cci & UCSI_CCI_BUSY) - ret = ucsi_run_command(ucsi, UCSI_CANCEL, &cci, NULL, 0, false) ?: -EBUSY; - else if (cci & UCSI_CCI_ERROR) + + if (cci & UCSI_CCI_ERROR) ret = ucsi_read_error(ucsi, connector_num); mutex_unlock(&ucsi->ppm_lock); @@ -752,104 +738,66 @@ static struct usb_power_delivery_capabilities *ucsi_get_pd_caps(struct ucsi_conn &pd_caps); } -static int ucsi_read_identity(struct ucsi_connector *con, u8 recipient, - u8 offset, u8 bytes, void *resp) +static int ucsi_get_pd_message(struct ucsi_connector *con, u8 recipient, + size_t bytes, void *data, u8 type) { - struct ucsi *ucsi = con->ucsi; + size_t len = min(bytes, UCSI_MAX_DATA_LENGTH(con->ucsi)); u64 command; + u8 offset; int ret; - command = UCSI_COMMAND(UCSI_GET_PD_MESSAGE) | - UCSI_CONNECTOR_NUMBER(con->num); - command |= UCSI_GET_PD_MESSAGE_RECIPIENT(recipient); - command |= UCSI_GET_PD_MESSAGE_OFFSET(offset); - command |= UCSI_GET_PD_MESSAGE_BYTES(bytes); - command |= UCSI_GET_PD_MESSAGE_TYPE(UCSI_GET_PD_MESSAGE_TYPE_IDENTITY); - - ret = ucsi_send_command(ucsi, command, resp, bytes); - if (ret < 0) - dev_err(ucsi->dev, "UCSI_GET_PD_MESSAGE failed (%d)\n", ret); - - return ret; -} - -static int ucsi_get_identity(struct ucsi_connector *con, u8 recipient, - struct usb_pd_identity *id) -{ - struct ucsi *ucsi = con->ucsi; - struct ucsi_pd_message_disc_id resp = {}; - int ret; - - if (ucsi->version < UCSI_VERSION_2_0) { - /* - * Before UCSI v2.0, MESSAGE_IN is 16 bytes which cannot fit - * the 28 byte identity response including the VDM header. - * First request the VDM header, ID Header VDO, Cert Stat VDO - * and Product VDO. - */ - ret = ucsi_read_identity(con, recipient, 0, 0x10, &resp); - if (ret < 0) - return ret; - + for (offset = 0; offset < bytes; offset += len) { + len = min(len, bytes - offset); - /* Then request Product Type VDO1 through Product Type VDO3. */ - ret = ucsi_read_identity(con, recipient, 0x10, 0xc, - &resp.vdo[0]); - if (ret < 0) - return ret; + command = UCSI_COMMAND(UCSI_GET_PD_MESSAGE) | UCSI_CONNECTOR_NUMBER(con->num); + command |= UCSI_GET_PD_MESSAGE_RECIPIENT(recipient); + command |= UCSI_GET_PD_MESSAGE_OFFSET(offset); + command |= UCSI_GET_PD_MESSAGE_BYTES(len); + command |= UCSI_GET_PD_MESSAGE_TYPE(type); - } else { - /* - * In UCSI v2.0 and after, MESSAGE_IN is large enough to request - * the large enough to request the full Discover Identity - * response at once. - */ - ret = ucsi_read_identity(con, recipient, 0x0, 0x1c, &resp); + ret = ucsi_send_command(con->ucsi, command, data + offset, len); if (ret < 0) return ret; } - id->id_header = resp.id_header; - id->cert_stat = resp.cert_stat; - id->product = resp.product; - id->vdo[0] = resp.vdo[0]; - id->vdo[1] = resp.vdo[1]; - id->vdo[2] = resp.vdo[2]; return 0; } static int ucsi_get_partner_identity(struct ucsi_connector *con) { + u32 vdo[7] = {}; int ret; - ret = ucsi_get_identity(con, UCSI_RECIPIENT_SOP, - &con->partner_identity); + ret = ucsi_get_pd_message(con, UCSI_RECIPIENT_SOP, sizeof(vdo), vdo, + UCSI_GET_PD_MESSAGE_TYPE_IDENTITY); if (ret < 0) return ret; + /* VDM Header is not part of struct usb_pd_identity, so dropping it. */ + con->partner_identity = *(struct usb_pd_identity *)&vdo[1]; + ret = typec_partner_set_identity(con->partner); - if (ret < 0) { - dev_err(con->ucsi->dev, "Failed to set partner identity (%d)\n", - ret); - } + if (ret < 0) + dev_err(con->ucsi->dev, "Failed to set partner identity (%d)\n", ret); return ret; } static int ucsi_get_cable_identity(struct ucsi_connector *con) { + u32 vdo[7] = {}; int ret; - ret = ucsi_get_identity(con, UCSI_RECIPIENT_SOP_P, - &con->cable_identity); + ret = ucsi_get_pd_message(con, UCSI_RECIPIENT_SOP_P, sizeof(vdo), vdo, + UCSI_GET_PD_MESSAGE_TYPE_IDENTITY); if (ret < 0) return ret; + con->cable_identity = *(struct usb_pd_identity *)&vdo[1]; + ret = typec_cable_set_identity(con->cable); - if (ret < 0) { - dev_err(con->ucsi->dev, "Failed to set cable identity (%d)\n", - ret); - } + if (ret < 0) + dev_err(con->ucsi->dev, "Failed to set cable identity (%d)\n", ret); return ret; } @@ -965,10 +913,20 @@ static void ucsi_unregister_plug(struct ucsi_connector *con) static int ucsi_register_cable(struct ucsi_connector *con) { + struct ucsi_cable_property cable_prop; struct typec_cable *cable; struct typec_cable_desc desc = {}; + u64 command; + int ret; + + command = UCSI_GET_CABLE_PROPERTY | UCSI_CONNECTOR_NUMBER(con->num); + ret = ucsi_send_command(con->ucsi, command, &cable_prop, sizeof(cable_prop)); + if (ret < 0) { + dev_err(con->ucsi->dev, "GET_CABLE_PROPERTY failed (%d)\n", ret); + return ret; + } - switch (UCSI_CABLE_PROP_FLAG_PLUG_TYPE(con->cable_prop.flags)) { + switch (UCSI_CABLE_PROP_FLAG_PLUG_TYPE(cable_prop.flags)) { case UCSI_CABLE_PROPERTY_PLUG_TYPE_A: desc.type = USB_PLUG_TYPE_A; break; @@ -983,11 +941,12 @@ static int ucsi_register_cable(struct ucsi_connector *con) break; } - desc.identity = &con->cable_identity; - desc.active = !!(UCSI_CABLE_PROP_FLAG_ACTIVE_CABLE & - con->cable_prop.flags); - desc.pd_revision = UCSI_CABLE_PROP_FLAG_PD_MAJOR_REV_AS_BCD( - con->cable_prop.flags); + if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) + desc.identity = &con->cable_identity; + desc.active = !!(UCSI_CABLE_PROP_FLAG_ACTIVE_CABLE & cable_prop.flags); + + if (con->ucsi->version >= UCSI_VERSION_2_1) + desc.pd_revision = UCSI_CABLE_PROP_FLAG_PD_MAJOR_REV_AS_BCD(cable_prop.flags); cable = typec_register_cable(con->port, &desc); if (IS_ERR(cable)) { @@ -1012,6 +971,27 @@ static void ucsi_unregister_cable(struct ucsi_connector *con) con->cable = NULL; } +static int ucsi_check_connector_capability(struct ucsi_connector *con) +{ + u64 command; + int ret; + + if (!con->partner || con->ucsi->version < UCSI_VERSION_2_1) + return 0; + + command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num); + ret = ucsi_send_command(con->ucsi, command, &con->cap, sizeof(con->cap)); + if (ret < 0) { + dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret); + return ret; + } + + typec_partner_set_pd_revision(con->partner, + UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags)); + + return ret; +} + static void ucsi_pwr_opmode_change(struct ucsi_connector *con) { switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { @@ -1021,6 +1001,7 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con) ucsi_partner_task(con, ucsi_get_src_pdos, 30, 0); ucsi_partner_task(con, ucsi_check_altmodes, 30, HZ); ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ); + ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ); break; case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: con->rdo = 0; @@ -1062,9 +1043,9 @@ static int ucsi_register_partner(struct ucsi_connector *con) if (pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD) ucsi_register_device_pdos(con); - desc.identity = &con->partner_identity; + if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) + desc.identity = &con->partner_identity; desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD; - desc.pd_revision = UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags); partner = typec_register_partner(con->port, &desc); if (IS_ERR(partner)) { @@ -1141,27 +1122,6 @@ static void ucsi_partner_change(struct ucsi_connector *con) con->num, u_role); } -static int ucsi_check_connector_capability(struct ucsi_connector *con) -{ - u64 command; - int ret; - - if (!con->partner || con->ucsi->version < UCSI_VERSION_2_0) - return 0; - - command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num); - ret = ucsi_send_command(con->ucsi, command, &con->cap, sizeof(con->cap)); - if (ret < 0) { - dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret); - return ret; - } - - typec_partner_set_pd_revision(con->partner, - UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags)); - - return ret; -} - static int ucsi_check_connection(struct ucsi_connector *con) { u8 prev_flags = con->status.flags; @@ -1193,21 +1153,11 @@ static int ucsi_check_connection(struct ucsi_connector *con) static int ucsi_check_cable(struct ucsi_connector *con) { - u64 command; int ret, num_plug_am; if (con->cable) return 0; - command = UCSI_GET_CABLE_PROPERTY | UCSI_CONNECTOR_NUMBER(con->num); - ret = ucsi_send_command(con->ucsi, command, &con->cable_prop, - sizeof(con->cable_prop)); - if (ret < 0) { - dev_err(con->ucsi->dev, "GET_CABLE_PROPERTY failed (%d)\n", - ret); - return ret; - } - ret = ucsi_register_cable(con); if (ret < 0) return ret; @@ -1249,6 +1199,10 @@ static void ucsi_handle_connector_change(struct work_struct *work) mutex_lock(&con->lock); + if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags)) + dev_err_once(ucsi->dev, "%s entered without EVENT_PENDING\n", + __func__); + command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); ret = ucsi_send_command_common(ucsi, command, &con->status, @@ -1283,15 +1237,16 @@ static void ucsi_handle_connector_change(struct work_struct *work) if (con->status.flags & UCSI_CONSTAT_CONNECTED) { ucsi_register_partner(con); ucsi_partner_task(con, ucsi_check_connection, 1, HZ); - ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ); if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) ucsi_partner_task(con, ucsi_get_partner_identity, 1, HZ); if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) ucsi_partner_task(con, ucsi_check_cable, 1, HZ); if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) == - UCSI_CONSTAT_PWR_OPMODE_PD) + UCSI_CONSTAT_PWR_OPMODE_PD) { ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ); + ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ); + } } else { ucsi_unregister_partner(con); } @@ -1340,12 +1295,26 @@ EXPORT_SYMBOL_GPL(ucsi_connector_change); /* -------------------------------------------------------------------------- */ +/* + * Hard Reset bit field was defined with value 1 in UCSI spec version 1.0. + * Starting with spec version 1.1, Hard Reset bit field was removed from the + * CONNECTOR_RESET command, until spec 2.0 reintroduced it with value 0, so, in effect, + * the value to pass in to the command for a Hard Reset is different depending + * on the supported UCSI version by the LPM. + * + * For performing a Data Reset on LPMs supporting version 2.0 and greater, + * this function needs to be called with the second argument set to 0. + */ static int ucsi_reset_connector(struct ucsi_connector *con, bool hard) { u64 command; command = UCSI_CONNECTOR_RESET | UCSI_CONNECTOR_NUMBER(con->num); - command |= hard ? UCSI_CONNECTOR_RESET_HARD : 0; + + if (con->ucsi->version < UCSI_VERSION_1_1) + command |= hard ? UCSI_CONNECTOR_RESET_HARD_VER_1_0 : 0; + else if (con->ucsi->version >= UCSI_VERSION_2_0) + command |= hard ? 0 : UCSI_CONNECTOR_RESET_DATA_VER_2_0; return ucsi_send_command(con->ucsi, command, NULL, 0); } @@ -1706,6 +1675,7 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) ucsi_register_device_pdos(con); ucsi_get_src_pdos(con); ucsi_check_altmodes(con); + ucsi_check_connector_capability(con); } trace_ucsi_register_port(con->num, &con->status); diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 57129f3c0814..4a017eb6a65b 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -29,6 +29,7 @@ struct dentry; #define UCSIv2_MESSAGE_OUT 272 /* UCSI versions */ +#define UCSI_VERSION_1_1 0x0110 #define UCSI_VERSION_1_2 0x0120 #define UCSI_VERSION_2_0 0x0200 #define UCSI_VERSION_2_1 0x0210 @@ -122,7 +123,9 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); #define UCSI_DEFAULT_GET_CONNECTOR_NUMBER(_cmd_) (((_cmd_) >> 16) & GENMASK(6, 0)) /* CONNECTOR_RESET command bits */ -#define UCSI_CONNECTOR_RESET_HARD BIT(23) /* Deprecated in v1.1 */ +#define UCSI_CONNECTOR_RESET_HARD_VER_1_0 BIT(23) /* Deprecated in v1.1 */ +#define UCSI_CONNECTOR_RESET_DATA_VER_2_0 BIT(23) /* Redefined in v2.0 */ + /* ACK_CC_CI bits */ #define UCSI_ACK_CONNECTOR_CHANGE BIT(16) @@ -344,47 +347,12 @@ struct ucsi_connector_status { #define UCSI_CONSTAT_PARTNER_TYPE_AUDIO 6 u32 request_data_obj; - u8 pwr_status[3]; -#define UCSI_CONSTAT_BC_STATUS(_p_) ((_p_[0]) & GENMASK(1, 0)) + u8 pwr_status; +#define UCSI_CONSTAT_BC_STATUS(_p_) ((_p_) & GENMASK(1, 0)) #define UCSI_CONSTAT_BC_NOT_CHARGING 0 #define UCSI_CONSTAT_BC_NOMINAL_CHARGING 1 #define UCSI_CONSTAT_BC_SLOW_CHARGING 2 #define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3 -#define UCSI_CONSTAT_PROVIDER_CAP_LIMIT(_p_) (((_p_[0]) & GENMASK(5, 2)) >> 2) -#define UCSI_CONSTAT_CAP_PWR_LOWERED 0 -#define UCSI_CONSTAT_CAP_PWR_BUDGET_LIMIT 1 -#define UCSI_CONSTAT_PROVIDER_PD_VERSION_OPER_MODE(_p_) \ - ((get_unaligned_le32(_p_) & GENMASK(21, 6)) >> 6) -#define UCSI_CONSTAT_ORIENTATION(_p_) (((_p_[2]) & GENMASK(6, 6)) >> 6) -#define UCSI_CONSTAT_ORIENTATION_DIRECT 0 -#define UCSI_CONSTAT_ORIENTATION_FLIPPED 1 -#define UCSI_CONSTAT_SINK_PATH_STATUS(_p_) (((_p_[2]) & GENMASK(7, 7)) >> 7) -#define UCSI_CONSTAT_SINK_PATH_DISABLED 0 -#define UCSI_CONSTAT_SINK_PATH_ENABLED 1 - u8 pwr_readings[9]; -#define UCSI_CONSTAT_REV_CURR_PROT_STATUS(_p_) ((_p_[0]) & 0x1) -#define UCSI_CONSTAT_PWR_READING_VALID(_p_) (((_p_[0]) & GENMASK(1, 1)) >> 1) -#define UCSI_CONSTAT_CURRENT_SCALE(_p_) (((_p_[0]) & GENMASK(4, 2)) >> 2) -#define UCSI_CONSTAT_PEAK_CURRENT(_p_) \ - ((get_unaligned_le32(_p_) & GENMASK(20, 5)) >> 5) -#define UCSI_CONSTAT_AVG_CURRENT(_p_) \ - ((get_unaligned_le32(&(_p_)[2]) & GENMASK(20, 5)) >> 5) -#define UCSI_CONSTAT_VOLTAGE_SCALE(_p_) \ - ((get_unaligned_le16(&(_p_)[4]) & GENMASK(8, 5)) >> 5) -#define UCSI_CONSTAT_VOLTAGE_READING(_p_) \ - ((get_unaligned_le32(&(_p_)[5]) & GENMASK(16, 1)) >> 1) -} __packed; - -/* - * Data structure filled by PPM in response to GET_PD_MESSAGE command with the - * Response Message Type set to Discover Identity Response. - */ -struct ucsi_pd_message_disc_id { - u32 vdm_header; - u32 id_header; - u32 cert_stat; - u32 product; - u32 vdo[3]; } __packed; /* -------------------------------------------------------------------------- */ @@ -435,6 +403,8 @@ struct ucsi { #define UCSI_DELAY_DEVICE_PDOS BIT(1) /* Reading PDOs fails until the parter is in PD mode */ }; +#define UCSI_MAX_DATA_LENGTH(u) (((u)->version < UCSI_VERSION_2_0) ? 0x10 : 0xff) + #define UCSI_MAX_SVID 5 #define UCSI_MAX_ALTMODES (UCSI_MAX_SVID * 6) @@ -465,7 +435,6 @@ struct ucsi_connector { struct ucsi_connector_status status; struct ucsi_connector_capability cap; - struct ucsi_cable_property cable_prop; struct power_supply *psy; struct power_supply_desc psy_desc; u32 rdo; diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 16c328497e0b..03c0fa8edc8d 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -68,6 +68,9 @@ struct pmic_glink_ucsi { struct work_struct notify_work; struct work_struct register_work; + spinlock_t state_lock; + bool ucsi_registered; + bool pd_running; u8 read_buf[UCSI_BUF_SIZE]; }; @@ -244,8 +247,20 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) static void pmic_glink_ucsi_register(struct work_struct *work) { struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); + unsigned long flags; + bool pd_running; - ucsi_register(ucsi->ucsi); + spin_lock_irqsave(&ucsi->state_lock, flags); + pd_running = ucsi->pd_running; + spin_unlock_irqrestore(&ucsi->state_lock, flags); + + if (!ucsi->ucsi_registered && pd_running) { + ucsi_register(ucsi->ucsi); + ucsi->ucsi_registered = true; + } else if (ucsi->ucsi_registered && !pd_running) { + ucsi_unregister(ucsi->ucsi); + ucsi->ucsi_registered = false; + } } static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) @@ -263,17 +278,18 @@ static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) case UC_UCSI_USBC_NOTIFY_IND: schedule_work(&ucsi->notify_work); break; - }; + } } static void pmic_glink_ucsi_pdr_notify(void *priv, int state) { struct pmic_glink_ucsi *ucsi = priv; + unsigned long flags; - if (state == SERVREG_SERVICE_STATE_UP) - schedule_work(&ucsi->register_work); - else if (state == SERVREG_SERVICE_STATE_DOWN) - ucsi_unregister(ucsi->ucsi); + spin_lock_irqsave(&ucsi->state_lock, flags); + ucsi->pd_running = (state == SERVREG_SERVICE_STATE_UP); + spin_unlock_irqrestore(&ucsi->state_lock, flags); + schedule_work(&ucsi->register_work); } static void pmic_glink_ucsi_destroy(void *data) @@ -320,6 +336,7 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, INIT_WORK(&ucsi->register_work, pmic_glink_ucsi_register); init_completion(&ucsi->read_ack); init_completion(&ucsi->write_ack); + spin_lock_init(&ucsi->state_lock); mutex_init(&ucsi->lock); ucsi->ucsi = ucsi_create(dev, &pmic_glink_ucsi_ops); @@ -367,12 +384,16 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, ucsi->port_orientation[port] = desc; } - ucsi->client = devm_pmic_glink_register_client(dev, - PMIC_GLINK_OWNER_USBC, - pmic_glink_ucsi_callback, - pmic_glink_ucsi_pdr_notify, - ucsi); - return PTR_ERR_OR_ZERO(ucsi->client); + ucsi->client = devm_pmic_glink_client_alloc(dev, PMIC_GLINK_OWNER_USBC, + pmic_glink_ucsi_callback, + pmic_glink_ucsi_pdr_notify, + ucsi); + if (IS_ERR(ucsi->client)) + return PTR_ERR(ucsi->client); + + pmic_glink_client_register(ucsi->client); + + return 0; } static void pmic_glink_ucsi_remove(struct auxiliary_device *adev) diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 302a89aeb258..8dac1edc74d4 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -372,7 +372,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } switch (wValue) { case USB_PORT_FEAT_SUSPEND: - if (hcd->speed == HCD_USB3) { + if (hcd->speed >= HCD_USB3) { pr_err(" ClearPortFeature: USB_PORT_FEAT_SUSPEND req not " "supported for USB 3.0 roothub\n"); goto error; @@ -388,7 +388,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_POWER: usbip_dbg_vhci_rh( " ClearPortFeature: USB_PORT_FEAT_POWER\n"); - if (hcd->speed == HCD_USB3) + if (hcd->speed >= HCD_USB3) vhci_hcd->port_status[rhport] &= ~USB_SS_PORT_STAT_POWER; else vhci_hcd->port_status[rhport] &= ~USB_PORT_STAT_POWER; @@ -404,19 +404,19 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case GetHubDescriptor: usbip_dbg_vhci_rh(" GetHubDescriptor\n"); - if (hcd->speed == HCD_USB3 && + if (hcd->speed >= HCD_USB3 && (wLength < USB_DT_SS_HUB_SIZE || wValue != (USB_DT_SS_HUB << 8))) { pr_err("Wrong hub descriptor type for USB 3.0 roothub.\n"); goto error; } - if (hcd->speed == HCD_USB3) + if (hcd->speed >= HCD_USB3) ss_hub_descriptor((struct usb_hub_descriptor *) buf); else hub_descriptor((struct usb_hub_descriptor *) buf); break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - if (hcd->speed != HCD_USB3) + if (hcd->speed < HCD_USB3) goto error; if ((wValue >> 8) != USB_DT_BOS) @@ -503,7 +503,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_LINK_STATE: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_LINK_STATE\n"); - if (hcd->speed != HCD_USB3) { + if (hcd->speed < HCD_USB3) { pr_err("USB_PORT_FEAT_LINK_STATE req not " "supported for USB 2.0 roothub\n"); goto error; @@ -521,7 +521,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_U2_TIMEOUT\n"); /* TODO: add suspend/resume support! */ - if (hcd->speed != HCD_USB3) { + if (hcd->speed < HCD_USB3) { pr_err("USB_PORT_FEAT_U1/2_TIMEOUT req not " "supported for USB 2.0 roothub\n"); goto error; @@ -531,7 +531,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_SUSPEND\n"); /* Applicable only for USB2.0 hub */ - if (hcd->speed == HCD_USB3) { + if (hcd->speed >= HCD_USB3) { pr_err("USB_PORT_FEAT_SUSPEND req not " "supported for USB 3.0 roothub\n"); goto error; @@ -551,7 +551,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, pr_err("invalid port number %d\n", wIndex); goto error; } - if (hcd->speed == HCD_USB3) + if (hcd->speed >= HCD_USB3) vhci_hcd->port_status[rhport] |= USB_SS_PORT_STAT_POWER; else vhci_hcd->port_status[rhport] |= USB_PORT_STAT_POWER; @@ -564,7 +564,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; } /* Applicable only for USB3.0 hub */ - if (hcd->speed != HCD_USB3) { + if (hcd->speed < HCD_USB3) { pr_err("USB_PORT_FEAT_BH_PORT_RESET req not " "supported for USB 2.0 roothub\n"); goto error; @@ -578,7 +578,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; } /* if it's already enabled, disable */ - if (hcd->speed == HCD_USB3) { + if (hcd->speed >= HCD_USB3) { vhci_hcd->port_status[rhport] = 0; vhci_hcd->port_status[rhport] = (USB_SS_PORT_STAT_POWER | @@ -602,7 +602,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } if (wValue >= 32) goto error; - if (hcd->speed == HCD_USB3) { + if (hcd->speed >= HCD_USB3) { if ((vhci_hcd->port_status[rhport] & USB_SS_PORT_STAT_POWER) != 0) { vhci_hcd->port_status[rhport] |= (1 << wValue); @@ -616,7 +616,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case GetPortErrorCount: usbip_dbg_vhci_rh(" GetPortErrorCount\n"); - if (hcd->speed != HCD_USB3) { + if (hcd->speed < HCD_USB3) { pr_err("GetPortErrorCount req not " "supported for USB 2.0 roothub\n"); goto error; @@ -626,7 +626,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case SetHubDepth: usbip_dbg_vhci_rh(" SetHubDepth\n"); - if (hcd->speed != HCD_USB3) { + if (hcd->speed < HCD_USB3) { pr_err("SetHubDepth req not supported for " "USB 2.0 roothub\n"); goto error; @@ -646,7 +646,7 @@ error: if (!invalid_rhport) { dump_port_status_diff(prev_port_status[rhport], vhci_hcd->port_status[rhport], - hcd->speed == HCD_USB3); + hcd->speed >= HCD_USB3); } } usbip_dbg_vhci_rh(" bye\n"); @@ -1157,8 +1157,8 @@ static int vhci_setup(struct usb_hcd *hcd) } else { vhci->vhci_hcd_ss = hcd_to_vhci_hcd(hcd); vhci->vhci_hcd_ss->vhci = vhci; - hcd->speed = HCD_USB3; - hcd->self.root_hub->speed = USB_SPEED_SUPER; + hcd->speed = HCD_USB31; + hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; } /* @@ -1319,7 +1319,7 @@ static const struct hc_driver vhci_hc_driver = { .product_desc = driver_desc, .hcd_priv_size = sizeof(struct vhci_hcd), - .flags = HCD_USB3 | HCD_SHARED, + .flags = HCD_USB31 | HCD_SHARED, .reset = vhci_setup, .start = vhci_start, diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index e2847cd3e6e3..d5865460e82d 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -283,6 +283,7 @@ static int valid_args(__u32 *pdev_nr, __u32 *rhport, case USB_SPEED_HIGH: case USB_SPEED_WIRELESS: case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: break; default: pr_err("Failed attach request for unsupported USB speed: %s\n", @@ -349,7 +350,7 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr, vhci_hcd = hcd_to_vhci_hcd(hcd); vhci = vhci_hcd->vhci; - if (speed == USB_SPEED_SUPER) + if (speed >= USB_SPEED_SUPER) vdev = &vhci->vhci_hcd_ss->vdev[rhport]; else vdev = &vhci->vhci_hcd_hs->vdev[rhport]; |