diff options
author | Ulf Hansson <ulf.hansson@linaro.org> | 2023-07-05 19:08:50 +0300 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2023-07-14 11:40:56 +0300 |
commit | 4419644bfc7f2ef86708758060d263500af9f88a (patch) | |
tree | c6b1de45d64ff3f25cb339632a24c1136ce0680b /drivers/genpd | |
parent | a8fcd3da73decacc8155c954a850c37777f75623 (diff) | |
download | linux-4419644bfc7f2ef86708758060d263500af9f88a.tar.xz |
soc: samsung: Move power-domain driver to the genpd dir
To simplify with maintenance let's move the samsung power-domain driver to
the new genpd directory. Going forward, patches are intended to be managed
through a separate git tree, according to MAINTAINERS.
Cc: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Cc: Alim Akhtar <alim.akhtar@samsung.com>
Cc: <linux-samsung-soc@vger.kernel.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/genpd')
-rw-r--r-- | drivers/genpd/Makefile | 1 | ||||
-rw-r--r-- | drivers/genpd/samsung/Makefile | 2 | ||||
-rw-r--r-- | drivers/genpd/samsung/exynos-pm-domains.c | 166 |
3 files changed, 169 insertions, 0 deletions
diff --git a/drivers/genpd/Makefile b/drivers/genpd/Makefile index c178421e0cbc..1cf0ff26a44f 100644 --- a/drivers/genpd/Makefile +++ b/drivers/genpd/Makefile @@ -7,3 +7,4 @@ obj-y += mediatek/ obj-y += qcom/ obj-y += renesas/ obj-y += rockchip/ +obj-y += samsung/ diff --git a/drivers/genpd/samsung/Makefile b/drivers/genpd/samsung/Makefile new file mode 100644 index 000000000000..397aa5908c1d --- /dev/null +++ b/drivers/genpd/samsung/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_EXYNOS_PM_DOMAINS) += exynos-pm-domains.o diff --git a/drivers/genpd/samsung/exynos-pm-domains.c b/drivers/genpd/samsung/exynos-pm-domains.c new file mode 100644 index 000000000000..d07f3c9d6903 --- /dev/null +++ b/drivers/genpd/samsung/exynos-pm-domains.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Exynos Generic power domain support. +// +// Copyright (c) 2012 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// Implementation of Exynos specific power domain control which is used in +// conjunction with runtime-pm. Support for both device-tree and non-device-tree +// based power domain support is included. + +#include <linux/io.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/pm_domain.h> +#include <linux/delay.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> + +struct exynos_pm_domain_config { + /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */ + u32 local_pwr_cfg; +}; + +/* + * Exynos specific wrapper around the generic power domain + */ +struct exynos_pm_domain { + void __iomem *base; + struct generic_pm_domain pd; + u32 local_pwr_cfg; +}; + +static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + struct exynos_pm_domain *pd; + void __iomem *base; + u32 timeout, pwr; + char *op; + + pd = container_of(domain, struct exynos_pm_domain, pd); + base = pd->base; + + pwr = power_on ? pd->local_pwr_cfg : 0; + writel_relaxed(pwr, base); + + /* Wait max 1ms */ + timeout = 10; + + while ((readl_relaxed(base + 0x4) & pd->local_pwr_cfg) != pwr) { + if (!timeout) { + op = (power_on) ? "enable" : "disable"; + pr_err("Power domain %s %s failed\n", domain->name, op); + return -ETIMEDOUT; + } + timeout--; + cpu_relax(); + usleep_range(80, 100); + } + + return 0; +} + +static int exynos_pd_power_on(struct generic_pm_domain *domain) +{ + return exynos_pd_power(domain, true); +} + +static int exynos_pd_power_off(struct generic_pm_domain *domain) +{ + return exynos_pd_power(domain, false); +} + +static const struct exynos_pm_domain_config exynos4210_cfg = { + .local_pwr_cfg = 0x7, +}; + +static const struct exynos_pm_domain_config exynos5433_cfg = { + .local_pwr_cfg = 0xf, +}; + +static const struct of_device_id exynos_pm_domain_of_match[] = { + { + .compatible = "samsung,exynos4210-pd", + .data = &exynos4210_cfg, + }, { + .compatible = "samsung,exynos5433-pd", + .data = &exynos5433_cfg, + }, + { }, +}; + +static const char *exynos_get_domain_name(struct device_node *node) +{ + const char *name; + + if (of_property_read_string(node, "label", &name) < 0) + name = kbasename(node->full_name); + return kstrdup_const(name, GFP_KERNEL); +} + +static int exynos_pd_probe(struct platform_device *pdev) +{ + const struct exynos_pm_domain_config *pm_domain_cfg; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct of_phandle_args child, parent; + struct exynos_pm_domain *pd; + int on, ret; + + pm_domain_cfg = of_device_get_match_data(dev); + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + pd->pd.name = exynos_get_domain_name(np); + if (!pd->pd.name) + return -ENOMEM; + + pd->base = of_iomap(np, 0); + if (!pd->base) { + kfree_const(pd->pd.name); + return -ENODEV; + } + + pd->pd.power_off = exynos_pd_power_off; + pd->pd.power_on = exynos_pd_power_on; + pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; + + on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; + + pm_genpd_init(&pd->pd, NULL, !on); + ret = of_genpd_add_provider_simple(np, &pd->pd); + + if (ret == 0 && of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", 0, &parent) == 0) { + child.np = np; + child.args_count = 0; + + if (of_genpd_add_subdomain(&parent, &child)) + pr_warn("%pOF failed to add subdomain: %pOF\n", + parent.np, child.np); + else + pr_info("%pOF has as child subdomain: %pOF.\n", + parent.np, child.np); + } + + pm_runtime_enable(dev); + return ret; +} + +static struct platform_driver exynos_pd_driver = { + .probe = exynos_pd_probe, + .driver = { + .name = "exynos-pd", + .of_match_table = exynos_pm_domain_of_match, + .suppress_bind_attrs = true, + } +}; + +static __init int exynos4_pm_init_power_domain(void) +{ + return platform_driver_register(&exynos_pd_driver); +} +core_initcall(exynos4_pm_init_power_domain); |