From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- kernel/drivers/usb/gadget/udc/renesas_usb3.c | 164 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 135 insertions(+), 29 deletions(-) diff --git a/kernel/drivers/usb/gadget/udc/renesas_usb3.c b/kernel/drivers/usb/gadget/udc/renesas_usb3.c index c17d7a7..a10f41c 100644 --- a/kernel/drivers/usb/gadget/udc/renesas_usb3.c +++ b/kernel/drivers/usb/gadget/udc/renesas_usb3.c @@ -352,6 +352,8 @@ int disabled_count; struct usb_request *ep0_req; + + enum usb_role connection_state; u16 test_mode; u8 ep0_buf[USB3_EP0_BUF_SIZE]; bool softconnect; @@ -360,6 +362,7 @@ bool extcon_usb; /* check vbus and set EXTCON_USB */ bool forced_b_device; bool start_to_connect; + bool role_sw_by_connector; }; #define gadget_to_renesas_usb3(_gadget) \ @@ -700,8 +703,11 @@ unsigned long flags; spin_lock_irqsave(&usb3->lock, flags); - usb3_set_mode_by_role_sw(usb3, host); - usb3_vbus_out(usb3, a_dev); + if (!usb3->role_sw_by_connector || + usb3->connection_state != USB_ROLE_NONE) { + usb3_set_mode_by_role_sw(usb3, host); + usb3_vbus_out(usb3, a_dev); + } /* for A-Peripheral or forced B-device mode */ if ((!host && a_dev) || usb3->start_to_connect) usb3_connect(usb3); @@ -717,7 +723,8 @@ { usb3->extcon_host = usb3_is_a_device(usb3); - if (usb3->extcon_host && !usb3->forced_b_device) + if ((!usb3->role_sw_by_connector && usb3->extcon_host && + !usb3->forced_b_device) || usb3->connection_state == USB_ROLE_HOST) usb3_mode_config(usb3, true, true); else usb3_mode_config(usb3, false, false); @@ -766,6 +773,18 @@ usb3_disable_irq_1(usb3, USB_INT_1_B2_RSUM); usb3_start_usb2_connection(usb3); usb3_transition_to_default_state(usb3, false); +} + +static void usb3_irq_epc_int_1_suspend(struct renesas_usb3 *usb3) +{ + usb3_disable_irq_1(usb3, USB_INT_1_B2_SPND); + + if (usb3->gadget.speed != USB_SPEED_UNKNOWN && + usb3->gadget.state != USB_STATE_NOTATTACHED) { + if (usb3->driver && usb3->driver->suspend) + usb3->driver->suspend(&usb3->gadget); + usb_gadget_set_state(&usb3->gadget, USB_STATE_SUSPENDED); + } } static void usb3_irq_epc_int_1_disable(struct renesas_usb3 *usb3) @@ -852,6 +871,9 @@ if (int_sta_1 & USB_INT_1_B2_RSUM) usb3_irq_epc_int_1_resume(usb3); + + if (int_sta_1 & USB_INT_1_B2_SPND) + usb3_irq_epc_int_1_suspend(usb3); if (int_sta_1 & USB_INT_1_SPEED) usb3_irq_epc_int_1_speed(usb3); @@ -1162,7 +1184,7 @@ static void usb3_p0_xfer(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req) { - int ret = -EAGAIN; + int ret; if (usb3_ep->dir_in) ret = usb3_write_pipe(usb3_ep, usb3_req, USB3_P0_WRITE); @@ -1538,10 +1560,10 @@ static bool usb3_std_req_set_address(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { - if (ctrl->wValue >= 128) + if (le16_to_cpu(ctrl->wValue) >= 128) return true; /* stall */ - usb3_set_device_address(usb3, ctrl->wValue); + usb3_set_device_address(usb3, le16_to_cpu(ctrl->wValue)); usb3_set_p0_con_for_no_data(usb3); return false; @@ -1576,6 +1598,7 @@ struct renesas_usb3_ep *usb3_ep; int num; u16 status = 0; + __le16 tx_data; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: @@ -1598,10 +1621,10 @@ } if (!stall) { - status = cpu_to_le16(status); + tx_data = cpu_to_le16(status); dev_dbg(usb3_to_dev(usb3), "get_status: req = %p\n", usb_req_to_usb3_req(usb3->ep0_req)); - usb3_pipe0_internal_xfer(usb3, &status, sizeof(status), + usb3_pipe0_internal_xfer(usb3, &tx_data, sizeof(tx_data), usb3_pipe0_get_status_completion); } @@ -1766,7 +1789,7 @@ static bool usb3_std_req_set_configuration(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { - if (ctrl->wValue > 0) + if (le16_to_cpu(ctrl->wValue) > 0) usb3_set_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON); else usb3_clear_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON); @@ -2333,26 +2356,79 @@ .set_selfpowered = renesas_usb3_set_selfpowered, }; -static enum usb_role renesas_usb3_role_switch_get(struct device *dev) +static enum usb_role renesas_usb3_role_switch_get(struct usb_role_switch *sw) { - struct renesas_usb3 *usb3 = dev_get_drvdata(dev); + struct renesas_usb3 *usb3 = usb_role_switch_get_drvdata(sw); enum usb_role cur_role; - pm_runtime_get_sync(dev); + pm_runtime_get_sync(usb3_to_dev(usb3)); cur_role = usb3_is_host(usb3) ? USB_ROLE_HOST : USB_ROLE_DEVICE; - pm_runtime_put(dev); + pm_runtime_put(usb3_to_dev(usb3)); return cur_role; } -static int renesas_usb3_role_switch_set(struct device *dev, - enum usb_role role) +static void handle_ext_role_switch_states(struct device *dev, + enum usb_role role) { struct renesas_usb3 *usb3 = dev_get_drvdata(dev); struct device *host = usb3->host_dev; - enum usb_role cur_role = renesas_usb3_role_switch_get(dev); + enum usb_role cur_role = renesas_usb3_role_switch_get(usb3->role_sw); - pm_runtime_get_sync(dev); + switch (role) { + case USB_ROLE_NONE: + usb3->connection_state = USB_ROLE_NONE; + if (cur_role == USB_ROLE_HOST) + device_release_driver(host); + if (usb3->driver) + usb3_disconnect(usb3); + usb3_vbus_out(usb3, false); + break; + case USB_ROLE_DEVICE: + if (usb3->connection_state == USB_ROLE_NONE) { + usb3->connection_state = USB_ROLE_DEVICE; + usb3_set_mode(usb3, false); + if (usb3->driver) + usb3_connect(usb3); + } else if (cur_role == USB_ROLE_HOST) { + device_release_driver(host); + usb3_set_mode(usb3, false); + if (usb3->driver) + usb3_connect(usb3); + } + usb3_vbus_out(usb3, false); + break; + case USB_ROLE_HOST: + if (usb3->connection_state == USB_ROLE_NONE) { + if (usb3->driver) + usb3_disconnect(usb3); + + usb3->connection_state = USB_ROLE_HOST; + usb3_set_mode(usb3, true); + usb3_vbus_out(usb3, true); + if (device_attach(host) < 0) + dev_err(dev, "device_attach(host) failed\n"); + } else if (cur_role == USB_ROLE_DEVICE) { + usb3_disconnect(usb3); + /* Must set the mode before device_attach of the host */ + usb3_set_mode(usb3, true); + /* This device_attach() might sleep */ + if (device_attach(host) < 0) + dev_err(dev, "device_attach(host) failed\n"); + } + break; + default: + break; + } +} + +static void handle_role_switch_states(struct device *dev, + enum usb_role role) +{ + struct renesas_usb3 *usb3 = dev_get_drvdata(dev); + struct device *host = usb3->host_dev; + enum usb_role cur_role = renesas_usb3_role_switch_get(usb3->role_sw); + if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) { device_release_driver(host); usb3_set_mode(usb3, false); @@ -2363,7 +2439,21 @@ if (device_attach(host) < 0) dev_err(dev, "device_attach(host) failed\n"); } - pm_runtime_put(dev); +} + +static int renesas_usb3_role_switch_set(struct usb_role_switch *sw, + enum usb_role role) +{ + struct renesas_usb3 *usb3 = usb_role_switch_get_drvdata(sw); + + pm_runtime_get_sync(usb3_to_dev(usb3)); + + if (usb3->role_sw_by_connector) + handle_ext_role_switch_states(usb3_to_dev(usb3), role); + else + handle_role_switch_states(usb3_to_dev(usb3), role); + + pm_runtime_put(usb3_to_dev(usb3)); return 0; } @@ -2464,7 +2554,7 @@ static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3, struct device *dev) { - usb3->dentry = debugfs_create_dir(dev_name(dev), NULL); + usb3->dentry = debugfs_create_dir(dev_name(dev), usb_debug_root); debugfs_create_file("b_device", 0644, usb3->dentry, usb3, &renesas_usb3_b_device_fops); @@ -2478,6 +2568,7 @@ debugfs_remove_recursive(usb3->dentry); device_remove_file(&pdev->dev, &dev_attr_role); + cancel_work_sync(&usb3->role_work); usb_role_switch_unregister(usb3->role_sw); usb_del_gadget_udc(&usb3->gadget); @@ -2610,12 +2701,24 @@ .ramsize_per_pipe = SZ_4K, }; +static const struct renesas_usb3_priv renesas_usb3_priv_r8a77990 = { + .ramsize_per_ramif = SZ_16K, + .num_ramif = 4, + .ramsize_per_pipe = SZ_4K, + .workaround_for_vbus = true, +}; + static const struct of_device_id usb3_of_match[] = { { + .compatible = "renesas,r8a774c0-usb3-peri", + .data = &renesas_usb3_priv_r8a77990, + }, { .compatible = "renesas,r8a7795-usb3-peri", .data = &renesas_usb3_priv_gen3, - }, - { + }, { + .compatible = "renesas,r8a77990-usb3-peri", + .data = &renesas_usb3_priv_r8a77990, + }, { .compatible = "renesas,rcar-gen3-usb3-peri", .data = &renesas_usb3_priv_gen3, }, @@ -2637,7 +2740,7 @@ EXTCON_NONE, }; -static const struct usb_role_switch_desc renesas_usb3_role_switch_desc = { +static struct usb_role_switch_desc renesas_usb3_role_switch_desc = { .set = renesas_usb3_role_switch_set, .get = renesas_usb3_role_switch_get, .allow_userspace_control = true, @@ -2646,7 +2749,6 @@ static int renesas_usb3_probe(struct platform_device *pdev) { struct renesas_usb3 *usb3; - struct resource *res; int irq, ret; const struct renesas_usb3_priv *priv; const struct soc_device_attribute *attr; @@ -2658,17 +2760,14 @@ priv = of_device_get_match_data(&pdev->dev); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); + if (irq < 0) return irq; - } usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL); if (!usb3) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - usb3->reg = devm_ioremap_resource(&pdev->dev, res); + usb3->reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(usb3->reg)) return PTR_ERR(usb3->reg); @@ -2727,6 +2826,13 @@ ret = device_create_file(&pdev->dev, &dev_attr_role); if (ret < 0) goto err_dev_create; + + if (device_property_read_bool(&pdev->dev, "usb-role-switch")) { + usb3->role_sw_by_connector = true; + renesas_usb3_role_switch_desc.fwnode = dev_fwnode(&pdev->dev); + } + + renesas_usb3_role_switch_desc.driver_data = usb3; INIT_WORK(&usb3->role_work, renesas_usb3_role_work); usb3->role_sw = usb_role_switch_register(&pdev->dev, @@ -2803,7 +2909,7 @@ .probe = renesas_usb3_probe, .remove = renesas_usb3_remove, .driver = { - .name = (char *)udc_name, + .name = udc_name, .pm = &renesas_usb3_pm_ops, .of_match_table = of_match_ptr(usb3_of_match), }, -- Gitblit v1.6.2