zx2967_pm_domains.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2017 ZTE Ltd.
  4. *
  5. * Author: Baoyou Xie <baoyou.xie@linaro.org>
  6. */
  7. #include <linux/delay.h>
  8. #include <linux/err.h>
  9. #include <linux/io.h>
  10. #include <linux/of.h>
  11. #include "zx2967_pm_domains.h"
  12. #define PCU_DM_CLKEN(zpd) ((zpd)->reg_offset[REG_CLKEN])
  13. #define PCU_DM_ISOEN(zpd) ((zpd)->reg_offset[REG_ISOEN])
  14. #define PCU_DM_RSTEN(zpd) ((zpd)->reg_offset[REG_RSTEN])
  15. #define PCU_DM_PWREN(zpd) ((zpd)->reg_offset[REG_PWREN])
  16. #define PCU_DM_ACK_SYNC(zpd) ((zpd)->reg_offset[REG_ACK_SYNC])
  17. static void __iomem *pcubase;
  18. static int zx2967_power_on(struct generic_pm_domain *domain)
  19. {
  20. struct zx2967_pm_domain *zpd = (struct zx2967_pm_domain *)domain;
  21. unsigned long loop = 1000;
  22. u32 val;
  23. val = readl_relaxed(pcubase + PCU_DM_PWREN(zpd));
  24. if (zpd->polarity == PWREN)
  25. val |= BIT(zpd->bit);
  26. else
  27. val &= ~BIT(zpd->bit);
  28. writel_relaxed(val, pcubase + PCU_DM_PWREN(zpd));
  29. do {
  30. udelay(1);
  31. val = readl_relaxed(pcubase + PCU_DM_ACK_SYNC(zpd))
  32. & BIT(zpd->bit);
  33. } while (--loop && !val);
  34. if (!loop) {
  35. pr_err("Error: %s %s fail\n", __func__, domain->name);
  36. return -EIO;
  37. }
  38. val = readl_relaxed(pcubase + PCU_DM_RSTEN(zpd));
  39. val |= BIT(zpd->bit);
  40. writel_relaxed(val, pcubase + PCU_DM_RSTEN(zpd));
  41. udelay(5);
  42. val = readl_relaxed(pcubase + PCU_DM_ISOEN(zpd));
  43. val &= ~BIT(zpd->bit);
  44. writel_relaxed(val, pcubase + PCU_DM_ISOEN(zpd));
  45. udelay(5);
  46. val = readl_relaxed(pcubase + PCU_DM_CLKEN(zpd));
  47. val |= BIT(zpd->bit);
  48. writel_relaxed(val, pcubase + PCU_DM_CLKEN(zpd));
  49. udelay(5);
  50. pr_debug("poweron %s\n", domain->name);
  51. return 0;
  52. }
  53. static int zx2967_power_off(struct generic_pm_domain *domain)
  54. {
  55. struct zx2967_pm_domain *zpd = (struct zx2967_pm_domain *)domain;
  56. unsigned long loop = 1000;
  57. u32 val;
  58. val = readl_relaxed(pcubase + PCU_DM_CLKEN(zpd));
  59. val &= ~BIT(zpd->bit);
  60. writel_relaxed(val, pcubase + PCU_DM_CLKEN(zpd));
  61. udelay(5);
  62. val = readl_relaxed(pcubase + PCU_DM_ISOEN(zpd));
  63. val |= BIT(zpd->bit);
  64. writel_relaxed(val, pcubase + PCU_DM_ISOEN(zpd));
  65. udelay(5);
  66. val = readl_relaxed(pcubase + PCU_DM_RSTEN(zpd));
  67. val &= ~BIT(zpd->bit);
  68. writel_relaxed(val, pcubase + PCU_DM_RSTEN(zpd));
  69. udelay(5);
  70. val = readl_relaxed(pcubase + PCU_DM_PWREN(zpd));
  71. if (zpd->polarity == PWREN)
  72. val &= ~BIT(zpd->bit);
  73. else
  74. val |= BIT(zpd->bit);
  75. writel_relaxed(val, pcubase + PCU_DM_PWREN(zpd));
  76. do {
  77. udelay(1);
  78. val = readl_relaxed(pcubase + PCU_DM_ACK_SYNC(zpd))
  79. & BIT(zpd->bit);
  80. } while (--loop && val);
  81. if (!loop) {
  82. pr_err("Error: %s %s fail\n", __func__, domain->name);
  83. return -EIO;
  84. }
  85. pr_debug("poweroff %s\n", domain->name);
  86. return 0;
  87. }
  88. int zx2967_pd_probe(struct platform_device *pdev,
  89. struct generic_pm_domain **zx_pm_domains,
  90. int domain_num)
  91. {
  92. struct genpd_onecell_data *genpd_data;
  93. struct resource *res;
  94. int i;
  95. genpd_data = devm_kzalloc(&pdev->dev, sizeof(*genpd_data), GFP_KERNEL);
  96. if (!genpd_data)
  97. return -ENOMEM;
  98. genpd_data->domains = zx_pm_domains;
  99. genpd_data->num_domains = domain_num;
  100. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  101. pcubase = devm_ioremap_resource(&pdev->dev, res);
  102. if (IS_ERR(pcubase))
  103. return PTR_ERR(pcubase);
  104. for (i = 0; i < domain_num; ++i) {
  105. zx_pm_domains[i]->power_on = zx2967_power_on;
  106. zx_pm_domains[i]->power_off = zx2967_power_off;
  107. pm_genpd_init(zx_pm_domains[i], NULL, false);
  108. }
  109. of_genpd_add_provider_onecell(pdev->dev.of_node, genpd_data);
  110. dev_info(&pdev->dev, "powerdomain init ok\n");
  111. return 0;
  112. }