1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * MMP PMU power island support
5 * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk>
8 #include <linux/pm_domain.h>
9 #include <linux/slab.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
;
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;
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 */
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
);
62 spin_unlock_irqrestore(pm_domain
->lock
, flags
);
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;
73 if (pm_domain
->flags
& MMP_PM_DOMAIN_NO_DISABLE
)
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
;
83 writel(val
, pm_domain
->reg
);
86 spin_unlock_irqrestore(pm_domain
->lock
, flags
);
91 struct generic_pm_domain
*mmp_pm_domain_register(const char *name
,
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
);
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
;