Skip to content

Commit

Permalink
clk: shmobile: Add CPG/MSTP Clock Domain support
Browse files Browse the repository at this point in the history
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: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Stephen Boyd <sboyd@codeaurora.org>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
  • Loading branch information
Geert Uytterhoeven authored and Simon Horman committed Aug 12, 2015
1 parent d770e55 commit 752b5ed
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
87 changes: 87 additions & 0 deletions drivers/clk/shmobile/clk-mstp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
*
Expand All @@ -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>

/*
Expand Down Expand Up @@ -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 changes: 12 additions & 0 deletions include/linux/clk/shmobile.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 752b5ed

Please sign in to comment.