Lines Matching +full:usb +full:- +full:port +full:- +full:id

1 // SPDX-License-Identifier: GPL-2.0+
3 * aspeed-vhub -- Driver for Aspeed SoC "vHub" USB gadget
5 * hub.c - virtual hub handling
27 #include <linux/usb/gadget.h>
31 #include <linux/dma-mapping.h>
34 #include <linux/usb.h>
35 #include <linux/usb/hcd.h>
39 /* usb 2.0 hub device descriptor
43 * - We may need to indicate TT support
44 * - We may need a device qualifier descriptor
46 * - Make vid/did overridable
47 * - make it look like usb1 if usb1 mode forced
138 * These strings converted to UTF-16 must be smaller than
143 .id = AST_VHUB_STR_SERIAL,
147 .id = AST_VHUB_STR_PRODUCT,
148 .s = "USB Virtual Hub"
151 .id = AST_VHUB_STR_MANUF,
170 * Mark it as self-powered, I doubt the BMC is powered off in ast_vhub_hub_dev_status()
171 * the USB bus ... in ast_vhub_hub_dev_status()
179 if (ep->vhub->wakeup_en) in ast_vhub_hub_dev_status()
196 if (ep->vhub->ep1_stalled) in ast_vhub_hub_ep_status()
214 ep->vhub->wakeup_en = is_set; in ast_vhub_hub_dev_feature()
242 ep->vhub->ep1_stalled = is_set; in ast_vhub_hub_ep_feature()
243 reg = readl(ep->vhub->regs + AST_VHUB_EP1_CTRL); in ast_vhub_hub_ep_feature()
250 writel(reg, ep->vhub->regs + AST_VHUB_EP1_CTRL); in ast_vhub_hub_ep_feature()
259 struct ast_vhub *vhub = ep->vhub; in ast_vhub_rep_desc()
265 * we can do some in-place patching if needed. We know in ast_vhub_rep_desc()
275 memcpy(ep->buf, &vhub->vhub_dev_desc, dsize); in ast_vhub_rep_desc()
276 BUILD_BUG_ON(dsize > sizeof(vhub->vhub_dev_desc)); in ast_vhub_rep_desc()
281 memcpy(ep->buf, &vhub->vhub_conf_desc, dsize); in ast_vhub_rep_desc()
282 BUILD_BUG_ON(dsize > sizeof(vhub->vhub_conf_desc)); in ast_vhub_rep_desc()
287 memcpy(ep->buf, &vhub->vhub_hub_desc, dsize); in ast_vhub_rep_desc()
288 BUILD_BUG_ON(dsize > sizeof(vhub->vhub_hub_desc)); in ast_vhub_rep_desc()
306 return (struct usb_gadget_strings *)container->stash; in ast_vhub_str_of_container()
319 max_langs = (size - hdr_len) / sizeof(sdesc->wData[0]); in ast_vhub_collect_languages()
320 list_for_each_entry(container, &vhub->vhub_str_desc, list) { in ast_vhub_collect_languages()
325 sdesc->wData[nlangs++] = cpu_to_le16(lang_str->language); in ast_vhub_collect_languages()
328 rc = hdr_len + nlangs * sizeof(sdesc->wData[0]); in ast_vhub_collect_languages()
329 sdesc->bLength = rc; in ast_vhub_collect_languages()
330 sdesc->bDescriptorType = USB_DT_STRING; in ast_vhub_collect_languages()
341 list_for_each_entry(container, &vhub->vhub_str_desc, list) { in ast_vhub_lookup_string()
343 if (lang_str->language == lang_id) in ast_vhub_lookup_string()
356 struct ast_vhub *vhub = ep->vhub; in ast_vhub_rep_string()
373 memcpy(ep->buf, buf, rc); in ast_vhub_rep_string()
380 struct ast_vhub *vhub = ep->vhub; in ast_vhub_std_hub_request()
383 wValue = le16_to_cpu(crq->wValue); in ast_vhub_std_hub_request()
384 wIndex = le16_to_cpu(crq->wIndex); in ast_vhub_std_hub_request()
385 wLength = le16_to_cpu(crq->wLength); in ast_vhub_std_hub_request()
388 if (vhub->speed == USB_SPEED_UNKNOWN) { in ast_vhub_std_hub_request()
389 u32 ustat = readl(vhub->regs + AST_VHUB_USBSTS); in ast_vhub_std_hub_request()
391 vhub->speed = USB_SPEED_HIGH; in ast_vhub_std_hub_request()
393 vhub->speed = USB_SPEED_FULL; in ast_vhub_std_hub_request()
394 UDCDBG(vhub, "USB status=%08x speed=%s\n", ustat, in ast_vhub_std_hub_request()
395 vhub->speed == USB_SPEED_HIGH ? "high" : "full"); in ast_vhub_std_hub_request()
398 switch ((crq->bRequestType << 8) | crq->bRequest) { in ast_vhub_std_hub_request()
402 writel(wValue, vhub->regs + AST_VHUB_CONF); in ast_vhub_std_hub_request()
456 unsigned int port) in ast_vhub_update_hub_ep1() argument
459 u32 reg = readl(vhub->regs + AST_VHUB_EP1_STS_CHG); in ast_vhub_update_hub_ep1()
460 u32 pmask = (1 << (port + 1)); in ast_vhub_update_hub_ep1()
461 if (vhub->ports[port].change) in ast_vhub_update_hub_ep1()
465 writel(reg, vhub->regs + AST_VHUB_EP1_STS_CHG); in ast_vhub_update_hub_ep1()
469 unsigned int port, in ast_vhub_change_port_stat() argument
474 struct ast_vhub_port *p = &vhub->ports[port]; in ast_vhub_change_port_stat()
477 /* Update port status */ in ast_vhub_change_port_stat()
478 prev = p->status; in ast_vhub_change_port_stat()
479 p->status = (prev & ~clr_flags) | set_flags; in ast_vhub_change_port_stat()
480 DDBG(&p->dev, "port %d status %04x -> %04x (C=%d)\n", in ast_vhub_change_port_stat()
481 port + 1, prev, p->status, set_c); in ast_vhub_change_port_stat()
485 u16 chg = p->status ^ prev; in ast_vhub_change_port_stat()
497 * the port as per USB spec, otherwise MacOS gets upset in ast_vhub_change_port_stat()
499 if (p->status & USB_PORT_STAT_ENABLE) in ast_vhub_change_port_stat()
502 p->change = chg; in ast_vhub_change_port_stat()
503 ast_vhub_update_hub_ep1(vhub, port); in ast_vhub_change_port_stat()
509 u32 reg = readl(vhub->regs + AST_VHUB_CTRL); in ast_vhub_send_host_wakeup()
512 writel(reg, vhub->regs + AST_VHUB_CTRL); in ast_vhub_send_host_wakeup()
516 unsigned int port, bool on) in ast_vhub_device_connect() argument
519 ast_vhub_change_port_stat(vhub, port, 0, in ast_vhub_device_connect()
522 ast_vhub_change_port_stat(vhub, port, in ast_vhub_device_connect()
531 if (vhub->wakeup_en) in ast_vhub_device_connect()
544 * Wake all sleeping ports. If a port is suspended by in ast_vhub_wake_work()
548 spin_lock_irqsave(&vhub->lock, flags); in ast_vhub_wake_work()
549 for (i = 0; i < vhub->max_ports; i++) { in ast_vhub_wake_work()
550 struct ast_vhub_port *p = &vhub->ports[i]; in ast_vhub_wake_work()
552 if (!(p->status & USB_PORT_STAT_SUSPEND)) in ast_vhub_wake_work()
557 ast_vhub_dev_resume(&p->dev); in ast_vhub_wake_work()
560 spin_unlock_irqrestore(&vhub->lock, flags); in ast_vhub_wake_work()
570 schedule_work(&vhub->wake_work); in ast_vhub_hub_wake_all()
573 static void ast_vhub_port_reset(struct ast_vhub *vhub, u8 port) in ast_vhub_port_reset() argument
575 struct ast_vhub_port *p = &vhub->ports[port]; in ast_vhub_port_reset()
579 ast_vhub_change_port_stat(vhub, port, in ast_vhub_port_reset()
585 if (!p->dev.driver) in ast_vhub_port_reset()
589 * This will either "start" the port or reset the in ast_vhub_port_reset()
592 ast_vhub_dev_reset(&p->dev); in ast_vhub_port_reset()
595 speed = p->dev.driver->max_speed; in ast_vhub_port_reset()
596 if (speed == USB_SPEED_UNKNOWN || speed > vhub->speed) in ast_vhub_port_reset()
597 speed = vhub->speed; in ast_vhub_port_reset()
623 ast_vhub_change_port_stat(vhub, port, clr, set, true); in ast_vhub_port_reset()
627 u8 port, u16 feat) in ast_vhub_set_port_feature() argument
629 struct ast_vhub *vhub = ep->vhub; in ast_vhub_set_port_feature()
632 if (port == 0 || port > vhub->max_ports) in ast_vhub_set_port_feature()
634 port--; in ast_vhub_set_port_feature()
635 p = &vhub->ports[port]; in ast_vhub_set_port_feature()
639 if (!(p->status & USB_PORT_STAT_ENABLE)) in ast_vhub_set_port_feature()
641 ast_vhub_change_port_stat(vhub, port, in ast_vhub_set_port_feature()
644 ast_vhub_dev_suspend(&p->dev); in ast_vhub_set_port_feature()
647 EPDBG(ep, "Port reset !\n"); in ast_vhub_set_port_feature()
648 ast_vhub_port_reset(vhub, port); in ast_vhub_set_port_feature()
652 * On Power-on, we mark the connected flag changed, in ast_vhub_set_port_feature()
656 if (p->status & USB_PORT_STAT_CONNECTION) { in ast_vhub_set_port_feature()
657 p->change |= USB_PORT_STAT_C_CONNECTION; in ast_vhub_set_port_feature()
658 ast_vhub_update_hub_ep1(vhub, port); in ast_vhub_set_port_feature()
670 u8 port, u16 feat) in ast_vhub_clr_port_feature() argument
672 struct ast_vhub *vhub = ep->vhub; in ast_vhub_clr_port_feature()
675 if (port == 0 || port > vhub->max_ports) in ast_vhub_clr_port_feature()
677 port--; in ast_vhub_clr_port_feature()
678 p = &vhub->ports[port]; in ast_vhub_clr_port_feature()
682 ast_vhub_change_port_stat(vhub, port, in ast_vhub_clr_port_feature()
686 ast_vhub_dev_suspend(&p->dev); in ast_vhub_clr_port_feature()
689 if (!(p->status & USB_PORT_STAT_SUSPEND)) in ast_vhub_clr_port_feature()
691 ast_vhub_change_port_stat(vhub, port, in ast_vhub_clr_port_feature()
694 ast_vhub_dev_resume(&p->dev); in ast_vhub_clr_port_feature()
707 /* Clear state-change feature */ in ast_vhub_clr_port_feature()
708 p->change &= ~(1u << (feat - 16)); in ast_vhub_clr_port_feature()
709 ast_vhub_update_hub_ep1(vhub, port); in ast_vhub_clr_port_feature()
716 u8 port) in ast_vhub_get_port_stat() argument
718 struct ast_vhub *vhub = ep->vhub; in ast_vhub_get_port_stat()
721 if (port == 0 || port > vhub->max_ports) in ast_vhub_get_port_stat()
723 port--; in ast_vhub_get_port_stat()
725 stat = vhub->ports[port].status; in ast_vhub_get_port_stat()
726 chg = vhub->ports[port].change; in ast_vhub_get_port_stat()
731 EPDBG(ep, " port status=%04x change=%04x\n", stat, chg); in ast_vhub_get_port_stat()
745 wValue = le16_to_cpu(crq->wValue); in ast_vhub_class_hub_request()
746 wIndex = le16_to_cpu(crq->wIndex); in ast_vhub_class_hub_request()
747 wLength = le16_to_cpu(crq->wLength); in ast_vhub_class_hub_request()
749 switch ((crq->bRequestType << 8) | crq->bRequest) { in ast_vhub_class_hub_request()
791 UDCDBG(vhub, "USB bus suspend\n"); in ast_vhub_hub_suspend()
793 if (vhub->suspended) in ast_vhub_hub_suspend()
796 vhub->suspended = true; in ast_vhub_hub_suspend()
802 for (i = 0; i < vhub->max_ports; i++) { in ast_vhub_hub_suspend()
803 struct ast_vhub_port *p = &vhub->ports[i]; in ast_vhub_hub_suspend()
805 if (!(p->status & USB_PORT_STAT_SUSPEND)) in ast_vhub_hub_suspend()
806 ast_vhub_dev_suspend(&p->dev); in ast_vhub_hub_suspend()
814 UDCDBG(vhub, "USB bus resume\n"); in ast_vhub_hub_resume()
816 if (!vhub->suspended) in ast_vhub_hub_resume()
819 vhub->suspended = false; in ast_vhub_hub_resume()
825 for (i = 0; i < vhub->max_ports; i++) { in ast_vhub_hub_resume()
826 struct ast_vhub_port *p = &vhub->ports[i]; in ast_vhub_hub_resume()
828 if (!(p->status & USB_PORT_STAT_SUSPEND)) in ast_vhub_hub_resume()
829 ast_vhub_dev_resume(&p->dev); in ast_vhub_hub_resume()
837 UDCDBG(vhub, "USB bus reset\n"); in ast_vhub_hub_reset()
843 if (vhub->speed == USB_SPEED_UNKNOWN) in ast_vhub_hub_reset()
847 vhub->suspended = false; in ast_vhub_hub_reset()
850 vhub->speed = USB_SPEED_UNKNOWN; in ast_vhub_hub_reset()
853 vhub->wakeup_en = false; in ast_vhub_hub_reset()
856 * Clear all port status, disable gadgets and "suspend" in ast_vhub_hub_reset()
857 * them. They will be woken up by a port reset. in ast_vhub_hub_reset()
859 for (i = 0; i < vhub->max_ports; i++) { in ast_vhub_hub_reset()
860 struct ast_vhub_port *p = &vhub->ports[i]; in ast_vhub_hub_reset()
863 p->status &= USB_PORT_STAT_CONNECTION; in ast_vhub_hub_reset()
864 p->change = 0; in ast_vhub_hub_reset()
867 ast_vhub_dev_suspend(&p->dev); in ast_vhub_hub_reset()
871 writel(0, vhub->regs + AST_VHUB_CONF); in ast_vhub_hub_reset()
872 writel(0, vhub->regs + AST_VHUB_EP0_CTRL); in ast_vhub_hub_reset()
875 vhub->regs + AST_VHUB_EP1_CTRL); in ast_vhub_hub_reset()
876 writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG); in ast_vhub_hub_reset()
882 u16 id; in ast_vhub_of_parse_dev_desc() local
885 if (!of_property_read_u32(vhub_np, "vhub-vendor-id", &data)) { in ast_vhub_of_parse_dev_desc()
886 id = (u16)data; in ast_vhub_of_parse_dev_desc()
887 vhub->vhub_dev_desc.idVendor = cpu_to_le16(id); in ast_vhub_of_parse_dev_desc()
889 if (!of_property_read_u32(vhub_np, "vhub-product-id", &data)) { in ast_vhub_of_parse_dev_desc()
890 id = (u16)data; in ast_vhub_of_parse_dev_desc()
891 vhub->vhub_dev_desc.idProduct = cpu_to_le16(id); in ast_vhub_of_parse_dev_desc()
893 if (!of_property_read_u32(vhub_np, "vhub-device-revision", &data)) { in ast_vhub_of_parse_dev_desc()
894 id = (u16)data; in ast_vhub_of_parse_dev_desc()
895 vhub->vhub_dev_desc.bcdDevice = cpu_to_le16(id); in ast_vhub_of_parse_dev_desc()
901 vhub->vhub_dev_desc.bcdUSB = cpu_to_le16(0x0100); in ast_vhub_fixup_usb1_dev_desc()
902 vhub->vhub_dev_desc.bDeviceProtocol = 0; in ast_vhub_fixup_usb1_dev_desc()
916 container = devm_kzalloc(&vhub->pdev->dev, size, GFP_KERNEL); in ast_vhub_str_container_alloc()
918 return ERR_PTR(-ENOMEM); in ast_vhub_str_container_alloc()
922 lang_str->strings = str_array; in ast_vhub_str_container_alloc()
929 struct usb_string *src_array = src->strings; in ast_vhub_str_deep_copy()
930 struct usb_string *dest_array = dest->strings; in ast_vhub_str_deep_copy()
932 dest->language = src->language; in ast_vhub_str_deep_copy()
938 } while (src_array->s); in ast_vhub_str_deep_copy()
954 list_add_tail(&container->list, &vhub->vhub_str_desc); in ast_vhub_str_alloc_add()
961 u8 id; member
965 {"serial-number", AST_VHUB_STR_SERIAL},
994 str_array[offset].id = str_id_map[i].id; in ast_vhub_of_parse_str_desc()
998 str_array[offset].id = 0; in ast_vhub_of_parse_str_desc()
1013 const struct device_node *vhub_np = vhub->pdev->dev.of_node; in ast_vhub_init_desc()
1016 memcpy(&vhub->vhub_dev_desc, &ast_vhub_dev_desc, in ast_vhub_init_desc()
1017 sizeof(vhub->vhub_dev_desc)); in ast_vhub_init_desc()
1019 if (vhub->force_usb1) in ast_vhub_init_desc()
1023 memcpy(&vhub->vhub_conf_desc, &ast_vhub_conf_desc, in ast_vhub_init_desc()
1024 sizeof(vhub->vhub_conf_desc)); in ast_vhub_init_desc()
1027 memcpy(&vhub->vhub_hub_desc, &ast_vhub_hub_desc, in ast_vhub_init_desc()
1028 sizeof(vhub->vhub_hub_desc)); in ast_vhub_init_desc()
1029 vhub->vhub_hub_desc.bNbrPorts = vhub->max_ports; in ast_vhub_init_desc()
1032 INIT_LIST_HEAD(&vhub->vhub_str_desc); in ast_vhub_init_desc()
1033 desc_np = of_get_child_by_name(vhub_np, "vhub-strings"); in ast_vhub_init_desc()
1044 vhub->speed = USB_SPEED_UNKNOWN; in ast_vhub_init_hub()
1045 INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); in ast_vhub_init_hub()