[PATCH 4/6] soc: samsung: pm_domains: Implement proper I/O operations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Instead of doing in-place readl()/writel() calls fed with magic numbers,
provide dedicated read/write functions which implement proper register
accesses:
  - Get rid of magic numbers by introducing actual constants for PD
    registers
  - Rework the write function to perform a RMW operation, as PD
    registers have some bits markes as "Reserved" in TRM, which
    shouldn't be changed
  - Add helper functions for reading the STATUS reg and writing
    CONFIGURATION reg, to make user code more neat and clean

New functions are designed in such a way that it's easy to rework those
further on top of regmap API.

Signed-off-by: Sam Protsenko <semen.protsenko@xxxxxxxxxx>
---
 drivers/soc/samsung/pm_domains.c | 42 +++++++++++++++++++++++++++++---
 1 file changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c
index 522a43005a5a..dd1ec3541e11 100644
--- a/drivers/soc/samsung/pm_domains.c
+++ b/drivers/soc/samsung/pm_domains.c
@@ -18,6 +18,10 @@
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
 
+/* Register offsets inside Power Domain area in PMU */
+#define EXYNOS_PD_CONF		0x0
+#define EXYNOS_PD_STATUS	0x4
+
 struct exynos_pm_domain_config {
 	/* Value for LOCAL_PWR_CFG and STATUS fields for each domain */
 	u32 local_pwr_cfg;
@@ -33,6 +37,37 @@ struct exynos_pm_domain {
 	u32 local_pwr_cfg;
 };
 
+static void exynos_pd_write(struct exynos_pm_domain *pd, unsigned int reg,
+			    unsigned int mask, unsigned int val)
+{
+	u32 v;
+
+	v = readl_relaxed(pd->base + reg);
+	v = (v & ~mask) | val;
+	writel_relaxed(v, pd->base + reg);
+}
+
+static void exynos_pd_read(struct exynos_pm_domain *pd, unsigned int reg,
+			   unsigned int *val)
+{
+	*val = readl_relaxed(pd->base + reg);
+}
+
+static unsigned int exynos_pd_read_status(struct exynos_pm_domain *pd)
+{
+	unsigned int val;
+
+	exynos_pd_read(pd, EXYNOS_PD_STATUS, &val);
+	val &= pd->local_pwr_cfg;
+
+	return val;
+}
+
+static void exynos_pd_write_conf(struct exynos_pm_domain *pd, u32 val)
+{
+	exynos_pd_write(pd, EXYNOS_PD_CONF, pd->local_pwr_cfg, val);
+}
+
 static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
 {
 	struct exynos_pm_domain *pd;
@@ -44,12 +79,12 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
 	base = pd->base;
 
 	pwr = power_on ? pd->local_pwr_cfg : 0;
-	writel_relaxed(pwr, base);
+	exynos_pd_write_conf(pd, pwr);
 
 	/* Wait max 1ms */
 	timeout = 10;
 
-	while ((readl_relaxed(base + 0x4) & pd->local_pwr_cfg) != pwr) {
+	while (exynos_pd_read_status(pd) != pwr) {
 		if (!timeout) {
 			op = (power_on) ? "enable" : "disable";
 			pr_err("Power domain %s %s failed\n", domain->name, op);
@@ -135,8 +170,7 @@ static int exynos_pd_probe(struct platform_device *pdev)
 	pd->pd.power_off = exynos_pd_power_off;
 	pd->pd.power_on = exynos_pd_power_on;
 
-	on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
-
+	on = exynos_pd_read_status(pd);
 	pm_genpd_init(&pd->pd, NULL, !on);
 	ret = of_genpd_add_provider_simple(np, &pd->pd);
 
-- 
2.39.2




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux