Merge tag 'block-5.11-2021-01-10' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / drivers / clk / mmp / pwr-island.c
blobab57c0e995c1d03bdebfeebeae311eb380bcfc97
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * MMP PMU power island support
5 * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk>
6 */
8 #include <linux/pm_domain.h>
9 #include <linux/slab.h>
10 #include <linux/io.h>
12 #include "clk.h"
14 #define to_mmp_pm_domain(genpd) container_of(genpd, struct mmp_pm_domain, genpd)
16 struct mmp_pm_domain {
17 struct generic_pm_domain genpd;
18 void __iomem *reg;
19 spinlock_t *lock;
20 u32 power_on;
21 u32 reset;
22 u32 clock_enable;
23 unsigned int flags;
26 static int mmp_pm_domain_power_on(struct generic_pm_domain *genpd)
28 struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd);
29 unsigned long flags = 0;
30 u32 val;
32 if (pm_domain->lock)
33 spin_lock_irqsave(pm_domain->lock, flags);
35 val = readl(pm_domain->reg);
37 /* Turn on the power island */
38 val |= pm_domain->power_on;
39 writel(val, pm_domain->reg);
41 /* Disable isolation */
42 val |= 0x100;
43 writel(val, pm_domain->reg);
45 /* Some blocks need to be reset after a power up */
46 if (pm_domain->reset || pm_domain->clock_enable) {
47 u32 after_power_on = val;
49 val &= ~pm_domain->reset;
50 writel(val, pm_domain->reg);
52 val |= pm_domain->clock_enable;
53 writel(val, pm_domain->reg);
55 val |= pm_domain->reset;
56 writel(val, pm_domain->reg);
58 writel(after_power_on, pm_domain->reg);
61 if (pm_domain->lock)
62 spin_unlock_irqrestore(pm_domain->lock, flags);
64 return 0;
67 static int mmp_pm_domain_power_off(struct generic_pm_domain *genpd)
69 struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd);
70 unsigned long flags = 0;
71 u32 val;
73 if (pm_domain->flags & MMP_PM_DOMAIN_NO_DISABLE)
74 return 0;
76 if (pm_domain->lock)
77 spin_lock_irqsave(pm_domain->lock, flags);
79 /* Turn off and isolate the the power island. */
80 val = readl(pm_domain->reg);
81 val &= ~pm_domain->power_on;
82 val &= ~0x100;
83 writel(val, pm_domain->reg);
85 if (pm_domain->lock)
86 spin_unlock_irqrestore(pm_domain->lock, flags);
88 return 0;
91 struct generic_pm_domain *mmp_pm_domain_register(const char *name,
92 void __iomem *reg,
93 u32 power_on, u32 reset, u32 clock_enable,
94 unsigned int flags, spinlock_t *lock)
96 struct mmp_pm_domain *pm_domain;
98 pm_domain = kzalloc(sizeof(*pm_domain), GFP_KERNEL);
99 if (!pm_domain)
100 return ERR_PTR(-ENOMEM);
102 pm_domain->reg = reg;
103 pm_domain->power_on = power_on;
104 pm_domain->reset = reset;
105 pm_domain->clock_enable = clock_enable;
106 pm_domain->flags = flags;
107 pm_domain->lock = lock;
109 pm_genpd_init(&pm_domain->genpd, NULL, true);
110 pm_domain->genpd.name = name;
111 pm_domain->genpd.power_on = mmp_pm_domain_power_on;
112 pm_domain->genpd.power_off = mmp_pm_domain_power_off;
114 return &pm_domain->genpd;