diff mbox

[v6,01/16] clk: samsung: add common clock framework helper functions for Samsung platforms

Message ID 1361175686-19400-2-git-send-email-thomas.abraham@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Thomas Abraham Feb. 18, 2013, 8:21 a.m. UTC
All Samsung platforms include different types of clock including fixed-rate,
mux, divider and gate clock types. There are typically hundreds of such clocks
on each of the Samsung platforms. To enable Samsung platforms to register these
clocks using the common clock framework, a bunch of utility functions are
introduced here which simplify the clock registration process. The clocks are
usually statically instantiated and registered with common clock framework.

Cc: Mike Turquette <mturquette@linaro.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Tested-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Tested-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
 drivers/clk/Makefile         |    1 +
 drivers/clk/samsung/Makefile |    5 +
 drivers/clk/samsung/clk.c    |  273 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.h    |  262 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 541 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/samsung/Makefile
 create mode 100644 drivers/clk/samsung/clk.c
 create mode 100644 drivers/clk/samsung/clk.h

Comments

Heiko Stübner March 3, 2013, 1:08 a.m. UTC | #1
Hi,

Am Montag, 18. Februar 2013, 09:21:11 schrieb Thomas Abraham:
> All Samsung platforms include different types of clock including
> fixed-rate, mux, divider and gate clock types. There are typically
> hundreds of such clocks on each of the Samsung platforms. To enable
> Samsung platforms to register these clocks using the common clock
> framework, a bunch of utility functions are introduced here which simplify
> the clock registration process. The clocks are usually statically
> instantiated and registered with common clock framework.
> 
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: Kukjin Kim <kgene.kim@samsung.com>
> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> Tested-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> Reviewed-by: Tomasz Figa <t.figa@samsung.com>
> Tested-by: Tomasz Figa <t.figa@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>

I'm playing around with this on my s3c2416 platform and it works like a charm 
for the most part - and the system already comes sort of up again :-) .

So,
Tested-by: Heiko Stuebner <heiko@sntech.de>


But is there an easy way to define more than one alias? On the s3c2416 for 
example the hsmmc hclk is the "hsmmc" io-clock, as well as the source for the 
"mmc_busclk.0". Same for the "uart" pclk, that is also a baud clock source.


Thanks
Heiko
Sylwester Nawrocki March 3, 2013, 11:17 a.m. UTC | #2
Hi,

On 03/03/2013 02:08 AM, Heiko Stübner wrote:
> But is there an easy way to define more than one alias? On the s3c2416 for
> example the hsmmc hclk is the "hsmmc" io-clock, as well as the source for the
> "mmc_busclk.0". Same for the "uart" pclk, that is also a baud clock source.

This driver currently provides for only one additional clkdev lookup entry
per a platform clock. I pointed out this desing issue in the early version
of the patch set. It's because a machine clock definition is coupled with
a clock consumer definition. And IMO various samsung_clock_register_*
functions should not have clk_register_clkdev() inside them. I.e. first
step could be registering all machine clocks and in the second one clkdev
lookup entries could be created. This is how most (all?) existing SoC
clock drivers are working.

But those multiple aliases are important only for machines with device
tree support, aren't they ?

I hope this patch series gets merged early to linux-next in the 3.10
cycle so the multiple accumulated fixup patches for this clock driver
can be merged as well and issues like that you pointed out can be
resolved with incremental patches.

Regards,
Sylwester
Tomasz Figa March 3, 2013, 11:45 a.m. UTC | #3
Hi,

On Sunday 03 of March 2013 12:17:29 Sylwester Nawrocki wrote:
> Hi,
> 
> On 03/03/2013 02:08 AM, Heiko Stübner wrote:
> > But is there an easy way to define more than one alias? On the s3c2416
> > for example the hsmmc hclk is the "hsmmc" io-clock, as well as the
> > source for the "mmc_busclk.0". Same for the "uart" pclk, that is also
> > a baud clock source.
> This driver currently provides for only one additional clkdev lookup
> entry per a platform clock. I pointed out this desing issue in the
> early version of the patch set. It's because a machine clock definition
> is coupled with a clock consumer definition. And IMO various
> samsung_clock_register_* functions should not have
> clk_register_clkdev() inside them. I.e. first step could be registering
> all machine clocks and in the second one clkdev lookup entries could be
> created. This is how most (all?) existing SoC clock drivers are
> working.
> 
> But those multiple aliases are important only for machines with device
> tree support, aren't they ?

I suppose you meant _without_ device tree support, right?

> I hope this patch series gets merged early to linux-next in the 3.10
> cycle so the multiple accumulated fixup patches for this clock driver
> can be merged as well and issues like that you pointed out can be
> resolved with incremental patches.

Yes, I hope so too.

Best regards,
Tomasz
Sylwester Nawrocki March 3, 2013, 11:59 a.m. UTC | #4
On 03/03/2013 12:17 PM, Sylwester Nawrocki wrote:
> On 03/03/2013 02:08 AM, Heiko Stübner wrote:
>> But is there an easy way to define more than one alias? On the s3c2416
>> for
>> example the hsmmc hclk is the "hsmmc" io-clock, as well as the source
>> for the
>> "mmc_busclk.0". Same for the "uart" pclk, that is also a baud clock
>> source.
[...]
> But those multiple aliases are important only for machines with device
                                                              ^^^^^
Sorry, this should have read "without". Also please note that due to
representing original struct clk_clksrc objects (mux + div + gate clock)
with separate primitive clocks device drivers may not work as before
where clk_{set/get}_parent() was called. I.e. a separate consumer clock
id needs to be used to control a clock mux. Hmm, however this issue
doesn't affect anything on s3c24xx, since such composite clocks have
been introduced only starting from s3c64xx.

I guess to create multiple aliases now a new helper function could be
created that takes as an argument a clock index (as in enum exynos4_clks)
and adds a clkdev lookup entry to a matched clk object. Probably it
wouldn't be difficult to rework the driver to be registering all clkdev
entries like this.

Do you have your source tree in any public git available ? ;) Perhaps
I could find a time to adjust and try it with s3c2440 based board.

> tree support, aren't they ?
Heiko Stübner March 3, 2013, 12:34 p.m. UTC | #5
Am Sonntag, 3. März 2013, 12:59:03 schrieb Sylwester Nawrocki:
> On 03/03/2013 12:17 PM, Sylwester Nawrocki wrote:
> > On 03/03/2013 02:08 AM, Heiko Stübner wrote:
> >> But is there an easy way to define more than one alias? On the s3c2416
> >> for
> >> example the hsmmc hclk is the "hsmmc" io-clock, as well as the source
> >> for the
> >> "mmc_busclk.0". Same for the "uart" pclk, that is also a baud clock
> >> source.
> 
> [...]
> 
> > But those multiple aliases are important only for machines with device
> 
>                                                               ^^^^^
> Sorry, this should have read "without". Also please note that due to
> representing original struct clk_clksrc objects (mux + div + gate clock)
> with separate primitive clocks device drivers may not work as before
> where clk_{set/get}_parent() was called. I.e. a separate consumer clock
> id needs to be used to control a clock mux. Hmm, however this issue
> doesn't affect anything on s3c24xx, since such composite clocks have
> been introduced only starting from s3c64xx.
> 
> I guess to create multiple aliases now a new helper function could be
> created that takes as an argument a clock index (as in enum exynos4_clks)
> and adds a clkdev lookup entry to a matched clk object. Probably it
> wouldn't be difficult to rework the driver to be registering all clkdev
> entries like this.
> 
> Do you have your source tree in any public git available ? ;) Perhaps
> I could find a time to adjust and try it with s3c2440 based board.

It's all quite messy still :-) ... I just managed to fix my last boot issues 
with adding the baud clock aliases. 

As I'm currently working on a linux-next variant with a lot of pending patches 
merged in, there is no public git tree of it. But I've attached an archive of 
the changes I did. As always I'm doing s3c2416 and s3c2443 as they are quite 
similar, but as always there is a big difference to SoCs earlier than s3c2443.


Heiko
Kim Kukjin March 7, 2013, 1:44 a.m. UTC | #6
Tomasz Figa wrote:
> 
> Hi,
> 
> On Sunday 03 of March 2013 12:17:29 Sylwester Nawrocki wrote:
> > Hi,
> >
> > On 03/03/2013 02:08 AM, Heiko Stübner wrote:
> > > But is there an easy way to define more than one alias? On the s3c2416
> > > for example the hsmmc hclk is the "hsmmc" io-clock, as well as the
> > > source for the "mmc_busclk.0". Same for the "uart" pclk, that is also
> > > a baud clock source.
> > This driver currently provides for only one additional clkdev lookup
> > entry per a platform clock. I pointed out this desing issue in the
> > early version of the patch set. It's because a machine clock definition
> > is coupled with a clock consumer definition. And IMO various
> > samsung_clock_register_* functions should not have
> > clk_register_clkdev() inside them. I.e. first step could be registering
> > all machine clocks and in the second one clkdev lookup entries could be
> > created. This is how most (all?) existing SoC clock drivers are
> > working.
> >
> > But those multiple aliases are important only for machines with device
> > tree support, aren't they ?
> 
> I suppose you meant _without_ device tree support, right?
> 
> > I hope this patch series gets merged early to linux-next in the 3.10
> > cycle so the multiple accumulated fixup patches for this clock driver
> > can be merged as well and issues like that you pointed out can be
> > resolved with incremental patches.
> 
> Yes, I hope so too.
>
Yes, I will in this weekend.

Note, I will modify [07/16] for universal_c210 as per Kyungmin's request,
I'm not sure about universal_c210 though.

Thanks.

- Kukjin
Kim Kukjin March 9, 2013, 9:15 a.m. UTC | #7
Kukjin Kim wrote:

[...]

Thomas,

As I said, I applied this whole series into Samsung tree, following error
happens with exynos4_defconfig(non-DT) though.

drivers/clk/samsung/clk.c: In function 'samsung_clk_of_register_fixed_ext':
drivers/clk/samsung/clk.c:251:2: error: implicit declaration of function
'for_each_matching_node_and_match' [-Werror=implicit-function-declaration]
drivers/clk/samsung/clk.c:251:60: error: expected ';' before '{' token
drivers/clk/samsung/clk.c:249:6: warning: unused variable 'freq'
[-Wunused-variable]
cc1: some warnings being treated as errors
make[3]: *** [drivers/clk/samsung/clk.o] Error 1
make[2]: *** [drivers/clk/samsung] Error 2
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [drivers/clk] Error 2
make[1]: *** Waiting for unfinished jobs....
make: *** [drivers] Error 2
make: *** Waiting for unfinished jobs....

I think, it's time to decide to support non-DT exynos continuously, above
compilation error can be fixed though.

Hey guys, how do you think?

- Kukjin
diff mbox

Patch

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 0ad642f..1467a48 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -26,6 +26,7 @@  obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o
 obj-$(CONFIG_ARCH_U8500)	+= ux500/
 obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
 obj-$(CONFIG_ARCH_ZYNQ)		+= clk-zynq.o
+obj-$(CONFIG_PLAT_SAMSUNG)	+= samsung/
 
 # Chip specific
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
new file mode 100644
index 0000000..bd920b4
--- /dev/null
+++ b/drivers/clk/samsung/Makefile
@@ -0,0 +1,5 @@ 
+#
+# Samsung Clock specific Makefile
+#
+
+obj-$(CONFIG_COMMON_CLK)	+= clk.o
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
new file mode 100644
index 0000000..aea1fb9
--- /dev/null
+++ b/drivers/clk/samsung/clk.c
@@ -0,0 +1,273 @@ 
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file includes utility functions to register clocks to common
+ * clock framework for Samsung platforms.
+*/
+
+#include <linux/syscore_ops.h>
+#include "clk.h"
+
+static DEFINE_SPINLOCK(lock);
+static struct clk **clk_table;
+static void __iomem *reg_base;
+#ifdef CONFIG_OF
+static struct clk_onecell_data clk_data;
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static struct samsung_clk_reg_dump *reg_dump;
+static unsigned long nr_reg_dump;
+
+static int samsung_clk_suspend(void)
+{
+	struct samsung_clk_reg_dump *rd = reg_dump;
+	unsigned long i;
+
+	for (i = 0; i < nr_reg_dump; i++, rd++)
+		rd->value = __raw_readl(reg_base + rd->offset);
+
+	return 0;
+}
+
+static void samsung_clk_resume(void)
+{
+	struct samsung_clk_reg_dump *rd = reg_dump;
+	unsigned long i;
+
+	for (i = 0; i < nr_reg_dump; i++, rd++)
+		__raw_writel(rd->value, reg_base + rd->offset);
+}
+
+static struct syscore_ops samsung_clk_syscore_ops = {
+	.suspend	= samsung_clk_suspend,
+	.resume		= samsung_clk_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+/* setup the essentials required to support clock lookup using ccf */
+void __init samsung_clk_init(struct device_node *np, void __iomem *base,
+		unsigned long nr_clks, unsigned long *rdump,
+		unsigned long nr_rdump)
+{
+	reg_base = base;
+	if (!np)
+		return;
+
+#ifdef CONFIG_OF
+	clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
+	if (!clk_table)
+		panic("could not allocate clock lookup table\n");
+
+	clk_data.clks = clk_table;
+	clk_data.clk_num = nr_clks;
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+	if (rdump && nr_rdump) {
+		unsigned int idx;
+		reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
+					* nr_rdump, GFP_KERNEL);
+		if (!reg_dump) {
+			pr_err("%s: memory alloc for register dump failed\n",
+					__func__);
+			return;
+		}
+
+		for (idx = 0; idx < nr_rdump; idx++)
+			reg_dump[idx].offset = rdump[idx];
+		nr_reg_dump = nr_rdump;
+		register_syscore_ops(&samsung_clk_syscore_ops);
+	}
+#endif
+}
+
+/* add a clock instance to the clock lookup table used for dt based lookup */
+void samsung_clk_add_lookup(struct clk *clk, unsigned int id)
+{
+	if (clk_table && id)
+		clk_table[id] = clk;
+}
+
+/* register a list of fixed clocks */
+void __init samsung_clk_register_fixed_rate(
+		struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx, ret;
+
+	for (idx = 0; idx < nr_clk; idx++, list++) {
+		clk = clk_register_fixed_rate(NULL, list->name,
+			list->parent_name, list->flags, list->fixed_rate);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+
+		samsung_clk_add_lookup(clk, list->id);
+
+		/*
+		 * Unconditionally add a clock lookup for the fixed rate clocks.
+		 * There are not many of these on any of Samsung platforms.
+		 */
+		ret = clk_register_clkdev(clk, list->name, NULL);
+		if (ret)
+			pr_err("%s: failed to register clock lookup for %s",
+				__func__, list->name);
+	}
+}
+
+/* register a list of fixed factor clocks */
+void __init samsung_clk_register_fixed_factor(
+		struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx;
+
+	for (idx = 0; idx < nr_clk; idx++, list++) {
+		clk = clk_register_fixed_factor(NULL, list->name,
+			list->parent_name, list->flags, list->mult, list->div);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+
+		samsung_clk_add_lookup(clk, list->id);
+	}
+}
+
+/* register a list of mux clocks */
+void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
+					unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx, ret;
+
+	for (idx = 0; idx < nr_clk; idx++, list++) {
+		clk = clk_register_mux(NULL, list->name, list->parent_names,
+			list->num_parents, list->flags, reg_base + list->offset,
+			list->shift, list->width, list->mux_flags, &lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+
+		samsung_clk_add_lookup(clk, list->id);
+
+		/* register a clock lookup only if a clock alias is specified */
+		if (list->alias) {
+			ret = clk_register_clkdev(clk, list->alias,
+						list->dev_name);
+			if (ret)
+				pr_err("%s: failed to register lookup %s\n",
+						__func__, list->alias);
+		}
+	}
+}
+
+/* register a list of div clocks */
+void __init samsung_clk_register_div(struct samsung_div_clock *list,
+					unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx, ret;
+
+	for (idx = 0; idx < nr_clk; idx++, list++) {
+		clk = clk_register_divider(NULL, list->name, list->parent_name,
+			list->flags, reg_base + list->offset, list->shift,
+			list->width, list->div_flags, &lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+
+		samsung_clk_add_lookup(clk, list->id);
+
+		/* register a clock lookup only if a clock alias is specified */
+		if (list->alias) {
+			ret = clk_register_clkdev(clk, list->alias,
+						list->dev_name);
+			if (ret)
+				pr_err("%s: failed to register lookup %s\n",
+						__func__, list->alias);
+		}
+	}
+}
+
+/* register a list of gate clocks */
+void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
+						unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx, ret;
+
+	for (idx = 0; idx < nr_clk; idx++, list++) {
+		clk = clk_register_gate(NULL, list->name, list->parent_name,
+				list->flags, reg_base + list->offset,
+				list->bit_idx, list->gate_flags, &lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				list->name);
+			continue;
+		}
+
+		/* register a clock lookup only if a clock alias is specified */
+		if (list->alias) {
+			ret = clk_register_clkdev(clk, list->alias,
+							list->dev_name);
+			if (ret)
+				pr_err("%s: failed to register lookup %s\n",
+					__func__, list->alias);
+		}
+
+		samsung_clk_add_lookup(clk, list->id);
+	}
+}
+
+/*
+ * obtain the clock speed of all external fixed clock sources from device
+ * tree and register it
+ */
+void __init samsung_clk_of_register_fixed_ext(
+			struct samsung_fixed_rate_clock *fixed_rate_clk,
+			unsigned int nr_fixed_rate_clk,
+			struct of_device_id *clk_matches)
+{
+	const struct of_device_id *match;
+	struct device_node *np;
+	u32 freq;
+
+	for_each_matching_node_and_match(np, clk_matches, &match) {
+		if (of_property_read_u32(np, "clock-frequency", &freq))
+			continue;
+		fixed_rate_clk[(u32)match->data].fixed_rate = freq;
+	}
+	samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk);
+}
+
+/* utility function to get the rate of a specified clock */
+unsigned long _get_rate(const char *clk_name)
+{
+	struct clk *clk;
+	unsigned long rate;
+
+	clk = clk_get(NULL, clk_name);
+	if (IS_ERR(clk)) {
+		pr_err("%s: could not find clock %s\n", __func__, clk_name);
+		return 0;
+	}
+	rate = clk_get_rate(clk);
+	clk_put(clk);
+	return rate;
+}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
new file mode 100644
index 0000000..961192f
--- /dev/null
+++ b/drivers/clk/samsung/clk.h
@@ -0,0 +1,262 @@ 
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for all Samsung platforms
+*/
+
+#ifndef __SAMSUNG_CLK_H
+#define __SAMSUNG_CLK_H
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <mach/map.h>
+
+/**
+ * struct samsung_fixed_rate_clock: information about fixed-rate clock
+ * @id: platform specific id of the clock.
+ * @name: name of this fixed-rate clock.
+ * @parent_name: optional parent clock name.
+ * @flags: optional fixed-rate clock flags.
+ * @fixed-rate: fixed clock rate of this clock.
+ */
+struct samsung_fixed_rate_clock {
+	unsigned int		id;
+	char			*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		fixed_rate;
+};
+
+#define FRATE(_id, cname, pname, f, frate)		\
+	{						\
+		.id		= _id,			\
+		.name		= cname,		\
+		.parent_name	= pname,		\
+		.flags		= f,			\
+		.fixed_rate	= frate,		\
+	}
+
+/*
+ * struct samsung_fixed_factor_clock: information about fixed-factor clock
+ * @id: platform specific id of the clock.
+ * @name: name of this fixed-factor clock.
+ * @parent_name: parent clock name.
+ * @mult: fixed multiplication factor.
+ * @div: fixed division factor.
+ * @flags: optional fixed-factor clock flags.
+ */
+struct samsung_fixed_factor_clock {
+	unsigned int		id;
+	char			*name;
+	const char		*parent_name;
+	unsigned long		mult;
+	unsigned long		div;
+	unsigned long		flags;
+};
+
+#define FFACTOR(_id, cname, pname, m, d, f)		\
+	{						\
+		.id		= _id,			\
+		.name		= cname,		\
+		.parent_name	= pname,		\
+		.mult		= m,			\
+		.div		= d,			\
+		.flags		= f,			\
+	}
+
+/**
+ * struct samsung_mux_clock: information about mux clock
+ * @id: platform specific id of the clock.
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this mux clock.
+ * @parent_names: array of pointer to parent clock names.
+ * @num_parents: number of parents listed in @parent_names.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the mux.
+ * @shift: starting bit location of the mux control bit-field in @reg.
+ * @width: width of the mux control bit-field in @reg.
+ * @mux_flags: flags for mux-type clock.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct samsung_mux_clock {
+	unsigned int		id;
+	const char		*dev_name;
+	const char		*name;
+	const char		**parent_names;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			mux_flags;
+	const char		*alias;
+};
+
+#define __MUX(_id, dname, cname, pnames, o, s, w, f, mf, a)	\
+	{							\
+		.id		= _id,				\
+		.dev_name	= dname,			\
+		.name		= cname,			\
+		.parent_names	= pnames,			\
+		.num_parents	= ARRAY_SIZE(pnames),		\
+		.flags		= f,				\
+		.offset		= o,				\
+		.shift		= s,				\
+		.width		= w,				\
+		.mux_flags	= mf,				\
+		.alias		= a,				\
+	}
+
+#define MUX(_id, cname, pnames, o, s, w)			\
+	__MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, NULL)
+
+#define MUX_A(_id, cname, pnames, o, s, w, a)			\
+	__MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, a)
+
+#define MUX_F(_id, cname, pnames, o, s, w, f, mf)		\
+	__MUX(_id, NULL, cname, pnames, o, s, w, f, mf, NULL)
+
+/**
+ * @id: platform specific id of the clock.
+ * struct samsung_div_clock: information about div clock
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this div clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the div.
+ * @shift: starting bit location of the div control bit-field in @reg.
+ * @div_flags: flags for div-type clock.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct samsung_div_clock {
+	unsigned int		id;
+	const char		*dev_name;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			div_flags;
+	const char		*alias;
+};
+
+#define __DIV(_id, dname, cname, pname, o, s, w, f, df, a)	\
+	{							\
+		.id		= _id,				\
+		.dev_name	= dname,			\
+		.name		= cname,			\
+		.parent_name	= pname,			\
+		.flags		= f,				\
+		.offset		= o,				\
+		.shift		= s,				\
+		.width		= w,				\
+		.div_flags	= df,				\
+		.alias		= a,				\
+	}
+
+#define DIV(_id, cname, pname, o, s, w)				\
+	__DIV(_id, NULL, cname, pname, o, s, w, 0, 0, NULL)
+
+#define DIV_A(_id, cname, pname, o, s, w, a)			\
+	__DIV(_id, NULL, cname, pname, o, s, w, 0, 0, a)
+
+#define DIV_F(_id, cname, pname, o, s, w, f, df)		\
+	__DIV(_id, NULL, cname, pname, o, s, w, f, df, NULL)
+
+/**
+ * struct samsung_gate_clock: information about gate clock
+ * @id: platform specific id of the clock.
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this gate clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the gate.
+ * @bit_idx: bit index of the gate control bit-field in @reg.
+ * @gate_flags: flags for gate-type clock.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct samsung_gate_clock {
+	unsigned int		id;
+	const char		*dev_name;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			bit_idx;
+	u8			gate_flags;
+	const char		*alias;
+};
+
+#define __GATE(_id, dname, cname, pname, o, b, f, gf, a)	\
+	{							\
+		.id		= _id,				\
+		.dev_name	= dname,			\
+		.name		= cname,			\
+		.parent_name	= pname,			\
+		.flags		= f,				\
+		.offset		= o,				\
+		.bit_idx	= b,				\
+		.gate_flags	= gf,				\
+		.alias		= a,				\
+	}
+
+#define GATE(_id, cname, pname, o, b, f, gf)			\
+	__GATE(_id, NULL, cname, pname, o, b, f, gf, NULL)
+
+#define GATE_A(_id, cname, pname, o, b, f, gf, a)		\
+	__GATE(_id, NULL, cname, pname, o, b, f, gf, a)
+
+#define GATE_D(_id, dname, cname, pname, o, b, f, gf)		\
+	__GATE(_id, dname, cname, pname, o, b, f, gf, NULL)
+
+#define GATE_DA(_id, dname, cname, pname, o, b, f, gf, a)	\
+	__GATE(_id, dname, cname, pname, o, b, f, gf, a)
+
+#define PNAME(x) static const char *x[] __initdata
+
+/**
+ * struct samsung_clk_reg_dump: register dump of clock controller registers.
+ * @offset: clock register offset from the controller base address.
+ * @value: the value to be register at offset.
+ */
+struct samsung_clk_reg_dump {
+	u32	offset;
+	u32	value;
+};
+
+extern void __init samsung_clk_init(struct device_node *np, void __iomem *base,
+		unsigned long nr_clks, unsigned long *rdump,
+		unsigned long nr_rdump);
+extern void __init samsung_clk_of_register_fixed_ext(
+		struct samsung_fixed_rate_clock *fixed_rate_clk,
+		unsigned int nr_fixed_rate_clk,
+		struct of_device_id *clk_matches);
+
+extern void samsung_clk_add_lookup(struct clk *clk, unsigned int id);
+
+extern void __init samsung_clk_register_fixed_rate(
+		struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk);
+extern void __init samsung_clk_register_fixed_factor(
+		struct samsung_fixed_factor_clock *list, unsigned int nr_clk);
+extern void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list,
+		unsigned int nr_clk);
+extern void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
+		unsigned int nr_clk);
+extern void __init samsung_clk_register_gate(
+		struct samsung_gate_clock *clk_list, unsigned int nr_clk);
+
+extern unsigned long _get_rate(const char *clk_name);
+
+#endif /* __SAMSUNG_CLK_H */