summaryrefslogtreecommitdiff
path: root/drivers/clk/renesas/clk-mstp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/renesas/clk-mstp.c')
-rw-r--r--drivers/clk/renesas/clk-mstp.c83
1 files changed, 41 insertions, 42 deletions
diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c
index 92ece221b0d4..2f65fe2c6bdf 100644
--- a/drivers/clk/renesas/clk-mstp.c
+++ b/drivers/clk/renesas/clk-mstp.c
@@ -10,14 +10,15 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include <linux/clk/renesas.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
/*
@@ -30,11 +31,12 @@
/**
* struct mstp_clock_group - MSTP gating clocks group
*
- * @data: clocks in this group
+ * @data: clock specifier translation for clocks in this group
* @smstpcr: module stop control register
* @mstpsr: module stop status register (optional)
* @lock: protects writes to SMSTPCR
* @width_8bit: registers are 8-bit, not 32-bit
+ * @clks: clocks in this group
*/
struct mstp_clock_group {
struct clk_onecell_data data;
@@ -42,6 +44,7 @@ struct mstp_clock_group {
void __iomem *mstpsr;
spinlock_t lock;
bool width_8bit;
+ struct clk *clks[];
};
/**
@@ -76,8 +79,8 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
struct mstp_clock_group *group = clock->group;
u32 bitmask = BIT(clock->bit_index);
unsigned long flags;
- unsigned int i;
u32 value;
+ int ret;
spin_lock_irqsave(&group->lock, flags);
@@ -99,19 +102,14 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
if (!enable || !group->mstpsr)
return 0;
- for (i = 1000; i > 0; --i) {
- if (!(cpg_mstp_read(group, group->mstpsr) & bitmask))
- break;
- cpu_relax();
- }
-
- if (!i) {
+ /* group->width_8bit is always false if group->mstpsr is present */
+ ret = readl_poll_timeout_atomic(group->mstpsr, value,
+ !(value & bitmask), 0, 10);
+ if (ret)
pr_err("%s: failed to enable %p[%d]\n", __func__,
group->smstpcr, clock->bit_index);
- return -ETIMEDOUT;
- }
- return 0;
+ return ret;
}
static int cpg_mstp_clock_enable(struct clk_hw *hw)
@@ -148,7 +146,7 @@ static struct clk * __init cpg_mstp_clock_register(const char *name,
const char *parent_name, unsigned int index,
struct mstp_clock_group *group)
{
- struct clk_init_data init;
+ struct clk_init_data init = {};
struct mstp_clock *clock;
struct clk *clk;
@@ -186,14 +184,11 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
struct clk **clks;
unsigned int i;
- group = kzalloc(sizeof(*group), GFP_KERNEL);
- clks = kmalloc_array(MSTP_MAX_CLOCKS, sizeof(*clks), GFP_KERNEL);
- if (group == NULL || clks == NULL) {
- kfree(group);
- kfree(clks);
+ group = kzalloc(struct_size(group, clks, MSTP_MAX_CLOCKS), GFP_KERNEL);
+ if (!group)
return;
- }
+ clks = group->clks;
spin_lock_init(&group->lock);
group->data.clks = clks;
@@ -203,7 +198,6 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
if (group->smstpcr == NULL) {
pr_err("%s: failed to remap SMSTPCR\n", __func__);
kfree(group);
- kfree(clks);
return;
}
@@ -213,7 +207,7 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
for (i = 0; i < MSTP_MAX_CLOCKS; ++i)
clks[i] = ERR_PTR(-ENOENT);
- if (of_find_property(np, "clock-indices", &i))
+ if (of_property_present(np, "clock-indices"))
idxname = "clock-indices";
else
idxname = "renesas,clock-indices";
@@ -243,22 +237,12 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
clks[clkidx] = cpg_mstp_clock_register(name, parent_name,
clkidx, group);
- if (!IS_ERR(clks[clkidx])) {
+ if (!IS_ERR(clks[clkidx]))
group->data.clk_num = max(group->data.clk_num,
clkidx + 1);
- /*
- * Register a clkdev to let board code retrieve the
- * clock by name and register aliases for non-DT
- * devices.
- *
- * FIXME: Remove this when all devices that require a
- * clock will be instantiated from DT.
- */
- clk_register_clkdev(clks[clkidx], name, NULL);
- } else {
+ else
pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
__func__, np, name, PTR_ERR(clks[clkidx]));
- }
}
of_clk_add_provider(np, of_clk_src_onecell_get, &group->data);
@@ -297,16 +281,12 @@ found:
return PTR_ERR(clk);
error = pm_clk_create(dev);
- if (error) {
- dev_err(dev, "pm_clk_create failed %d\n", error);
+ if (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);
+ if (error)
goto fail_destroy;
- }
return 0;
@@ -323,6 +303,9 @@ void cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev)
pm_clk_destroy(dev);
}
+static struct device_node *cpg_mstp_pd_np __initdata = NULL;
+static struct generic_pm_domain *cpg_mstp_pd_genpd __initdata = NULL;
+
void __init cpg_mstp_add_clk_domain(struct device_node *np)
{
struct generic_pm_domain *pd;
@@ -338,10 +321,26 @@ void __init cpg_mstp_add_clk_domain(struct device_node *np)
return;
pd->name = np->name;
- pd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
+ pd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ALWAYS_ON |
+ GENPD_FLAG_ACTIVE_WAKEUP;
pd->attach_dev = cpg_mstp_attach_dev;
pd->detach_dev = cpg_mstp_detach_dev;
pm_genpd_init(pd, &pm_domain_always_on_gov, false);
- of_genpd_add_provider_simple(np, pd);
+ cpg_mstp_pd_np = of_node_get(np);
+ cpg_mstp_pd_genpd = pd;
+}
+
+static int __init cpg_mstp_pd_init_provider(void)
+{
+ int error;
+
+ if (!cpg_mstp_pd_np)
+ return -ENODEV;
+
+ error = of_genpd_add_provider_simple(cpg_mstp_pd_np, cpg_mstp_pd_genpd);
+
+ of_node_put(cpg_mstp_pd_np);
+ return error;
}
+postcore_initcall(cpg_mstp_pd_init_provider);