.. | .. |
---|
3 | 3 | * core.c - ChipIdea USB IP core family device controller |
---|
4 | 4 | * |
---|
5 | 5 | * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. |
---|
| 6 | + * Copyright (C) 2020 NXP |
---|
6 | 7 | * |
---|
7 | 8 | * Author: David Lopo |
---|
8 | | - */ |
---|
9 | | - |
---|
10 | | -/* |
---|
11 | | - * Description: ChipIdea USB IP core family device controller |
---|
| 9 | + * Peter Chen <peter.chen@nxp.com> |
---|
12 | 10 | * |
---|
13 | | - * This driver is composed of several blocks: |
---|
14 | | - * - HW: hardware interface |
---|
15 | | - * - DBG: debug facilities (optional) |
---|
16 | | - * - UTIL: utilities |
---|
17 | | - * - ISR: interrupts handling |
---|
18 | | - * - ENDPT: endpoint operations (Gadget API) |
---|
19 | | - * - GADGET: gadget operations (Gadget API) |
---|
20 | | - * - BUS: bus glue code, bus abstraction layer |
---|
21 | | - * |
---|
22 | | - * Compile Options |
---|
23 | | - * - STALL_IN: non-empty bulk-in pipes cannot be halted |
---|
24 | | - * if defined mass storage compliance succeeds but with warnings |
---|
25 | | - * => case 4: Hi > Dn |
---|
26 | | - * => case 5: Hi > Di |
---|
27 | | - * => case 8: Hi <> Do |
---|
28 | | - * if undefined usbtest 13 fails |
---|
29 | | - * - TRACE: enable function tracing (depends on DEBUG) |
---|
30 | | - * |
---|
31 | | - * Main Features |
---|
32 | | - * - Chapter 9 & Mass Storage Compliance with Gadget File Storage |
---|
33 | | - * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined) |
---|
34 | | - * - Normal & LPM support |
---|
35 | | - * |
---|
36 | | - * USBTEST Report |
---|
37 | | - * - OK: 0-12, 13 (STALL_IN defined) & 14 |
---|
38 | | - * - Not Supported: 15 & 16 (ISO) |
---|
39 | | - * |
---|
40 | | - * TODO List |
---|
41 | | - * - Suspend & Remote Wakeup |
---|
| 11 | + * Main Features: |
---|
| 12 | + * - Four transfers are supported, usbtest is passed |
---|
| 13 | + * - USB Certification for gadget: CH9 and Mass Storage are passed |
---|
| 14 | + * - Low power mode |
---|
| 15 | + * - USB wakeup |
---|
42 | 16 | */ |
---|
43 | 17 | #include <linux/delay.h> |
---|
44 | 18 | #include <linux/device.h> |
---|
.. | .. |
---|
53 | 27 | #include <linux/kernel.h> |
---|
54 | 28 | #include <linux/slab.h> |
---|
55 | 29 | #include <linux/pm_runtime.h> |
---|
| 30 | +#include <linux/pinctrl/consumer.h> |
---|
56 | 31 | #include <linux/usb/ch9.h> |
---|
57 | 32 | #include <linux/usb/gadget.h> |
---|
58 | 33 | #include <linux/usb/otg.h> |
---|
.. | .. |
---|
180 | 155 | |
---|
181 | 156 | /** |
---|
182 | 157 | * hw_port_test_set: writes port test mode (execute without interruption) |
---|
| 158 | + * @ci: the controller |
---|
183 | 159 | * @mode: new value |
---|
184 | 160 | * |
---|
185 | 161 | * This function returns an error code |
---|
.. | .. |
---|
271 | 247 | ci->rev = ci_get_revision(ci); |
---|
272 | 248 | |
---|
273 | 249 | dev_dbg(ci->dev, |
---|
274 | | - "ChipIdea HDRC found, revision: %d, lpm: %d; cap: %p op: %p\n", |
---|
| 250 | + "revision: %d, lpm: %d; cap: %px op: %px\n", |
---|
275 | 251 | ci->rev, ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op); |
---|
276 | 252 | |
---|
277 | 253 | /* setup lock mode ? */ |
---|
.. | .. |
---|
522 | 498 | hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); |
---|
523 | 499 | |
---|
524 | 500 | if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) { |
---|
525 | | - pr_err("cannot enter in %s device mode", ci_role(ci)->name); |
---|
526 | | - pr_err("lpm = %i", ci->hw_bank.lpm); |
---|
| 501 | + dev_err(ci->dev, "cannot enter in %s device mode\n", |
---|
| 502 | + ci_role(ci)->name); |
---|
| 503 | + dev_err(ci->dev, "lpm = %i\n", ci->hw_bank.lpm); |
---|
527 | 504 | return -ENODEV; |
---|
528 | 505 | } |
---|
529 | 506 | |
---|
.. | .. |
---|
607 | 584 | return NOTIFY_DONE; |
---|
608 | 585 | } |
---|
609 | 586 | |
---|
| 587 | +static enum usb_role ci_usb_role_switch_get(struct usb_role_switch *sw) |
---|
| 588 | +{ |
---|
| 589 | + struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw); |
---|
| 590 | + enum usb_role role; |
---|
| 591 | + unsigned long flags; |
---|
| 592 | + |
---|
| 593 | + spin_lock_irqsave(&ci->lock, flags); |
---|
| 594 | + role = ci_role_to_usb_role(ci); |
---|
| 595 | + spin_unlock_irqrestore(&ci->lock, flags); |
---|
| 596 | + |
---|
| 597 | + return role; |
---|
| 598 | +} |
---|
| 599 | + |
---|
| 600 | +static int ci_usb_role_switch_set(struct usb_role_switch *sw, |
---|
| 601 | + enum usb_role role) |
---|
| 602 | +{ |
---|
| 603 | + struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw); |
---|
| 604 | + struct ci_hdrc_cable *cable = NULL; |
---|
| 605 | + enum usb_role current_role = ci_role_to_usb_role(ci); |
---|
| 606 | + enum ci_role ci_role = usb_role_to_ci_role(role); |
---|
| 607 | + unsigned long flags; |
---|
| 608 | + |
---|
| 609 | + if ((ci_role != CI_ROLE_END && !ci->roles[ci_role]) || |
---|
| 610 | + (current_role == role)) |
---|
| 611 | + return 0; |
---|
| 612 | + |
---|
| 613 | + pm_runtime_get_sync(ci->dev); |
---|
| 614 | + /* Stop current role */ |
---|
| 615 | + spin_lock_irqsave(&ci->lock, flags); |
---|
| 616 | + if (current_role == USB_ROLE_DEVICE) |
---|
| 617 | + cable = &ci->platdata->vbus_extcon; |
---|
| 618 | + else if (current_role == USB_ROLE_HOST) |
---|
| 619 | + cable = &ci->platdata->id_extcon; |
---|
| 620 | + |
---|
| 621 | + if (cable) { |
---|
| 622 | + cable->changed = true; |
---|
| 623 | + cable->connected = false; |
---|
| 624 | + ci_irq(ci); |
---|
| 625 | + spin_unlock_irqrestore(&ci->lock, flags); |
---|
| 626 | + if (ci->wq && role != USB_ROLE_NONE) |
---|
| 627 | + flush_workqueue(ci->wq); |
---|
| 628 | + spin_lock_irqsave(&ci->lock, flags); |
---|
| 629 | + } |
---|
| 630 | + |
---|
| 631 | + cable = NULL; |
---|
| 632 | + |
---|
| 633 | + /* Start target role */ |
---|
| 634 | + if (role == USB_ROLE_DEVICE) |
---|
| 635 | + cable = &ci->platdata->vbus_extcon; |
---|
| 636 | + else if (role == USB_ROLE_HOST) |
---|
| 637 | + cable = &ci->platdata->id_extcon; |
---|
| 638 | + |
---|
| 639 | + if (cable) { |
---|
| 640 | + cable->changed = true; |
---|
| 641 | + cable->connected = true; |
---|
| 642 | + ci_irq(ci); |
---|
| 643 | + } |
---|
| 644 | + spin_unlock_irqrestore(&ci->lock, flags); |
---|
| 645 | + pm_runtime_put_sync(ci->dev); |
---|
| 646 | + |
---|
| 647 | + return 0; |
---|
| 648 | +} |
---|
| 649 | + |
---|
| 650 | +static struct usb_role_switch_desc ci_role_switch = { |
---|
| 651 | + .set = ci_usb_role_switch_set, |
---|
| 652 | + .get = ci_usb_role_switch_get, |
---|
| 653 | + .allow_userspace_control = true, |
---|
| 654 | +}; |
---|
| 655 | + |
---|
610 | 656 | static int ci_get_platdata(struct device *dev, |
---|
611 | 657 | struct ci_hdrc_platform_data *platdata) |
---|
612 | 658 | { |
---|
.. | .. |
---|
625 | 671 | |
---|
626 | 672 | if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) { |
---|
627 | 673 | /* Get the vbus regulator */ |
---|
628 | | - platdata->reg_vbus = devm_regulator_get(dev, "vbus"); |
---|
| 674 | + platdata->reg_vbus = devm_regulator_get_optional(dev, "vbus"); |
---|
629 | 675 | if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { |
---|
630 | 676 | return -EPROBE_DEFER; |
---|
631 | 677 | } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { |
---|
.. | .. |
---|
732 | 778 | else |
---|
733 | 779 | cable->connected = false; |
---|
734 | 780 | } |
---|
| 781 | + |
---|
| 782 | + if (device_property_read_bool(dev, "usb-role-switch")) |
---|
| 783 | + ci_role_switch.fwnode = dev->fwnode; |
---|
| 784 | + |
---|
| 785 | + platdata->pctl = devm_pinctrl_get(dev); |
---|
| 786 | + if (!IS_ERR(platdata->pctl)) { |
---|
| 787 | + struct pinctrl_state *p; |
---|
| 788 | + |
---|
| 789 | + p = pinctrl_lookup_state(platdata->pctl, "default"); |
---|
| 790 | + if (!IS_ERR(p)) |
---|
| 791 | + platdata->pins_default = p; |
---|
| 792 | + |
---|
| 793 | + p = pinctrl_lookup_state(platdata->pctl, "host"); |
---|
| 794 | + if (!IS_ERR(p)) |
---|
| 795 | + platdata->pins_host = p; |
---|
| 796 | + |
---|
| 797 | + p = pinctrl_lookup_state(platdata->pctl, "device"); |
---|
| 798 | + if (!IS_ERR(p)) |
---|
| 799 | + platdata->pins_device = p; |
---|
| 800 | + } |
---|
| 801 | + |
---|
735 | 802 | return 0; |
---|
736 | 803 | } |
---|
737 | 804 | |
---|
.. | .. |
---|
820 | 887 | } |
---|
821 | 888 | EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); |
---|
822 | 889 | |
---|
| 890 | +/** |
---|
| 891 | + * ci_hdrc_query_available_role: get runtime available operation mode |
---|
| 892 | + * |
---|
| 893 | + * The glue layer can get current operation mode (host/peripheral/otg) |
---|
| 894 | + * This function should be called after ci core device has created. |
---|
| 895 | + * |
---|
| 896 | + * @pdev: the platform device of ci core. |
---|
| 897 | + * |
---|
| 898 | + * Return runtime usb_dr_mode. |
---|
| 899 | + */ |
---|
| 900 | +enum usb_dr_mode ci_hdrc_query_available_role(struct platform_device *pdev) |
---|
| 901 | +{ |
---|
| 902 | + struct ci_hdrc *ci = platform_get_drvdata(pdev); |
---|
| 903 | + |
---|
| 904 | + if (!ci) |
---|
| 905 | + return USB_DR_MODE_UNKNOWN; |
---|
| 906 | + if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) |
---|
| 907 | + return USB_DR_MODE_OTG; |
---|
| 908 | + else if (ci->roles[CI_ROLE_HOST]) |
---|
| 909 | + return USB_DR_MODE_HOST; |
---|
| 910 | + else if (ci->roles[CI_ROLE_GADGET]) |
---|
| 911 | + return USB_DR_MODE_PERIPHERAL; |
---|
| 912 | + else |
---|
| 913 | + return USB_DR_MODE_UNKNOWN; |
---|
| 914 | +} |
---|
| 915 | +EXPORT_SYMBOL_GPL(ci_hdrc_query_available_role); |
---|
| 916 | + |
---|
823 | 917 | static inline void ci_role_destroy(struct ci_hdrc *ci) |
---|
824 | 918 | { |
---|
825 | 919 | ci_hdrc_gadget_destroy(ci); |
---|
.. | .. |
---|
872 | 966 | strlen(ci->roles[role]->name))) |
---|
873 | 967 | break; |
---|
874 | 968 | |
---|
875 | | - if (role == CI_ROLE_END || role == ci->role) |
---|
| 969 | + if (role == CI_ROLE_END) |
---|
876 | 970 | return -EINVAL; |
---|
| 971 | + |
---|
| 972 | + mutex_lock(&ci->mutex); |
---|
| 973 | + |
---|
| 974 | + if (role == ci->role) { |
---|
| 975 | + mutex_unlock(&ci->mutex); |
---|
| 976 | + return n; |
---|
| 977 | + } |
---|
877 | 978 | |
---|
878 | 979 | pm_runtime_get_sync(dev); |
---|
879 | 980 | disable_irq(ci->irq); |
---|
.. | .. |
---|
883 | 984 | ci_handle_vbus_change(ci); |
---|
884 | 985 | enable_irq(ci->irq); |
---|
885 | 986 | pm_runtime_put_sync(dev); |
---|
| 987 | + mutex_unlock(&ci->mutex); |
---|
886 | 988 | |
---|
887 | 989 | return (ret == 0) ? n : ret; |
---|
888 | 990 | } |
---|
.. | .. |
---|
892 | 994 | &dev_attr_role.attr, |
---|
893 | 995 | NULL, |
---|
894 | 996 | }; |
---|
895 | | - |
---|
896 | | -static const struct attribute_group ci_attr_group = { |
---|
897 | | - .attrs = ci_attrs, |
---|
898 | | -}; |
---|
| 997 | +ATTRIBUTE_GROUPS(ci); |
---|
899 | 998 | |
---|
900 | 999 | static int ci_hdrc_probe(struct platform_device *pdev) |
---|
901 | 1000 | { |
---|
.. | .. |
---|
921 | 1020 | return -ENOMEM; |
---|
922 | 1021 | |
---|
923 | 1022 | spin_lock_init(&ci->lock); |
---|
| 1023 | + mutex_init(&ci->mutex); |
---|
924 | 1024 | ci->dev = dev; |
---|
925 | 1025 | ci->platdata = dev_get_platdata(dev); |
---|
926 | 1026 | ci->imx28_write_fix = !!(ci->platdata->flags & |
---|
.. | .. |
---|
944 | 1044 | } else if (ci->platdata->usb_phy) { |
---|
945 | 1045 | ci->usb_phy = ci->platdata->usb_phy; |
---|
946 | 1046 | } else { |
---|
947 | | - ci->usb_phy = devm_usb_get_phy_by_phandle(dev->parent, "phys", |
---|
948 | | - 0); |
---|
| 1047 | + /* Look for a generic PHY first */ |
---|
949 | 1048 | ci->phy = devm_phy_get(dev->parent, "usb-phy"); |
---|
950 | 1049 | |
---|
951 | | - /* Fallback to grabbing any registered USB2 PHY */ |
---|
952 | | - if (IS_ERR(ci->usb_phy) && |
---|
953 | | - PTR_ERR(ci->usb_phy) != -EPROBE_DEFER) |
---|
| 1050 | + if (PTR_ERR(ci->phy) == -EPROBE_DEFER) { |
---|
| 1051 | + ret = -EPROBE_DEFER; |
---|
| 1052 | + goto ulpi_exit; |
---|
| 1053 | + } else if (IS_ERR(ci->phy)) { |
---|
| 1054 | + ci->phy = NULL; |
---|
| 1055 | + } |
---|
| 1056 | + |
---|
| 1057 | + /* Look for a legacy USB PHY from device-tree next */ |
---|
| 1058 | + if (!ci->phy) { |
---|
| 1059 | + ci->usb_phy = devm_usb_get_phy_by_phandle(dev->parent, |
---|
| 1060 | + "phys", 0); |
---|
| 1061 | + |
---|
| 1062 | + if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) { |
---|
| 1063 | + ret = -EPROBE_DEFER; |
---|
| 1064 | + goto ulpi_exit; |
---|
| 1065 | + } else if (IS_ERR(ci->usb_phy)) { |
---|
| 1066 | + ci->usb_phy = NULL; |
---|
| 1067 | + } |
---|
| 1068 | + } |
---|
| 1069 | + |
---|
| 1070 | + /* Look for any registered legacy USB PHY as last resort */ |
---|
| 1071 | + if (!ci->phy && !ci->usb_phy) { |
---|
954 | 1072 | ci->usb_phy = devm_usb_get_phy(dev->parent, |
---|
955 | 1073 | USB_PHY_TYPE_USB2); |
---|
956 | 1074 | |
---|
957 | | - /* if both generic PHY and USB PHY layers aren't enabled */ |
---|
958 | | - if (PTR_ERR(ci->phy) == -ENOSYS && |
---|
959 | | - PTR_ERR(ci->usb_phy) == -ENXIO) { |
---|
| 1075 | + if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) { |
---|
| 1076 | + ret = -EPROBE_DEFER; |
---|
| 1077 | + goto ulpi_exit; |
---|
| 1078 | + } else if (IS_ERR(ci->usb_phy)) { |
---|
| 1079 | + ci->usb_phy = NULL; |
---|
| 1080 | + } |
---|
| 1081 | + } |
---|
| 1082 | + |
---|
| 1083 | + /* No USB PHY was found in the end */ |
---|
| 1084 | + if (!ci->phy && !ci->usb_phy) { |
---|
960 | 1085 | ret = -ENXIO; |
---|
961 | 1086 | goto ulpi_exit; |
---|
962 | 1087 | } |
---|
963 | | - |
---|
964 | | - if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) { |
---|
965 | | - ret = -EPROBE_DEFER; |
---|
966 | | - goto ulpi_exit; |
---|
967 | | - } |
---|
968 | | - |
---|
969 | | - if (IS_ERR(ci->phy)) |
---|
970 | | - ci->phy = NULL; |
---|
971 | | - else if (IS_ERR(ci->usb_phy)) |
---|
972 | | - ci->usb_phy = NULL; |
---|
973 | 1088 | } |
---|
974 | 1089 | |
---|
975 | 1090 | ret = ci_usb_phy_init(ci); |
---|
976 | 1091 | if (ret) { |
---|
977 | 1092 | dev_err(dev, "unable to init phy: %d\n", ret); |
---|
978 | | - return ret; |
---|
| 1093 | + goto ulpi_exit; |
---|
979 | 1094 | } |
---|
980 | 1095 | |
---|
981 | 1096 | ci->hw_bank.phys = res->start; |
---|
982 | 1097 | |
---|
983 | 1098 | ci->irq = platform_get_irq(pdev, 0); |
---|
984 | 1099 | if (ci->irq < 0) { |
---|
985 | | - dev_err(dev, "missing IRQ\n"); |
---|
986 | 1100 | ret = ci->irq; |
---|
987 | 1101 | goto deinit_phy; |
---|
988 | 1102 | } |
---|
.. | .. |
---|
1025 | 1139 | } |
---|
1026 | 1140 | } |
---|
1027 | 1141 | |
---|
| 1142 | + if (ci_role_switch.fwnode) { |
---|
| 1143 | + ci_role_switch.driver_data = ci; |
---|
| 1144 | + ci->role_switch = usb_role_switch_register(dev, |
---|
| 1145 | + &ci_role_switch); |
---|
| 1146 | + if (IS_ERR(ci->role_switch)) { |
---|
| 1147 | + ret = PTR_ERR(ci->role_switch); |
---|
| 1148 | + goto deinit_otg; |
---|
| 1149 | + } |
---|
| 1150 | + } |
---|
| 1151 | + |
---|
1028 | 1152 | if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { |
---|
1029 | 1153 | if (ci->is_otg) { |
---|
1030 | 1154 | ci->role = ci_otg_role(ci); |
---|
.. | .. |
---|
1046 | 1170 | |
---|
1047 | 1171 | if (!ci_otg_is_fsm_mode(ci)) { |
---|
1048 | 1172 | /* only update vbus status for peripheral */ |
---|
1049 | | - if (ci->role == CI_ROLE_GADGET) |
---|
| 1173 | + if (ci->role == CI_ROLE_GADGET) { |
---|
| 1174 | + /* Pull down DP for possible charger detection */ |
---|
| 1175 | + hw_write(ci, OP_USBCMD, USBCMD_RS, 0); |
---|
1050 | 1176 | ci_handle_vbus_change(ci); |
---|
| 1177 | + } |
---|
1051 | 1178 | |
---|
1052 | 1179 | ret = ci_role_start(ci, ci->role); |
---|
1053 | 1180 | if (ret) { |
---|
.. | .. |
---|
1080 | 1207 | device_set_wakeup_capable(&pdev->dev, true); |
---|
1081 | 1208 | dbg_create_files(ci); |
---|
1082 | 1209 | |
---|
1083 | | - ret = sysfs_create_group(&dev->kobj, &ci_attr_group); |
---|
1084 | | - if (ret) |
---|
1085 | | - goto remove_debug; |
---|
1086 | | - |
---|
1087 | 1210 | return 0; |
---|
1088 | 1211 | |
---|
1089 | | -remove_debug: |
---|
1090 | | - dbg_remove_files(ci); |
---|
1091 | 1212 | stop: |
---|
| 1213 | + if (ci->role_switch) |
---|
| 1214 | + usb_role_switch_unregister(ci->role_switch); |
---|
| 1215 | +deinit_otg: |
---|
1092 | 1216 | if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) |
---|
1093 | 1217 | ci_hdrc_otg_destroy(ci); |
---|
1094 | 1218 | deinit_gadget: |
---|
.. | .. |
---|
1107 | 1231 | { |
---|
1108 | 1232 | struct ci_hdrc *ci = platform_get_drvdata(pdev); |
---|
1109 | 1233 | |
---|
| 1234 | + if (ci->role_switch) |
---|
| 1235 | + usb_role_switch_unregister(ci->role_switch); |
---|
| 1236 | + |
---|
1110 | 1237 | if (ci->supports_runtime_pm) { |
---|
1111 | 1238 | pm_runtime_get_sync(&pdev->dev); |
---|
1112 | 1239 | pm_runtime_disable(&pdev->dev); |
---|
.. | .. |
---|
1114 | 1241 | } |
---|
1115 | 1242 | |
---|
1116 | 1243 | dbg_remove_files(ci); |
---|
1117 | | - sysfs_remove_group(&ci->dev->kobj, &ci_attr_group); |
---|
1118 | 1244 | ci_role_destroy(ci); |
---|
1119 | 1245 | ci_hdrc_enter_lpm(ci, true); |
---|
1120 | 1246 | ci_usb_phy_exit(ci); |
---|
.. | .. |
---|
1317 | 1443 | .driver = { |
---|
1318 | 1444 | .name = "ci_hdrc", |
---|
1319 | 1445 | .pm = &ci_pm_ops, |
---|
| 1446 | + .dev_groups = ci_groups, |
---|
1320 | 1447 | }, |
---|
1321 | 1448 | }; |
---|
1322 | 1449 | |
---|