aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Hunter <jonathanh@nvidia.com>2018-10-16 07:22:43 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-10-18 13:44:39 -0400
commit6494a9ad86de921766afe91066f53a794f6c52ea (patch)
tree872d81841fcf4ea9baad12490bcab6d7eccd5793
parent8c14796b6b2485a31a50318d76d6bc4518dc9d39 (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.c89
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
937static 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
950static 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
931static int tegra_xusb_probe(struct platform_device *pdev) 988static 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:
1222disable_rpm: 1284disable_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);
1225disable_xusbc: 1287put_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);
1228disable_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 }
1231put_padctl: 1294put_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);