diff mbox

[v2,04/13] clk: davinci - common clk driver initialization

Message ID 1348683037-9705-5-git-send-email-m-karicheri2@ti.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Murali Karicheri Sept. 26, 2012, 6:10 p.m. UTC
This is the common clk driver initialization function for DaVinci
SoCs and other SoCs that uses similar hardware architecture.
Different clocks present in the SoC are passed to this function
using a clk table and this function initialize the various drivers.
Existing driver such as clk-fixed-rate, clk-divider, clk-mux and
DaVinci specific clk drivers are initialized by this function.
Also adds clock lookup for shared clocks used by various drivers.
davinci-clock.h declares the various structures used for defining
the DaVinci clocks.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>

Comments

Sekhar Nori Oct. 11, 2012, 12:31 p.m. UTC | #1
Hi Murali,

I have given this patch a partial review. I suspect this patch will
change much based on the comment I gave for 9/13.

On 9/26/2012 11:40 PM, Murali Karicheri wrote:
> This is the common clk driver initialization function for DaVinci
> SoCs and other SoCs that uses similar hardware architecture.
> Different clocks present in the SoC are passed to this function
> using a clk table and this function initialize the various drivers.
> Existing driver such as clk-fixed-rate, clk-divider, clk-mux and
> DaVinci specific clk drivers are initialized by this function.
> Also adds clock lookup for shared clocks used by various drivers.
> davinci-clock.h declares the various structures used for defining
> the DaVinci clocks.
> 
> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
> 
> diff --git a/drivers/clk/davinci/davinci-clock.c b/drivers/clk/davinci/davinci-clock.c
> new file mode 100644
> index 0000000..cbd5201
> --- /dev/null
> +++ b/drivers/clk/davinci/davinci-clock.c
> @@ -0,0 +1,232 @@
> +/*
> + * Clock initialization code for DaVinci devices
> + *
> + * Copyright (C) 2006-2012 Texas Instruments.
> + * Copyright (C) 2008-2009 Deep Root Systems, LLC
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +#include <linux/init.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/platform_data/clk-davinci-pll.h>
> +#include <linux/platform_data/clk-keystone-pll.h>
> +#include <linux/platform_data/clk-davinci-psc.h>
> +#include <linux/platform_data/davinci-clock.h>

Needs to be kept sorted.

> +
> +static DEFINE_SPINLOCK(_lock);

No need of the underscore prefix.

> +
> +struct clk *davinci_lookup_clk(struct davinci_clk_lookup *clocks,
> +				const char *con_id)
> +{
> +	struct davinci_clk_lookup *c;
> +
> +	for (c = clocks; c->_clk; c++) {
> +		if (c->con_id && !strcmp(c->con_id, con_id))
> +			return c->clk;
> +	}
> +	return NULL;
> +}

This is a global function, but it is not exported in a header file.
Should this be static instead?

> +
> +#ifdef	CONFIG_CLK_DAVINCI_PLL
> +static void register_davinci_pll_clk(struct davinci_clk_lookup *c,
> +			struct clk_davinci_pll_data *pll_data)
> +{
> +
> +	WARN_ON(!pll_data->phy_pllm);

I don't think it is right to check for zero physical address. It is not
true on any of the DaVinci platforms, but it is possible to design
hardware where physical address of the PLL multipler is zero.

> +	pll_data->pllm = ioremap(pll_data->phy_pllm, 4);
> +	WARN_ON(!pll_data->pllm);

Along with the warning for users, you also need to return an -ENOMEM so
callers are aware? Or you can skip the WARN_ON and simply return -ENOMEM.

> +	if (pll_data->phy_prediv) {
> +		pll_data->prediv = ioremap(pll_data->phy_prediv, 4);
> +		WARN_ON(!pll_data->prediv);
> +	}
> +	if (pll_data->phy_postdiv) {
> +		pll_data->postdiv = ioremap(pll_data->phy_postdiv, 4);
> +		WARN_ON(!pll_data->postdiv);
> +	}

Comments above apply here as well.

> +	c->clk = clk_register_davinci_pll(NULL,
> +			c->_clk->name, c->_clk->parent->name,
> +			pll_data);
> +}
> +#else
> +static void register_davinci_pll_clk(struct davinci_clk_lookup *c,
> +			struct clk_davinci_pll_data *pll_data)
> +{
> +	return;
> +}
> +#endif
> +
> +#ifdef	CONFIG_CLK_KEYSTONE_PLL
> +static void register_keystone_pll_clk(struct davinci_clk_lookup *c,
> +			struct clk_keystone_pll_data *pll_data)
> +{
> +	WARN_ON(!pll_data->phy_pllm);
> +	pll_data->pllm = ioremap(pll_data->phy_pllm, 4);
> +	WARN_ON(!pll_data->pllm);
> +	WARN_ON(!pll_data->phy_main_pll_ctl0);
> +	pll_data->main_pll_ctl0 =
> +		ioremap(pll_data->phy_main_pll_ctl0, 4);
> +	WARN_ON(!pll_data->main_pll_ctl0);
> +	c->clk = clk_register_keystone_pll(NULL,
> +			c->_clk->name, c->_clk->parent->name,
> +			 pll_data);
> +}
> +#else
> +static void register_keystone_pll_clk(struct davinci_clk_lookup *c,
> +			struct clk_keystone_pll_data *pll_data)
> +{
> +	return;
> +}
> +#endif
> +
> +int __init davinci_common_clk_init(struct davinci_clk_lookup *clocks,
> +				struct davinci_dev_lookup *dev_clk_lookups,
> +				u8 num_gpscs, u32 *psc_bases)

psc_bases should be of type phys_add_t.

> +{
> +	void __iomem **base = NULL, *reg;
> +	struct davinci_clk_lookup *c;
> +	struct davinci_clk *_clk;
> +	unsigned long rate;
> +	int i, skip;
> +
> +	WARN_ON(!num_gpscs);

Need to return error if this is hit. In general revisit the need to
return an error wherever you have WARN_ON().

Thanks,
Sekhar
diff mbox

Patch

diff --git a/drivers/clk/davinci/davinci-clock.c b/drivers/clk/davinci/davinci-clock.c
new file mode 100644
index 0000000..cbd5201
--- /dev/null
+++ b/drivers/clk/davinci/davinci-clock.c
@@ -0,0 +1,232 @@ 
+/*
+ * Clock initialization code for DaVinci devices
+ *
+ * Copyright (C) 2006-2012 Texas Instruments.
+ * Copyright (C) 2008-2009 Deep Root Systems, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/init.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/platform_data/clk-davinci-pll.h>
+#include <linux/platform_data/clk-keystone-pll.h>
+#include <linux/platform_data/clk-davinci-psc.h>
+#include <linux/platform_data/davinci-clock.h>
+
+static DEFINE_SPINLOCK(_lock);
+
+struct clk *davinci_lookup_clk(struct davinci_clk_lookup *clocks,
+				const char *con_id)
+{
+	struct davinci_clk_lookup *c;
+
+	for (c = clocks; c->_clk; c++) {
+		if (c->con_id && !strcmp(c->con_id, con_id))
+			return c->clk;
+	}
+	return NULL;
+}
+
+#ifdef	CONFIG_CLK_DAVINCI_PLL
+static void register_davinci_pll_clk(struct davinci_clk_lookup *c,
+			struct clk_davinci_pll_data *pll_data)
+{
+
+	WARN_ON(!pll_data->phy_pllm);
+	pll_data->pllm = ioremap(pll_data->phy_pllm, 4);
+	WARN_ON(!pll_data->pllm);
+	if (pll_data->phy_prediv) {
+		pll_data->prediv = ioremap(pll_data->phy_prediv, 4);
+		WARN_ON(!pll_data->prediv);
+	}
+	if (pll_data->phy_postdiv) {
+		pll_data->postdiv = ioremap(pll_data->phy_postdiv, 4);
+		WARN_ON(!pll_data->postdiv);
+	}
+	c->clk = clk_register_davinci_pll(NULL,
+			c->_clk->name, c->_clk->parent->name,
+			pll_data);
+}
+#else
+static void register_davinci_pll_clk(struct davinci_clk_lookup *c,
+			struct clk_davinci_pll_data *pll_data)
+{
+	return;
+}
+#endif
+
+#ifdef	CONFIG_CLK_KEYSTONE_PLL
+static void register_keystone_pll_clk(struct davinci_clk_lookup *c,
+			struct clk_keystone_pll_data *pll_data)
+{
+	WARN_ON(!pll_data->phy_pllm);
+	pll_data->pllm = ioremap(pll_data->phy_pllm, 4);
+	WARN_ON(!pll_data->pllm);
+	WARN_ON(!pll_data->phy_main_pll_ctl0);
+	pll_data->main_pll_ctl0 =
+		ioremap(pll_data->phy_main_pll_ctl0, 4);
+	WARN_ON(!pll_data->main_pll_ctl0);
+	c->clk = clk_register_keystone_pll(NULL,
+			c->_clk->name, c->_clk->parent->name,
+			 pll_data);
+}
+#else
+static void register_keystone_pll_clk(struct davinci_clk_lookup *c,
+			struct clk_keystone_pll_data *pll_data)
+{
+	return;
+}
+#endif
+
+int __init davinci_common_clk_init(struct davinci_clk_lookup *clocks,
+				struct davinci_dev_lookup *dev_clk_lookups,
+				u8 num_gpscs, u32 *psc_bases)
+{
+	void __iomem **base = NULL, *reg;
+	struct davinci_clk_lookup *c;
+	struct davinci_clk *_clk;
+	unsigned long rate;
+	int i, skip;
+
+	WARN_ON(!num_gpscs);
+	WARN_ON(psc_bases == NULL);
+
+	base = kzalloc(sizeof(void __iomem *) * num_gpscs, GFP_KERNEL);
+	WARN_ON(!base);
+	for (i = 0; i < num_gpscs; i++) {
+		base[i] = ioremap(psc_bases[i], SZ_4K);
+		WARN_ON(!base[i]);
+	}
+
+	for (c = clocks; c->_clk; c++) {
+		skip = 0;
+		_clk = c->_clk;
+
+		WARN_ON(!_clk->clk_data.data);
+		switch (_clk->type) {
+		case DAVINCI_FIXED_RATE_CLK:
+		{
+			struct clk_fixed_rate_data *data = _clk->clk_data.fixed_rate;
+
+			if (data->recalc)
+				rate = data->recalc(0);
+			else
+				rate = data->rate;
+
+			c->clk = clk_register_fixed_rate(NULL, _clk->name,
+					NULL, data->flags, rate);
+			break;
+		}
+		case KEYSTONE_MAIN_PLL_CLK:
+		{
+			struct clk_keystone_pll_data *data =
+					_clk->clk_data.keystone_pll;
+
+			register_keystone_pll_clk(c, data);
+			break;
+		}
+		case DAVINCI_MAIN_PLL_CLK:
+		{
+			struct clk_davinci_pll_data *data =
+					_clk->clk_data.davinci_pll;
+
+			register_davinci_pll_clk(c, data);
+			break;
+		}
+		case DAVINCI_PRG_DIV_CLK:
+		{
+			struct clk_divider_data *data = _clk->clk_data.pll_div;
+
+			/* This is a PLL derived clock with divider specified by
+			 * div_reg in pll_div_data.
+			 */
+			reg = ioremap(data->div_reg, 4);
+			WARN_ON(!reg);
+			c->clk = clk_register_divider(NULL, _clk->name,
+					_clk->parent->name, data->flags,
+					reg, data->shift, data->width,
+					data->divider_flags, &_lock);
+			break;
+		}
+		case DAVINCI_PSC_CLK:
+		{
+			struct clk_davinci_psc_data *data = _clk->clk_data.psc;
+
+			WARN_ON(!base);
+			WARN_ON(data->gpsc >= num_gpscs);
+			data->base = base[data->gpsc];
+			c->clk = clk_register_davinci_psc(NULL, _clk->name,
+					_clk->parent->name, data, &_lock);
+			break;
+		}
+		case DAVINCI_MUX_CLK:
+		{
+			struct clk_mux_data *data = _clk->clk_data.mux;
+
+			WARN_ON(!data->phys_base);
+			reg = ioremap(data->phys_base, 4);
+			WARN_ON(!reg);
+			c->clk = clk_register_mux(NULL, _clk->name,
+					data->parents, data->num_parents,
+					data->flags, reg, data->shift,
+					data->width, data->mux_flags, &_lock);
+			break;
+		}
+		case DAVINCI_FIXED_FACTOR_CLK:
+		{
+			struct clk_fixed_factor_data *data
+						 = _clk->clk_data.fixed_factor;
+
+			WARN_ON(!data->mult);
+			WARN_ON(!data->div);
+			c->clk = clk_register_fixed_factor(NULL, _clk->name,
+					_clk->parent->name, data->flags,
+					data->mult, data->div);
+			break;
+		}
+		default:
+			skip = 1;
+			pr_warn("Unknown clock - %s\n", _clk->name);
+		}
+
+		if (!skip) {
+			WARN_ON(!c->clk);
+			if (clk_register_clkdev(c->clk,
+					c->con_id, c->dev_id) < 0) {
+				pr_err("Error in registering clkdev, %s\n",
+					_clk->name);
+			}
+			/* Enable ALWAYS_ENABLED clocks */
+			if (_clk->flags & ALWAYS_ENABLED)
+				clk_prepare_enable(c->clk);
+		}
+	}
+
+	if (dev_clk_lookups) {
+		struct davinci_dev_lookup *c;
+		struct clk *clk;
+
+		for (c = dev_clk_lookups; c->con_id; c++) {
+			/* register the clock lookup table */
+			clk = davinci_lookup_clk(clocks, c->con_id);
+			WARN_ON(!clk);
+
+			for (i = 0; i < c->num_devs; i++) {
+				if (clk_register_clkdev(clk,
+					c->lookups[i].con_id,
+					c->lookups[i].dev_id) < 0) {
+					pr_err("Error in registering clkdev" \
+						" for dev_id %s\n",
+						c->lookups[i].dev_id);
+				}
+			}
+		}
+	}
+	return 0;
+}
diff --git a/include/linux/platform_data/davinci-clock.h b/include/linux/platform_data/davinci-clock.h
new file mode 100644
index 0000000..942547e
--- /dev/null
+++ b/include/linux/platform_data/davinci-clock.h
@@ -0,0 +1,145 @@ 
+/*
+ * TI DaVinci Clock definitions -  Contains Macros and Types used for
+ * defining various clocks on a DaVinci SoC
+ *
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DAVINCI_CLOCK_H
+#define __DAVINCI_CLOCK_H
+
+#include <linux/types.h>
+
+struct clk;
+
+#define CLK(dev, con, ck)	\
+	{			\
+		.dev_id = dev,	\
+		.con_id = con,	\
+		._clk = ck,	\
+	}			\
+
+/* general flags: */
+#define ALWAYS_ENABLED		BIT(0)
+
+/* configuration data for clk mux */
+struct clk_mux_data {
+	u32			flags;
+	u8			mux_flags;
+	u8			shift;
+	u8			width;
+	u8			num_parents;
+	const char		**parents;
+	u32			phys_base;
+};
+
+/* configuration data for PLL divider clock */
+struct clk_divider_data {
+	u32			flags;
+	u8			divider_flags;
+	u32                     div_reg;
+	/* H/W supported max rate */
+	unsigned long		maxrate;
+	/* Width and shift for divider clock register mask */
+	u8			shift;
+	u8			width;
+};
+
+/* configuration data for fixed factor clocks. Some clocks in DaVinci are just
+ * duplicate clock pins that can be represented by this using a factor of 1
+ * for multiplier and divider
+ */
+struct clk_fixed_factor_data {
+	u32			flags;
+	u32			mult;
+	u32			div;
+};
+
+/* configuration data for fixed ref clock */
+struct clk_fixed_rate_data {
+	u32			flags;
+	unsigned long		rate;
+	/* where a register has input clock rate settings this function
+	 * is used to read that value from SoC specific code
+	 */
+	unsigned long		(*recalc)(unsigned long parent_rate);
+};
+
+/* forward declaration for other clock drivers */
+struct clk_davinci_pll_data;
+struct clk_keystone_pll_data;
+struct clk_psc_data;
+
+enum davinci_clk_type {
+	DAVINCI_MAIN_PLL_CLK,
+	KEYSTONE_MAIN_PLL_CLK,
+	DAVINCI_FIXED_RATE_CLK,
+	/* Use programmable divider */
+	DAVINCI_PRG_DIV_CLK,
+	/* Use fixed divider and multiplier */
+	DAVINCI_FIXED_FACTOR_CLK,
+	DAVINCI_PSC_CLK,
+	DAVINCI_MUX_CLK,
+};
+
+/* struct for defining DaVinci clocks for a SoC. Only one of the data ptr
+ * to be valid (non NULL). davinci_clk_init() in drivers/clk/davinci/clock.c
+ * check these ptr values to determine what clock register function to call
+ * to register a particular clock.
+ */
+struct davinci_clk {
+	const char			*name;
+	/* General flag for all drivers */
+	u32				flags;
+	struct davinci_clk		*parent;
+	enum davinci_clk_type		type;
+	/* one of these will be present in each SoC */
+	union {
+		/* root ref clock data */
+		struct clk_fixed_rate_data	*fixed_rate;
+		struct clk_davinci_pll_data	*davinci_pll;
+		struct clk_keystone_pll_data	*keystone_pll;
+		struct clk_divider_data		*pll_div;
+		struct clk_davinci_psc_data	*psc;
+		struct clk_mux_data		*mux;
+		struct clk_fixed_factor_data	*fixed_factor;
+		void				*data;
+	} clk_data;
+};
+
+/* struct for the DaVinci clock tables. */
+struct davinci_clk_lookup {
+	const char		*dev_id;
+	const char		*con_id;
+	struct davinci_clk      *_clk;
+	/* This saves the opaque clk ptr returned by clk_register() and is
+	 * saved to use later to register clkdevs for a specific clk node.
+	 */
+	struct clk		*clk;
+};
+
+/* struct for the DaVinci clkdev lookups. When several drivers uses the same
+ * clock, this structure is used to define a dev look up table that maps
+ * clkdevs to a clks node.
+ */
+struct davinci_dev_lookup {
+	const char		*con_id;
+	unsigned short		num_devs;
+	struct clk_lookup	*lookups;
+};
+
+/* clock init function for a DaVinci SoC (defined in drivers/clk/clock.c).
+ * This can also be used on other TI SoCs that has similar clock hardware.
+ */
+extern int davinci_common_clk_init(struct davinci_clk_lookup *clocks,
+				struct davinci_dev_lookup *dev_lookups,
+				u8 num_gpscs, u32 *psc_bases);
+#endif