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

Commit 1f7db7bb authored by Chris Brandt's avatar Chris Brandt Committed by Geert Uytterhoeven
Browse files

clk: renesas: cpg-mssr: Add early clock support



Add support for SoCs that need to register core and module clocks early in
order to use OF drivers that exclusively use macros such as
TIMER_OF_DECLARE.

Signed-off-by: default avatarChris Brandt <chris.brandt@renesas.com>
Signed-off-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
parent 9ef5e037
Loading
Loading
Loading
Loading
+76 −21
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ struct cpg_mssr_priv {
	struct device *dev;
	void __iomem *base;
	spinlock_t rmw_lock;
	struct device_node *np;

	struct clk **clks;
	unsigned int num_core_clks;
@@ -144,6 +145,7 @@ struct cpg_mssr_priv {
	} smstpcr_saved[ARRAY_SIZE(smstpcr)];
};

static struct cpg_mssr_priv *cpg_mssr_priv;

/**
 * struct mstp_clock - MSTP gating clock
@@ -319,7 +321,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,

	switch (core->type) {
	case CLK_TYPE_IN:
		clk = of_clk_get_by_name(priv->dev->of_node, core->name);
		clk = of_clk_get_by_name(priv->np, core->name);
		break;

	case CLK_TYPE_FF:
@@ -891,42 +893,43 @@ static const struct dev_pm_ops cpg_mssr_pm = {
#define DEV_PM_OPS	NULL
#endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */

static int __init cpg_mssr_probe(struct platform_device *pdev)
static int __init cpg_mssr_common_init(struct device *dev,
				       struct device_node *np,
				       const struct cpg_mssr_info *info)
{
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	const struct cpg_mssr_info *info;
	struct cpg_mssr_priv *priv;
	struct clk **clks = NULL;
	unsigned int nclks, i;
	struct resource *res;
	struct clk **clks;
	int error;

	info = of_device_get_match_data(dev);
	if (info->init) {
		error = info->init(dev);
		if (error)
			return error;
	}

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->np = np;
	priv->dev = dev;
	spin_lock_init(&priv->rmw_lock);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	priv->base = devm_ioremap_resource(dev, res);
	if (IS_ERR(priv->base))
		return PTR_ERR(priv->base);
	priv->base = of_iomap(np, 0);
	if (!priv->base) {
		error = -ENOMEM;
		goto out_err;
	}

	nclks = info->num_total_core_clks + info->num_hw_mod_clks;
	clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
	if (!clks)
		return -ENOMEM;
	clks = kmalloc_array(nclks, sizeof(*clks), GFP_KERNEL);
	if (!clks) {
		error = -ENOMEM;
		goto out_err;
	}

	dev_set_drvdata(dev, priv);
	cpg_mssr_priv = priv;
	priv->clks = clks;
	priv->num_core_clks = info->num_total_core_clks;
	priv->num_mod_clks = info->num_hw_mod_clks;
@@ -937,16 +940,68 @@ static int __init cpg_mssr_probe(struct platform_device *pdev)
	for (i = 0; i < nclks; i++)
		clks[i] = ERR_PTR(-ENOENT);

	error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
	if (error)
		goto out_err;

	return 0;

out_err:
	kfree(clks);
	if (priv->base)
		iounmap(priv->base);
	kfree(priv);

	return error;
}

void __init cpg_mssr_early_init(struct device_node *np,
				const struct cpg_mssr_info *info)
{
	int error;
	int i;

	error = cpg_mssr_common_init(NULL, np, info);
	if (error)
		return;

	for (i = 0; i < info->num_early_core_clks; i++)
		cpg_mssr_register_core_clk(&info->early_core_clks[i], info,
					   cpg_mssr_priv);

	for (i = 0; i < info->num_early_mod_clks; i++)
		cpg_mssr_register_mod_clk(&info->early_mod_clks[i], info,
					  cpg_mssr_priv);

}

static int __init cpg_mssr_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	const struct cpg_mssr_info *info;
	struct cpg_mssr_priv *priv;
	unsigned int i;
	int error;

	info = of_device_get_match_data(dev);

	if (!cpg_mssr_priv) {
		error = cpg_mssr_common_init(dev, dev->of_node, info);
		if (error)
			return error;
	}

	priv = cpg_mssr_priv;
	priv->dev = dev;
	dev_set_drvdata(dev, priv);

	for (i = 0; i < info->num_core_clks; i++)
		cpg_mssr_register_core_clk(&info->core_clks[i], info, priv);

	for (i = 0; i < info->num_mod_clks; i++)
		cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv);

	error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
	if (error)
		return error;

	error = devm_add_action_or_reset(dev,
					 cpg_mssr_del_clk_provider,
					 np);
+13 −0
Original line number Diff line number Diff line
@@ -91,6 +91,11 @@ struct device_node;
    /**
     * SoC-specific CPG/MSSR Description
     *
     * @early_core_clks: Array of Early Core Clock definitions
     * @num_early_core_clks: Number of entries in early_core_clks[]
     * @early_mod_clks: Array of Early Module Clock definitions
     * @num_early_mod_clks: Number of entries in early_mod_clks[]
     *
     * @core_clks: Array of Core Clock definitions
     * @num_core_clks: Number of entries in core_clks[]
     * @last_dt_core_clk: ID of the last Core Clock exported to DT
@@ -117,6 +122,12 @@ struct device_node;
     */

struct cpg_mssr_info {
	/* Early Clocks */
	const struct cpg_core_clk *early_core_clks;
	unsigned int num_early_core_clks;
	const struct mssr_mod_clk *early_mod_clks;
	unsigned int num_early_mod_clks;

	/* Core Clocks */
	const struct cpg_core_clk *core_clks;
	unsigned int num_core_clks;
@@ -164,6 +175,8 @@ extern const struct cpg_mssr_info r8a77980_cpg_mssr_info;
extern const struct cpg_mssr_info r8a77990_cpg_mssr_info;
extern const struct cpg_mssr_info r8a77995_cpg_mssr_info;

void __init cpg_mssr_early_init(struct device_node *np,
				const struct cpg_mssr_info *info);

    /*
     * Helpers for fixing up clock tables depending on SoC revision