Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 752b5ed5 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Simon Horman
Browse files

clk: shmobile: Add CPG/MSTP Clock Domain support



Add Clock Domain support to the Clock Pulse Generator (CPG) Module Stop
(MSTP) Clocks driver using the generic PM Domain.  This allows to
power-manage the module clocks of SoC devices that are part of the
CPG/MSTP Clock Domain using Runtime PM, or for system suspend/resume.

SoC devices that are part of the CPG/MSTP Clock Domain and can be
power-managed through an MSTP clock should be tagged in DT with a
proper "power-domains" property.

The CPG/MSTP Clock Domain code will scan such devices for clocks that
are suitable for power-managing the device, by looking for a clock that
is compatible with "renesas,cpg-mstp-clocks".

Signed-off-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarStephen Boyd <sboyd@codeaurora.org>
Reviewed-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Reviewed-by: default avatarKevin Hilman <khilman@linaro.org>
Signed-off-by: default avatarSimon Horman <horms+renesas@verge.net.au>
parent d770e558
Loading
Loading
Loading
Loading
+87 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
 * R-Car MSTP clocks
 *
 * Copyright (C) 2013 Ideas On Board SPRL
 * Copyright (C) 2015 Glider bvba
 *
 * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 *
@@ -10,11 +11,16 @@
 * the Free Software Foundation; version 2 of the License.
 */

#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
#include <linux/spinlock.h>

/*
@@ -236,3 +242,84 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
	of_clk_add_provider(np, of_clk_src_onecell_get, &group->data);
}
CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init);


#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
int cpg_mstp_attach_dev(struct generic_pm_domain *domain, struct device *dev)
{
	struct device_node *np = dev->of_node;
	struct of_phandle_args clkspec;
	struct clk *clk;
	int i = 0;
	int error;

	while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
					   &clkspec)) {
		if (of_device_is_compatible(clkspec.np,
					    "renesas,cpg-mstp-clocks"))
			goto found;

		of_node_put(clkspec.np);
		i++;
	}

	return 0;

found:
	clk = of_clk_get_from_provider(&clkspec);
	of_node_put(clkspec.np);

	if (IS_ERR(clk))
		return PTR_ERR(clk);

	error = pm_clk_create(dev);
	if (error) {
		dev_err(dev, "pm_clk_create failed %d\n", error);
		goto fail_put;
	}

	error = pm_clk_add_clk(dev, clk);
	if (error) {
		dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
		goto fail_destroy;
	}

	return 0;

fail_destroy:
	pm_clk_destroy(dev);
fail_put:
	clk_put(clk);
	return error;
}

void cpg_mstp_detach_dev(struct generic_pm_domain *domain, struct device *dev)
{
	if (!list_empty(&dev->power.subsys_data->clock_list))
		pm_clk_destroy(dev);
}

void __init cpg_mstp_add_clk_domain(struct device_node *np)
{
	struct generic_pm_domain *pd;
	u32 ncells;

	if (of_property_read_u32(np, "#power-domain-cells", &ncells)) {
		pr_warn("%s lacks #power-domain-cells\n", np->full_name);
		return;
	}

	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
	if (!pd)
		return;

	pd->name = np->name;

	pd->flags = GENPD_FLAG_PM_CLK;
	pm_genpd_init(pd, &simple_qos_governor, false);
	pd->attach_dev = cpg_mstp_attach_dev;
	pd->detach_dev = cpg_mstp_detach_dev;

	of_genpd_add_provider_simple(np, pd);
}
#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
+12 −0
Original line number Diff line number Diff line
@@ -16,8 +16,20 @@

#include <linux/types.h>

struct device;
struct device_node;
struct generic_pm_domain;

void r8a7778_clocks_init(u32 mode);
void r8a7779_clocks_init(u32 mode);
void rcar_gen2_clocks_init(u32 mode);

#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
void cpg_mstp_add_clk_domain(struct device_node *np);
int cpg_mstp_attach_dev(struct generic_pm_domain *domain, struct device *dev);
void cpg_mstp_detach_dev(struct generic_pm_domain *domain, struct device *dev);
#else
static inline void cpg_mstp_add_clk_domain(struct device_node *np) {}
#endif

#endif