Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * MMP PMU power island support
  4 *
  5 * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk>
  6 */
  7
  8#include <linux/pm_domain.h>
  9#include <linux/slab.h>
 10#include <linux/io.h>
 11
 12#include "clk.h"
 13
 14#define to_mmp_pm_domain(genpd) container_of(genpd, struct mmp_pm_domain, genpd)
 15
 16struct 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;
 24};
 25
 26static int mmp_pm_domain_power_on(struct generic_pm_domain *genpd)
 27{
 28	struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd);
 29	unsigned long flags = 0;
 30	u32 val;
 31
 32	if (pm_domain->lock)
 33		spin_lock_irqsave(pm_domain->lock, flags);
 34
 35	val = readl(pm_domain->reg);
 36
 37	/* Turn on the power island */
 38	val |= pm_domain->power_on;
 39	writel(val, pm_domain->reg);
 40
 41	/* Disable isolation */
 42	val |= 0x100;
 43	writel(val, pm_domain->reg);
 44
 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;
 48
 49		val &= ~pm_domain->reset;
 50		writel(val, pm_domain->reg);
 51
 52		val |= pm_domain->clock_enable;
 53		writel(val, pm_domain->reg);
 54
 55		val |= pm_domain->reset;
 56		writel(val, pm_domain->reg);
 57
 58		writel(after_power_on, pm_domain->reg);
 59	}
 60
 61	if (pm_domain->lock)
 62		spin_unlock_irqrestore(pm_domain->lock, flags);
 63
 64	return 0;
 65}
 66
 67static int mmp_pm_domain_power_off(struct generic_pm_domain *genpd)
 68{
 69	struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd);
 70	unsigned long flags = 0;
 71	u32 val;
 72
 73	if (pm_domain->flags & MMP_PM_DOMAIN_NO_DISABLE)
 74		return 0;
 75
 76	if (pm_domain->lock)
 77		spin_lock_irqsave(pm_domain->lock, flags);
 78
 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);
 84
 85	if (pm_domain->lock)
 86		spin_unlock_irqrestore(pm_domain->lock, flags);
 87
 88	return 0;
 89}
 90
 91struct 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)
 95{
 96	struct mmp_pm_domain *pm_domain;
 97
 98	pm_domain = kzalloc(sizeof(*pm_domain), GFP_KERNEL);
 99	if (!pm_domain)
100		return ERR_PTR(-ENOMEM);
101
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;
108
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;
113
114	return &pm_domain->genpd;
115}