gpcv2.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*
  2. * Copyright 2017 Impinj, Inc
  3. * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
  4. *
  5. * Based on the code of analogus driver:
  6. *
  7. * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
  8. *
  9. * The code contained herein is licensed under the GNU General Public
  10. * License. You may obtain a copy of the GNU General Public License
  11. * Version 2 or later at the following locations:
  12. *
  13. * http://www.opensource.org/licenses/gpl-license.html
  14. * http://www.gnu.org/copyleft/gpl.html
  15. */
  16. #include <linux/platform_device.h>
  17. #include <linux/pm_domain.h>
  18. #include <linux/regmap.h>
  19. #include <linux/regulator/consumer.h>
  20. #include <dt-bindings/power/imx7-power.h>
  21. #define GPC_LPCR_A7_BSC 0x000
  22. #define GPC_PGC_CPU_MAPPING 0x0ec
  23. #define USB_HSIC_PHY_A7_DOMAIN BIT(6)
  24. #define USB_OTG2_PHY_A7_DOMAIN BIT(5)
  25. #define USB_OTG1_PHY_A7_DOMAIN BIT(4)
  26. #define PCIE_PHY_A7_DOMAIN BIT(3)
  27. #define MIPI_PHY_A7_DOMAIN BIT(2)
  28. #define GPC_PU_PGC_SW_PUP_REQ 0x0f8
  29. #define GPC_PU_PGC_SW_PDN_REQ 0x104
  30. #define USB_HSIC_PHY_SW_Pxx_REQ BIT(4)
  31. #define USB_OTG2_PHY_SW_Pxx_REQ BIT(3)
  32. #define USB_OTG1_PHY_SW_Pxx_REQ BIT(2)
  33. #define PCIE_PHY_SW_Pxx_REQ BIT(1)
  34. #define MIPI_PHY_SW_Pxx_REQ BIT(0)
  35. #define GPC_M4_PU_PDN_FLG 0x1bc
  36. #define PGC_MIPI 4
  37. #define PGC_PCIE 5
  38. #define PGC_USB_HSIC 8
  39. #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40)
  40. #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc)
  41. #define GPC_PGC_CTRL_PCR BIT(0)
  42. struct imx7_pgc_domain {
  43. struct generic_pm_domain genpd;
  44. struct regmap *regmap;
  45. struct regulator *regulator;
  46. unsigned int pgc;
  47. const struct {
  48. u32 pxx;
  49. u32 map;
  50. } bits;
  51. const int voltage;
  52. struct device *dev;
  53. };
  54. static int imx7_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
  55. bool on)
  56. {
  57. struct imx7_pgc_domain *domain = container_of(genpd,
  58. struct imx7_pgc_domain,
  59. genpd);
  60. unsigned int offset = on ?
  61. GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
  62. const bool enable_power_control = !on;
  63. const bool has_regulator = !IS_ERR(domain->regulator);
  64. unsigned long deadline;
  65. int ret = 0;
  66. regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
  67. domain->bits.map, domain->bits.map);
  68. if (has_regulator && on) {
  69. ret = regulator_enable(domain->regulator);
  70. if (ret) {
  71. dev_err(domain->dev, "failed to enable regulator\n");
  72. goto unmap;
  73. }
  74. }
  75. if (enable_power_control)
  76. regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
  77. GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR);
  78. regmap_update_bits(domain->regmap, offset,
  79. domain->bits.pxx, domain->bits.pxx);
  80. /*
  81. * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
  82. * for PUP_REQ/PDN_REQ bit to be cleared
  83. */
  84. deadline = jiffies + msecs_to_jiffies(1);
  85. while (true) {
  86. u32 pxx_req;
  87. regmap_read(domain->regmap, offset, &pxx_req);
  88. if (!(pxx_req & domain->bits.pxx))
  89. break;
  90. if (time_after(jiffies, deadline)) {
  91. dev_err(domain->dev, "falied to command PGC\n");
  92. ret = -ETIMEDOUT;
  93. /*
  94. * If we were in a process of enabling a
  95. * domain and failed we might as well disable
  96. * the regulator we just enabled. And if it
  97. * was the opposite situation and we failed to
  98. * power down -- keep the regulator on
  99. */
  100. on = !on;
  101. break;
  102. }
  103. cpu_relax();
  104. }
  105. if (enable_power_control)
  106. regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
  107. GPC_PGC_CTRL_PCR, 0);
  108. if (has_regulator && !on) {
  109. int err;
  110. err = regulator_disable(domain->regulator);
  111. if (err)
  112. dev_err(domain->dev,
  113. "failed to disable regulator: %d\n", ret);
  114. /* Preserve earlier error code */
  115. ret = ret ?: err;
  116. }
  117. unmap:
  118. regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
  119. domain->bits.map, 0);
  120. return ret;
  121. }
  122. static int imx7_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd)
  123. {
  124. return imx7_gpc_pu_pgc_sw_pxx_req(genpd, true);
  125. }
  126. static int imx7_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd)
  127. {
  128. return imx7_gpc_pu_pgc_sw_pxx_req(genpd, false);
  129. }
  130. static struct imx7_pgc_domain imx7_pgc_domains[] = {
  131. [IMX7_POWER_DOMAIN_MIPI_PHY] = {
  132. .genpd = {
  133. .name = "mipi-phy",
  134. },
  135. .bits = {
  136. .pxx = MIPI_PHY_SW_Pxx_REQ,
  137. .map = MIPI_PHY_A7_DOMAIN,
  138. },
  139. .voltage = 1000000,
  140. .pgc = PGC_MIPI,
  141. },
  142. [IMX7_POWER_DOMAIN_PCIE_PHY] = {
  143. .genpd = {
  144. .name = "pcie-phy",
  145. },
  146. .bits = {
  147. .pxx = PCIE_PHY_SW_Pxx_REQ,
  148. .map = PCIE_PHY_A7_DOMAIN,
  149. },
  150. .voltage = 1000000,
  151. .pgc = PGC_PCIE,
  152. },
  153. [IMX7_POWER_DOMAIN_USB_HSIC_PHY] = {
  154. .genpd = {
  155. .name = "usb-hsic-phy",
  156. },
  157. .bits = {
  158. .pxx = USB_HSIC_PHY_SW_Pxx_REQ,
  159. .map = USB_HSIC_PHY_A7_DOMAIN,
  160. },
  161. .voltage = 1200000,
  162. .pgc = PGC_USB_HSIC,
  163. },
  164. };
  165. static int imx7_pgc_domain_probe(struct platform_device *pdev)
  166. {
  167. struct imx7_pgc_domain *domain = pdev->dev.platform_data;
  168. int ret;
  169. domain->dev = &pdev->dev;
  170. domain->regulator = devm_regulator_get_optional(domain->dev, "power");
  171. if (IS_ERR(domain->regulator)) {
  172. if (PTR_ERR(domain->regulator) != -ENODEV) {
  173. if (PTR_ERR(domain->regulator) != -EPROBE_DEFER)
  174. dev_err(domain->dev, "Failed to get domain's regulator\n");
  175. return PTR_ERR(domain->regulator);
  176. }
  177. } else {
  178. regulator_set_voltage(domain->regulator,
  179. domain->voltage, domain->voltage);
  180. }
  181. ret = pm_genpd_init(&domain->genpd, NULL, true);
  182. if (ret) {
  183. dev_err(domain->dev, "Failed to init power domain\n");
  184. return ret;
  185. }
  186. ret = of_genpd_add_provider_simple(domain->dev->of_node,
  187. &domain->genpd);
  188. if (ret) {
  189. dev_err(domain->dev, "Failed to add genpd provider\n");
  190. pm_genpd_remove(&domain->genpd);
  191. }
  192. return ret;
  193. }
  194. static int imx7_pgc_domain_remove(struct platform_device *pdev)
  195. {
  196. struct imx7_pgc_domain *domain = pdev->dev.platform_data;
  197. of_genpd_del_provider(domain->dev->of_node);
  198. pm_genpd_remove(&domain->genpd);
  199. return 0;
  200. }
  201. static const struct platform_device_id imx7_pgc_domain_id[] = {
  202. { "imx7-pgc-domain", },
  203. { },
  204. };
  205. static struct platform_driver imx7_pgc_domain_driver = {
  206. .driver = {
  207. .name = "imx7-pgc",
  208. },
  209. .probe = imx7_pgc_domain_probe,
  210. .remove = imx7_pgc_domain_remove,
  211. .id_table = imx7_pgc_domain_id,
  212. };
  213. builtin_platform_driver(imx7_pgc_domain_driver)
  214. static int imx_gpcv2_probe(struct platform_device *pdev)
  215. {
  216. static const struct regmap_range yes_ranges[] = {
  217. regmap_reg_range(GPC_LPCR_A7_BSC,
  218. GPC_M4_PU_PDN_FLG),
  219. regmap_reg_range(GPC_PGC_CTRL(PGC_MIPI),
  220. GPC_PGC_SR(PGC_MIPI)),
  221. regmap_reg_range(GPC_PGC_CTRL(PGC_PCIE),
  222. GPC_PGC_SR(PGC_PCIE)),
  223. regmap_reg_range(GPC_PGC_CTRL(PGC_USB_HSIC),
  224. GPC_PGC_SR(PGC_USB_HSIC)),
  225. };
  226. static const struct regmap_access_table access_table = {
  227. .yes_ranges = yes_ranges,
  228. .n_yes_ranges = ARRAY_SIZE(yes_ranges),
  229. };
  230. static const struct regmap_config regmap_config = {
  231. .reg_bits = 32,
  232. .val_bits = 32,
  233. .reg_stride = 4,
  234. .rd_table = &access_table,
  235. .wr_table = &access_table,
  236. .max_register = SZ_4K,
  237. };
  238. struct device *dev = &pdev->dev;
  239. struct device_node *pgc_np, *np;
  240. struct regmap *regmap;
  241. struct resource *res;
  242. void __iomem *base;
  243. int ret;
  244. pgc_np = of_get_child_by_name(dev->of_node, "pgc");
  245. if (!pgc_np) {
  246. dev_err(dev, "No power domains specified in DT\n");
  247. return -EINVAL;
  248. }
  249. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  250. base = devm_ioremap_resource(dev, res);
  251. if (IS_ERR(base))
  252. return PTR_ERR(base);
  253. regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
  254. if (IS_ERR(regmap)) {
  255. ret = PTR_ERR(regmap);
  256. dev_err(dev, "failed to init regmap (%d)\n", ret);
  257. return ret;
  258. }
  259. for_each_child_of_node(pgc_np, np) {
  260. struct platform_device *pd_pdev;
  261. struct imx7_pgc_domain *domain;
  262. u32 domain_index;
  263. ret = of_property_read_u32(np, "reg", &domain_index);
  264. if (ret) {
  265. dev_err(dev, "Failed to read 'reg' property\n");
  266. of_node_put(np);
  267. return ret;
  268. }
  269. if (domain_index >= ARRAY_SIZE(imx7_pgc_domains)) {
  270. dev_warn(dev,
  271. "Domain index %d is out of bounds\n",
  272. domain_index);
  273. continue;
  274. }
  275. domain = &imx7_pgc_domains[domain_index];
  276. domain->regmap = regmap;
  277. domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req;
  278. domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req;
  279. pd_pdev = platform_device_alloc("imx7-pgc-domain",
  280. domain_index);
  281. if (!pd_pdev) {
  282. dev_err(dev, "Failed to allocate platform device\n");
  283. of_node_put(np);
  284. return -ENOMEM;
  285. }
  286. pd_pdev->dev.platform_data = domain;
  287. pd_pdev->dev.parent = dev;
  288. pd_pdev->dev.of_node = np;
  289. ret = platform_device_add(pd_pdev);
  290. if (ret) {
  291. platform_device_put(pd_pdev);
  292. of_node_put(np);
  293. return ret;
  294. }
  295. }
  296. return 0;
  297. }
  298. static const struct of_device_id imx_gpcv2_dt_ids[] = {
  299. { .compatible = "fsl,imx7d-gpc" },
  300. { }
  301. };
  302. static struct platform_driver imx_gpc_driver = {
  303. .driver = {
  304. .name = "imx-gpcv2",
  305. .of_match_table = imx_gpcv2_dt_ids,
  306. },
  307. .probe = imx_gpcv2_probe,
  308. };
  309. builtin_platform_driver(imx_gpc_driver)