diff options
author | Jon Hunter <jonathanh@nvidia.com> | 2018-10-16 07:22:43 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-10-18 13:44:39 -0400 |
commit | 6494a9ad86de921766afe91066f53a794f6c52ea (patch) | |
tree | 872d81841fcf4ea9baad12490bcab6d7eccd5793 | |
parent | 8c14796b6b2485a31a50318d76d6bc4518dc9d39 (diff) |
usb: xhci: tegra: Add genpd support
The generic power-domain framework has been updated to allow devices
that require more than one power-domain to create a new device for
each power-domain required and then link these new power-domain
devices to the consumer device.
Update the Tegra xHCI driver to use the new APIs provided by the
generic power-domain framework so we can use the generic power-domain
framework for managing the xHCI controllers power-domains. Please
note that to maintain backward compatibility with older device-tree
blobs these new generic power-domain APIs are only used if the
'power-domains' property is present and otherwise we fall back to
using the legacy Tegra APIs for managing the power-domains.
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/host/xhci-tegra.c | 89 |
1 files changed, 77 insertions, 12 deletions
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 920a50a54095..6b5db344de30 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/phy/tegra/xusb.h> | 18 | #include <linux/phy/tegra/xusb.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/pm.h> | 20 | #include <linux/pm.h> |
21 | #include <linux/pm_domain.h> | ||
21 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
22 | #include <linux/regulator/consumer.h> | 23 | #include <linux/regulator/consumer.h> |
23 | #include <linux/reset.h> | 24 | #include <linux/reset.h> |
@@ -194,6 +195,11 @@ struct tegra_xusb { | |||
194 | struct reset_control *host_rst; | 195 | struct reset_control *host_rst; |
195 | struct reset_control *ss_rst; | 196 | struct reset_control *ss_rst; |
196 | 197 | ||
198 | struct device *genpd_dev_host; | ||
199 | struct device *genpd_dev_ss; | ||
200 | struct device_link *genpd_dl_host; | ||
201 | struct device_link *genpd_dl_ss; | ||
202 | |||
197 | struct phy **phys; | 203 | struct phy **phys; |
198 | unsigned int num_phys; | 204 | unsigned int num_phys; |
199 | 205 | ||
@@ -928,6 +934,57 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) | |||
928 | return 0; | 934 | return 0; |
929 | } | 935 | } |
930 | 936 | ||
937 | static void tegra_xusb_powerdomain_remove(struct device *dev, | ||
938 | struct tegra_xusb *tegra) | ||
939 | { | ||
940 | if (tegra->genpd_dl_ss) | ||
941 | device_link_del(tegra->genpd_dl_ss); | ||
942 | if (tegra->genpd_dl_host) | ||
943 | device_link_del(tegra->genpd_dl_host); | ||
944 | if (tegra->genpd_dev_ss) | ||
945 | dev_pm_domain_detach(tegra->genpd_dev_ss, true); | ||
946 | if (tegra->genpd_dev_host) | ||
947 | dev_pm_domain_detach(tegra->genpd_dev_host, true); | ||
948 | } | ||
949 | |||
950 | static int tegra_xusb_powerdomain_init(struct device *dev, | ||
951 | struct tegra_xusb *tegra) | ||
952 | { | ||
953 | int err; | ||
954 | |||
955 | tegra->genpd_dev_host = dev_pm_domain_attach_by_name(dev, "xusb_host"); | ||
956 | if (IS_ERR(tegra->genpd_dev_host)) { | ||
957 | err = PTR_ERR(tegra->genpd_dev_host); | ||
958 | dev_err(dev, "failed to get host pm-domain: %d\n", err); | ||
959 | return err; | ||
960 | } | ||
961 | |||
962 | tegra->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "xusb_ss"); | ||
963 | if (IS_ERR(tegra->genpd_dev_ss)) { | ||
964 | err = PTR_ERR(tegra->genpd_dev_ss); | ||
965 | dev_err(dev, "failed to get superspeed pm-domain: %d\n", err); | ||
966 | return err; | ||
967 | } | ||
968 | |||
969 | tegra->genpd_dl_host = device_link_add(dev, tegra->genpd_dev_host, | ||
970 | DL_FLAG_PM_RUNTIME | | ||
971 | DL_FLAG_STATELESS); | ||
972 | if (!tegra->genpd_dl_host) { | ||
973 | dev_err(dev, "adding host device link failed!\n"); | ||
974 | return -ENODEV; | ||
975 | } | ||
976 | |||
977 | tegra->genpd_dl_ss = device_link_add(dev, tegra->genpd_dev_ss, | ||
978 | DL_FLAG_PM_RUNTIME | | ||
979 | DL_FLAG_STATELESS); | ||
980 | if (!tegra->genpd_dl_ss) { | ||
981 | dev_err(dev, "adding superspeed device link failed!\n"); | ||
982 | return -ENODEV; | ||
983 | } | ||
984 | |||
985 | return 0; | ||
986 | } | ||
987 | |||
931 | static int tegra_xusb_probe(struct platform_device *pdev) | 988 | static int tegra_xusb_probe(struct platform_device *pdev) |
932 | { | 989 | { |
933 | struct tegra_xusb_mbox_msg msg; | 990 | struct tegra_xusb_mbox_msg msg; |
@@ -1038,7 +1095,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1038 | goto put_padctl; | 1095 | goto put_padctl; |
1039 | } | 1096 | } |
1040 | 1097 | ||
1041 | if (!pdev->dev.pm_domain) { | 1098 | if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { |
1042 | tegra->host_rst = devm_reset_control_get(&pdev->dev, | 1099 | tegra->host_rst = devm_reset_control_get(&pdev->dev, |
1043 | "xusb_host"); | 1100 | "xusb_host"); |
1044 | if (IS_ERR(tegra->host_rst)) { | 1101 | if (IS_ERR(tegra->host_rst)) { |
@@ -1069,17 +1126,22 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1069 | tegra->host_clk, | 1126 | tegra->host_clk, |
1070 | tegra->host_rst); | 1127 | tegra->host_rst); |
1071 | if (err) { | 1128 | if (err) { |
1129 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); | ||
1072 | dev_err(&pdev->dev, | 1130 | dev_err(&pdev->dev, |
1073 | "failed to enable XUSBC domain: %d\n", err); | 1131 | "failed to enable XUSBC domain: %d\n", err); |
1074 | goto disable_xusba; | 1132 | goto put_padctl; |
1075 | } | 1133 | } |
1134 | } else { | ||
1135 | err = tegra_xusb_powerdomain_init(&pdev->dev, tegra); | ||
1136 | if (err) | ||
1137 | goto put_powerdomains; | ||
1076 | } | 1138 | } |
1077 | 1139 | ||
1078 | tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies, | 1140 | tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies, |
1079 | sizeof(*tegra->supplies), GFP_KERNEL); | 1141 | sizeof(*tegra->supplies), GFP_KERNEL); |
1080 | if (!tegra->supplies) { | 1142 | if (!tegra->supplies) { |
1081 | err = -ENOMEM; | 1143 | err = -ENOMEM; |
1082 | goto disable_xusbc; | 1144 | goto put_powerdomains; |
1083 | } | 1145 | } |
1084 | 1146 | ||
1085 | for (i = 0; i < tegra->soc->num_supplies; i++) | 1147 | for (i = 0; i < tegra->soc->num_supplies; i++) |
@@ -1089,7 +1151,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1089 | tegra->supplies); | 1151 | tegra->supplies); |
1090 | if (err) { | 1152 | if (err) { |
1091 | dev_err(&pdev->dev, "failed to get regulators: %d\n", err); | 1153 | dev_err(&pdev->dev, "failed to get regulators: %d\n", err); |
1092 | goto disable_xusbc; | 1154 | goto put_powerdomains; |
1093 | } | 1155 | } |
1094 | 1156 | ||
1095 | for (i = 0; i < tegra->soc->num_types; i++) | 1157 | for (i = 0; i < tegra->soc->num_types; i++) |
@@ -1099,7 +1161,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1099 | sizeof(*tegra->phys), GFP_KERNEL); | 1161 | sizeof(*tegra->phys), GFP_KERNEL); |
1100 | if (!tegra->phys) { | 1162 | if (!tegra->phys) { |
1101 | err = -ENOMEM; | 1163 | err = -ENOMEM; |
1102 | goto disable_xusbc; | 1164 | goto put_powerdomains; |
1103 | } | 1165 | } |
1104 | 1166 | ||
1105 | for (i = 0, k = 0; i < tegra->soc->num_types; i++) { | 1167 | for (i = 0, k = 0; i < tegra->soc->num_types; i++) { |
@@ -1115,7 +1177,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1115 | "failed to get PHY %s: %ld\n", prop, | 1177 | "failed to get PHY %s: %ld\n", prop, |
1116 | PTR_ERR(phy)); | 1178 | PTR_ERR(phy)); |
1117 | err = PTR_ERR(phy); | 1179 | err = PTR_ERR(phy); |
1118 | goto disable_xusbc; | 1180 | goto put_powerdomains; |
1119 | } | 1181 | } |
1120 | 1182 | ||
1121 | tegra->phys[k++] = phy; | 1183 | tegra->phys[k++] = phy; |
@@ -1126,7 +1188,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
1126 | dev_name(&pdev->dev)); | 1188 | dev_name(&pdev->dev)); |
1127 | if (!tegra->hcd) { | 1189 | if (!tegra->hcd) { |
1128 | err = -ENOMEM; | 1190 | err = -ENOMEM; |
1129 | goto disable_xusbc; | 1191 | goto put_powerdomains; |
1130 | } | 1192 | } |
1131 | 1193 | ||
1132 | /* | 1194 | /* |
@@ -1222,12 +1284,13 @@ put_rpm: | |||
1222 | disable_rpm: | 1284 | disable_rpm: |
1223 | pm_runtime_disable(&pdev->dev); | 1285 | pm_runtime_disable(&pdev->dev); |
1224 | usb_put_hcd(tegra->hcd); | 1286 | usb_put_hcd(tegra->hcd); |
1225 | disable_xusbc: | 1287 | put_powerdomains: |
1226 | if (!pdev->dev.pm_domain) | 1288 | if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { |
1227 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); | 1289 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); |
1228 | disable_xusba: | ||
1229 | if (!pdev->dev.pm_domain) | ||
1230 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); | 1290 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); |
1291 | } else { | ||
1292 | tegra_xusb_powerdomain_remove(&pdev->dev, tegra); | ||
1293 | } | ||
1231 | put_padctl: | 1294 | put_padctl: |
1232 | tegra_xusb_padctl_put(tegra->padctl); | 1295 | tegra_xusb_padctl_put(tegra->padctl); |
1233 | return err; | 1296 | return err; |
@@ -1249,9 +1312,11 @@ static int tegra_xusb_remove(struct platform_device *pdev) | |||
1249 | pm_runtime_put_sync(&pdev->dev); | 1312 | pm_runtime_put_sync(&pdev->dev); |
1250 | pm_runtime_disable(&pdev->dev); | 1313 | pm_runtime_disable(&pdev->dev); |
1251 | 1314 | ||
1252 | if (!pdev->dev.pm_domain) { | 1315 | if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) { |
1253 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); | 1316 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); |
1254 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); | 1317 | tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); |
1318 | } else { | ||
1319 | tegra_xusb_powerdomain_remove(&pdev->dev, tegra); | ||
1255 | } | 1320 | } |
1256 | 1321 | ||
1257 | tegra_xusb_padctl_put(tegra->padctl); | 1322 | tegra_xusb_padctl_put(tegra->padctl); |