| .. | .. |
|---|
| 352 | 352 | int disabled_count; |
|---|
| 353 | 353 | |
|---|
| 354 | 354 | struct usb_request *ep0_req; |
|---|
| 355 | + |
|---|
| 356 | + enum usb_role connection_state; |
|---|
| 355 | 357 | u16 test_mode; |
|---|
| 356 | 358 | u8 ep0_buf[USB3_EP0_BUF_SIZE]; |
|---|
| 357 | 359 | bool softconnect; |
|---|
| .. | .. |
|---|
| 360 | 362 | bool extcon_usb; /* check vbus and set EXTCON_USB */ |
|---|
| 361 | 363 | bool forced_b_device; |
|---|
| 362 | 364 | bool start_to_connect; |
|---|
| 365 | + bool role_sw_by_connector; |
|---|
| 363 | 366 | }; |
|---|
| 364 | 367 | |
|---|
| 365 | 368 | #define gadget_to_renesas_usb3(_gadget) \ |
|---|
| .. | .. |
|---|
| 700 | 703 | unsigned long flags; |
|---|
| 701 | 704 | |
|---|
| 702 | 705 | spin_lock_irqsave(&usb3->lock, flags); |
|---|
| 703 | | - usb3_set_mode_by_role_sw(usb3, host); |
|---|
| 704 | | - usb3_vbus_out(usb3, a_dev); |
|---|
| 706 | + if (!usb3->role_sw_by_connector || |
|---|
| 707 | + usb3->connection_state != USB_ROLE_NONE) { |
|---|
| 708 | + usb3_set_mode_by_role_sw(usb3, host); |
|---|
| 709 | + usb3_vbus_out(usb3, a_dev); |
|---|
| 710 | + } |
|---|
| 705 | 711 | /* for A-Peripheral or forced B-device mode */ |
|---|
| 706 | 712 | if ((!host && a_dev) || usb3->start_to_connect) |
|---|
| 707 | 713 | usb3_connect(usb3); |
|---|
| .. | .. |
|---|
| 717 | 723 | { |
|---|
| 718 | 724 | usb3->extcon_host = usb3_is_a_device(usb3); |
|---|
| 719 | 725 | |
|---|
| 720 | | - if (usb3->extcon_host && !usb3->forced_b_device) |
|---|
| 726 | + if ((!usb3->role_sw_by_connector && usb3->extcon_host && |
|---|
| 727 | + !usb3->forced_b_device) || usb3->connection_state == USB_ROLE_HOST) |
|---|
| 721 | 728 | usb3_mode_config(usb3, true, true); |
|---|
| 722 | 729 | else |
|---|
| 723 | 730 | usb3_mode_config(usb3, false, false); |
|---|
| .. | .. |
|---|
| 766 | 773 | usb3_disable_irq_1(usb3, USB_INT_1_B2_RSUM); |
|---|
| 767 | 774 | usb3_start_usb2_connection(usb3); |
|---|
| 768 | 775 | usb3_transition_to_default_state(usb3, false); |
|---|
| 776 | +} |
|---|
| 777 | + |
|---|
| 778 | +static void usb3_irq_epc_int_1_suspend(struct renesas_usb3 *usb3) |
|---|
| 779 | +{ |
|---|
| 780 | + usb3_disable_irq_1(usb3, USB_INT_1_B2_SPND); |
|---|
| 781 | + |
|---|
| 782 | + if (usb3->gadget.speed != USB_SPEED_UNKNOWN && |
|---|
| 783 | + usb3->gadget.state != USB_STATE_NOTATTACHED) { |
|---|
| 784 | + if (usb3->driver && usb3->driver->suspend) |
|---|
| 785 | + usb3->driver->suspend(&usb3->gadget); |
|---|
| 786 | + usb_gadget_set_state(&usb3->gadget, USB_STATE_SUSPENDED); |
|---|
| 787 | + } |
|---|
| 769 | 788 | } |
|---|
| 770 | 789 | |
|---|
| 771 | 790 | static void usb3_irq_epc_int_1_disable(struct renesas_usb3 *usb3) |
|---|
| .. | .. |
|---|
| 852 | 871 | |
|---|
| 853 | 872 | if (int_sta_1 & USB_INT_1_B2_RSUM) |
|---|
| 854 | 873 | usb3_irq_epc_int_1_resume(usb3); |
|---|
| 874 | + |
|---|
| 875 | + if (int_sta_1 & USB_INT_1_B2_SPND) |
|---|
| 876 | + usb3_irq_epc_int_1_suspend(usb3); |
|---|
| 855 | 877 | |
|---|
| 856 | 878 | if (int_sta_1 & USB_INT_1_SPEED) |
|---|
| 857 | 879 | usb3_irq_epc_int_1_speed(usb3); |
|---|
| .. | .. |
|---|
| 1162 | 1184 | static void usb3_p0_xfer(struct renesas_usb3_ep *usb3_ep, |
|---|
| 1163 | 1185 | struct renesas_usb3_request *usb3_req) |
|---|
| 1164 | 1186 | { |
|---|
| 1165 | | - int ret = -EAGAIN; |
|---|
| 1187 | + int ret; |
|---|
| 1166 | 1188 | |
|---|
| 1167 | 1189 | if (usb3_ep->dir_in) |
|---|
| 1168 | 1190 | ret = usb3_write_pipe(usb3_ep, usb3_req, USB3_P0_WRITE); |
|---|
| .. | .. |
|---|
| 1538 | 1560 | static bool usb3_std_req_set_address(struct renesas_usb3 *usb3, |
|---|
| 1539 | 1561 | struct usb_ctrlrequest *ctrl) |
|---|
| 1540 | 1562 | { |
|---|
| 1541 | | - if (ctrl->wValue >= 128) |
|---|
| 1563 | + if (le16_to_cpu(ctrl->wValue) >= 128) |
|---|
| 1542 | 1564 | return true; /* stall */ |
|---|
| 1543 | 1565 | |
|---|
| 1544 | | - usb3_set_device_address(usb3, ctrl->wValue); |
|---|
| 1566 | + usb3_set_device_address(usb3, le16_to_cpu(ctrl->wValue)); |
|---|
| 1545 | 1567 | usb3_set_p0_con_for_no_data(usb3); |
|---|
| 1546 | 1568 | |
|---|
| 1547 | 1569 | return false; |
|---|
| .. | .. |
|---|
| 1576 | 1598 | struct renesas_usb3_ep *usb3_ep; |
|---|
| 1577 | 1599 | int num; |
|---|
| 1578 | 1600 | u16 status = 0; |
|---|
| 1601 | + __le16 tx_data; |
|---|
| 1579 | 1602 | |
|---|
| 1580 | 1603 | switch (ctrl->bRequestType & USB_RECIP_MASK) { |
|---|
| 1581 | 1604 | case USB_RECIP_DEVICE: |
|---|
| .. | .. |
|---|
| 1598 | 1621 | } |
|---|
| 1599 | 1622 | |
|---|
| 1600 | 1623 | if (!stall) { |
|---|
| 1601 | | - status = cpu_to_le16(status); |
|---|
| 1624 | + tx_data = cpu_to_le16(status); |
|---|
| 1602 | 1625 | dev_dbg(usb3_to_dev(usb3), "get_status: req = %p\n", |
|---|
| 1603 | 1626 | usb_req_to_usb3_req(usb3->ep0_req)); |
|---|
| 1604 | | - usb3_pipe0_internal_xfer(usb3, &status, sizeof(status), |
|---|
| 1627 | + usb3_pipe0_internal_xfer(usb3, &tx_data, sizeof(tx_data), |
|---|
| 1605 | 1628 | usb3_pipe0_get_status_completion); |
|---|
| 1606 | 1629 | } |
|---|
| 1607 | 1630 | |
|---|
| .. | .. |
|---|
| 1766 | 1789 | static bool usb3_std_req_set_configuration(struct renesas_usb3 *usb3, |
|---|
| 1767 | 1790 | struct usb_ctrlrequest *ctrl) |
|---|
| 1768 | 1791 | { |
|---|
| 1769 | | - if (ctrl->wValue > 0) |
|---|
| 1792 | + if (le16_to_cpu(ctrl->wValue) > 0) |
|---|
| 1770 | 1793 | usb3_set_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON); |
|---|
| 1771 | 1794 | else |
|---|
| 1772 | 1795 | usb3_clear_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON); |
|---|
| .. | .. |
|---|
| 2333 | 2356 | .set_selfpowered = renesas_usb3_set_selfpowered, |
|---|
| 2334 | 2357 | }; |
|---|
| 2335 | 2358 | |
|---|
| 2336 | | -static enum usb_role renesas_usb3_role_switch_get(struct device *dev) |
|---|
| 2359 | +static enum usb_role renesas_usb3_role_switch_get(struct usb_role_switch *sw) |
|---|
| 2337 | 2360 | { |
|---|
| 2338 | | - struct renesas_usb3 *usb3 = dev_get_drvdata(dev); |
|---|
| 2361 | + struct renesas_usb3 *usb3 = usb_role_switch_get_drvdata(sw); |
|---|
| 2339 | 2362 | enum usb_role cur_role; |
|---|
| 2340 | 2363 | |
|---|
| 2341 | | - pm_runtime_get_sync(dev); |
|---|
| 2364 | + pm_runtime_get_sync(usb3_to_dev(usb3)); |
|---|
| 2342 | 2365 | cur_role = usb3_is_host(usb3) ? USB_ROLE_HOST : USB_ROLE_DEVICE; |
|---|
| 2343 | | - pm_runtime_put(dev); |
|---|
| 2366 | + pm_runtime_put(usb3_to_dev(usb3)); |
|---|
| 2344 | 2367 | |
|---|
| 2345 | 2368 | return cur_role; |
|---|
| 2346 | 2369 | } |
|---|
| 2347 | 2370 | |
|---|
| 2348 | | -static int renesas_usb3_role_switch_set(struct device *dev, |
|---|
| 2349 | | - enum usb_role role) |
|---|
| 2371 | +static void handle_ext_role_switch_states(struct device *dev, |
|---|
| 2372 | + enum usb_role role) |
|---|
| 2350 | 2373 | { |
|---|
| 2351 | 2374 | struct renesas_usb3 *usb3 = dev_get_drvdata(dev); |
|---|
| 2352 | 2375 | struct device *host = usb3->host_dev; |
|---|
| 2353 | | - enum usb_role cur_role = renesas_usb3_role_switch_get(dev); |
|---|
| 2376 | + enum usb_role cur_role = renesas_usb3_role_switch_get(usb3->role_sw); |
|---|
| 2354 | 2377 | |
|---|
| 2355 | | - pm_runtime_get_sync(dev); |
|---|
| 2378 | + switch (role) { |
|---|
| 2379 | + case USB_ROLE_NONE: |
|---|
| 2380 | + usb3->connection_state = USB_ROLE_NONE; |
|---|
| 2381 | + if (cur_role == USB_ROLE_HOST) |
|---|
| 2382 | + device_release_driver(host); |
|---|
| 2383 | + if (usb3->driver) |
|---|
| 2384 | + usb3_disconnect(usb3); |
|---|
| 2385 | + usb3_vbus_out(usb3, false); |
|---|
| 2386 | + break; |
|---|
| 2387 | + case USB_ROLE_DEVICE: |
|---|
| 2388 | + if (usb3->connection_state == USB_ROLE_NONE) { |
|---|
| 2389 | + usb3->connection_state = USB_ROLE_DEVICE; |
|---|
| 2390 | + usb3_set_mode(usb3, false); |
|---|
| 2391 | + if (usb3->driver) |
|---|
| 2392 | + usb3_connect(usb3); |
|---|
| 2393 | + } else if (cur_role == USB_ROLE_HOST) { |
|---|
| 2394 | + device_release_driver(host); |
|---|
| 2395 | + usb3_set_mode(usb3, false); |
|---|
| 2396 | + if (usb3->driver) |
|---|
| 2397 | + usb3_connect(usb3); |
|---|
| 2398 | + } |
|---|
| 2399 | + usb3_vbus_out(usb3, false); |
|---|
| 2400 | + break; |
|---|
| 2401 | + case USB_ROLE_HOST: |
|---|
| 2402 | + if (usb3->connection_state == USB_ROLE_NONE) { |
|---|
| 2403 | + if (usb3->driver) |
|---|
| 2404 | + usb3_disconnect(usb3); |
|---|
| 2405 | + |
|---|
| 2406 | + usb3->connection_state = USB_ROLE_HOST; |
|---|
| 2407 | + usb3_set_mode(usb3, true); |
|---|
| 2408 | + usb3_vbus_out(usb3, true); |
|---|
| 2409 | + if (device_attach(host) < 0) |
|---|
| 2410 | + dev_err(dev, "device_attach(host) failed\n"); |
|---|
| 2411 | + } else if (cur_role == USB_ROLE_DEVICE) { |
|---|
| 2412 | + usb3_disconnect(usb3); |
|---|
| 2413 | + /* Must set the mode before device_attach of the host */ |
|---|
| 2414 | + usb3_set_mode(usb3, true); |
|---|
| 2415 | + /* This device_attach() might sleep */ |
|---|
| 2416 | + if (device_attach(host) < 0) |
|---|
| 2417 | + dev_err(dev, "device_attach(host) failed\n"); |
|---|
| 2418 | + } |
|---|
| 2419 | + break; |
|---|
| 2420 | + default: |
|---|
| 2421 | + break; |
|---|
| 2422 | + } |
|---|
| 2423 | +} |
|---|
| 2424 | + |
|---|
| 2425 | +static void handle_role_switch_states(struct device *dev, |
|---|
| 2426 | + enum usb_role role) |
|---|
| 2427 | +{ |
|---|
| 2428 | + struct renesas_usb3 *usb3 = dev_get_drvdata(dev); |
|---|
| 2429 | + struct device *host = usb3->host_dev; |
|---|
| 2430 | + enum usb_role cur_role = renesas_usb3_role_switch_get(usb3->role_sw); |
|---|
| 2431 | + |
|---|
| 2356 | 2432 | if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) { |
|---|
| 2357 | 2433 | device_release_driver(host); |
|---|
| 2358 | 2434 | usb3_set_mode(usb3, false); |
|---|
| .. | .. |
|---|
| 2363 | 2439 | if (device_attach(host) < 0) |
|---|
| 2364 | 2440 | dev_err(dev, "device_attach(host) failed\n"); |
|---|
| 2365 | 2441 | } |
|---|
| 2366 | | - pm_runtime_put(dev); |
|---|
| 2442 | +} |
|---|
| 2443 | + |
|---|
| 2444 | +static int renesas_usb3_role_switch_set(struct usb_role_switch *sw, |
|---|
| 2445 | + enum usb_role role) |
|---|
| 2446 | +{ |
|---|
| 2447 | + struct renesas_usb3 *usb3 = usb_role_switch_get_drvdata(sw); |
|---|
| 2448 | + |
|---|
| 2449 | + pm_runtime_get_sync(usb3_to_dev(usb3)); |
|---|
| 2450 | + |
|---|
| 2451 | + if (usb3->role_sw_by_connector) |
|---|
| 2452 | + handle_ext_role_switch_states(usb3_to_dev(usb3), role); |
|---|
| 2453 | + else |
|---|
| 2454 | + handle_role_switch_states(usb3_to_dev(usb3), role); |
|---|
| 2455 | + |
|---|
| 2456 | + pm_runtime_put(usb3_to_dev(usb3)); |
|---|
| 2367 | 2457 | |
|---|
| 2368 | 2458 | return 0; |
|---|
| 2369 | 2459 | } |
|---|
| .. | .. |
|---|
| 2464 | 2554 | static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3, |
|---|
| 2465 | 2555 | struct device *dev) |
|---|
| 2466 | 2556 | { |
|---|
| 2467 | | - usb3->dentry = debugfs_create_dir(dev_name(dev), NULL); |
|---|
| 2557 | + usb3->dentry = debugfs_create_dir(dev_name(dev), usb_debug_root); |
|---|
| 2468 | 2558 | |
|---|
| 2469 | 2559 | debugfs_create_file("b_device", 0644, usb3->dentry, usb3, |
|---|
| 2470 | 2560 | &renesas_usb3_b_device_fops); |
|---|
| .. | .. |
|---|
| 2610 | 2700 | .ramsize_per_pipe = SZ_4K, |
|---|
| 2611 | 2701 | }; |
|---|
| 2612 | 2702 | |
|---|
| 2703 | +static const struct renesas_usb3_priv renesas_usb3_priv_r8a77990 = { |
|---|
| 2704 | + .ramsize_per_ramif = SZ_16K, |
|---|
| 2705 | + .num_ramif = 4, |
|---|
| 2706 | + .ramsize_per_pipe = SZ_4K, |
|---|
| 2707 | + .workaround_for_vbus = true, |
|---|
| 2708 | +}; |
|---|
| 2709 | + |
|---|
| 2613 | 2710 | static const struct of_device_id usb3_of_match[] = { |
|---|
| 2614 | 2711 | { |
|---|
| 2712 | + .compatible = "renesas,r8a774c0-usb3-peri", |
|---|
| 2713 | + .data = &renesas_usb3_priv_r8a77990, |
|---|
| 2714 | + }, { |
|---|
| 2615 | 2715 | .compatible = "renesas,r8a7795-usb3-peri", |
|---|
| 2616 | 2716 | .data = &renesas_usb3_priv_gen3, |
|---|
| 2617 | | - }, |
|---|
| 2618 | | - { |
|---|
| 2717 | + }, { |
|---|
| 2718 | + .compatible = "renesas,r8a77990-usb3-peri", |
|---|
| 2719 | + .data = &renesas_usb3_priv_r8a77990, |
|---|
| 2720 | + }, { |
|---|
| 2619 | 2721 | .compatible = "renesas,rcar-gen3-usb3-peri", |
|---|
| 2620 | 2722 | .data = &renesas_usb3_priv_gen3, |
|---|
| 2621 | 2723 | }, |
|---|
| .. | .. |
|---|
| 2637 | 2739 | EXTCON_NONE, |
|---|
| 2638 | 2740 | }; |
|---|
| 2639 | 2741 | |
|---|
| 2640 | | -static const struct usb_role_switch_desc renesas_usb3_role_switch_desc = { |
|---|
| 2742 | +static struct usb_role_switch_desc renesas_usb3_role_switch_desc = { |
|---|
| 2641 | 2743 | .set = renesas_usb3_role_switch_set, |
|---|
| 2642 | 2744 | .get = renesas_usb3_role_switch_get, |
|---|
| 2643 | 2745 | .allow_userspace_control = true, |
|---|
| .. | .. |
|---|
| 2646 | 2748 | static int renesas_usb3_probe(struct platform_device *pdev) |
|---|
| 2647 | 2749 | { |
|---|
| 2648 | 2750 | struct renesas_usb3 *usb3; |
|---|
| 2649 | | - struct resource *res; |
|---|
| 2650 | 2751 | int irq, ret; |
|---|
| 2651 | 2752 | const struct renesas_usb3_priv *priv; |
|---|
| 2652 | 2753 | const struct soc_device_attribute *attr; |
|---|
| .. | .. |
|---|
| 2658 | 2759 | priv = of_device_get_match_data(&pdev->dev); |
|---|
| 2659 | 2760 | |
|---|
| 2660 | 2761 | irq = platform_get_irq(pdev, 0); |
|---|
| 2661 | | - if (irq < 0) { |
|---|
| 2662 | | - dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); |
|---|
| 2762 | + if (irq < 0) |
|---|
| 2663 | 2763 | return irq; |
|---|
| 2664 | | - } |
|---|
| 2665 | 2764 | |
|---|
| 2666 | 2765 | usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL); |
|---|
| 2667 | 2766 | if (!usb3) |
|---|
| 2668 | 2767 | return -ENOMEM; |
|---|
| 2669 | 2768 | |
|---|
| 2670 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 2671 | | - usb3->reg = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 2769 | + usb3->reg = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 2672 | 2770 | if (IS_ERR(usb3->reg)) |
|---|
| 2673 | 2771 | return PTR_ERR(usb3->reg); |
|---|
| 2674 | 2772 | |
|---|
| .. | .. |
|---|
| 2727 | 2825 | ret = device_create_file(&pdev->dev, &dev_attr_role); |
|---|
| 2728 | 2826 | if (ret < 0) |
|---|
| 2729 | 2827 | goto err_dev_create; |
|---|
| 2828 | + |
|---|
| 2829 | + if (device_property_read_bool(&pdev->dev, "usb-role-switch")) { |
|---|
| 2830 | + usb3->role_sw_by_connector = true; |
|---|
| 2831 | + renesas_usb3_role_switch_desc.fwnode = dev_fwnode(&pdev->dev); |
|---|
| 2832 | + } |
|---|
| 2833 | + |
|---|
| 2834 | + renesas_usb3_role_switch_desc.driver_data = usb3; |
|---|
| 2730 | 2835 | |
|---|
| 2731 | 2836 | INIT_WORK(&usb3->role_work, renesas_usb3_role_work); |
|---|
| 2732 | 2837 | usb3->role_sw = usb_role_switch_register(&pdev->dev, |
|---|
| .. | .. |
|---|
| 2803 | 2908 | .probe = renesas_usb3_probe, |
|---|
| 2804 | 2909 | .remove = renesas_usb3_remove, |
|---|
| 2805 | 2910 | .driver = { |
|---|
| 2806 | | - .name = (char *)udc_name, |
|---|
| 2911 | + .name = udc_name, |
|---|
| 2807 | 2912 | .pm = &renesas_usb3_pm_ops, |
|---|
| 2808 | 2913 | .of_match_table = of_match_ptr(usb3_of_match), |
|---|
| 2809 | 2914 | }, |
|---|