zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/Kconfig b/ap/os/linux/linux-3.4.x/drivers/clk/Kconfig
new file mode 100644
index 0000000..165e1fe
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/Kconfig
@@ -0,0 +1,47 @@
+
+config CLKDEV_LOOKUP
+	bool
+	select HAVE_CLK
+
+config HAVE_CLK_PREPARE
+	bool
+
+config HAVE_MACH_CLKDEV
+	bool
+
+config COMMON_CLK
+	bool
+	select HAVE_CLK_PREPARE
+	---help---
+	  The common clock framework is a single definition of struct
+	  clk, useful across many platforms, as well as an
+	  implementation of the clock API in include/linux/clk.h.
+	  Architectures utilizing the common struct clk should select
+	  this option.
+
+menu "Common Clock Framework"
+	depends on COMMON_CLK
+
+config COMMON_CLK_DISABLE_UNUSED
+	bool "Disabled unused clocks at boot"
+	depends on COMMON_CLK
+	---help---
+	  Traverses the entire clock tree and disables any clocks that are
+	  enabled in hardware but have not been enabled by any device drivers.
+	  This saves power and keeps the software model of the clock in line
+	  with reality.
+
+	  If in doubt, say "N".
+
+config COMMON_CLK_DEBUG
+	bool "DebugFS representation of clock tree"
+	depends on COMMON_CLK
+	select DEBUG_FS
+	---help---
+	  Creates a directory hierchy in debugfs for visualizing the clk
+	  tree structure.  Each directory contains read-only members
+	  that export information specific to that clk node: clk_rate,
+	  clk_flags, clk_prepare_count, clk_enable_count &
+	  clk_notifier_count.
+
+endmenu
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/Makefile b/ap/os/linux/linux-3.4.x/drivers/clk/Makefile
new file mode 100644
index 0000000..df513c4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/Makefile
@@ -0,0 +1,5 @@
+
+obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
+obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-fixed-rate.o clk-gate.o \
+				   clk-mux.o clk-divider.o
+obj-$(CONFIG_PLAT_ZTE)		+= zte/
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/clk-divider.c b/ap/os/linux/linux-3.4.x/drivers/clk/clk-divider.c
new file mode 100644
index 0000000..d5ac6a7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/clk-divider.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Adjustable divider clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+
+/*
+ * DOC: basic adjustable divider clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is adjustable.  clk->rate = parent->rate / divisor
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+
+#define div_mask(d)	((1 << (d->width)) - 1)
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct clk_divider *divider = to_clk_divider(hw);
+	unsigned int div;
+
+	div = readl(divider->reg) >> divider->shift;
+	div &= div_mask(divider);
+
+	if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
+		div++;
+
+	return parent_rate / div;
+}
+EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
+
+/*
+ * The reverse of DIV_ROUND_UP: The maximum number which
+ * divided by m is r
+ */
+#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
+
+static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
+		unsigned long *best_parent_rate)
+{
+	struct clk_divider *divider = to_clk_divider(hw);
+	int i, bestdiv = 0;
+	unsigned long parent_rate, best = 0, now, maxdiv;
+
+	if (!rate)
+		rate = 1;
+
+	maxdiv = (1 << divider->width);
+
+	if (divider->flags & CLK_DIVIDER_ONE_BASED)
+		maxdiv--;
+
+	if (!best_parent_rate) {
+		parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+		bestdiv = DIV_ROUND_UP(parent_rate, rate);
+		bestdiv = bestdiv == 0 ? 1 : bestdiv;
+		bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
+		return bestdiv;
+	}
+
+	/*
+	 * The maximum divider we can use without overflowing
+	 * unsigned long in rate * i below
+	 */
+	maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+	for (i = 1; i <= maxdiv; i++) {
+		parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
+				MULT_ROUND_UP(rate, i));
+		now = parent_rate / i;
+		if (now <= rate && now > best) {
+			bestdiv = i;
+			best = now;
+			*best_parent_rate = parent_rate;
+		}
+	}
+
+	if (!bestdiv) {
+		bestdiv = (1 << divider->width);
+		if (divider->flags & CLK_DIVIDER_ONE_BASED)
+			bestdiv--;
+		*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
+	}
+
+	return bestdiv;
+}
+
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	int div;
+	div = clk_divider_bestdiv(hw, rate, prate);
+
+	if (prate)
+		return *prate / div;
+	else {
+		unsigned long r;
+		r = __clk_get_rate(__clk_get_parent(hw->clk));
+		return r / div;
+	}
+}
+EXPORT_SYMBOL_GPL(clk_divider_round_rate);
+
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_divider *divider = to_clk_divider(hw);
+	unsigned int div;
+	unsigned long flags = 0;
+	u32 val;
+
+	div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate;
+
+	if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
+		div--;
+
+	if (div > div_mask(divider))
+		div = div_mask(divider);
+
+	if (divider->lock)
+		spin_lock_irqsave(divider->lock, flags);
+
+	val = readl(divider->reg);
+	val &= ~(div_mask(divider) << divider->shift);
+	val |= div << divider->shift;
+	writel(val, divider->reg);
+
+	if (divider->lock)
+		spin_unlock_irqrestore(divider->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_divider_set_rate);
+
+struct clk_ops clk_divider_ops = {
+	.recalc_rate = clk_divider_recalc_rate,
+	.round_rate = clk_divider_round_rate,
+	.set_rate = clk_divider_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_divider_ops);
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_divider_flags, spinlock_t *lock)
+{
+	struct clk_divider *div;
+	struct clk *clk;
+
+	div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
+
+	if (!div) {
+		pr_err("%s: could not allocate divider clk\n", __func__);
+		return NULL;
+	}
+
+	/* struct clk_divider assignments */
+	div->reg = reg;
+	div->shift = shift;
+	div->width = width;
+	div->flags = clk_divider_flags;
+	div->lock = lock;
+
+	if (parent_name) {
+		div->parent[0] = kstrdup(parent_name, GFP_KERNEL);
+		if (!div->parent[0])
+			goto out;
+	}
+
+	clk = clk_register(dev, name,
+			&clk_divider_ops, &div->hw,
+			div->parent,
+			(parent_name ? 1 : 0),
+			flags);
+	if (clk)
+		return clk;
+
+out:
+	kfree(div->parent[0]);
+	kfree(div);
+
+	return NULL;
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/clk-fixed-rate.c b/ap/os/linux/linux-3.4.x/drivers/clk/clk-fixed-rate.c
new file mode 100644
index 0000000..90c79fb
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/clk-fixed-rate.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Fixed rate clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+/*
+ * DOC: basic fixed-rate clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parents are prepared
+ * enable - clk_enable only ensures parents are enabled
+ * rate - rate is always a fixed value.  No clk_set_rate support
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
+
+static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	return to_clk_fixed_rate(hw)->fixed_rate;
+}
+EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate);
+
+struct clk_ops clk_fixed_rate_ops = {
+	.recalc_rate = clk_fixed_rate_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
+
+struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		unsigned long fixed_rate)
+{
+	struct clk_fixed_rate *fixed;
+	char **parent_names = NULL;
+	u8 len;
+
+	fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
+
+	if (!fixed) {
+		pr_err("%s: could not allocate fixed clk\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* struct clk_fixed_rate assignments */
+	fixed->fixed_rate = fixed_rate;
+
+	if (parent_name) {
+		parent_names = kmalloc(sizeof(char *), GFP_KERNEL);
+
+		if (! parent_names)
+			goto out;
+
+		len = sizeof(char) * strlen(parent_name);
+
+		parent_names[0] = kmalloc(len, GFP_KERNEL);
+
+		if (!parent_names[0])
+			goto out;
+
+		strncpy(parent_names[0], parent_name, len);
+	}
+
+out:
+	return clk_register(dev, name,
+			&clk_fixed_rate_ops, &fixed->hw,
+			parent_names,
+			(parent_name ? 1 : 0),
+			flags);
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/clk-gate.c b/ap/os/linux/linux-3.4.x/drivers/clk/clk-gate.c
new file mode 100644
index 0000000..b5902e2
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/clk-gate.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Gated clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+
+/**
+ * DOC: basic gatable clock which can gate and ungate it's ouput
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional & control gating
+ * rate - inherits rate from parent.  No clk_set_rate support
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+
+static void clk_gate_set_bit(struct clk_gate *gate)
+{
+	u32 reg;
+	unsigned long flags = 0;
+
+	if (gate->lock)
+		spin_lock_irqsave(gate->lock, flags);
+
+	reg = readl(gate->reg);
+	reg |= BIT(gate->bit_idx);
+	writel(reg, gate->reg);
+
+	if (gate->lock)
+		spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static void clk_gate_clear_bit(struct clk_gate *gate)
+{
+	u32 reg;
+	unsigned long flags = 0;
+
+	if (gate->lock)
+		spin_lock_irqsave(gate->lock, flags);
+
+	reg = readl(gate->reg);
+	reg &= ~BIT(gate->bit_idx);
+	writel(reg, gate->reg);
+
+	if (gate->lock)
+		spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static int clk_gate_enable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+		clk_gate_clear_bit(gate);
+	else
+		clk_gate_set_bit(gate);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_gate_enable);
+
+static void clk_gate_disable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+		clk_gate_set_bit(gate);
+	else
+		clk_gate_clear_bit(gate);
+}
+EXPORT_SYMBOL_GPL(clk_gate_disable);
+
+static int clk_gate_is_enabled(struct clk_hw *hw)
+{
+	u32 reg;
+	struct clk_gate *gate = to_clk_gate(hw);
+
+	reg = readl(gate->reg);
+
+	/* if a set bit disables this clk, flip it before masking */
+	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+		reg ^= BIT(gate->bit_idx);
+
+	reg &= BIT(gate->bit_idx);
+
+	return reg ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
+
+struct clk_ops clk_gate_ops = {
+	.enable = clk_gate_enable,
+	.disable = clk_gate_disable,
+	.is_enabled = clk_gate_is_enabled,
+};
+EXPORT_SYMBOL_GPL(clk_gate_ops);
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+	struct clk_gate *gate;
+	struct clk *clk;
+
+	gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+
+	if (!gate) {
+		pr_err("%s: could not allocate gated clk\n", __func__);
+		return NULL;
+	}
+
+	/* struct clk_gate assignments */
+	gate->reg = reg;
+	gate->bit_idx = bit_idx;
+	gate->flags = clk_gate_flags;
+	gate->lock = lock;
+
+	if (parent_name) {
+		gate->parent[0] = kstrdup(parent_name, GFP_KERNEL);
+		if (!gate->parent[0])
+			goto out;
+	}
+
+	clk = clk_register(dev, name,
+			&clk_gate_ops, &gate->hw,
+			gate->parent,
+			(parent_name ? 1 : 0),
+			flags);
+	if (clk)
+		return clk;
+out:
+	kfree(gate->parent[0]);
+	kfree(gate);
+
+	return NULL;
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/clk-mux.c b/ap/os/linux/linux-3.4.x/drivers/clk/clk-mux.c
new file mode 100644
index 0000000..c71ad1f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/clk-mux.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Simple multiplexer clock implementation
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+/*
+ * DOC: basic adjustable multiplexer clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is only affected by parent switching.  No clk_set_rate support
+ * parent - parent is adjustable through clk_set_parent
+ */
+
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
+
+static u8 clk_mux_get_parent(struct clk_hw *hw)
+{
+	struct clk_mux *mux = to_clk_mux(hw);
+	u32 val;
+
+	/*
+	 * FIXME need a mux-specific flag to determine if val is bitwise or numeric
+	 * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
+	 * to 0x7 (index starts at one)
+	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
+	 * val = 0x4 really means "bit 2, index starts at bit 0"
+	 */
+	val = readl(mux->reg) >> mux->shift;
+	val &= (1 << mux->width) - 1;
+
+	if (val && (mux->flags & CLK_MUX_INDEX_BIT))
+		val = ffs(val) - 1;
+
+	if (val && (mux->flags & CLK_MUX_INDEX_ONE))
+		val--;
+
+	if (val >= __clk_get_num_parents(hw->clk))
+		return -EINVAL;
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(clk_mux_get_parent);
+
+static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_mux *mux = to_clk_mux(hw);
+	u32 val;
+	unsigned long flags = 0;
+
+	if (mux->flags & CLK_MUX_INDEX_BIT)
+		index = (1 << ffs(index));
+
+	if (mux->flags & CLK_MUX_INDEX_ONE)
+		index++;
+
+	if (mux->lock)
+		spin_lock_irqsave(mux->lock, flags);
+
+	val = readl(mux->reg);
+	val &= ~(((1 << mux->width) - 1) << mux->shift);
+	val |= index << mux->shift;
+	writel(val, mux->reg);
+
+	if (mux->lock)
+		spin_unlock_irqrestore(mux->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_mux_set_parent);
+
+struct clk_ops clk_mux_ops = {
+	.get_parent = clk_mux_get_parent,
+	.set_parent = clk_mux_set_parent,
+};
+EXPORT_SYMBOL_GPL(clk_mux_ops);
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+		char **parent_names, u8 num_parents, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_mux_flags, spinlock_t *lock)
+{
+	struct clk_mux *mux;
+
+	mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL);
+
+	if (!mux) {
+		pr_err("%s: could not allocate mux clk\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* struct clk_mux assignments */
+	mux->reg = reg;
+	mux->shift = shift;
+	mux->width = width;
+	mux->flags = clk_mux_flags;
+	mux->lock = lock;
+
+	return clk_register(dev, name, &clk_mux_ops, &mux->hw,
+			parent_names, num_parents, flags);
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/clk.c b/ap/os/linux/linux-3.4.x/drivers/clk/clk.c
new file mode 100644
index 0000000..4c63665
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/clk.c
@@ -0,0 +1,1468 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Standard functionality for the common clock API.  See Documentation/clk.txt
+ */
+
+#include <linux/clk-private.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+static DEFINE_SPINLOCK(enable_lock);
+static DEFINE_MUTEX(prepare_lock);
+
+static HLIST_HEAD(clk_root_list);
+static HLIST_HEAD(clk_orphan_list);
+static LIST_HEAD(clk_notifier_list);
+
+/***        debugfs support        ***/
+
+#ifdef CONFIG_COMMON_CLK_DEBUG
+#include <linux/debugfs.h>
+
+static struct dentry *rootdir;
+static struct dentry *orphandir;
+static int inited = 0;
+
+/* caller must hold prepare_lock */
+static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+{
+	struct dentry *d;
+	int ret = -ENOMEM;
+
+	if (!clk || !pdentry) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	d = debugfs_create_dir(clk->name, pdentry);
+	if (!d)
+		goto out;
+
+	clk->dentry = d;
+
+	d = debugfs_create_u32("clk_rate", S_IRUGO, clk->dentry,
+			(u32 *)&clk->rate);
+	if (!d)
+		goto err_out;
+
+	d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry,
+			(u32 *)&clk->flags);
+	if (!d)
+		goto err_out;
+
+	d = debugfs_create_u32("clk_prepare_count", S_IRUGO, clk->dentry,
+			(u32 *)&clk->prepare_count);
+	if (!d)
+		goto err_out;
+
+	d = debugfs_create_u32("clk_enable_count", S_IRUGO, clk->dentry,
+			(u32 *)&clk->enable_count);
+	if (!d)
+		goto err_out;
+
+	d = debugfs_create_u32("clk_notifier_count", S_IRUGO, clk->dentry,
+			(u32 *)&clk->notifier_count);
+	if (!d)
+		goto err_out;
+
+	ret = 0;
+	goto out;
+
+err_out:
+	debugfs_remove(clk->dentry);
+out:
+	return ret;
+}
+
+/* caller must hold prepare_lock */
+static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry)
+{
+	struct clk *child;
+	struct hlist_node *tmp;
+	int ret = -EINVAL;;
+
+	if (!clk || !pdentry)
+		goto out;
+
+	ret = clk_debug_create_one(clk, pdentry);
+
+	if (ret)
+		goto out;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node)
+		clk_debug_create_subtree(child, clk->dentry);
+
+	ret = 0;
+out:
+	return ret;
+}
+
+/**
+ * clk_debug_register - add a clk node to the debugfs clk tree
+ * @clk: the clk being added to the debugfs clk tree
+ *
+ * Dynamically adds a clk to the debugfs clk tree if debugfs has been
+ * initialized.  Otherwise it bails out early since the debugfs clk tree
+ * will be created lazily by clk_debug_init as part of a late_initcall.
+ *
+ * Caller must hold prepare_lock.  Only clk_init calls this function (so
+ * far) so this is taken care.
+ */
+static int clk_debug_register(struct clk *clk)
+{
+	struct clk *parent;
+	struct dentry *pdentry;
+	int ret = 0;
+
+	if (!inited)
+		goto out;
+
+	parent = clk->parent;
+
+	/*
+	 * Check to see if a clk is a root clk.  Also check that it is
+	 * safe to add this clk to debugfs
+	 */
+	if (!parent)
+		if (clk->flags & CLK_IS_ROOT)
+			pdentry = rootdir;
+		else
+			pdentry = orphandir;
+	else
+		if (parent->dentry)
+			pdentry = parent->dentry;
+		else
+			goto out;
+
+	ret = clk_debug_create_subtree(clk, pdentry);
+
+out:
+	return ret;
+}
+
+/**
+ * clk_debug_init - lazily create the debugfs clk tree visualization
+ *
+ * clks are often initialized very early during boot before memory can
+ * be dynamically allocated and well before debugfs is setup.
+ * clk_debug_init walks the clk tree hierarchy while holding
+ * prepare_lock and creates the topology as part of a late_initcall,
+ * thus insuring that clks initialized very early will still be
+ * represented in the debugfs clk tree.  This function should only be
+ * called once at boot-time, and all other clks added dynamically will
+ * be done so with clk_debug_register.
+ */
+static int __init clk_debug_init(void)
+{
+	struct clk *clk;
+	struct hlist_node *tmp;
+
+	rootdir = debugfs_create_dir("clk", NULL);
+
+	if (!rootdir)
+		return -ENOMEM;
+
+	orphandir = debugfs_create_dir("orphans", rootdir);
+
+	if (!orphandir)
+		return -ENOMEM;
+
+	mutex_lock(&prepare_lock);
+
+	hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
+		clk_debug_create_subtree(clk, rootdir);
+
+	hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
+		clk_debug_create_subtree(clk, orphandir);
+
+	inited = 1;
+
+	mutex_unlock(&prepare_lock);
+
+	return 0;
+}
+late_initcall(clk_debug_init);
+#else
+static inline int clk_debug_register(struct clk *clk) { return 0; }
+#endif /* CONFIG_COMMON_CLK_DEBUG */
+
+#ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED
+/* caller must hold prepare_lock */
+static void clk_disable_unused_subtree(struct clk *clk)
+{
+	struct clk *child;
+	struct hlist_node *tmp;
+	unsigned long flags;
+
+	if (!clk)
+		goto out;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node)
+		clk_disable_unused_subtree(child);
+
+	spin_lock_irqsave(&enable_lock, flags);
+
+	if (clk->enable_count)
+		goto unlock_out;
+
+	if (clk->flags & CLK_IGNORE_UNUSED)
+		goto unlock_out;
+
+	if (__clk_is_enabled(clk) && clk->ops->disable)
+		clk->ops->disable(clk->hw);
+
+unlock_out:
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+out:
+	return;
+}
+
+static int clk_disable_unused(void)
+{
+	struct clk *clk;
+	struct hlist_node *tmp;
+
+	mutex_lock(&prepare_lock);
+
+	hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
+		clk_disable_unused_subtree(clk);
+
+	hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
+		clk_disable_unused_subtree(clk);
+
+	mutex_unlock(&prepare_lock);
+
+	return 0;
+}
+late_initcall(clk_disable_unused);
+#else
+static inline int clk_disable_unused(struct clk *clk) { return 0; }
+#endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */
+
+/***    helper functions   ***/
+
+inline const char *__clk_get_name(struct clk *clk)
+{
+	return !clk ? NULL : clk->name;
+}
+
+inline struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+	return !clk ? NULL : clk->hw;
+}
+
+inline u8 __clk_get_num_parents(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->num_parents;
+}
+
+inline struct clk *__clk_get_parent(struct clk *clk)
+{
+	return !clk ? NULL : clk->parent;
+}
+
+inline int __clk_get_enable_count(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->enable_count;
+}
+
+inline int __clk_get_prepare_count(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->prepare_count;
+}
+
+unsigned long __clk_get_rate(struct clk *clk)
+{
+	unsigned long ret;
+
+	if (!clk) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = clk->rate;
+
+	if (clk->flags & CLK_IS_ROOT)
+		goto out;
+
+	if (!clk->parent)
+		ret = -ENODEV;
+
+out:
+	return ret;
+}
+
+inline unsigned long __clk_get_flags(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->flags;
+}
+
+int __clk_is_enabled(struct clk *clk)
+{
+	int ret;
+
+	if (!clk)
+		return -EINVAL;
+
+	/*
+	 * .is_enabled is only mandatory for clocks that gate
+	 * fall back to software usage counter if .is_enabled is missing
+	 */
+	if (!clk->ops->is_enabled) {
+		ret = clk->enable_count ? 1 : 0;
+		goto out;
+	}
+
+	ret = clk->ops->is_enabled(clk->hw);
+out:
+	return ret;
+}
+
+static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
+{
+	struct clk *child;
+	struct clk *ret;
+	struct hlist_node *tmp;
+
+	if (!strcmp(clk->name, name))
+		return clk;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+		ret = __clk_lookup_subtree(name, child);
+		if (ret)
+			return ret;
+	}
+
+	return NULL;
+}
+
+struct clk *__clk_lookup(const char *name)
+{
+	struct clk *root_clk;
+	struct clk *ret;
+	struct hlist_node *tmp;
+
+	if (!name)
+		return NULL;
+
+	/* search the 'proper' clk tree first */
+	hlist_for_each_entry(root_clk, tmp, &clk_root_list, child_node) {
+		ret = __clk_lookup_subtree(name, root_clk);
+		if (ret)
+			return ret;
+	}
+
+	/* if not found, then search the orphan tree */
+	hlist_for_each_entry(root_clk, tmp, &clk_orphan_list, child_node) {
+		ret = __clk_lookup_subtree(name, root_clk);
+		if (ret)
+			return ret;
+	}
+
+	return NULL;
+}
+
+/***        clk api        ***/
+
+void __clk_unprepare(struct clk *clk)
+{
+	if (!clk)
+		return;
+
+	if (WARN_ON(clk->prepare_count == 0))
+		return;
+
+	if (--clk->prepare_count > 0)
+		return;
+
+	WARN_ON(clk->enable_count > 0);
+
+	if (clk->ops->unprepare)
+		clk->ops->unprepare(clk->hw);
+
+	__clk_unprepare(clk->parent);
+}
+
+/**
+ * clk_unprepare - undo preparation of a clock source
+ * @clk: the clk being unprepare
+ *
+ * clk_unprepare may sleep, which differentiates it from clk_disable.  In a
+ * simple case, clk_unprepare can be used instead of clk_disable to gate a clk
+ * if the operation may sleep.  One example is a clk which is accessed over
+ * I2c.  In the complex case a clk gate operation may require a fast and a slow
+ * part.  It is this reason that clk_unprepare and clk_disable are not mutually
+ * exclusive.  In fact clk_disable must be called before clk_unprepare.
+ */
+void clk_unprepare(struct clk *clk)
+{
+	mutex_lock(&prepare_lock);
+	__clk_unprepare(clk);
+	mutex_unlock(&prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int __clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk)
+		return 0;
+
+	if (clk->prepare_count == 0) {
+		ret = __clk_prepare(clk->parent);
+		if (ret)
+			return ret;
+
+		if (clk->ops->prepare) {
+			ret = clk->ops->prepare(clk->hw);
+			if (ret) {
+				__clk_unprepare(clk->parent);
+				return ret;
+			}
+		}
+	}
+
+	clk->prepare_count++;
+
+	return 0;
+}
+
+/**
+ * clk_prepare - prepare a clock source
+ * @clk: the clk being prepared
+ *
+ * clk_prepare may sleep, which differentiates it from clk_enable.  In a simple
+ * case, clk_prepare can be used instead of clk_enable to ungate a clk if the
+ * operation may sleep.  One example is a clk which is accessed over I2c.  In
+ * the complex case a clk ungate operation may require a fast and a slow part.
+ * It is this reason that clk_prepare and clk_enable are not mutually
+ * exclusive.  In fact clk_prepare must be called before clk_enable.
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_prepare(struct clk *clk)
+{
+	int ret;
+
+	mutex_lock(&prepare_lock);
+	ret = __clk_prepare(clk);
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+static void __clk_disable(struct clk *clk)
+{
+	if (!clk)
+		return;
+
+	if (WARN_ON(clk->enable_count == 0))
+		return;
+
+	if (--clk->enable_count > 0)
+		return;
+
+	if (clk->ops->disable)
+		clk->ops->disable(clk->hw);
+
+	__clk_disable(clk->parent);
+}
+
+/**
+ * clk_disable - gate a clock
+ * @clk: the clk being gated
+ *
+ * clk_disable must not sleep, which differentiates it from clk_unprepare.  In
+ * a simple case, clk_disable can be used instead of clk_unprepare to gate a
+ * clk if the operation is fast and will never sleep.  One example is a
+ * SoC-internal clk which is controlled via simple register writes.  In the
+ * complex case a clk gate operation may require a fast and a slow part.  It is
+ * this reason that clk_unprepare and clk_disable are not mutually exclusive.
+ * In fact clk_disable must be called before clk_unprepare.
+ */
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&enable_lock, flags);
+	__clk_disable(clk);
+	spin_unlock_irqrestore(&enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+static int __clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk)
+		return 0;
+
+	if (WARN_ON(clk->prepare_count == 0))
+		return -ESHUTDOWN;
+
+	if (clk->enable_count == 0) {
+		ret = __clk_enable(clk->parent);
+
+		if (ret)
+			return ret;
+
+		if (clk->ops->enable) {
+			ret = clk->ops->enable(clk->hw);
+			if (ret) {
+				__clk_disable(clk->parent);
+				return ret;
+			}
+		}
+	}
+
+	clk->enable_count++;
+	return 0;
+}
+
+/**
+ * clk_enable - ungate a clock
+ * @clk: the clk being ungated
+ *
+ * clk_enable must not sleep, which differentiates it from clk_prepare.  In a
+ * simple case, clk_enable can be used instead of clk_prepare to ungate a clk
+ * if the operation will never sleep.  One example is a SoC-internal clk which
+ * is controlled via simple register writes.  In the complex case a clk ungate
+ * operation may require a fast and a slow part.  It is this reason that
+ * clk_enable and clk_prepare are not mutually exclusive.  In fact clk_prepare
+ * must be called before clk_enable.  Returns 0 on success, -EERROR
+ * otherwise.
+ */
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&enable_lock, flags);
+	ret = __clk_enable(clk);
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk.  Does not query the hardware.  If
+ * clk is NULL then returns -EINVAL.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+	unsigned long rate;
+
+	mutex_lock(&prepare_lock);
+	rate = __clk_get_rate(clk);
+	mutex_unlock(&prepare_lock);
+
+	return rate;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+/**
+ * __clk_round_rate - round the given rate for a clk
+ * @clk: round the rate of this clock
+ *
+ * Caller must hold prepare_lock.  Useful for clk_ops such as .set_rate
+ */
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long unused;
+
+	if (!clk)
+		return -EINVAL;
+
+	if (!clk->ops->round_rate)
+		return clk->rate;
+
+	if (clk->flags & CLK_SET_RATE_PARENT)
+		return clk->ops->round_rate(clk->hw, rate, &unused);
+	else
+		return clk->ops->round_rate(clk->hw, rate, NULL);
+}
+
+/**
+ * clk_round_rate - round the given rate for a clk
+ * @clk: the clk for which we are rounding a rate
+ * @rate: the rate which is to be rounded
+ *
+ * Takes in a rate as input and rounds it to a rate that the clk can actually
+ * use which is then returned.  If clk doesn't support round_rate operation
+ * then the parent rate is returned.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long ret;
+
+	mutex_lock(&prepare_lock);
+	ret = __clk_round_rate(clk, rate);
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+/**
+ * __clk_notify - call clk notifier chain
+ * @clk: struct clk * that is changing rate
+ * @msg: clk notifier type (see include/linux/clk.h)
+ * @old_rate: old clk rate
+ * @new_rate: new clk rate
+ *
+ * Triggers a notifier call chain on the clk rate-change notification
+ * for 'clk'.  Passes a pointer to the struct clk and the previous
+ * and current rates to the notifier callback.  Intended to be called by
+ * internal clock code only.  Returns NOTIFY_DONE from the last driver
+ * called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
+ * a driver returns that.
+ */
+static int __clk_notify(struct clk *clk, unsigned long msg,
+		unsigned long old_rate, unsigned long new_rate)
+{
+	struct clk_notifier *cn;
+	struct clk_notifier_data cnd;
+	int ret = NOTIFY_DONE;
+
+	cnd.clk = clk;
+	cnd.old_rate = old_rate;
+	cnd.new_rate = new_rate;
+
+	list_for_each_entry(cn, &clk_notifier_list, node) {
+		if (cn->clk == clk) {
+			ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
+					&cnd);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * __clk_recalc_rates
+ * @clk: first clk in the subtree
+ * @msg: notification type (see include/linux/clk.h)
+ *
+ * Walks the subtree of clks starting with clk and recalculates rates as it
+ * goes.  Note that if a clk does not implement the .recalc_rate callback then
+ * it is assumed that the clock will take on the rate of it's parent.
+ *
+ * clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
+ * if necessary.
+ *
+ * Caller must hold prepare_lock.
+ */
+static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
+{
+	unsigned long old_rate;
+	unsigned long parent_rate = 0;
+	struct hlist_node *tmp;
+	struct clk *child;
+
+	old_rate = clk->rate;
+
+	if (clk->parent)
+		parent_rate = clk->parent->rate;
+
+	if (clk->ops->recalc_rate)
+		clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate);
+	else
+		clk->rate = parent_rate;
+
+	/*
+	 * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
+	 * & ABORT_RATE_CHANGE notifiers
+	 */
+	if (clk->notifier_count && msg)
+		__clk_notify(clk, msg, old_rate, clk->rate);
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node)
+		__clk_recalc_rates(child, msg);
+}
+
+/**
+ * __clk_speculate_rates
+ * @clk: first clk in the subtree
+ * @parent_rate: the "future" rate of clk's parent
+ *
+ * Walks the subtree of clks starting with clk, speculating rates as it
+ * goes and firing off PRE_RATE_CHANGE notifications as necessary.
+ *
+ * Unlike clk_recalc_rates, clk_speculate_rates exists only for sending
+ * pre-rate change notifications and returns early if no clks in the
+ * subtree have subscribed to the notifications.  Note that if a clk does not
+ * implement the .recalc_rate callback then it is assumed that the clock will
+ * take on the rate of it's parent.
+ *
+ * Caller must hold prepare_lock.
+ */
+static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
+{
+	struct hlist_node *tmp;
+	struct clk *child;
+	unsigned long new_rate;
+	int ret = NOTIFY_DONE;
+
+	if (clk->ops->recalc_rate)
+		new_rate = clk->ops->recalc_rate(clk->hw, parent_rate);
+	else
+		new_rate = parent_rate;
+
+	/* abort the rate change if a driver returns NOTIFY_BAD */
+	if (clk->notifier_count)
+		ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
+
+	if (ret == NOTIFY_BAD)
+		goto out;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+		ret = __clk_speculate_rates(child, new_rate);
+		if (ret == NOTIFY_BAD)
+			break;
+	}
+
+out:
+	return ret;
+}
+
+static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
+{
+	struct clk *child;
+	struct hlist_node *tmp;
+
+	clk->new_rate = new_rate;
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+		if (child->ops->recalc_rate)
+			child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
+		else
+			child->new_rate = new_rate;
+		clk_calc_subtree(child, child->new_rate);
+	}
+}
+
+/*
+ * calculate the new rates returning the topmost clock that has to be
+ * changed.
+ */
+static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
+{
+	struct clk *top = clk;
+	unsigned long best_parent_rate = clk->parent->rate;
+	unsigned long new_rate;
+
+	if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) {
+		clk->new_rate = clk->rate;
+		return NULL;
+	}
+
+	if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) {
+		top = clk_calc_new_rates(clk->parent, rate);
+		new_rate = clk->new_rate = clk->parent->new_rate;
+
+		goto out;
+	}
+
+	if (clk->flags & CLK_SET_RATE_PARENT)
+		new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
+	else
+		new_rate = clk->ops->round_rate(clk->hw, rate, NULL);
+
+	if (best_parent_rate != clk->parent->rate) {
+		top = clk_calc_new_rates(clk->parent, best_parent_rate);
+
+		goto out;
+	}
+
+out:
+	clk_calc_subtree(clk, new_rate);
+
+	return top;
+}
+
+/*
+ * Notify about rate changes in a subtree. Always walk down the whole tree
+ * so that in case of an error we can walk down the whole tree again and
+ * abort the change.
+ */
+static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
+{
+	struct hlist_node *tmp;
+	struct clk *child, *fail_clk = NULL;
+	int ret = NOTIFY_DONE;
+
+	if (clk->rate == clk->new_rate)
+		return 0;
+
+	if (clk->notifier_count) {
+		ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
+		if (ret == NOTIFY_BAD)
+			fail_clk = clk;
+	}
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+		clk = clk_propagate_rate_change(child, event);
+		if (clk)
+			fail_clk = clk;
+	}
+
+	return fail_clk;
+}
+
+/*
+ * walk down a subtree and set the new rates notifying the rate
+ * change on the way
+ */
+static void clk_change_rate(struct clk *clk)
+{
+	struct clk *child;
+	unsigned long old_rate;
+	unsigned long best_parent_rate = 0;
+	struct hlist_node *tmp;
+
+	old_rate = clk->rate;
+
+	if (clk->parent)
+		best_parent_rate = clk->parent->rate;
+
+	if (clk->ops->set_rate)
+		clk->ops->set_rate(clk->hw, clk->new_rate);
+
+	if (clk->ops->recalc_rate)
+		clk->rate = clk->ops->recalc_rate(clk->hw, best_parent_rate);
+	else
+		clk->rate = best_parent_rate;
+
+	if (clk->notifier_count && old_rate != clk->rate)
+		__clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
+
+	hlist_for_each_entry(child, tmp, &clk->children, child_node)
+		clk_change_rate(child);
+}
+
+/**
+ * clk_set_rate - specify a new rate for clk
+ * @clk: the clk whose rate is being changed
+ * @rate: the new rate for clk
+ *
+ * In the simplest case clk_set_rate will only change the rate of clk.
+ *
+ * If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call
+ * will fail; only when the clk is disabled will it be able to change
+ * its rate.
+ *
+ * Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to
+ * recursively propagate up to clk's parent; whether or not this happens
+ * depends on the outcome of clk's .round_rate implementation.  If
+ * *parent_rate is 0 after calling .round_rate then upstream parent
+ * propagation is ignored.  If *parent_rate comes back with a new rate
+ * for clk's parent then we propagate up to clk's parent and set it's
+ * rate.  Upward propagation will continue until either a clk does not
+ * support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting
+ * changes to clk's parent_rate.  If there is a failure during upstream
+ * propagation then clk_set_rate will unwind and restore each clk's rate
+ * that had been successfully changed.  Afterwards a rate change abort
+ * notification will be propagated downstream, starting from the clk
+ * that failed.
+ *
+ * At the end of all of the rate setting, clk_set_rate internally calls
+ * __clk_recalc_rates and propagates the rate changes downstream,
+ * starting from the highest clk whose rate was changed.  This has the
+ * added benefit of propagating post-rate change notifiers.
+ *
+ * Note that while post-rate change and rate change abort notifications
+ * are guaranteed to be sent to a clk only once per call to
+ * clk_set_rate, pre-change notifications will be sent for every clk
+ * whose rate is changed.  Stacking pre-change notifications is noisy
+ * for the drivers subscribed to them, but this allows drivers to react
+ * to intermediate clk rate changes up until the point where the final
+ * rate is achieved at the end of upstream propagation.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	struct clk *top, *fail_clk;
+	int ret = 0;
+
+	/* prevent racing with updates to the clock topology */
+	mutex_lock(&prepare_lock);
+
+	/* bail early if nothing to do */
+	if (rate == clk->rate)
+		goto out;
+
+	/* calculate new rates and get the topmost changed clock */
+	top = clk_calc_new_rates(clk, rate);
+	if (!top) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* notify that we are about to change rates */
+	fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
+	if (fail_clk) {
+		pr_warn("%s: failed to set %s rate\n", __func__,
+				fail_clk->name);
+		clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* change the rates */
+	clk_change_rate(top);
+
+	mutex_unlock(&prepare_lock);
+
+	return 0;
+out:
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+/**
+ * clk_get_parent - return the parent of a clk
+ * @clk: the clk whose parent gets returned
+ *
+ * Simply returns clk->parent.  Returns NULL if clk is NULL.
+ */
+struct clk *clk_get_parent(struct clk *clk)
+{
+	struct clk *parent;
+
+	mutex_lock(&prepare_lock);
+	parent = __clk_get_parent(clk);
+	mutex_unlock(&prepare_lock);
+
+	return parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+/*
+ * .get_parent is mandatory for clocks with multiple possible parents.  It is
+ * optional for single-parent clocks.  Always call .get_parent if it is
+ * available and WARN if it is missing for multi-parent clocks.
+ *
+ * For single-parent clocks without .get_parent, first check to see if the
+ * .parents array exists, and if so use it to avoid an expensive tree
+ * traversal.  If .parents does not exist then walk the tree with __clk_lookup.
+ */
+static struct clk *__clk_init_parent(struct clk *clk)
+{
+	struct clk *ret = NULL;
+	u8 index;
+
+	/* handle the trivial cases */
+
+	if (!clk->num_parents)
+		goto out;
+
+	if (clk->num_parents == 1) {
+		if (IS_ERR_OR_NULL(clk->parent))
+			ret = clk->parent = __clk_lookup(clk->parent_names[0]);
+		ret = clk->parent;
+		goto out;
+	}
+
+	if (!clk->ops->get_parent) {
+		WARN(!clk->ops->get_parent,
+			"%s: multi-parent clocks must implement .get_parent\n",
+			__func__);
+		goto out;
+	};
+
+	/*
+	 * Do our best to cache parent clocks in clk->parents.  This prevents
+	 * unnecessary and expensive calls to __clk_lookup.  We don't set
+	 * clk->parent here; that is done by the calling function
+	 */
+
+	index = clk->ops->get_parent(clk->hw);
+
+	if (!clk->parents)
+		clk->parents =
+			kzalloc((sizeof(struct clk*) * clk->num_parents),
+					GFP_KERNEL);
+
+	if (!clk->parents)
+		ret = __clk_lookup(clk->parent_names[index]);
+	else if (!clk->parents[index])
+		ret = clk->parents[index] =
+			__clk_lookup(clk->parent_names[index]);
+	else
+		ret = clk->parents[index];
+
+out:
+	return ret;
+}
+
+void __clk_reparent(struct clk *clk, struct clk *new_parent)
+{
+#ifdef CONFIG_COMMON_CLK_DEBUG
+	struct dentry *d;
+	struct dentry *new_parent_d;
+#endif
+
+	if (!clk || !new_parent)
+		return;
+
+	hlist_del(&clk->child_node);
+
+	if (new_parent)
+		hlist_add_head(&clk->child_node, &new_parent->children);
+	else
+		hlist_add_head(&clk->child_node, &clk_orphan_list);
+
+#ifdef CONFIG_COMMON_CLK_DEBUG
+	if (!inited)
+		goto out;
+
+	if (new_parent)
+		new_parent_d = new_parent->dentry;
+	else
+		new_parent_d = orphandir;
+
+	d = debugfs_rename(clk->dentry->d_parent, clk->dentry,
+			new_parent_d, clk->name);
+	if (d)
+		clk->dentry = d;
+	else
+		pr_debug("%s: failed to rename debugfs entry for %s\n",
+				__func__, clk->name);
+out:
+#endif
+
+	clk->parent = new_parent;
+
+	__clk_recalc_rates(clk, POST_RATE_CHANGE);
+}
+
+static int __clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct clk *old_parent;
+	unsigned long flags;
+	int ret = -EINVAL;
+	u8 i;
+
+	old_parent = clk->parent;
+
+	if (!clk->parents)
+		clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
+								GFP_KERNEL);
+
+	/*
+	 * find index of new parent clock using cached parent ptrs,
+	 * or if not yet cached, use string name comparison and cache
+	 * them now to avoid future calls to __clk_lookup.
+	 */
+	for (i = 0; i < clk->num_parents; i++) {
+		if (clk->parents && clk->parents[i] == parent)
+			break;
+		else if (!strcmp(clk->parent_names[i], parent->name)) {
+			if (clk->parents)
+				clk->parents[i] = __clk_lookup(parent->name);
+			break;
+		}
+	}
+
+	if (i == clk->num_parents) {
+		pr_debug("%s: clock %s is not a possible parent of clock %s\n",
+				__func__, parent->name, clk->name);
+		goto out;
+	}
+
+	/* migrate prepare and enable */
+	if (clk->prepare_count)
+		__clk_prepare(parent);
+
+	/* FIXME replace with clk_is_enabled(clk) someday */
+	spin_lock_irqsave(&enable_lock, flags);
+	if (clk->enable_count)
+		__clk_enable(parent);
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+	/* change clock input source */
+	ret = clk->ops->set_parent(clk->hw, i);
+
+	/* clean up old prepare and enable */
+	spin_lock_irqsave(&enable_lock, flags);
+	if (clk->enable_count)
+		__clk_disable(old_parent);
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+	if (clk->prepare_count)
+		__clk_unprepare(old_parent);
+
+out:
+	return ret;
+}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as it's new input source.  If clk has the
+ * CLK_SET_PARENT_GATE flag set then clk must be gated for this
+ * operation to succeed.  After successfully changing clk's parent
+ * clk_set_parent will update the clk topology, sysfs topology and
+ * propagate rate recalculation via __clk_recalc_rates.  Returns 0 on
+ * success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	int ret = 0;
+
+	if (!clk || !clk->ops)
+		return -EINVAL;
+
+	if (!clk->ops->set_parent)
+		return -ENOSYS;
+
+	/* prevent racing with updates to the clock topology */
+	mutex_lock(&prepare_lock);
+
+	if (clk->parent == parent)
+		goto out;
+
+	/* propagate PRE_RATE_CHANGE notifications */
+	if (clk->notifier_count)
+		ret = __clk_speculate_rates(clk, parent->rate);
+
+	/* abort if a driver objects */
+	if (ret == NOTIFY_STOP)
+		goto out;
+
+	/* only re-parent if the clock is not in use */
+	if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count)
+		ret = -EBUSY;
+	else
+		ret = __clk_set_parent(clk, parent);
+
+	/* propagate ABORT_RATE_CHANGE if .set_parent failed */
+	if (ret) {
+		__clk_recalc_rates(clk, ABORT_RATE_CHANGE);
+		goto out;
+	}
+
+	/* propagate rate recalculation downstream */
+	__clk_reparent(clk, parent);
+
+out:
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+/**
+ * __clk_init - initialize the data structures in a struct clk
+ * @dev:	device initializing this clk, placeholder for now
+ * @clk:	clk being initialized
+ *
+ * Initializes the lists in struct clk, queries the hardware for the
+ * parent and rate and sets them both.
+ *
+ * Any struct clk passed into __clk_init must have the following members
+ * populated:
+ * 	.name
+ * 	.ops
+ * 	.hw
+ * 	.parent_names
+ * 	.num_parents
+ * 	.flags
+ *
+ * Essentially, everything that would normally be passed into clk_register is
+ * assumed to be initialized already in __clk_init.  The other members may be
+ * populated, but are optional.
+ *
+ * __clk_init is only exposed via clk-private.h and is intended for use with
+ * very large numbers of clocks that need to be statically initialized.  It is
+ * a layering violation to include clk-private.h from any code which implements
+ * a clock's .ops; as such any statically initialized clock data MUST be in a
+ * separate C file from the logic that implements it's operations.
+ */
+void __clk_init(struct device *dev, struct clk *clk)
+{
+	int i;
+	struct clk *orphan;
+	struct hlist_node *tmp, *tmp2;
+
+	if (!clk)
+		return;
+
+	mutex_lock(&prepare_lock);
+
+	/* check to see if a clock with this name is already registered */
+	if (__clk_lookup(clk->name))
+		goto out;
+
+	/* throw a WARN if any entries in parent_names are NULL */
+	for (i = 0; i < clk->num_parents; i++)
+		WARN(!clk->parent_names[i],
+				"%s: invalid NULL in %s's .parent_names\n",
+				__func__, clk->name);
+
+	/*
+	 * Allocate an array of struct clk *'s to avoid unnecessary string
+	 * look-ups of clk's possible parents.  This can fail for clocks passed
+	 * in to clk_init during early boot; thus any access to clk->parents[]
+	 * must always check for a NULL pointer and try to populate it if
+	 * necessary.
+	 *
+	 * If clk->parents is not NULL we skip this entire block.  This allows
+	 * for clock drivers to statically initialize clk->parents.
+	 */
+	if (clk->num_parents && !clk->parents) {
+		clk->parents = kmalloc((sizeof(struct clk*) * clk->num_parents),
+				GFP_KERNEL);
+		/*
+		 * __clk_lookup returns NULL for parents that have not been
+		 * clk_init'd; thus any access to clk->parents[] must check
+		 * for a NULL pointer.  We can always perform lazy lookups for
+		 * missing parents later on.
+		 */
+		if (clk->parents)
+			for (i = 0; i < clk->num_parents; i++)
+				clk->parents[i] =
+					__clk_lookup(clk->parent_names[i]);
+	}
+
+	clk->parent = __clk_init_parent(clk);
+
+	/*
+	 * Populate clk->parent if parent has already been __clk_init'd.  If
+	 * parent has not yet been __clk_init'd then place clk in the orphan
+	 * list.  If clk has set the CLK_IS_ROOT flag then place it in the root
+	 * clk list.
+	 *
+	 * Every time a new clk is clk_init'd then we walk the list of orphan
+	 * clocks and re-parent any that are children of the clock currently
+	 * being clk_init'd.
+	 */
+	if (clk->parent)
+		hlist_add_head(&clk->child_node,
+				&clk->parent->children);
+	else if (clk->flags & CLK_IS_ROOT)
+		hlist_add_head(&clk->child_node, &clk_root_list);
+	else
+		hlist_add_head(&clk->child_node, &clk_orphan_list);
+
+	/*
+	 * Set clk's rate.  The preferred method is to use .recalc_rate.  For
+	 * simple clocks and lazy developers the default fallback is to use the
+	 * parent's rate.  If a clock doesn't have a parent (or is orphaned)
+	 * then rate is set to zero.
+	 */
+	if (clk->ops->recalc_rate)
+		clk->rate = clk->ops->recalc_rate(clk->hw,
+				__clk_get_rate(clk->parent));
+	else if (clk->parent)
+		clk->rate = clk->parent->rate;
+	else
+		clk->rate = 0;
+
+	/*
+	 * walk the list of orphan clocks and reparent any that are children of
+	 * this clock
+	 */
+	hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node)
+		for (i = 0; i < orphan->num_parents; i++)
+			if (!strcmp(clk->name, orphan->parent_names[i])) {
+				__clk_reparent(orphan, clk);
+				break;
+			}
+
+	/*
+	 * optional platform-specific magic
+	 *
+	 * The .init callback is not used by any of the basic clock types, but
+	 * exists for weird hardware that must perform initialization magic.
+	 * Please consider other ways of solving initialization problems before
+	 * using this callback, as it's use is discouraged.
+	 */
+	if (clk->ops->init)
+		clk->ops->init(clk->hw);
+
+	clk_debug_register(clk);
+
+out:
+	mutex_unlock(&prepare_lock);
+
+	return;
+}
+
+/**
+ * clk_register - allocate a new clock, register it and return an opaque cookie
+ * @dev: device that is registering this clock
+ * @name: clock name
+ * @ops: operations this clock supports
+ * @hw: link to hardware-specific clock data
+ * @parent_names: array of string names for all possible parents
+ * @num_parents: number of possible parents
+ * @flags: framework-level hints and quirks
+ *
+ * clk_register is the primary interface for populating the clock tree with new
+ * clock nodes.  It returns a pointer to the newly allocated struct clk which
+ * cannot be dereferenced by driver code but may be used in conjuction with the
+ * rest of the clock API.
+ */
+struct clk *clk_register(struct device *dev, const char *name,
+		const struct clk_ops *ops, struct clk_hw *hw,
+		char **parent_names, u8 num_parents, unsigned long flags)
+{
+	struct clk *clk;
+
+	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+	if (!clk)
+		return NULL;
+
+	clk->name = name;
+	clk->ops = ops;
+	clk->hw = hw;
+	clk->flags = flags;
+	clk->parent_names = parent_names;
+	clk->num_parents = num_parents;
+	hw->clk = clk;
+
+	__clk_init(dev, clk);
+
+	return clk;
+}
+EXPORT_SYMBOL_GPL(clk_register);
+
+/***        clk rate change notifiers        ***/
+
+/**
+ * clk_notifier_register - add a clk rate change notifier
+ * @clk: struct clk * to watch
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request notification when clk's rate changes.  This uses an SRCU
+ * notifier because we want it to block and notifier unregistrations are
+ * uncommon.  The callbacks associated with the notifier must not
+ * re-enter into the clk framework by calling any top-level clk APIs;
+ * this will cause a nested prepare_lock mutex.
+ *
+ * Pre-change notifier callbacks will be passed the current, pre-change
+ * rate of the clk via struct clk_notifier_data.old_rate.  The new,
+ * post-change rate of the clk is passed via struct
+ * clk_notifier_data.new_rate.
+ *
+ * Post-change notifiers will pass the now-current, post-change rate of
+ * the clk in both struct clk_notifier_data.old_rate and struct
+ * clk_notifier_data.new_rate.
+ *
+ * Abort-change notifiers are effectively the opposite of pre-change
+ * notifiers: the original pre-change clk rate is passed in via struct
+ * clk_notifier_data.new_rate and the failed post-change rate is passed
+ * in via struct clk_notifier_data.old_rate.
+ *
+ * clk_notifier_register() must be called from non-atomic context.
+ * Returns -EINVAL if called with null arguments, -ENOMEM upon
+ * allocation failure; otherwise, passes along the return value of
+ * srcu_notifier_chain_register().
+ */
+int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
+{
+	struct clk_notifier *cn;
+	int ret = -ENOMEM;
+
+	if (!clk || !nb)
+		return -EINVAL;
+
+	mutex_lock(&prepare_lock);
+
+	/* search the list of notifiers for this clk */
+	list_for_each_entry(cn, &clk_notifier_list, node)
+		if (cn->clk == clk)
+			break;
+
+	/* if clk wasn't in the notifier list, allocate new clk_notifier */
+	if (cn->clk != clk) {
+		cn = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
+		if (!cn)
+			goto out;
+
+		cn->clk = clk;
+		srcu_init_notifier_head(&cn->notifier_head);
+
+		list_add(&cn->node, &clk_notifier_list);
+	}
+
+	ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
+
+	clk->notifier_count++;
+
+out:
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_notifier_register);
+
+/**
+ * clk_notifier_unregister - remove a clk rate change notifier
+ * @clk: struct clk *
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request no further notification for changes to 'clk' and frees memory
+ * allocated in clk_notifier_register.
+ *
+ * Returns -EINVAL if called with null arguments; otherwise, passes
+ * along the return value of srcu_notifier_chain_unregister().
+ */
+int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
+{
+	struct clk_notifier *cn = NULL;
+	int ret = -EINVAL;
+
+	if (!clk || !nb)
+		return -EINVAL;
+
+	mutex_lock(&prepare_lock);
+
+	list_for_each_entry(cn, &clk_notifier_list, node)
+		if (cn->clk == clk)
+			break;
+
+	if (cn->clk == clk) {
+		ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
+
+		clk->notifier_count--;
+
+		/* XXX the notifier code should handle this better */
+		if (!cn->notifier_head.head) {
+			srcu_cleanup_notifier_head(&cn->notifier_head);
+			list_del(&cn->node);
+			kfree(cn);
+		}
+
+	} else {
+		ret = -ENOENT;
+	}
+
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_notifier_unregister);
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/clkdev.c b/ap/os/linux/linux-3.4.x/drivers/clk/clkdev.c
new file mode 100644
index 0000000..6db161f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/clkdev.c
@@ -0,0 +1,175 @@
+/*
+ * drivers/clk/clkdev.c
+ *
+ *  Copyright (C) 2008 Russell King.
+ *
+ * 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.
+ *
+ * Helper for the clk API to assist looking up a struct clk.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+
+/*
+ * Find the correct struct clk for the device and connection ID.
+ * We do slightly fuzzy matching here:
+ *  An entry with a NULL ID is assumed to be a wildcard.
+ *  If an entry has a device ID, it must match
+ *  If an entry has a connection ID, it must match
+ * Then we take the most specific entry - with the following
+ * order of precedence: dev+con > dev only > con only.
+ */
+static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
+{
+	struct clk_lookup *p, *cl = NULL;
+	int match, best = 0;
+
+	list_for_each_entry(p, &clocks, node) {
+		match = 0;
+		if (p->dev_id) {
+			if (!dev_id || strcmp(p->dev_id, dev_id))
+				continue;
+			match += 2;
+		}
+		if (p->con_id) {
+			if (!con_id || strcmp(p->con_id, con_id))
+				continue;
+			match += 1;
+		}
+
+		if (match > best) {
+			cl = p;
+			if (match != 3)
+				best = match;
+			else
+				break;
+		}
+	}
+	return cl;
+}
+
+struct clk *clk_get_sys(const char *dev_id, const char *con_id)
+{
+	struct clk_lookup *cl;
+
+	mutex_lock(&clocks_mutex);
+	cl = clk_find(dev_id, con_id);
+	if (cl && !__clk_get(cl->clk))
+		cl = NULL;
+	mutex_unlock(&clocks_mutex);
+
+	return cl ? cl->clk : ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get_sys);
+
+struct clk *clk_get(struct device *dev, const char *con_id)
+{
+	const char *dev_id = dev ? dev_name(dev) : NULL;
+
+	return clk_get_sys(dev_id, con_id);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+	__clk_put(clk);
+}
+EXPORT_SYMBOL(clk_put);
+
+void clkdev_add(struct clk_lookup *cl)
+{
+	mutex_lock(&clocks_mutex);
+	list_add_tail(&cl->node, &clocks);
+	mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL(clkdev_add);
+
+void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
+{
+	mutex_lock(&clocks_mutex);
+	while (num--) {
+		list_add_tail(&cl->node, &clocks);
+		cl++;
+	}
+	mutex_unlock(&clocks_mutex);
+}
+
+#define MAX_DEV_ID	20
+#define MAX_CON_ID	16
+
+struct clk_lookup_alloc {
+	struct clk_lookup cl;
+	char	dev_id[MAX_DEV_ID];
+	char	con_id[MAX_CON_ID];
+};
+
+struct clk_lookup * __init_refok
+clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
+{
+	struct clk_lookup_alloc *cla;
+
+	cla = __clkdev_alloc(sizeof(*cla));
+	if (!cla)
+		return NULL;
+
+	cla->cl.clk = clk;
+	if (con_id) {
+		strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
+		cla->cl.con_id = cla->con_id;
+	}
+
+	if (dev_fmt) {
+		va_list ap;
+
+		va_start(ap, dev_fmt);
+		vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
+		cla->cl.dev_id = cla->dev_id;
+		va_end(ap);
+	}
+
+	return &cla->cl;
+}
+EXPORT_SYMBOL(clkdev_alloc);
+
+int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
+	struct device *dev)
+{
+	struct clk *r = clk_get(dev, id);
+	struct clk_lookup *l;
+
+	if (IS_ERR(r))
+		return PTR_ERR(r);
+
+	l = clkdev_alloc(r, alias, alias_dev_name);
+	clk_put(r);
+	if (!l)
+		return -ENODEV;
+	clkdev_add(l);
+	return 0;
+}
+EXPORT_SYMBOL(clk_add_alias);
+
+/*
+ * clkdev_drop - remove a clock dynamically allocated
+ */
+void clkdev_drop(struct clk_lookup *cl)
+{
+	mutex_lock(&clocks_mutex);
+	list_del(&cl->node);
+	mutex_unlock(&clocks_mutex);
+	kfree(cl);
+}
+EXPORT_SYMBOL(clkdev_drop);
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/zte/Makefile b/ap/os/linux/linux-3.4.x/drivers/clk/zte/Makefile
new file mode 100644
index 0000000..271eb91
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/zte/Makefile
@@ -0,0 +1,3 @@
+obj-y					     		+= clk.o
+obj-$(CONFIG_ARCH_ZX297520V2)         += clk-zx297520v2.o
+obj-$(CONFIG_ARCH_ZX297520V3)         += clk-zx297520v3.o
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk-zx297520v2.c b/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk-zx297520v2.c
new file mode 100644
index 0000000..d0ec9e4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk-zx297520v2.c
@@ -0,0 +1,1344 @@
+/*
+ * arch/arm/mach-zx297520v2/zx297520v2-clock.c
+ *
+ *  Copyright (C) 2015 ZTE-TSP
+ *
+ * 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/module.h>
+
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <linux/math64.h>
+
+#include <linux/clkdev.h>
+#include <mach/spinlock.h>
+#include <mach/board.h>
+#include <mach/iomap.h>
+#include <linux/clk-private.h>
+
+#include "clk.h"
+
+#define DEFINE_ZX29_CLK(hwclk,clkops,num,names) \
+    struct clk * parents_##hwclk[num]; \
+    static struct clk hwclk##_clk = { \
+    .name = #hwclk "_clk", \
+    .hw = &hwclk.hw, \
+    .ops = &clkops, \
+    .num_parents = num, \
+    .parent_names = names, \
+    .parents = parents_##hwclk, \
+    .flags = CLK_AUTO_ROUND_PARENT, \
+}
+
+#define DEFINE_ZX29_CLK_FLAG(hwclk,clkops,num,names, flag) \
+    struct clk * parents_##hwclk[num]; \
+    static struct clk hwclk##_clk = { \
+    .name = #hwclk "_clk", \
+    .hw = &hwclk.hw, \
+    .ops = &clkops, \
+    .num_parents = num, \
+    .parent_names = names, \
+    .parents = parents_##hwclk, \
+    .flags = flag, \
+}
+
+/*
+ * enable the clk.
+ */
+static int zx297520v2_clk_enable(struct clk_hw *hw)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_en_reg.reg_bit_size == 0)
+        return 0;
+
+    regaddr = zx29clk->clk_en_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+	data |= 1<<zx29clk->clk_en_reg.reg_bit_offset;
+	iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/*
+ * disable the clk.
+ */
+static void zx297520v2_clk_disable(struct clk_hw *hw)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_en_reg.reg_bit_size == 0)
+        return ;
+
+    regaddr = zx29clk->clk_en_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+	data &= ~(1<<zx29clk->clk_en_reg.reg_bit_offset);
+	iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return ;
+}
+
+/*
+ * get clk's enable state.
+ */
+static int zx297520v2_is_enabled(struct clk_hw *hw)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_en_reg.reg_bit_size == 0)
+        return 1;
+
+    regaddr = zx29clk->clk_en_reg.reg_addr;
+
+	data=ioread32(regaddr);
+	data>>=zx29clk->clk_en_reg.reg_bit_offset;
+
+    if(data & 0x1)
+        return 1;
+    else
+        return 0;
+}
+
+/*
+ * set the clk division for new rate.
+ *
+ * new_rate = parent->rate/(clk_div+1)
+ */
+static int zx297520v2_clk_set_rate(struct clk_hw *hw, unsigned long new_rate)//, unsigned long parent_rate)
+{
+    unsigned long parent_rate = 0;
+    unsigned long clk_div = 0;
+	void __iomem *regaddr = NULL;
+	unsigned int data = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->hw.clk == NULL || zx29clk->hw.clk->parent == NULL)
+        return -EINVAL;
+    if(zx29clk->clk_div_reg.reg_bit_size == 0)
+        return -EINVAL;
+
+    parent_rate = zx29clk->hw.clk->parent->rate;
+    clk_div = parent_rate/new_rate;
+	/*get the max division*/
+    if(clk_div >= (1<<zx29clk->clk_div_reg.reg_bit_size))
+        clk_div = (1<<zx29clk->clk_div_reg.reg_bit_size);
+
+    if(clk_div)
+	{
+        clk_div--;
+    }
+
+    regaddr = zx29clk->clk_div_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+	data &= ~(((1<<(zx29clk->clk_div_reg.reg_bit_size))-1)<<zx29clk->clk_div_reg.reg_bit_offset);
+    data |= clk_div<<zx29clk->clk_div_reg.reg_bit_offset;
+    iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/*
+ * get the clk's rate.
+ *
+ * new_rate = parent->rate/(clk_div+1)
+ */
+static unsigned long zx297520v2_clk_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	void __iomem *regaddr = NULL;
+	unsigned int data = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+	/*if no clk division, return parent's rate */
+    if(zx29clk->clk_div_reg.reg_bit_size == 0) {
+        if(zx29clk->hw.clk->num_parents)
+            return parent_rate;
+        else
+            return 0;
+    }
+
+    regaddr = zx29clk->clk_div_reg.reg_addr;
+
+	data=ioread32(regaddr);
+    data >>= zx29clk->clk_div_reg.reg_bit_offset;
+	data &= ((1<<(zx29clk->clk_div_reg.reg_bit_size))-1);
+
+    return parent_rate/(data+1);
+}
+
+#if 0
+/*
+ * get the clk's rate.
+ *
+ * new_rate = parent->rate/(2^clk_div)
+ */
+static unsigned long zx297520v2_clk_recalc_rate_x2(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	void __iomem *regaddr = NULL;
+	unsigned int data = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_div_reg.reg_bit_size == 0) {
+        if(zx29clk->hw.clk->num_parents)
+            return parent_rate;
+        else
+            return 0;
+    }
+
+    regaddr = zx29clk->clk_div_reg.reg_addr;
+
+	data=ioread32(regaddr);
+    data >>= zx29clk->clk_div_reg.reg_bit_offset;
+	data &= ((1<<(zx29clk->clk_div_reg.reg_bit_size))-1);
+
+    return parent_rate/(0x1<<data);
+}
+#endif
+
+/*
+ * select parent from given parents.
+ *
+ * index < num_parents
+ */
+static int zx297520v2_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	void __iomem *regaddr = NULL;
+	unsigned int data = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->hw.clk->num_parents==0 || index>=zx29clk->hw.clk->num_parents)
+        return -EINVAL;
+    if(zx29clk->clk_sel_reg.reg_bit_size == 0)
+        return 0;
+
+    regaddr = zx29clk->clk_sel_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+	data &= ~(((1<<(zx29clk->clk_sel_reg.reg_bit_size))-1)<<zx29clk->clk_sel_reg.reg_bit_offset);
+    data |= index<<zx29clk->clk_sel_reg.reg_bit_offset;
+    iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/*
+ * get current parent select.
+ *
+ * return index begin with 0.
+ */
+static u8 zx297520v2_get_parent(struct clk_hw *hw)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->hw.clk->num_parents < 2 || zx29clk->clk_sel_reg.reg_bit_size ==0)
+        return 0;
+
+    regaddr = zx29clk->clk_sel_reg.reg_addr;
+
+	data = ioread32(regaddr);
+    data >>= zx29clk->clk_sel_reg.reg_bit_offset;
+    data &= (1<<(zx29clk->clk_sel_reg.reg_bit_size))-1;
+
+    return data;
+}
+
+/*
+ * calc the rate we can support.
+ *
+ * rate: request rate(maybe we can not support exactly)
+ */
+static long zx297520v2_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long * best_parent_rate)
+{
+    unsigned long parent_rate = 0;
+    unsigned long clk_div = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->hw.clk == NULL || zx29clk->hw.clk->parent == NULL)
+        return 0;
+//    if(zx29clk->clk_div_reg.reg_bit_size == 0)
+//        return 0;
+
+    parent_rate = zx29clk->hw.clk->parent->rate;
+    clk_div = parent_rate/rate;
+    if(clk_div >= (1<<zx29clk->clk_div_reg.reg_bit_size))
+    {
+        clk_div = (1<<zx29clk->clk_div_reg.reg_bit_size);
+    }
+
+    if(!clk_div)
+        return parent_rate;
+
+	if ((zx29clk->hw.clk->flags & CLK_NO_ODD_DIV) && (clk_div & 0x1) && (clk_div != 0x1))
+		clk_div++;
+
+    return parent_rate/(clk_div);
+}
+
+/*
+ * set auto clk gate.
+ *
+ * this only set once when system start.
+ */
+static int zx297520v2_set_auto_gate(struct clk_hw *hw, bool enable)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_gate_reg.reg_bit_size == 0)
+        return -EINVAL;
+
+    regaddr = zx29clk->clk_gate_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+    if(enable)
+	    data |= 1<<zx29clk->clk_gate_reg.reg_bit_offset;
+    else
+	    data &= ~(1<<zx29clk->clk_gate_reg.reg_bit_offset);
+	iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/**************************************************************************
+*   peripheral clk divider new algorithm
+*
+*   1. default algorithm:  new_rate = parent_rate/(1+clk_div)
+*   2. new algorithm:  new_rate = parent_rate/(2*(integer_num+(clk_sel+fra_div/fra_base)/2))
+*
+***************************************************************************
+*/
+#define	CLK_FRA_DIV(a)			(zx_read_reg(a)&0xff)
+#define	CLK_FRA_BASE(a)			((zx_read_reg(a)>>8)&0xff)
+#define	CLK_INTEGER_NUM(a)		((zx_read_reg(a)>>16)&0xff)
+#define	CLK_CLK_SEL(a)			((zx_read_reg(a)>>24)&1)
+
+/*
+{2.0, 	MIX_CLK_DIVIDER(0, 	  0xff, 1, 0)	},
+{2.5, 	MIX_CLK_DIVIDER(0x7f, 0xff, 1, 0)	},
+{3.0, 	MIX_CLK_DIVIDER(0, 	  0xff, 1, 1)	},
+{3.5, 	MIX_CLK_DIVIDER(0x7f, 0xff, 1, 1)	},
+*/
+/* d--fra_div  b--fra_base  n--integer_num  s--clk_sel */
+#define	MIX_CLK_DIVIDER(d,b,n,s)	\
+	(d|(b<<8)|(n<<16)|(s<<24))
+
+#define	MAX_CLK_DIVIDER			0x200//(2.0*(0xff+(1.0+0xff/0xff)/2.0))
+#define	FLOAT_CALC_FACTOR		(u64)(1000*1000)
+
+static void parase_float_clk_divider(u64 clk_div,
+                                     unsigned int *fra_div,
+                                     unsigned int *fra_base,
+                                     unsigned int *integer_num,
+                                     unsigned int *clk_sel)
+{
+	*integer_num = (unsigned int)div64_u64(clk_div, FLOAT_CALC_FACTOR)/2;
+	*clk_sel	 = (unsigned int)div64_u64(clk_div, FLOAT_CALC_FACTOR)%2;
+	*fra_base	 = 0xff;
+	*fra_div     = (unsigned int)div64_u64((clk_div-*integer_num*FLOAT_CALC_FACTOR*2-*clk_sel*FLOAT_CALC_FACTOR)*255,
+											FLOAT_CALC_FACTOR);
+}
+
+/*
+ * set the clk division for new rate.
+ *
+ */
+static int zx297520v2_clk_set_rate_float(struct clk_hw *hw, unsigned long new_rate)
+{
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+	unsigned int fra_div = 0;
+	unsigned int fra_base = 0;
+	unsigned int integer_num = 0;
+	unsigned int clk_sel = 0;
+	u64 tmp_parent_rate;
+	u64 clk_div = 0;
+
+    if(zx29clk->hw.clk == NULL || zx29clk->hw.clk->parent == NULL)
+        return -EINVAL;
+    if(zx29clk->clk_div_reg.reg_addr == 0)
+        return -EINVAL;
+
+    tmp_parent_rate = zx29clk->hw.clk->parent->rate*FLOAT_CALC_FACTOR;
+	clk_div	= div64_u64(tmp_parent_rate, new_rate);
+
+	/*get the max division*/
+    if(clk_div >= MAX_CLK_DIVIDER*FLOAT_CALC_FACTOR)
+        clk_div = MAX_CLK_DIVIDER*FLOAT_CALC_FACTOR;
+
+	parase_float_clk_divider(clk_div, &fra_div, &fra_base, &integer_num, &clk_sel);
+
+	hw_spin_lock(CLK_HWLOCK);
+	zx_write_reg(zx29clk->clk_div_reg.reg_addr,
+				 MIX_CLK_DIVIDER(fra_div, fra_base, integer_num, clk_sel));
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/*
+ * get the clk's rate.
+ *
+ * new_rate = parent_rate/(2*(integer_num+(clk_sel+fra_div/fra_base)/2))
+ */
+static unsigned long zx297520v2_clk_recalc_rate_float(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+	unsigned int fra_div = 0;
+	unsigned int fra_base = 0;
+	unsigned int clk_sel = 0;
+	unsigned int integer_num = 0;
+	u64 tmp_parent_rate = (u64)parent_rate*FLOAT_CALC_FACTOR;
+	u64 clk_div = 0;
+
+    regaddr = zx29clk->clk_div_reg.reg_addr;
+
+	/*if no clk division, return parent's rate */
+    if(regaddr == 0) {
+        if(zx29clk->hw.clk->num_parents)
+            return parent_rate;
+        else
+            return 0;
+    }
+
+	fra_div 	= CLK_FRA_DIV(regaddr);
+	fra_base 	= CLK_FRA_BASE(regaddr);
+	clk_sel 	= CLK_CLK_SEL(regaddr);
+	integer_num = CLK_INTEGER_NUM(regaddr);
+
+	clk_div = (2*integer_num+clk_sel)*FLOAT_CALC_FACTOR+div64_u64(fra_div*FLOAT_CALC_FACTOR,fra_base);
+
+    return (unsigned long)div64_u64(tmp_parent_rate, clk_div);
+}
+
+/*
+ * calc the rate we can support.
+ *
+ * rate: request rate(maybe we can not support exactly)
+ */
+static long zx297520v2_clk_round_rate_float(struct clk_hw *hw, unsigned long rate,
+					unsigned long * best_parent_rate)
+{
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+	u64 tmp_parent_rate;
+	u64 clk_div = 0;
+
+    if(zx29clk->hw.clk == NULL || zx29clk->hw.clk->parent == NULL)
+        return 0;
+    if(zx29clk->clk_div_reg.reg_addr == 0)
+		return 0;
+
+	tmp_parent_rate = zx29clk->hw.clk->parent->rate*FLOAT_CALC_FACTOR;
+	clk_div	= div64_u64(tmp_parent_rate, rate);
+
+	if(clk_div >= MAX_CLK_DIVIDER*FLOAT_CALC_FACTOR)
+		clk_div = MAX_CLK_DIVIDER*FLOAT_CALC_FACTOR;
+
+    if(!clk_div)
+        return (long)div64_u64(tmp_parent_rate, FLOAT_CALC_FACTOR);
+	else
+    	return (long)div64_u64(tmp_parent_rate, clk_div);
+}
+
+static int clk_rootclk_enable(struct clk_hw *hw)
+{
+    return 0;
+}
+static void clk_rootclk_disable(struct clk_hw *hw)
+{
+    return ;
+}
+
+static int clk_rootclk_is_enabled(struct clk_hw *hw)
+{
+    return 1;
+}
+
+static int clk_rootclk_set_rate(struct clk_hw *hw, unsigned long new_rate)//, unsigned long parent_rate)
+{
+    return 0;
+}
+
+static struct clk_ops peripheral_clk_ops =
+{
+    .enable 		= zx297520v2_clk_enable,
+    .disable 		= zx297520v2_clk_disable,
+	.set_auto_gate 	= zx297520v2_set_auto_gate,
+    .set_rate 		= zx297520v2_clk_set_rate,
+    .recalc_rate 	= zx297520v2_clk_recalc_rate,
+    .set_parent 	= zx297520v2_clk_set_parent,
+    .round_rate 	= zx297520v2_clk_round_rate,
+    .get_parent 	= zx297520v2_get_parent,
+    .is_enabled 	= zx297520v2_is_enabled,
+};
+
+static struct clk_ops peripheral_float_clk_ops =
+{
+    .enable 		= zx297520v2_clk_enable,
+    .disable 		= zx297520v2_clk_disable,
+	.set_auto_gate 	= zx297520v2_set_auto_gate,
+    .set_rate 		= zx297520v2_clk_set_rate_float,
+    .recalc_rate 	= zx297520v2_clk_recalc_rate_float,
+    .set_parent 	= zx297520v2_clk_set_parent,
+    .round_rate 	= zx297520v2_clk_round_rate_float,
+    .get_parent 	= zx297520v2_get_parent,
+    .is_enabled 	= zx297520v2_is_enabled,
+};
+
+static struct clk_ops cpu_clk_ops =
+{
+    .enable 		= zx297520v2_clk_enable,
+    .disable 		= zx297520v2_clk_disable,
+    .set_auto_gate 	= zx297520v2_set_auto_gate,
+    .set_rate 		= zx297520v2_clk_set_rate,
+    .recalc_rate 	= zx297520v2_clk_recalc_rate,
+    .set_parent 	= zx297520v2_clk_set_parent,
+    .round_rate 	= zx297520v2_clk_round_rate,
+    .get_parent 	= zx297520v2_get_parent,
+    .is_enabled 	= zx297520v2_is_enabled,
+};
+
+struct clk_ops root_clk_ops = {
+    .enable 	= clk_rootclk_enable,
+	.disable 	= clk_rootclk_disable,
+	.is_enabled = clk_rootclk_is_enabled,
+	.set_rate 	= clk_rootclk_set_rate,
+};
+
+
+/*
+*   root clk
+*/
+DEFINE_ZX29_ROOT_CLK(main_clk_32k, 	32768);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_12m, 	12*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_39m, 	39*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_52m, 	52*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_78m, 	78*1000*1000);
+#if CONFIG_ARCH_ZX297520V2FPGA
+DEFINE_ZX29_ROOT_CLK(main_clk_26m, 	25*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_104m, 25*1000*1000);
+#else
+DEFINE_ZX29_ROOT_CLK(main_clk_26m, 	26*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_104m, 104*1000*1000);
+#endif
+DEFINE_ZX29_ROOT_CLK(mpll_clk_124m8, 124800*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_156m, 156*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_208m, 208*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_312m, 312*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_624m, 624*1000*1000);
+DEFINE_ZX29_ROOT_CLK(dpll_clk_491m52, 491520*1000);
+DEFINE_ZX29_ROOT_CLK(dpll_clk_122m88, 122880*1000);
+DEFINE_ZX29_ROOT_CLK(dpll_clk_81m92, 81920*1000);
+DEFINE_ZX29_ROOT_CLK(upll_clk_480m, 480*1000*1000);
+DEFINE_ZX29_ROOT_CLK(upll_clk_96m, 	96*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_25m, 	25*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_50m, 	50*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_100m, 100*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_178m, 178*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_200m, 200*1000*1000);
+
+
+/*
+*   a1_uart0
+*/
+char*  a1_uart_wclk_parents[2] =
+{
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(main_clk_26m)
+};
+char*  lsp_uart_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_104m)
+};
+static struct zx29_hwclk uart0_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5C,	13,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5C,	14,	1},
+};
+DEFINE_ZX29_CLK(uart0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk uart0_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5C,	12,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x40,	2,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x40,	0,	0},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5C,	15,	1},
+};
+DEFINE_ZX29_CLK(uart0_work,peripheral_clk_ops,2,a1_uart_wclk_parents);
+
+/*
+*   lsp_uart1
+*/
+static struct zx29_hwclk uart1_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x28,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x28,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x28, 	11,	1},
+};
+DEFINE_ZX29_CLK(uart1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk uart1_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x28,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x28,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x28,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x28, 	10,	1},
+};
+DEFINE_ZX29_CLK(uart1_work,peripheral_clk_ops,2,lsp_uart_wclk_parents);
+
+/*
+*   lsp_uart2
+*/
+static struct zx29_hwclk uart2_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x3c,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x3c,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x3c, 	11,	1},
+};
+DEFINE_ZX29_CLK(uart2_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk uart2_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x3c,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x3c,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x3c,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x3c, 	10,	1},
+};
+DEFINE_ZX29_CLK(uart2_work,peripheral_clk_ops,2,lsp_uart_wclk_parents);
+
+/*
+*   a1_timer1
+*/
+char*  a1_timer_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(main_clk_32k)
+};
+char*  lsp_timer_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_32k),
+	NAME_CLK(main_clk_26m)
+};
+static struct zx29_hwclk timer1_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	1,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x60,	2,	1},
+};
+DEFINE_ZX29_CLK(timer1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer1_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	0,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x44,	0,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x50,	0,	4},
+};
+DEFINE_ZX29_CLK(timer1_work,peripheral_clk_ops,2,a1_timer_wclk_parents);
+
+/*
+*   a1_timer2
+*/
+static struct zx29_hwclk timer2_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	5,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x60,	6,	1},
+};
+DEFINE_ZX29_CLK(timer2_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer2_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	4,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x44,	1,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x50,	4,	4},
+};
+DEFINE_ZX29_CLK(timer2_work,peripheral_clk_ops,2,a1_timer_wclk_parents);
+
+/*
+*   a1_timer3
+*/
+static struct zx29_hwclk timer3_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	9,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x60,	10,	1},
+};
+DEFINE_ZX29_CLK(timer3_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer3_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	8,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x44,	2,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x50,	8,	4},
+};
+DEFINE_ZX29_CLK(timer3_work,peripheral_clk_ops,2,a1_timer_wclk_parents);
+
+/*
+*   lsp_timer0
+*/
+static struct zx29_hwclk timer0_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x44,	0,	1},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x44,	11,	1},
+};
+DEFINE_ZX29_CLK(timer0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer0_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x44,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x44,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x44,	12,	4},
+};
+DEFINE_ZX29_CLK(timer0_work,peripheral_clk_ops,2,lsp_timer_wclk_parents);
+
+/*
+*   lsp_timer4
+*/
+static struct zx29_hwclk timer4_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x4C,	0,	1},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x4C,	11,	1},
+};
+DEFINE_ZX29_CLK(timer4_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer4_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x4C,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x4C,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x4C,	12,	4},
+};
+DEFINE_ZX29_CLK(timer4_work,peripheral_clk_ops,2,lsp_timer_wclk_parents);
+
+
+/**************************************************************************
+*   i2c
+***************************************************************************
+*/
+char*  a1_i2c_wclk_parents[2] =
+{
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(main_clk_26m)
+};
+char*  lsp_i2c_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_104m)
+};
+
+/*
+*   a1_i2c0
+*/
+static struct zx29_hwclk i2c0_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,		8,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x54, 	10,	1},
+};
+DEFINE_ZX29_CLK(i2c0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk i2c0_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,		9,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x3C,		1,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x54, 	11,	1},
+};
+DEFINE_ZX29_CLK(i2c0_work,peripheral_clk_ops,2,a1_i2c_wclk_parents);
+/*
+*   lsp_i2c1
+*/
+static struct zx29_hwclk i2c1_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x2C,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x2C,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x2C, 	11,	1},
+};
+DEFINE_ZX29_CLK(i2c1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk i2c1_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x2C,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x2C,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x2C,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x2C, 	10,	1},
+};
+DEFINE_ZX29_CLK(i2c1_work,peripheral_clk_ops,2,lsp_i2c_wclk_parents);
+
+/**************************************************************************
+*   ssp
+***************************************************************************
+*/
+char*  lsp_ssp_wclk_parents[3] =
+{
+	NAME_CLK(mpll_clk_156m),
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(main_clk_26m)
+};
+
+/*
+*   lsp_ssp0
+*/
+static struct zx29_hwclk ssp0_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x30,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x30,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x30, 	11,	1},
+};
+DEFINE_ZX29_CLK(ssp0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk ssp0_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x30,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x30,	4,	2},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x30,	12,	4},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x30, 	10,	1},
+};
+DEFINE_ZX29_CLK_FLAG(ssp0_work,peripheral_clk_ops,3,lsp_ssp_wclk_parents, (CLK_AUTO_ROUND_PARENT | CLK_NO_ODD_DIV));
+/*
+*   lsp_ssp1
+*/
+static struct zx29_hwclk ssp1_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x48,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x48,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x48, 	11,	1},
+};
+DEFINE_ZX29_CLK(ssp1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk ssp1_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x48,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x48,	4,	2},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x48,	12,	4},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x48, 	10,	1},
+};
+DEFINE_ZX29_CLK_FLAG(ssp1_work,peripheral_clk_ops,3,lsp_ssp_wclk_parents, (CLK_AUTO_ROUND_PARENT | CLK_NO_ODD_DIV));
+
+/**************************************************************************
+*   ap wdt
+***************************************************************************
+*/
+char*  lsp_wdt_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_32k),
+	NAME_CLK(main_clk_26m)
+};
+
+static struct zx29_hwclk ap_wdt_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x40,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x40,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x40, 	11,	1},
+};
+DEFINE_ZX29_CLK(ap_wdt_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk ap_wdt_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x40,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x40,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x40,	12,	4},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x40, 	10,	1},
+};
+DEFINE_ZX29_CLK(ap_wdt_work,peripheral_clk_ops,2,lsp_wdt_wclk_parents);
+
+/**************************************************************************
+*   tdm
+***************************************************************************
+*/
+char*  lsp_tdm_wclk_parents[3] =
+{
+	NAME_CLK(dpll_clk_81m92),
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_104m)
+};
+
+static struct zx29_hwclk tdm_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x50,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x50,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x50, 	11,	1},
+};
+DEFINE_ZX29_CLK(tdm_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk tdm_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x50,	1,	1},
+	.clk_sel_reg	={ZX_MATRIX_CRM_BASE+0x50,	0,	0},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x54,	24,	2},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x50, 	10,	1},
+};
+DEFINE_ZX29_CLK(tdm_work,peripheral_float_clk_ops,3,lsp_tdm_wclk_parents);
+
+/**************************************************************************
+*   i2s
+***************************************************************************
+*/
+char*  lsp_i2s_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_104m)
+};
+
+static struct zx29_hwclk i2s0_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x14,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x14,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x14, 	11,	1},
+};
+DEFINE_ZX29_CLK(i2s0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk i2s0_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x14,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x14,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x18,	0,	2},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x14, 	10,	1},
+};
+DEFINE_ZX29_CLK(i2s0_work,peripheral_float_clk_ops,2,lsp_i2s_wclk_parents);
+
+static struct zx29_hwclk i2s1_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x1C,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x1C,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x1C, 	11,	1},
+};
+DEFINE_ZX29_CLK(i2s1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk i2s1_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x1C,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x1C,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x20,	0,	2},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x1C, 	10,	1},
+};
+DEFINE_ZX29_CLK(i2s1_work,peripheral_float_clk_ops,2,lsp_i2s_wclk_parents);
+
+/**************************************************************************
+*   spifc
+***************************************************************************
+*/
+char*  lsp_spifc_wclk_parents[] =
+{
+	NAME_CLK(mpll_clk_156m),
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_124m8),
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(mpll_clk_52m)
+};
+
+static struct zx29_hwclk spifc_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x24,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x24,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x24, 	11,	1},
+};
+DEFINE_ZX29_CLK(spifc_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk spifc_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x24,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x24,	4,	3},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x24,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x24, 	10,	1},
+};
+DEFINE_ZX29_CLK(spifc_work,peripheral_clk_ops,ARRAY_SIZE(lsp_spifc_wclk_parents),lsp_spifc_wclk_parents);
+
+/**************************************************************************
+*   kpd
+***************************************************************************
+*/
+char*  kpd_wclk_parents[] =
+{
+	NAME_CLK(main_clk_32k),
+};
+
+static struct zx29_hwclk kpd_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5C,	17,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x5C,	0,	0},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5C, 19,	1},
+};
+DEFINE_ZX29_CLK(kpd_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk kpd_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5C,	16,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x5C,	0,	0},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x5C,	0,	0},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5C, 18,	1},
+};
+DEFINE_ZX29_CLK(kpd_work,peripheral_clk_ops,ARRAY_SIZE(kpd_wclk_parents),kpd_wclk_parents);
+
+/**************************************************************************
+*   rtc
+***************************************************************************
+*/
+char*  rtc_wclk_parents[] =
+{
+	NAME_CLK(main_clk_32k),
+};
+
+static struct zx29_hwclk rtc_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,	0,	1},
+
+};
+DEFINE_ZX29_CLK(rtc_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk rtc_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,	1,	1},
+};
+DEFINE_ZX29_CLK(rtc_work,peripheral_clk_ops,ARRAY_SIZE(rtc_wclk_parents),rtc_wclk_parents);
+
+/**************************************************************************
+*   hs_ahb (parent of hsic/usb ahb clk)
+***************************************************************************
+*/
+char*  hs_ahb_parents[] =
+{
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(mpll_clk_52m),
+};
+static struct zx29_hwclk hs_ahb =
+{
+/*	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,	12,	1}, */
+	.clk_sel_reg 	={ZX_TOP_CRM_BASE+0x3C,	4,	2},
+};
+DEFINE_ZX29_CLK(hs_ahb,peripheral_clk_ops,ARRAY_SIZE(hs_ahb_parents),hs_ahb_parents);
+
+/**************************************************************************
+*   usb2.0
+***************************************************************************
+*/
+char*  usb_12m_parents[] =
+{
+	NAME_CLK(mpll_clk_12m),
+};
+
+char*  usb_480m_parents[] =
+{
+	NAME_CLK(upll_clk_480m),
+};
+
+char*  usb_ahb_parents[] =
+{
+	"hs_ahb_clk",
+};
+static struct zx29_hwclk usb_ahb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x6C,	4,	1},
+};
+DEFINE_ZX29_CLK(usb_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk usb_12m =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x6C,	3,	1},
+};
+DEFINE_ZX29_CLK(usb_12m,peripheral_clk_ops,ARRAY_SIZE(usb_12m_parents),usb_12m_parents);
+
+/**************************************************************************
+ *   HSIC
+ **************************************************************************
+ */
+static struct zx29_hwclk hsic_ahb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x6C,	2,	1},
+};
+DEFINE_ZX29_CLK(hsic_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk hsic_12m =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x6C,	1,	1},
+};
+DEFINE_ZX29_CLK(hsic_12m,peripheral_clk_ops,ARRAY_SIZE(usb_12m_parents),usb_12m_parents);
+
+static struct zx29_hwclk hsic_480m =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x6C,	0,	1},
+};
+DEFINE_ZX29_CLK(hsic_480m,peripheral_clk_ops,ARRAY_SIZE(usb_480m_parents),usb_480m_parents);
+
+/**************************************************************************
+ *   GMAC
+ **************************************************************************
+ */
+char*  gmac_rmii_parents[] =
+{
+	NAME_CLK(gpll_clk_50m),
+};
+
+static struct zx29_hwclk gmac_ahb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x110,	2,	1},
+};
+DEFINE_ZX29_CLK(gmac_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk gmac_apb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x110,	1,	1},
+};
+DEFINE_ZX29_CLK(gmac_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk gmac_rmii =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x110,	0,	1},
+};
+DEFINE_ZX29_CLK(gmac_rmii,peripheral_clk_ops,ARRAY_SIZE(gmac_rmii_parents),gmac_rmii_parents);
+
+/**************************************************************************
+ *   SD
+ **************************************************************************
+ */
+char*  sd0_work_parents[] =
+{
+	NAME_CLK(gpll_clk_200m),
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_156m),
+	NAME_CLK(gpll_clk_100m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(gpll_clk_50m),
+	NAME_CLK(gpll_clk_178m),
+	NAME_CLK(gpll_clk_25m),
+
+};
+char*  sd1_work_parents[] =
+{
+	NAME_CLK(gpll_clk_100m),
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(gpll_clk_50m),
+	NAME_CLK(mpll_clk_39m),
+	NAME_CLK(gpll_clk_25m),
+};
+char*  sd_cdet_parents[] =
+{
+	NAME_CLK(main_clk_32k),
+};
+static struct zx29_hwclk sd0_ahb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	12,	1},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x54,	16,	1},
+};
+DEFINE_ZX29_CLK(sd0_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk sd0_work =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	13,	1},
+	.clk_sel_reg	={ZX_MATRIX_CRM_BASE+0x50,	4,	3},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x54,	17,	1},
+};
+DEFINE_ZX29_CLK(sd0_work,peripheral_clk_ops,ARRAY_SIZE(sd0_work_parents),sd0_work_parents);
+
+static struct zx29_hwclk sd0_cdet =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	14,	1},
+};
+DEFINE_ZX29_CLK(sd0_cdet,peripheral_clk_ops,ARRAY_SIZE(sd_cdet_parents),sd_cdet_parents);
+
+static struct zx29_hwclk sd1_ahb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	4,	1},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x54,	8,	1},
+};
+DEFINE_ZX29_CLK(sd1_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk sd1_work =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	5,	1},
+	.clk_sel_reg	={ZX_MATRIX_CRM_BASE+0x50,	8,	3},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x54,	9,	1},
+};
+DEFINE_ZX29_CLK(sd1_work,peripheral_clk_ops,ARRAY_SIZE(sd1_work_parents),sd1_work_parents);
+
+static struct zx29_hwclk sd1_cdet =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	6,	1},
+};
+DEFINE_ZX29_CLK(sd1_cdet,peripheral_clk_ops,ARRAY_SIZE(sd_cdet_parents),sd_cdet_parents);
+/*
+*   axi
+*
+*   can select 156/26/122.88/104/78/52/39
+*   can not div
+*/
+char*  axi_clk_parents[] =
+{
+	NAME_CLK(mpll_clk_156m),
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(dpll_clk_122m88),
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(mpll_clk_52m),
+	NAME_CLK(mpll_clk_39m)
+};
+static struct zx29_hwclk axi = {
+	/*             reg_addr				bit_offset	  bit_size	*/
+	.clk_en_reg ={0,                        0,          0},
+	.clk_sel_reg={ZX_MATRIX_CRM_BASE+0x0, 	0, 			3},
+	.clk_div_reg={0,                        0,          0},
+};
+
+DEFINE_ZX29_CLK(axi,peripheral_clk_ops,ARRAY_SIZE(axi_clk_parents),axi_clk_parents);
+
+/*
+*   ap cpu
+*
+*   can select 26/52/78/104/208/312/491.52/624
+*   can not div, gated with hw
+*/
+char*  cpu_clk_parents[] =
+{
+	NAME_CLK(mpll_clk_624m),
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(dpll_clk_491m52),
+	NAME_CLK(mpll_clk_312m),
+	NAME_CLK(mpll_clk_208m),
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(mpll_clk_52m)
+};
+static struct zx29_hwclk cpu_work = {
+	/*             reg_addr				bit_offset	  bit_size	*/
+	.clk_en_reg ={0,                        0,          0},
+	.clk_sel_reg={ZX_MATRIX_CRM_BASE+0x40, 	0, 			3},
+	.clk_div_reg={0,                        0,          0},
+};
+DEFINE_ZX29_CLK(cpu_work,cpu_clk_ops,ARRAY_SIZE(cpu_clk_parents),cpu_clk_parents);
+
+/*for zx297520v2, we do not operate pll and global resource,
+  we only support periph_clocks and clk source select */
+struct clk_lookup periph_clocks_lookups[] = {
+	/*              dev_id       name           		clk struct */
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(main_clk_32k), 	&main_clk_32k),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(main_clk_26m), 	&main_clk_26m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_12m), 	&mpll_clk_12m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_39m), 	&mpll_clk_39m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_52m), 	&mpll_clk_52m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_78m), 	&mpll_clk_78m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_104m), 	&mpll_clk_104m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_124m8), 	&mpll_clk_124m8),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_156m), 	&mpll_clk_156m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_208m), 	&mpll_clk_208m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_312m), 	&mpll_clk_312m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_624m), 	&mpll_clk_624m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(dpll_clk_491m52), 	&dpll_clk_491m52),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(dpll_clk_122m88), 	&dpll_clk_122m88),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(dpll_clk_81m92), 	&dpll_clk_81m92),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(upll_clk_480m), 	&upll_clk_480m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(upll_clk_96m), 	&upll_clk_96m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_25m), 	&gpll_clk_25m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_50m), 	&gpll_clk_50m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_100m), 	&gpll_clk_100m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_178m), 	&gpll_clk_178m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_200m), 	&gpll_clk_200m),
+
+
+	CLK_ZX29_CONFIG(NULL, 			  "axi_clk", 		&axi_clk),
+
+	CLK_ZX29_CONFIG(NULL, 			  "cpu_clk",  		&cpu_work_clk),
+
+	CLK_ZX29_CONFIG(NULL,      		  "hs_ahb_clk", 	&hs_ahb_clk),
+
+	CLK_ZX29_CONFIG("zx29_ap_wdt.0",  "work_clk", 		&ap_wdt_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_wdt.0",  "apb_clk",  		&ap_wdt_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_uart.0", 	  "work_clk", 		&uart0_work_clk),
+	CLK_ZX29_CONFIG("zx29_uart.0",    "apb_clk",  		&uart0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_uart.1",    "work_clk", 		&uart1_work_clk),
+	CLK_ZX29_CONFIG("zx29_uart.1",    "apb_clk",  		&uart1_apb_clk),
+	CLK_ZX29_CONFIG("zx29_uart.2",    "work_clk", 		&uart2_work_clk),
+	CLK_ZX29_CONFIG("zx29_uart.2",    "apb_clk",  		&uart2_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_ap_timer0", "work_clk", 		&timer0_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer0", "apb_clk", 		&timer0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer1", "work_clk", 		&timer1_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer1", "apb_clk", 		&timer1_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer2", "work_clk", 		&timer2_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer2", "apb_clk", 		&timer2_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer3", "work_clk", 		&timer3_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer3", "apb_clk", 		&timer3_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer4", "work_clk", 		&timer4_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer4", "apb_clk", 		&timer4_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_i2c.0", 	  "work_clk", 		&i2c0_work_clk),
+	CLK_ZX29_CONFIG("zx29_i2c.0", 	  "apb_clk", 		&i2c0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_i2c.1", 	  "work_clk", 		&i2c1_work_clk),
+	CLK_ZX29_CONFIG("zx29_i2c.1", 	  "apb_clk", 		&i2c1_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_ssp.0", 	  "work_clk", 		&ssp0_work_clk),
+	CLK_ZX29_CONFIG("zx29_ssp.0", 	  "apb_clk", 		&ssp0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ssp.1", 	  "work_clk", 		&ssp1_work_clk),
+	CLK_ZX29_CONFIG("zx29_ssp.1", 	  "apb_clk", 		&ssp1_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_tdm.0", 	  "work_clk", 		&tdm_work_clk),
+	CLK_ZX29_CONFIG("zx29_tdm.0", 	  "apb_clk",  		&tdm_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_i2s.0", 	  "work_clk", 		&i2s0_work_clk),
+	CLK_ZX29_CONFIG("zx29_i2s.0", 	  "apb_clk", 		&i2s0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_i2s.1", 	  "work_clk", 		&i2s1_work_clk),
+	CLK_ZX29_CONFIG("zx29_i2s.1", 	  "apb_clk", 		&i2s1_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_spifc.0",   "work_clk", 		&spifc_work_clk),
+	CLK_ZX29_CONFIG("zx29_spifc.0",   "apb_clk",  		&spifc_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_kpd.0",     "work_clk", 		&kpd_work_clk),
+	CLK_ZX29_CONFIG("zx29_kpd.0",     "apb_clk",  		&kpd_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_rtc.0",     "work_clk", 		&rtc_work_clk),
+	CLK_ZX29_CONFIG("zx29_rtc.0",     "apb_clk",  		&rtc_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_usb.0",     "ahb_clk", 		&usb_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_usb.0",     "12m_clk",  		&usb_12m_clk),
+
+	CLK_ZX29_CONFIG("zx29_hsic.0",    "ahb_clk", 		&hsic_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_hsic.0",    "12m_clk",  		&hsic_12m_clk),
+	CLK_ZX29_CONFIG("zx29_hsic.0",    "480m_clk",  		&hsic_480m_clk),
+
+	CLK_ZX29_CONFIG("zx29_gmac.0",    "ahb_clk", 		&gmac_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_gmac.0",    "apb_clk",  		&gmac_apb_clk),
+	CLK_ZX29_CONFIG("zx29_gmac.0",    "rmii_clk",  		&gmac_rmii_clk),
+
+	CLK_ZX29_CONFIG("zx29_sd.0",      "ahb_clk", 		&sd0_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_sd.0",      "work_clk",  		&sd0_work_clk),
+	CLK_ZX29_CONFIG("zx29_sd.0",      "cdet_clk",  		&sd0_cdet_clk),
+
+	CLK_ZX29_CONFIG("zx29_sd.1",      "ahb_clk", 		&sd1_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_sd.1",      "work_clk",  		&sd1_work_clk),
+	CLK_ZX29_CONFIG("zx29_sd.1",      "cdet_clk",  		&sd1_cdet_clk),
+
+	//wifi_bt
+};
+
+unsigned int periph_clocks_lookups_num=ARRAY_SIZE(periph_clocks_lookups);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk-zx297520v3.c b/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk-zx297520v3.c
new file mode 100644
index 0000000..019a503
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk-zx297520v3.c
@@ -0,0 +1,1570 @@
+/*
+ * arch/arm/mach-zx297520v3/zx297520v3-clock.c
+ *
+ *  Copyright (C) 2015 ZTE-TSP
+ *
+ * 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/module.h>
+
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <linux/math64.h>
+
+#include <linux/clkdev.h>
+#include <mach/spinlock.h>
+#include <mach/board.h>
+#include <mach/iomap.h>
+#include <linux/clk-private.h>
+
+#include "clk.h"
+
+#define DEFINE_ZX29_CLK(hwclk,clkops,num,names) \
+    struct clk * parents_##hwclk[num]; \
+    static struct clk hwclk##_clk = { \
+    .name = #hwclk "_clk", \
+    .hw = &hwclk.hw, \
+    .ops = &clkops, \
+    .num_parents = num, \
+    .parent_names = names, \
+    .parents = parents_##hwclk, \
+    .flags = CLK_AUTO_ROUND_PARENT, \
+}
+
+#define DEFINE_ZX29_CLK_FLAG(hwclk,clkops,num,names, flag) \
+    struct clk * parents_##hwclk[num]; \
+    static struct clk hwclk##_clk = { \
+    .name = #hwclk "_clk", \
+    .hw = &hwclk.hw, \
+    .ops = &clkops, \
+    .num_parents = num, \
+    .parent_names = names, \
+    .parents = parents_##hwclk, \
+    .flags = flag, \
+}
+
+/*
+ * enable the clk.
+ */
+static int zx297520v3_clk_enable(struct clk_hw *hw)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_en_reg.reg_bit_size == 0)
+        return 0;
+
+    regaddr = zx29clk->clk_en_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+	data |= 1<<zx29clk->clk_en_reg.reg_bit_offset;
+	iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/*
+ * disable the clk.
+ */
+static void zx297520v3_clk_disable(struct clk_hw *hw)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_en_reg.reg_bit_size == 0)
+        return ;
+
+    regaddr = zx29clk->clk_en_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+	data &= ~(1<<zx29clk->clk_en_reg.reg_bit_offset);
+	iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return ;
+}
+
+/*
+ * get clk's enable state.
+ */
+static int zx297520v3_is_enabled(struct clk_hw *hw)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_en_reg.reg_bit_size == 0)
+        return 1;
+
+    regaddr = zx29clk->clk_en_reg.reg_addr;
+
+	data=ioread32(regaddr);
+	data>>=zx29clk->clk_en_reg.reg_bit_offset;
+
+    if(data & 0x1)
+        return 1;
+    else
+        return 0;
+}
+
+/*
+ * set the clk division for new rate.
+ *
+ * new_rate = parent->rate/(clk_div+1)
+ */
+static int zx297520v3_clk_set_rate(struct clk_hw *hw, unsigned long new_rate)//, unsigned long parent_rate)
+{
+    unsigned long parent_rate = 0;
+    unsigned long clk_div = 0;
+	void __iomem *regaddr = NULL;
+	unsigned int data = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->hw.clk == NULL || zx29clk->hw.clk->parent == NULL)
+        return -EINVAL;
+    if((zx29clk->clk_div_reg.reg_bit_size == 0)||(new_rate == 0))
+        return -EINVAL;
+
+    parent_rate = zx29clk->hw.clk->parent->rate;
+    clk_div = parent_rate/new_rate;
+	/*get the max division*/
+    if(clk_div >= (1<<zx29clk->clk_div_reg.reg_bit_size))
+        clk_div = (1<<zx29clk->clk_div_reg.reg_bit_size);
+
+    if(clk_div)
+	{
+        clk_div--;
+    }
+
+    regaddr = zx29clk->clk_div_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+	data &= ~(((1<<(zx29clk->clk_div_reg.reg_bit_size))-1)<<zx29clk->clk_div_reg.reg_bit_offset);
+    data |= clk_div<<zx29clk->clk_div_reg.reg_bit_offset;
+    iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/*
+ * get the clk's rate.
+ *
+ * new_rate = parent->rate/(clk_div+1)
+ */
+static unsigned long zx297520v3_clk_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	void __iomem *regaddr = NULL;
+	unsigned int data = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+	/*if no clk division, return parent's rate */
+    if(zx29clk->clk_div_reg.reg_bit_size == 0) {
+        if(zx29clk->hw.clk->num_parents)
+            return parent_rate;
+        else
+            return 0;
+    }
+
+    regaddr = zx29clk->clk_div_reg.reg_addr;
+
+	data=ioread32(regaddr);
+    data >>= zx29clk->clk_div_reg.reg_bit_offset;
+	data &= ((1<<(zx29clk->clk_div_reg.reg_bit_size))-1);
+
+    return parent_rate/(data+1);
+}
+
+#if 0
+/*
+ * get the clk's rate.
+ *
+ * new_rate = parent->rate/(2^clk_div)
+ */
+static unsigned long zx297520v3_clk_recalc_rate_x2(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	void __iomem *regaddr = NULL;
+	unsigned int data = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_div_reg.reg_bit_size == 0) {
+        if(zx29clk->hw.clk->num_parents)
+            return parent_rate;
+        else
+            return 0;
+    }
+
+    regaddr = zx29clk->clk_div_reg.reg_addr;
+
+	data=ioread32(regaddr);
+    data >>= zx29clk->clk_div_reg.reg_bit_offset;
+	data &= ((1<<(zx29clk->clk_div_reg.reg_bit_size))-1);
+
+    return parent_rate/(0x1<<data);
+}
+#endif
+
+/*
+ * select parent from given parents.
+ *
+ * index < num_parents
+ */
+static int zx297520v3_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	void __iomem *regaddr = NULL;
+	unsigned int data = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->hw.clk->num_parents==0 || index>=zx29clk->hw.clk->num_parents)
+        return -EINVAL;
+    if(zx29clk->clk_sel_reg.reg_bit_size == 0)
+        return 0;
+
+    regaddr = zx29clk->clk_sel_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+	data &= ~(((1<<(zx29clk->clk_sel_reg.reg_bit_size))-1)<<zx29clk->clk_sel_reg.reg_bit_offset);
+    data |= index<<zx29clk->clk_sel_reg.reg_bit_offset;
+    iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/*
+ * get current parent select.
+ *
+ * return index begin with 0.
+ */
+static u8 zx297520v3_get_parent(struct clk_hw *hw)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->hw.clk->num_parents < 2 || zx29clk->clk_sel_reg.reg_bit_size ==0)
+        return 0;
+
+    regaddr = zx29clk->clk_sel_reg.reg_addr;
+
+	data = ioread32(regaddr);
+    data >>= zx29clk->clk_sel_reg.reg_bit_offset;
+    data &= (1<<(zx29clk->clk_sel_reg.reg_bit_size))-1;
+
+    return data;
+}
+
+/*
+ * calc the rate we can support.
+ *
+ * rate: request rate(maybe we can not support exactly)
+ */
+static long zx297520v3_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long * best_parent_rate)
+{
+    unsigned long parent_rate = 0;
+    unsigned long clk_div = 0;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->hw.clk == NULL || zx29clk->hw.clk->parent == NULL)
+        return 0;
+//    if(zx29clk->clk_div_reg.reg_bit_size == 0)
+//        return 0;
+
+    parent_rate = zx29clk->hw.clk->parent->rate;
+    clk_div = parent_rate/rate;
+    if(clk_div >= (1<<zx29clk->clk_div_reg.reg_bit_size))
+    {
+        clk_div = (1<<zx29clk->clk_div_reg.reg_bit_size);
+    }
+
+    if(!clk_div)
+        return parent_rate;
+
+	if ((zx29clk->hw.clk->flags & CLK_NO_ODD_DIV) && (clk_div & 0x1) && (clk_div != 0x1))
+		clk_div++;
+
+    return parent_rate/(clk_div);
+}
+
+/*
+ * set auto clk gate.
+ *
+ * this only set once when system start.
+ */
+static int zx297520v3_set_auto_gate(struct clk_hw *hw, bool enable)
+{
+	unsigned int data = 0;
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+
+    if(zx29clk->clk_gate_reg.reg_bit_size == 0)
+        return -EINVAL;
+
+    regaddr = zx29clk->clk_gate_reg.reg_addr;
+
+	hw_spin_lock(CLK_HWLOCK);
+	data=ioread32(regaddr);
+    if(enable)
+	    data |= 1<<zx29clk->clk_gate_reg.reg_bit_offset;
+    else
+	    data &= ~(1<<zx29clk->clk_gate_reg.reg_bit_offset);
+	iowrite32(data,regaddr);
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/**************************************************************************
+*   peripheral clk divider new algorithm
+*
+*   1. default algorithm:  new_rate = parent_rate/(1+clk_div)
+*   2. new algorithm:  new_rate = parent_rate/(2*(integer_num+(clk_sel+fra_div/fra_base)/2))
+*
+***************************************************************************
+*/
+#define	CLK_FRA_DIV(a)			(zx_read_reg(a)&0xff)
+#define	CLK_FRA_BASE(a)			((zx_read_reg(a)>>8)&0xff)
+#define	CLK_INTEGER_NUM(a)		((zx_read_reg(a)>>16)&0xff)
+#define	CLK_CLK_SEL(a)			((zx_read_reg(a)>>24)&1)
+
+/*
+{2.0, 	MIX_CLK_DIVIDER(0, 	  0xff, 1, 0)	},
+{2.5, 	MIX_CLK_DIVIDER(0x7f, 0xff, 1, 0)	},
+{3.0, 	MIX_CLK_DIVIDER(0, 	  0xff, 1, 1)	},
+{3.5, 	MIX_CLK_DIVIDER(0x7f, 0xff, 1, 1)	},
+*/
+/* d--fra_div  b--fra_base  n--integer_num  s--clk_sel */
+#define	MIX_CLK_DIVIDER(d,b,n,s)	\
+	(d|(b<<8)|(n<<16)|(s<<24))
+
+#define	MAX_CLK_DIVIDER			0x200//(2.0*(0xff+(1.0+0xff/0xff)/2.0))
+#define	FLOAT_CALC_FACTOR		(u64)(1000*1000)
+
+static void parase_float_clk_divider(u64 clk_div,
+                                     unsigned int *fra_div,
+                                     unsigned int *fra_base,
+                                     unsigned int *integer_num,
+                                     unsigned int *clk_sel)
+{
+	*integer_num = (unsigned int)div64_u64(clk_div, FLOAT_CALC_FACTOR)/2;
+	*clk_sel	 = (unsigned int)div64_u64(clk_div, FLOAT_CALC_FACTOR)%2;
+	*fra_base	 = 0xff;
+	*fra_div     = (unsigned int)div64_u64((clk_div-*integer_num*FLOAT_CALC_FACTOR*2-*clk_sel*FLOAT_CALC_FACTOR)*255,
+											FLOAT_CALC_FACTOR);
+}
+
+/*
+ * set the clk division for new rate.
+ *
+ */
+static int zx297520v3_clk_set_rate_float(struct clk_hw *hw, unsigned long new_rate)
+{
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+	unsigned int fra_div = 0;
+	unsigned int fra_base = 0;
+	unsigned int integer_num = 0;
+	unsigned int clk_sel = 0;
+	u64 tmp_parent_rate;
+	u64 clk_div = 0;
+
+    if(zx29clk->hw.clk == NULL || zx29clk->hw.clk->parent == NULL)
+        return -EINVAL;
+    if(zx29clk->clk_div_reg.reg_addr == 0)
+        return -EINVAL;
+
+    tmp_parent_rate = zx29clk->hw.clk->parent->rate*FLOAT_CALC_FACTOR;
+	clk_div	= div64_u64(tmp_parent_rate, new_rate);
+
+	/*get the max division*/
+    if(clk_div >= MAX_CLK_DIVIDER*FLOAT_CALC_FACTOR)
+        clk_div = MAX_CLK_DIVIDER*FLOAT_CALC_FACTOR;
+
+	parase_float_clk_divider(clk_div, &fra_div, &fra_base, &integer_num, &clk_sel);
+
+	hw_spin_lock(CLK_HWLOCK);
+	zx_write_reg(zx29clk->clk_div_reg.reg_addr,
+				 MIX_CLK_DIVIDER(fra_div, fra_base, integer_num, clk_sel));
+	hw_spin_unlock(CLK_HWLOCK);
+
+    return 0;
+}
+
+/*
+ * get the clk's rate.
+ *
+ * new_rate = parent_rate/(2*(integer_num+(clk_sel+fra_div/fra_base)/2))
+ */
+static unsigned long zx297520v3_clk_recalc_rate_float(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	void __iomem *regaddr = NULL;
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+	unsigned int fra_div = 0;
+	unsigned int fra_base = 0;
+	unsigned int clk_sel = 0;
+	unsigned int integer_num = 0;
+	u64 tmp_parent_rate = (u64)parent_rate*FLOAT_CALC_FACTOR;
+	u64 clk_div = 0;
+
+    regaddr = zx29clk->clk_div_reg.reg_addr;
+
+	/*if no clk division, return parent's rate */
+    if(regaddr == 0) {
+        if(zx29clk->hw.clk->num_parents)
+            return parent_rate;
+        else
+            return 0;
+    }
+
+	fra_div 	= CLK_FRA_DIV(regaddr);
+	fra_base 	= CLK_FRA_BASE(regaddr);
+	clk_sel 	= CLK_CLK_SEL(regaddr);
+	integer_num = CLK_INTEGER_NUM(regaddr);
+
+	clk_div = (2*integer_num+clk_sel)*FLOAT_CALC_FACTOR+div64_u64(fra_div*FLOAT_CALC_FACTOR,fra_base);
+
+    return (unsigned long)div64_u64(tmp_parent_rate, clk_div);
+}
+
+/*
+ * calc the rate we can support.
+ *
+ * rate: request rate(maybe we can not support exactly)
+ */
+static long zx297520v3_clk_round_rate_float(struct clk_hw *hw, unsigned long rate,
+					unsigned long * best_parent_rate)
+{
+    struct zx29_hwclk *zx29clk = to_zx29_hwclk(hw);
+	u64 tmp_parent_rate;
+	u64 clk_div = 0;
+
+    if(zx29clk->hw.clk == NULL || zx29clk->hw.clk->parent == NULL)
+        return 0;
+    if(zx29clk->clk_div_reg.reg_addr == 0)
+		return 0;
+
+	tmp_parent_rate = zx29clk->hw.clk->parent->rate*FLOAT_CALC_FACTOR;
+	clk_div	= div64_u64(tmp_parent_rate, rate);
+
+	if(clk_div >= MAX_CLK_DIVIDER*FLOAT_CALC_FACTOR)
+		clk_div = MAX_CLK_DIVIDER*FLOAT_CALC_FACTOR;
+
+    if(!clk_div)
+        return (long)div64_u64(tmp_parent_rate, FLOAT_CALC_FACTOR);
+	else
+    	return (long)div64_u64(tmp_parent_rate, clk_div);
+}
+
+static int clk_rootclk_enable(struct clk_hw *hw)
+{
+    return 0;
+}
+static void clk_rootclk_disable(struct clk_hw *hw)
+{
+    return ;
+}
+
+static int clk_rootclk_is_enabled(struct clk_hw *hw)
+{
+    return 1;
+}
+
+static int clk_rootclk_set_rate(struct clk_hw *hw, unsigned long new_rate)//, unsigned long parent_rate)
+{
+    return 0;
+}
+
+static struct clk_ops peripheral_clk_ops =
+{
+    .enable 		= zx297520v3_clk_enable,
+    .disable 		= zx297520v3_clk_disable,
+	.set_auto_gate 	= zx297520v3_set_auto_gate,
+    .set_rate 		= zx297520v3_clk_set_rate,
+    .recalc_rate 	= zx297520v3_clk_recalc_rate,
+    .set_parent 	= zx297520v3_clk_set_parent,
+    .round_rate 	= zx297520v3_clk_round_rate,
+    .get_parent 	= zx297520v3_get_parent,
+    .is_enabled 	= zx297520v3_is_enabled,
+};
+
+static struct clk_ops peripheral_float_clk_ops =
+{
+    .enable 		= zx297520v3_clk_enable,
+    .disable 		= zx297520v3_clk_disable,
+	.set_auto_gate 	= zx297520v3_set_auto_gate,
+    .set_rate 		= zx297520v3_clk_set_rate_float,
+    .recalc_rate 	= zx297520v3_clk_recalc_rate_float,
+    .set_parent 	= zx297520v3_clk_set_parent,
+    .round_rate 	= zx297520v3_clk_round_rate_float,
+    .get_parent 	= zx297520v3_get_parent,
+    .is_enabled 	= zx297520v3_is_enabled,
+};
+
+static struct clk_ops cpu_clk_ops =
+{
+    .enable 		= zx297520v3_clk_enable,
+    .disable 		= zx297520v3_clk_disable,
+    .set_auto_gate 	= zx297520v3_set_auto_gate,
+    .set_rate 		= zx297520v3_clk_set_rate,
+    .recalc_rate 	= zx297520v3_clk_recalc_rate,
+    .set_parent 	= zx297520v3_clk_set_parent,
+    .round_rate 	= zx297520v3_clk_round_rate,
+    .get_parent 	= zx297520v3_get_parent,
+    .is_enabled 	= zx297520v3_is_enabled,
+};
+
+struct clk_ops root_clk_ops = {
+    .enable 	= clk_rootclk_enable,
+	.disable 	= clk_rootclk_disable,
+	.is_enabled = clk_rootclk_is_enabled,
+	.set_rate 	= clk_rootclk_set_rate,
+};
+
+
+/*
+*   root clk
+*/
+DEFINE_ZX29_ROOT_CLK(main_clk_32k, 	32768);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_12m, 	12*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_24m, 	24*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_39m, 	39*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_52m, 	52*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_78m, 	78*1000*1000);
+#if CONFIG_ARCH_ZX297520v3FPGA
+DEFINE_ZX29_ROOT_CLK(main_clk_26m, 	25*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_104m, 25*1000*1000);
+#else
+DEFINE_ZX29_ROOT_CLK(main_clk_26m, 	26*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_104m, 104*1000*1000);
+#endif
+DEFINE_ZX29_ROOT_CLK(mpll_clk_124m8, 124800*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_156m, 156*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_208m, 208*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_312m, 312*1000*1000);
+DEFINE_ZX29_ROOT_CLK(mpll_clk_624m, 624*1000*1000);
+DEFINE_ZX29_ROOT_CLK(dpll_clk_491m52, 491520*1000);
+DEFINE_ZX29_ROOT_CLK(dpll_clk_122m88, 122880*1000);
+DEFINE_ZX29_ROOT_CLK(dpll_clk_81m92, 81920*1000);
+DEFINE_ZX29_ROOT_CLK(upll_clk_480m, 480*1000*1000);
+DEFINE_ZX29_ROOT_CLK(upll_clk_96m, 	96*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_25m, 	25*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_50m, 	50*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_100m, 100*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_178m, 178*1000*1000);
+DEFINE_ZX29_ROOT_CLK(gpll_clk_200m, 200*1000*1000);
+
+
+/*
+*   a1_uart0
+*/
+char*  a1_uart_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_104m)
+};
+char*  lsp_uart_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_104m)
+};
+static struct zx29_hwclk uart0_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5C,	13,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5C,	14,	1},
+};
+DEFINE_ZX29_CLK(uart0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk uart0_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5C,	12,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x40,	2,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x40,	0,	0},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5C,	15,	1},
+};
+DEFINE_ZX29_CLK(uart0_work,peripheral_clk_ops,2,a1_uart_wclk_parents);
+
+/*
+*   lsp_uart1
+*/
+static struct zx29_hwclk uart1_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x28,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x28,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x28, 	11,	1},
+};
+DEFINE_ZX29_CLK(uart1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk uart1_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x28,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x28,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x28,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x28, 	10,	1},
+};
+DEFINE_ZX29_CLK(uart1_work,peripheral_clk_ops,2,lsp_uart_wclk_parents);
+
+/*
+*   lsp_uart2
+*/
+static struct zx29_hwclk uart2_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x3c,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x3c,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x3c, 	11,	1},
+};
+DEFINE_ZX29_CLK(uart2_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk uart2_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x3c,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x3c,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x3c,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x3c, 	10,	1},
+};
+DEFINE_ZX29_CLK(uart2_work,peripheral_clk_ops,2,lsp_uart_wclk_parents);
+
+/*
+*   a1_timer1
+*/
+char*  a1_timer_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_32k),
+	NAME_CLK(main_clk_26m)
+};
+char*  lsp_timer_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_32k),
+	NAME_CLK(main_clk_26m)
+};
+static struct zx29_hwclk timer1_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	1,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x60,	2,	1},
+};
+DEFINE_ZX29_CLK(timer1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer1_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	0,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x44,	0,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x50,	0,	4},
+};
+DEFINE_ZX29_CLK(timer1_work,peripheral_clk_ops,2,a1_timer_wclk_parents);
+
+/*
+*   a1_timer2
+*/
+static struct zx29_hwclk timer2_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	5,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x60,	6,	1},
+};
+DEFINE_ZX29_CLK(timer2_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer2_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	4,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x44,	1,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x50,	4,	4},
+};
+DEFINE_ZX29_CLK(timer2_work,peripheral_clk_ops,2,a1_timer_wclk_parents);
+
+/*
+*   a1_timer3
+*/
+static struct zx29_hwclk timer3_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	9,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x60,	10,	1},
+};
+DEFINE_ZX29_CLK(timer3_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer3_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x60,	8,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x44,	2,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x50,	8,	4},
+};
+DEFINE_ZX29_CLK(timer3_work,peripheral_clk_ops,2,a1_timer_wclk_parents);
+
+/*
+*   ps_timer1
+*/
+static struct zx29_hwclk ps_timer1_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5c,	9,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5c,	10,	1},
+};
+DEFINE_ZX29_CLK(ps_timer1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk ps_timer1_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5c,	8,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x40,	1,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x4c,	4,	4},
+};
+DEFINE_ZX29_CLK(ps_timer1_work,peripheral_clk_ops,2,a1_timer_wclk_parents);
+
+/*
+*   ps_timer2
+*/
+static struct zx29_hwclk ps_timer2_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5c,	5,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5c,	6,	1},
+};
+DEFINE_ZX29_CLK(ps_timer2_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk ps_timer2_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5c,	4,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x40,	0,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x4c,	0,	4},
+};
+DEFINE_ZX29_CLK(ps_timer2_work,peripheral_clk_ops,2,a1_timer_wclk_parents);
+
+
+/*
+*   lsp_timer0
+*/
+static struct zx29_hwclk timer0_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x44,	0,	1},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x44,	11,	1},
+};
+DEFINE_ZX29_CLK(timer0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer0_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x44,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x44,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x44,	12,	4},
+};
+DEFINE_ZX29_CLK(timer0_work,peripheral_clk_ops,2,lsp_timer_wclk_parents);
+
+/*
+*   lsp_timer4
+*/
+static struct zx29_hwclk timer4_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x4C,	0,	1},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x4C,	11,	1},
+};
+DEFINE_ZX29_CLK(timer4_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk timer4_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x4C,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x4C,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x4C,	12,	4},
+};
+DEFINE_ZX29_CLK(timer4_work,peripheral_clk_ops,2,lsp_timer_wclk_parents);
+
+/*
+*   ps_timer0
+*/
+static struct zx29_hwclk ps_timer0_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x4,	0,	1},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x4,	11,	1},
+};
+DEFINE_ZX29_CLK(ps_timer0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk ps_timer0_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x4,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x4,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x4,	12,	4},
+};
+DEFINE_ZX29_CLK(ps_timer0_work,peripheral_clk_ops,2,lsp_timer_wclk_parents);
+
+
+
+/**************************************************************************
+*   i2c
+***************************************************************************
+*/
+char*  a1_i2c_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_104m)
+};
+char*  lsp_i2c_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_104m)
+};
+
+/*
+*   a1_i2c0
+*/
+static struct zx29_hwclk i2c0_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,		8,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x54, 	10,	1},
+};
+DEFINE_ZX29_CLK(i2c0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk i2c0_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,		9,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x3C,		1,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x54, 	11,	1},
+};
+DEFINE_ZX29_CLK(i2c0_work,peripheral_clk_ops,2,a1_i2c_wclk_parents);
+/*
+*   lsp_i2c1
+*/
+static struct zx29_hwclk i2c1_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x2C,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x2C,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x2C, 	11,	1},
+};
+DEFINE_ZX29_CLK(i2c1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk i2c1_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x2C,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x2C,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x2C,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x2C, 	10,	1},
+};
+DEFINE_ZX29_CLK(i2c1_work,peripheral_clk_ops,2,lsp_i2c_wclk_parents);
+
+/**************************************************************************
+*   ssp
+***************************************************************************
+*/
+char*  lsp_ssp_wclk_parents[3] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_156m),
+	NAME_CLK(mpll_clk_104m)
+};
+
+/*
+*   lsp_ssp0
+*/
+static struct zx29_hwclk ssp0_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x30,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x30,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x30, 	11,	1},
+};
+DEFINE_ZX29_CLK(ssp0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk ssp0_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x30,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x30,	4,	2},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x30,	12,	4},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x30, 	10,	1},
+};
+DEFINE_ZX29_CLK_FLAG(ssp0_work,peripheral_clk_ops,3,lsp_ssp_wclk_parents, (CLK_AUTO_ROUND_PARENT | CLK_NO_ODD_DIV));
+/*
+*   lsp_ssp1
+*/
+static struct zx29_hwclk ssp1_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x48,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x48,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x48, 	11,	1},
+};
+DEFINE_ZX29_CLK(ssp1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk ssp1_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x48,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x48,	4,	2},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x48,	12,	4},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x48, 	10,	1},
+};
+DEFINE_ZX29_CLK_FLAG(ssp1_work,peripheral_clk_ops,3,lsp_ssp_wclk_parents, (CLK_AUTO_ROUND_PARENT | CLK_NO_ODD_DIV));
+
+/**************************************************************************
+*   ap wdt
+***************************************************************************
+*/
+char*  lsp_wdt_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_32k),
+	NAME_CLK(main_clk_26m)
+};
+
+static struct zx29_hwclk ap_wdt_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x40,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x40,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x40, 	11,	1},
+};
+DEFINE_ZX29_CLK(ap_wdt_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk ap_wdt_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x40,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x40,	4,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x40,	12,	4},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x40, 	10,	1},
+};
+DEFINE_ZX29_CLK(ap_wdt_work,peripheral_clk_ops,2,lsp_wdt_wclk_parents);
+
+/**************************************************************************
+*   tdm
+***************************************************************************
+*/
+char*  lsp_tdm_wclk_parents[3] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(dpll_clk_122m88),
+	NAME_CLK(mpll_clk_104m)
+};
+
+static struct zx29_hwclk tdm_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x50,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x50,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x50, 	11,	1},
+};
+DEFINE_ZX29_CLK(tdm_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk tdm_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x50,	1,	1},
+	.clk_sel_reg	={ZX_MATRIX_CRM_BASE+0x50,	24,	2},
+//	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x54,	24,	2},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x50, 	10,	1},
+};
+DEFINE_ZX29_CLK(tdm_work,peripheral_float_clk_ops,3,lsp_tdm_wclk_parents);
+
+/**************************************************************************
+*   i2s
+***************************************************************************
+*/
+char*  lsp_i2s_wclk_parents[2] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(dpll_clk_122m88),
+	NAME_CLK(mpll_clk_104m)
+};
+
+static struct zx29_hwclk i2s0_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x14,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x14,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x14, 	11,	1},
+};
+DEFINE_ZX29_CLK(i2s0_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk i2s0_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x14,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x14,	4,	2},
+//	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x18,	0,	2},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x14, 	10,	1},
+};
+DEFINE_ZX29_CLK(i2s0_work,peripheral_float_clk_ops,2,lsp_i2s_wclk_parents);
+
+static struct zx29_hwclk i2s1_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x1C,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x1C,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x1C, 	11,	1},
+};
+DEFINE_ZX29_CLK(i2s1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk i2s1_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x1C,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x1C,	4,	2},
+//	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x20,	0,	2},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x1C, 	10,	1},
+};
+DEFINE_ZX29_CLK(i2s1_work,peripheral_float_clk_ops,2,lsp_i2s_wclk_parents);
+
+/**************************************************************************
+*   spifc
+***************************************************************************
+*/
+char*  lsp_spifc_wclk_parents[] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_156m),
+	NAME_CLK(mpll_clk_124m8),
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(mpll_clk_52m)
+};
+
+static struct zx29_hwclk spifc_apb =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x24,	0,	1},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x24,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x24, 	11,	1},
+};
+DEFINE_ZX29_CLK(spifc_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk spifc_work =
+{
+	.clk_en_reg 	={ZX_LSP_CRPM_BASE+0x24,	1,	1},
+	.clk_sel_reg	={ZX_LSP_CRPM_BASE+0x24,	4,	3},
+	.clk_div_reg	={ZX_LSP_CRPM_BASE+0x24,	0,	0},
+	.clk_gate_reg	={ZX_LSP_CRPM_BASE+0x24, 	10,	1},
+};
+DEFINE_ZX29_CLK(spifc_work,peripheral_clk_ops,ARRAY_SIZE(lsp_spifc_wclk_parents),lsp_spifc_wclk_parents);
+
+/**************************************************************************
+*   kpd
+***************************************************************************
+*/
+char*  kpd_wclk_parents[] =
+{
+	NAME_CLK(main_clk_32k),
+};
+
+static struct zx29_hwclk kpd_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5C,	17,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x5C,	0,	0},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5C, 19,	1},
+};
+DEFINE_ZX29_CLK(kpd_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk kpd_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x5C,	16,	1},
+	.clk_sel_reg	={ZX_TOP_CRM_BASE+0x5C,	0,	0},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x5C,	0,	0},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x5C, 18,	1},
+};
+DEFINE_ZX29_CLK(kpd_work,peripheral_clk_ops,ARRAY_SIZE(kpd_wclk_parents),kpd_wclk_parents);
+
+/**************************************************************************
+*   rtc
+***************************************************************************
+*/
+char*  rtc_wclk_parents[] =
+{
+	NAME_CLK(main_clk_32k),
+};
+
+static struct zx29_hwclk rtc_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,	0,	1},
+
+};
+DEFINE_ZX29_CLK(rtc_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk rtc_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,	1,	1},
+};
+DEFINE_ZX29_CLK(rtc_work,peripheral_clk_ops,ARRAY_SIZE(rtc_wclk_parents),rtc_wclk_parents);
+
+/**************************************************************************
+*   usim1
+***************************************************************************
+*/
+char*  usim1_wclk_parents[] =
+{
+	NAME_CLK(main_clk_26m),
+};
+
+static struct zx29_hwclk usim1_apb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,	29,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x54, 	31,	1},	
+
+};
+DEFINE_ZX29_CLK(usim1_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk usim1_work =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,	28,	1},
+	.clk_gate_reg	={ZX_TOP_CRM_BASE+0x54, 	30,	1},
+	.clk_div_reg	={ZX_TOP_CRM_BASE+0x48,	12,	1},
+	
+		
+};
+DEFINE_ZX29_CLK(usim1_work,peripheral_clk_ops,ARRAY_SIZE(usim1_wclk_parents),usim1_wclk_parents);
+
+/**************************************************************************
+*   hs_ahb (parent of hsic/usb ahb clk)
+***************************************************************************
+*/
+char*  hs_ahb_parents[] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(mpll_clk_78m)
+};
+static struct zx29_hwclk hs_ahb =
+{
+/*	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x54,	12,	1}, */
+	.clk_sel_reg 	={ZX_TOP_CRM_BASE+0x3C,	4,	2},
+};
+DEFINE_ZX29_CLK(hs_ahb,peripheral_clk_ops,ARRAY_SIZE(hs_ahb_parents),hs_ahb_parents);
+
+/**************************************************************************
+*   usb2.0
+***************************************************************************
+*/
+char*  usb_12m_parents[] =
+{
+	NAME_CLK(mpll_clk_12m),
+};
+
+char*  usb_24m_parents[] =
+{
+	NAME_CLK(mpll_clk_24m),
+};
+
+char*  usb_480m_parents[] =
+{
+	NAME_CLK(upll_clk_480m),
+};
+
+char*  usb_ahb_parents[] =
+{
+	"hs_ahb_clk",
+};
+static struct zx29_hwclk usb_ahb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x6C,	4,	1},
+};
+DEFINE_ZX29_CLK(usb_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk usb_24m =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x6C,	3,	1},
+};
+DEFINE_ZX29_CLK(usb_24m,peripheral_clk_ops,ARRAY_SIZE(usb_24m_parents),usb_24m_parents);
+
+/**************************************************************************
+ *   HSIC
+ **************************************************************************
+ */
+static struct zx29_hwclk hsic_ahb =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x6C,	2,	1},
+};
+DEFINE_ZX29_CLK(hsic_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk hsic_12m =
+{
+	.clk_en_reg 	={ZX_TOP_CRM_BASE+0x6C,	1,	1},
+};
+DEFINE_ZX29_CLK(hsic_12m,peripheral_clk_ops,ARRAY_SIZE(usb_12m_parents),usb_12m_parents);
+
+
+/**************************************************************************
+ *   GMAC
+ **************************************************************************
+ */
+char*  gmac_rmii_parents[] =
+{
+	NAME_CLK(gpll_clk_50m),
+};
+
+static struct zx29_hwclk gmac_ahb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x110,	2,	1},
+};
+DEFINE_ZX29_CLK(gmac_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk gmac_apb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x110,	1,	1},
+};
+DEFINE_ZX29_CLK(gmac_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk gmac_rmii =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x110,	0,	1},
+};
+DEFINE_ZX29_CLK(gmac_rmii,peripheral_clk_ops,ARRAY_SIZE(gmac_rmii_parents),gmac_rmii_parents);
+
+/**************************************************************************
+ *   SD
+ **************************************************************************
+ */
+char*  sd0_work_parents[] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_156m),
+	NAME_CLK(gpll_clk_100m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(gpll_clk_50m),
+	NAME_CLK(gpll_clk_25m),
+
+};
+char*  sd1_work_parents[] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(gpll_clk_100m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(gpll_clk_50m),
+	NAME_CLK(mpll_clk_39m),
+	NAME_CLK(gpll_clk_25m),
+};
+char*  sd_cdet_parents[] =
+{
+	NAME_CLK(main_clk_32k),
+};
+static struct zx29_hwclk sd0_ahb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	12,	1},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x54,	16,	1},
+};
+DEFINE_ZX29_CLK(sd0_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk sd0_work =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	13,	1},
+	.clk_sel_reg	={ZX_MATRIX_CRM_BASE+0x50,	4,	3},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x54,	17,	1},
+};
+DEFINE_ZX29_CLK(sd0_work,peripheral_clk_ops,ARRAY_SIZE(sd0_work_parents),sd0_work_parents);
+
+static struct zx29_hwclk sd0_cdet =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	14,	1},
+};
+DEFINE_ZX29_CLK(sd0_cdet,peripheral_clk_ops,ARRAY_SIZE(sd_cdet_parents),sd_cdet_parents);
+
+static struct zx29_hwclk sd1_ahb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	4,	1},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x54,	8,	1},
+};
+DEFINE_ZX29_CLK(sd1_ahb,peripheral_clk_ops,ARRAY_SIZE(usb_ahb_parents),usb_ahb_parents);
+
+static struct zx29_hwclk sd1_work =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	5,	1},
+	.clk_sel_reg	={ZX_MATRIX_CRM_BASE+0x50,	8,	3},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x54,	9,	1},
+};
+DEFINE_ZX29_CLK(sd1_work,peripheral_clk_ops,ARRAY_SIZE(sd1_work_parents),sd1_work_parents);
+
+static struct zx29_hwclk sd1_cdet =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x54,	6,	1},
+};
+DEFINE_ZX29_CLK(sd1_cdet,peripheral_clk_ops,ARRAY_SIZE(sd_cdet_parents),sd_cdet_parents);
+
+
+/**************************************************************************
+ *   EDCP
+ **************************************************************************
+ */
+char*  edcp_work_parents[] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_208m),
+	NAME_CLK(mpll_clk_156m),
+	NAME_CLK(mpll_clk_104m),
+};
+
+static struct zx29_hwclk edcp_ahb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x64,	1,	1},
+};
+DEFINE_ZX29_CLK(edcp_ahb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk edcp_syncaxi =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x64,	0,	1},
+};
+DEFINE_ZX29_CLK(edcp_syncaxi,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk edcp_asyncaxi =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x64,	2,	1},
+	.clk_sel_reg	={ZX_MATRIX_CRM_BASE+0x50,	16,	2},
+};
+DEFINE_ZX29_CLK(edcp_asyncaxi,peripheral_clk_ops,ARRAY_SIZE(edcp_work_parents),edcp_work_parents);
+
+
+/**************************************************************************
+ *   VOU
+ **************************************************************************
+ */
+static struct zx29_hwclk vou_osd_apb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	18,	1},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x168,	19,	1},
+};
+DEFINE_ZX29_CLK(vou_osd_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_osd_axi =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	16,	1},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x168,	17,	1},
+};
+DEFINE_ZX29_CLK(vou_osd_axi,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_osd_vedio =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	15,	1},
+};
+DEFINE_ZX29_CLK(vou_osd_vedio,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_osd_graphic =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	14,	1},
+};
+DEFINE_ZX29_CLK(vou_osd_graphic,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_osd_mainmix =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	13,	1},
+};
+DEFINE_ZX29_CLK(vou_osd_mainmix,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_osd_ppu =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	12,	1},
+};
+DEFINE_ZX29_CLK(vou_osd_ppu,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_csc_work =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	6,	1},
+};
+DEFINE_ZX29_CLK(vou_csc_work,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_csc_apb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	4,	1},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x168,	5,	1},
+};
+DEFINE_ZX29_CLK(vou_csc_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_axi =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	2,	1},
+};
+DEFINE_ZX29_CLK(vou_axi,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_apb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	1,	1},
+};
+DEFINE_ZX29_CLK(vou_apb,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_work =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	0,	1},
+};
+DEFINE_ZX29_CLK(vou_work,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_mcu_work =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	10,	1},
+};
+DEFINE_ZX29_CLK(vou_mcu_work,peripheral_clk_ops,0,NULL);
+
+static struct zx29_hwclk vou_mcu_apb =
+{
+	.clk_en_reg 	={ZX_MATRIX_CRM_BASE+0x168,	8,	1},
+	.clk_gate_reg	={ZX_MATRIX_CRM_BASE+0x168,	9,	1},
+};
+DEFINE_ZX29_CLK(vou_mcu_apb,peripheral_clk_ops,0,NULL);
+
+/*
+*   axi
+*
+*   can select 156/26/122.88/104/78/52/39
+*   can not div
+*/
+char*  axi_clk_parents[] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_156m),
+	NAME_CLK(mpll_clk_124m8),
+	NAME_CLK(mpll_clk_104m),
+	NAME_CLK(mpll_clk_78m),
+	NAME_CLK(mpll_clk_52m),
+	NAME_CLK(mpll_clk_39m)
+};
+static struct zx29_hwclk axi = {
+	/*             reg_addr				bit_offset	  bit_size	*/
+	.clk_en_reg ={0,                        0,          0},
+	.clk_sel_reg={ZX_MATRIX_CRM_BASE+0x0, 	0, 			3},
+	.clk_div_reg={0,                        0,          0},
+};
+
+DEFINE_ZX29_CLK(axi,peripheral_clk_ops,ARRAY_SIZE(axi_clk_parents),axi_clk_parents);
+
+/*
+*   ap cpu
+*
+*   can select 26/52/78/104/208/312/491.52/624
+*   can not div, gated with hw
+*/
+char*  cpu_clk_parents[] =
+{
+	NAME_CLK(main_clk_26m),
+	NAME_CLK(mpll_clk_624m),
+	NAME_CLK(mpll_clk_312m),
+	NAME_CLK(mpll_clk_156m)
+
+};
+static struct zx29_hwclk cpu_work = {
+	/*             reg_addr				bit_offset	  bit_size	*/
+	.clk_en_reg ={0,                        0,          0},
+	.clk_sel_reg={ZX_MATRIX_CRM_BASE+0x20, 	0, 			2},
+	.clk_div_reg={0,                        0,          0},
+};
+DEFINE_ZX29_CLK(cpu_work,cpu_clk_ops,ARRAY_SIZE(cpu_clk_parents),cpu_clk_parents);
+
+/*for zx297520v3, we do not operate pll and global resource,
+  we only support periph_clocks and clk source select */
+struct clk_lookup periph_clocks_lookups[] = {
+	/*              dev_id       name           		clk struct */
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(main_clk_32k), 	&main_clk_32k),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(main_clk_26m), 	&main_clk_26m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_12m), 	&mpll_clk_12m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_24m), 	&mpll_clk_24m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_39m), 	&mpll_clk_39m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_52m), 	&mpll_clk_52m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_78m), 	&mpll_clk_78m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_104m), 	&mpll_clk_104m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_124m8), 	&mpll_clk_124m8),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_156m), 	&mpll_clk_156m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_208m), 	&mpll_clk_208m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_312m), 	&mpll_clk_312m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(mpll_clk_624m), 	&mpll_clk_624m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(dpll_clk_491m52), 	&dpll_clk_491m52),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(dpll_clk_122m88), 	&dpll_clk_122m88),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(dpll_clk_81m92), 	&dpll_clk_81m92),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(upll_clk_480m), 	&upll_clk_480m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(upll_clk_96m), 	&upll_clk_96m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_25m), 	&gpll_clk_25m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_50m), 	&gpll_clk_50m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_100m), 	&gpll_clk_100m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_178m), 	&gpll_clk_178m),
+	CLK_ZX29_CONFIG(NULL, 	NAME_CLK(gpll_clk_200m), 	&gpll_clk_200m),
+
+
+	CLK_ZX29_CONFIG(NULL, 			  "axi_clk", 		&axi_clk),
+
+	CLK_ZX29_CONFIG(NULL, 			  "cpu_clk",  		&cpu_work_clk),
+
+	CLK_ZX29_CONFIG(NULL,      		  "hs_ahb_clk", 	&hs_ahb_clk),
+
+	CLK_ZX29_CONFIG("zx29_ap_wdt.0",  "work_clk", 		&ap_wdt_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_wdt.0",  "apb_clk",  		&ap_wdt_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_uart.0", 	  "work_clk", 		&uart0_work_clk),
+	CLK_ZX29_CONFIG("zx29_uart.0",    "apb_clk",  		&uart0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_uart.1",    "work_clk", 		&uart1_work_clk),
+	CLK_ZX29_CONFIG("zx29_uart.1",    "apb_clk",  		&uart1_apb_clk),
+	CLK_ZX29_CONFIG("zx29_uart.2",    "work_clk", 		&uart2_work_clk),
+	CLK_ZX29_CONFIG("zx29_uart.2",    "apb_clk",  		&uart2_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_ap_timer0", "work_clk", 		&timer0_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer0", "apb_clk", 		&timer0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer1", "work_clk", 		&timer1_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer1", "apb_clk", 		&timer1_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer2", "work_clk", 		&timer2_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer2", "apb_clk", 		&timer2_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer3", "work_clk", 		&timer3_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer3", "apb_clk", 		&timer3_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer4", "work_clk", 		&timer4_work_clk),
+	CLK_ZX29_CONFIG("zx29_ap_timer4", "apb_clk", 		&timer4_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_ps_timer0", "work_clk", 		&ps_timer0_work_clk),
+	CLK_ZX29_CONFIG("zx29_ps_timer0", "apb_clk", 		&ps_timer0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ps_timer1", "work_clk", 		&ps_timer1_work_clk),
+	CLK_ZX29_CONFIG("zx29_ps_timer1", "apb_clk", 		&ps_timer1_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ps_timer2", "work_clk", 		&ps_timer2_work_clk),
+	CLK_ZX29_CONFIG("zx29_ps_timer2", "apb_clk", 		&ps_timer2_apb_clk),
+	
+	CLK_ZX29_CONFIG("zx29_i2c.0", 	  "work_clk", 		&i2c0_work_clk),
+	CLK_ZX29_CONFIG("zx29_i2c.0", 	  "apb_clk", 		&i2c0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_i2c.1", 	  "work_clk", 		&i2c1_work_clk),
+	CLK_ZX29_CONFIG("zx29_i2c.1", 	  "apb_clk", 		&i2c1_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_ssp.0", 	  "work_clk", 		&ssp0_work_clk),
+	CLK_ZX29_CONFIG("zx29_ssp.0", 	  "apb_clk", 		&ssp0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_ssp.1", 	  "work_clk", 		&ssp1_work_clk),
+	CLK_ZX29_CONFIG("zx29_ssp.1", 	  "apb_clk", 		&ssp1_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_tdm.0", 	  "work_clk", 		&tdm_work_clk),
+	CLK_ZX29_CONFIG("zx29_tdm.0", 	  "apb_clk",  		&tdm_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_i2s.0", 	  "work_clk", 		&i2s0_work_clk),
+	CLK_ZX29_CONFIG("zx29_i2s.0", 	  "apb_clk", 		&i2s0_apb_clk),
+	CLK_ZX29_CONFIG("zx29_i2s.1", 	  "work_clk", 		&i2s1_work_clk),
+	CLK_ZX29_CONFIG("zx29_i2s.1", 	  "apb_clk", 		&i2s1_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_spifc.0",   "work_clk", 		&spifc_work_clk),
+	CLK_ZX29_CONFIG("zx29_spifc.0",   "apb_clk",  		&spifc_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_kpd.0",     "work_clk", 		&kpd_work_clk),
+	CLK_ZX29_CONFIG("zx29_kpd.0",     "apb_clk",  		&kpd_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_rtc.0",     "work_clk", 		&rtc_work_clk),
+	CLK_ZX29_CONFIG("zx29_rtc.0",     "apb_clk",  		&rtc_apb_clk),
+
+	CLK_ZX29_CONFIG("zx29_usim1.0",     "work_clk", 	&usim1_work_clk),
+	CLK_ZX29_CONFIG("zx29_usim1.0",     "apb_clk",  	&usim1_apb_clk),
+	
+	CLK_ZX29_CONFIG("zx29_usb.0",     "ahb_clk", 		&usb_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_usb.0",     "24m_clk",  		&usb_24m_clk),
+
+	CLK_ZX29_CONFIG("zx29_hsic.0",    "ahb_clk", 		&hsic_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_hsic.0",    "12m_clk",  		&hsic_12m_clk),
+
+	CLK_ZX29_CONFIG("zx29_gmac.0",    "ahb_clk", 		&gmac_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_gmac.0",    "apb_clk",  		&gmac_apb_clk),
+	CLK_ZX29_CONFIG("zx29_gmac.0",    "rmii_clk",  		&gmac_rmii_clk),
+
+	CLK_ZX29_CONFIG("zx29_sd.0",      "ahb_clk", 		&sd0_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_sd.0",      "work_clk",  		&sd0_work_clk),
+	CLK_ZX29_CONFIG("zx29_sd.0",      "cdet_clk",  		&sd0_cdet_clk),
+
+	CLK_ZX29_CONFIG("zx29_sd.1",      "ahb_clk", 		&sd1_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_sd.1",      "work_clk",  		&sd1_work_clk),
+	CLK_ZX29_CONFIG("zx29_sd.1",      "cdet_clk",  		&sd1_cdet_clk),
+
+	CLK_ZX29_CONFIG("zx29_edcp.0",      "ahb_clk", 		&edcp_ahb_clk),
+	CLK_ZX29_CONFIG("zx29_edcp.0",      "sync_axi_clk", &edcp_syncaxi_clk),
+	CLK_ZX29_CONFIG("zx29_edcp.0",      "async_axi_clk",&edcp_asyncaxi_clk),
+
+	CLK_ZX29_CONFIG("zx29_vou",      "osd_apb_clk", 	&vou_osd_apb_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "osd_axi_clk", 	&vou_osd_axi_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "osd_vedio_clk", 	&vou_osd_vedio_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "osd_graphic_clk", &vou_osd_graphic_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "osd_mainmix_clk", &vou_osd_mainmix_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "osd_ppu_clk", 	&vou_osd_ppu_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "csc_work_clk", 	&vou_csc_work_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "csc_apb_clk", 	&vou_csc_apb_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "axi_clk", 		&vou_axi_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "apb_clk", 		&vou_apb_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "work_clk", 		&vou_work_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "mcu_work_clk", 	&vou_mcu_work_clk),
+	CLK_ZX29_CONFIG("zx29_vou",      "mcu_apb_clk", 	&vou_mcu_apb_clk),
+	//wifi_bt
+};
+
+unsigned int periph_clocks_lookups_num=ARRAY_SIZE(periph_clocks_lookups);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk.c b/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk.c
new file mode 100644
index 0000000..e458e2b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk.c
@@ -0,0 +1,823 @@
+/*
+ * linux/arch/arm/mach-zx297520v2/clock.c
+ *
+ * Copyright (C) 2013 ZTE-TSP <geanfeng@zte.com.cn>
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+
+#include <linux/clkdev.h>
+#include <mach/iomap.h>
+#include <linux/clk-private.h>
+
+#include <mach/board.h>
+#include <mach/debug.h>
+#include "clk.h"
+
+static DEFINE_SPINLOCK(enable_lock);
+static DEFINE_MUTEX(prepare_lock);
+static LIST_HEAD(clocks);
+
+/***    helper functions   ***/
+
+inline const char *__clk_get_name(struct clk *clk)
+{
+	return !clk ? NULL : clk->name;
+}
+
+inline struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+	return !clk ? NULL : clk->hw;
+}
+
+inline u8 __clk_get_num_parents(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->num_parents;
+}
+
+inline struct clk *__clk_get_parent(struct clk *clk)
+{
+	return !clk ? NULL : clk->parent;
+}
+
+inline int __clk_get_enable_count(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->enable_count;
+}
+
+static unsigned long __clk_get_rate(struct clk *clk)
+{
+	unsigned long ret;
+
+	if (!clk) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = clk->rate;
+
+	if (clk->flags & CLK_IS_ROOT)
+		goto out;
+
+	if (!clk->parent)
+		ret = -ENODEV;
+
+out:
+	return ret;
+}
+
+inline unsigned long __clk_get_flags(struct clk *clk)
+{
+	return !clk ? -EINVAL : clk->flags;
+}
+
+static int __clk_is_enabled(struct clk *clk)
+{
+	int ret;
+
+	if (!clk)
+		return -EINVAL;
+
+	/*
+	 * .is_enabled is only mandatory for clocks that gate
+	 * fall back to software usage counter if .is_enabled is missing
+	 */
+	if (!clk->ops->is_enabled) {
+		ret = clk->enable_count ? 1 : 0;
+		goto out;
+	}
+
+	ret = clk->ops->is_enabled(clk->hw);
+out:
+	return ret;
+}
+
+/***        clk api        ***/
+
+static void __clk_disable(struct clk *clk)
+{
+	if (!clk)
+		return;
+
+	if (WARN_ON(clk->enable_count == 0))
+		return;
+
+	if (--clk->enable_count > 0)
+		return;
+
+	if (clk->ops->disable)
+		clk->ops->disable(clk->hw);
+
+	__clk_disable(clk->parent);
+}
+
+/**
+ * clk_disable - gate a clock
+ * @clk: the clk being gated
+ *
+ * clk_disable must not sleep, which differentiates it from clk_unprepare.  In
+ * a simple case, clk_disable can be used instead of clk_unprepare to gate a
+ * clk if the operation is fast and will never sleep.  One example is a
+ * SoC-internal clk which is controlled via simple register writes.  In the
+ * complex case a clk gate operation may require a fast and a slow part.  It is
+ * this reason that clk_unprepare and clk_disable are not mutually exclusive.
+ * In fact clk_disable must be called before clk_unprepare.
+ */
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&enable_lock, flags);
+	__clk_disable(clk);
+	spin_unlock_irqrestore(&enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+static int __clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk)
+		return 0;
+
+	if (clk->enable_count == 0) {
+		ret = __clk_enable(clk->parent);
+
+		if (ret)
+			return ret;
+
+		if (clk->ops->enable) {
+			ret = clk->ops->enable(clk->hw);
+			if (ret) {
+				__clk_disable(clk->parent);
+				return ret;
+			}
+		}
+	}
+
+	clk->enable_count++;
+	return 0;
+}
+
+/**
+ * clk_enable - ungate a clock
+ * @clk: the clk being ungated
+ *
+ * clk_enable must not sleep, which differentiates it from clk_prepare.  In a
+ * simple case, clk_enable can be used instead of clk_prepare to ungate a clk
+ * if the operation will never sleep.  One example is a SoC-internal clk which
+ * is controlled via simple register writes.  In the complex case a clk ungate
+ * operation may require a fast and a slow part.  It is this reason that
+ * clk_enable and clk_prepare are not mutually exclusive.  In fact clk_prepare
+ * must be called before clk_enable.  Returns 0 on success, -EERROR
+ * otherwise.
+ */
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&enable_lock, flags);
+	ret = __clk_enable(clk);
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+int clk_is_enabled(struct clk *clk)
+{
+		unsigned long flags;
+		int ret;
+
+		spin_lock_irqsave(&enable_lock, flags);
+		ret = __clk_is_enabled(clk);
+		spin_unlock_irqrestore(&enable_lock, flags);
+
+		return ret;
+}
+EXPORT_SYMBOL(clk_is_enabled);
+
+/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk.  Does not query the hardware.  If
+ * clk is NULL then returns -EINVAL.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+	unsigned long rate;
+
+	mutex_lock(&prepare_lock);
+	rate = __clk_get_rate(clk);
+	mutex_unlock(&prepare_lock);
+
+	return rate;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+/**
+ * __clk_round_rate - round the given rate for a clk
+ * @clk: round the rate of this clock
+ *
+ * Caller must hold prepare_lock.  Useful for clk_ops such as .set_rate
+ */
+static unsigned long __clk_round_rate(struct clk *clk, unsigned long rate, struct clk **best_parent)
+{
+    int i;
+    unsigned long tmp_rate;
+    unsigned long tmp_rate2;
+    unsigned long best_rate;
+    unsigned long diff_rate;
+	struct clk *old_parent;
+	struct clk *sel_parent;
+    
+	if (!clk)
+		return -EINVAL;
+
+	if (!clk->ops->round_rate)
+		return clk->rate;
+    
+    sel_parent = clk->parent;
+    
+    if (clk->num_parents > 1 && (clk->flags & CLK_AUTO_ROUND_PARENT)) {
+        old_parent = clk->parent;
+        best_rate = 0;
+        diff_rate = rate;
+        
+        for ( i=0; i < clk->num_parents; i++) {
+            clk->parent = clk->parents[i];
+            tmp_rate = clk->ops->round_rate(clk->hw, rate, NULL);
+
+            if (tmp_rate > rate)
+                tmp_rate2 = tmp_rate - rate;
+            else
+                tmp_rate2 = rate - tmp_rate;
+            
+            if (tmp_rate2 == 0) {
+                best_rate = tmp_rate;
+                sel_parent = clk->parent;
+               break;
+            } else if (diff_rate > tmp_rate2) {
+                diff_rate = tmp_rate2;
+                best_rate = tmp_rate; /*sel match clock*/
+                sel_parent = clk->parent;
+            } else if (best_rate == 0) {
+                best_rate = tmp_rate;
+            }
+        }
+        clk->parent = old_parent;
+    }
+    else
+    {
+        best_rate = clk->ops->round_rate(clk->hw, rate, NULL);
+    }
+
+    if(best_parent)
+        *best_parent = sel_parent;
+	return best_rate;
+}
+
+/**
+ * clk_round_rate - round the given rate for a clk
+ * @clk: the clk for which we are rounding a rate
+ * @rate: the rate which is to be rounded
+ *
+ * Takes in a rate as input and rounds it to a rate that the clk can actually
+ * use which is then returned.  If clk doesn't support round_rate operation
+ * then the parent rate is returned.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long ret;
+
+	mutex_lock(&prepare_lock);
+	ret = __clk_round_rate(clk, rate, NULL);
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+
+/**
+ * clk_get_parent - return the parent of a clk
+ * @clk: the clk whose parent gets returned
+ *
+ * Simply returns clk->parent.  Returns NULL if clk is NULL.
+ */
+struct clk *clk_get_parent(struct clk *clk)
+{
+	struct clk *parent;
+
+	mutex_lock(&prepare_lock);
+	parent = __clk_get_parent(clk);
+	mutex_unlock(&prepare_lock);
+
+	return parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+/**
+ * __clk_recalc_rates
+ * @clk: first clk in the subtree
+ * @msg: notification type (see include/linux/clk.h)
+ *
+ * Walks the subtree of clks starting with clk and recalculates rates as it
+ * goes.  Note that if a clk does not implement the .recalc_rate callback then
+ * it is assumed that the clock will take on the rate of it's parent.
+ *
+ * clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
+ * if necessary.
+ *
+ * Caller must hold prepare_lock.
+ */
+static void __clk_recalc_rates(struct clk *clk)
+{
+	unsigned long parent_rate = 0;
+
+	if (clk->parent) {
+        __clk_recalc_rates(clk->parent);
+        parent_rate = clk->parent->rate;
+	} else {
+	    parent_rate = clk->rate;
+	}
+
+	if (clk->ops->recalc_rate)
+		clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate);
+	else
+		clk->rate = parent_rate;
+
+}
+
+static int __clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct clk *old_parent;
+	unsigned long flags;
+	int ret = -EINVAL;
+	u8 i;
+
+	old_parent = clk->parent;
+
+	if (!clk->parents)
+        return -EINVAL;
+
+	/*
+	 * find index of new parent clock using cached parent ptrs,
+	 * or if not yet cached, use string name comparison and cache
+	 * them now to avoid future calls to __clk_lookup.
+	 */
+	for (i = 0; i < clk->num_parents; i++) {
+		if (clk->parents && clk->parents[i] == parent)
+			break;
+		else if (!strcmp(clk->parent_names[i], parent->name)) {
+			if (clk->parents) {
+				clk->parents[i] = clk_get(NULL, parent->name);
+                clk_put(clk->parents[i]);
+			}
+			break;
+		}
+	}
+
+	if (i == clk->num_parents) {
+		pr_debug("%s: clock %s is not a possible parent of clock %s\n",
+				__func__, parent->name, clk->name);
+		goto out;
+	}
+
+	/* FIXME replace with clk_is_enabled(clk) someday */
+	spin_lock_irqsave(&enable_lock, flags);
+	if (clk->enable_count)
+		__clk_enable(parent);
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+	/* change clock input source */
+	ret = clk->ops->set_parent(clk->hw, i);
+
+	/* clean up old prepare and enable */
+	spin_lock_irqsave(&enable_lock, flags);
+	if (clk->enable_count)
+		__clk_disable(old_parent);
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+out:
+	return ret;
+}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as it's new input source.  If clk has the
+ * CLK_SET_PARENT_GATE flag set then clk must be gated for this
+ * operation to succeed.  After successfully changing clk's parent
+ * clk_set_parent will update the clk topology, sysfs topology and
+ * propagate rate recalculation via __clk_recalc_rates.  Returns 0 on
+ * success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	int ret = 0;
+
+	if (!clk || !clk->ops)
+		return -EINVAL;
+
+	if (!clk->ops->set_parent || !clk->num_parents)
+		return -ENOSYS;
+
+	/* prevent racing with updates to the clock topology */
+	mutex_lock(&prepare_lock);
+
+	if (clk->parent == parent)
+		goto out;
+
+    if(clk->flags & CLK_AUTO_ROUND_PARENT) {
+        clk->flags &= ~CLK_AUTO_ROUND_PARENT;/*once set parent, cancel round parent*/
+    }
+    
+	ret = __clk_set_parent(clk, parent);
+
+	if (ret) {
+		__clk_recalc_rates(clk);
+		goto out;
+	}
+    
+	clk->parent = parent;
+
+	__clk_recalc_rates(clk);
+
+out:
+	mutex_unlock(&prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+/**
+ * clk_set_rate - specify a new rate for clk
+ * @clk: the clk whose rate is being changed
+ * @rate: the new rate for clk
+ *
+ * In the simplest case clk_set_rate will only change the rate of clk.
+ *
+ * If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call
+ * will fail; only when the clk is disabled will it be able to change
+ * its rate.
+ *
+ * Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to
+ * recursively propagate up to clk's parent; whether or not this happens
+ * depends on the outcome of clk's .round_rate implementation.  If
+ * *parent_rate is 0 after calling .round_rate then upstream parent
+ * propagation is ignored.  If *parent_rate comes back with a new rate
+ * for clk's parent then we propagate up to clk's parent and set it's
+ * rate.  Upward propagation will continue until either a clk does not
+ * support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting
+ * changes to clk's parent_rate.  If there is a failure during upstream
+ * propagation then clk_set_rate will unwind and restore each clk's rate
+ * that had been successfully changed.  Afterwards a rate change abort
+ * notification will be propagated downstream, starting from the clk
+ * that failed.
+ *
+ * At the end of all of the rate setting, clk_set_rate internally calls
+ * __clk_recalc_rates and propagates the rate changes downstream,
+ * starting from the highest clk whose rate was changed.  This has the
+ * added benefit of propagating post-rate change notifiers.
+ *
+ * Note that while post-rate change and rate change abort notifications
+ * are guaranteed to be sent to a clk only once per call to
+ * clk_set_rate, pre-change notifications will be sent for every clk
+ * whose rate is changed.  Stacking pre-change notifications is noisy
+ * for the drivers subscribed to them, but this allows drivers to react
+ * to intermediate clk rate changes up until the point where the final
+ * rate is achieved at the end of upstream propagation.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+    struct clk *best_parent = NULL;
+    
+	/* prevent racing with updates to the clock topology */
+	mutex_lock(&prepare_lock);
+
+	/* bail early if nothing to do */
+	if (clk == NULL || rate == clk->rate)
+		goto out;
+
+    clk->new_rate = __clk_round_rate(clk, rate, &best_parent);
+
+    if(clk->num_parents && best_parent != NULL && best_parent != clk->parent) {
+        __clk_set_parent(clk, best_parent);
+	    clk->parent = best_parent;
+    }
+    
+	/* change the rates */
+	if (clk->ops->set_rate)
+		clk->ops->set_rate(clk->hw, clk->new_rate);
+
+	if (clk->ops->recalc_rate)
+		__clk_recalc_rates(clk);
+    
+    WARN(!clk->parent,"%s,clk %s 's parent is NULL.\n",__func__, clk->name);
+        
+	mutex_unlock(&prepare_lock);
+
+	return 0;
+out:
+	mutex_unlock(&prepare_lock);
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_rate);
+/**
+ * clk_set_auto_gate - set the clock auto gate
+ * @clk: clock source
+ * @enable: enable auto gate true or false
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_auto_gate(struct clk *clk, bool enable)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&enable_lock, flags);
+	if (clk->ops->set_auto_gate)
+		ret = clk->ops->set_auto_gate(clk->hw, enable);
+  	spin_unlock_irqrestore(&enable_lock, flags);
+
+    return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_auto_gate);
+
+/**
+ * clk_register - allocate a new clock, register it and return an opaque cookie
+ * @dev: device that is registering this clock
+ * @name: clock name
+ * @ops: operations this clock supports
+ * @hw: link to hardware-specific clock data
+ * @parent_names: array of string names for all possible parents
+ * @num_parents: number of possible parents
+ * @flags: framework-level hints and quirks
+ *
+ * clk_register is the primary interface for populating the clock tree with new
+ * clock nodes.  It returns a pointer to the newly allocated struct clk which
+ * cannot be dereferenced by driver code but may be used in conjuction with the
+ * rest of the clock API.
+ */
+static int clk_register(struct clk *clk)
+{
+	int i, index;
+
+    if(clk == NULL)
+        return -EINVAL;
+    
+    if(clk->hw != NULL)
+        clk->hw->clk = clk;
+
+	/* throw a WARN if any entries in parent_names are NULL */
+	for (i = 0; i < clk->num_parents; i++)
+		WARN(!clk->parent_names[i],
+				"%s: invalid NULL in %s's .parent_names\n",
+				__func__, clk->name);
+
+	/*
+	 * Allocate an array of struct clk *'s to avoid unnecessary string
+	 * look-ups of clk's possible parents.  This can fail for clocks passed
+	 * in to clk_init during early boot; thus any access to clk->parents[]
+	 * must always check for a NULL pointer and try to populate it if
+	 * necessary.
+	 *
+	 * If clk->parents is not NULL we skip this entire block.  This allows
+	 * for clock drivers to statically initialize clk->parents.
+	 */
+	for (i = 0; i < clk->num_parents; i++){
+		clk->parents[i] = clk_get(NULL,clk->parent_names[i]);
+        clk_put(clk->parents[i]);
+	}
+
+	/*get clk's parent used*/
+    if(clk->num_parents) {
+        index = clk->ops->get_parent(clk->hw);
+        if(index < clk->num_parents)
+            clk->parent = clk->parents[index];
+        else
+            WARN(1,"clk %s get parent error.\n",clk->name);
+    }
+
+	/*
+	 * Set clk's rate.  The preferred method is to use .recalc_rate.  For
+	 * simple clocks and lazy developers the default fallback is to use the
+	 * parent's rate.  If a clock doesn't have a parent (or is orphaned)
+	 * then rate is set to zero.
+	 */
+	__clk_recalc_rates(clk);
+
+	/*
+	 * optional platform-specific magic
+	 *
+	 * The .init callback is not used by any of the basic clock types, but
+	 * exists for weird hardware that must perform initialization magic.
+	 * Please consider other ways of solving initialization problems before
+	 * using this callback, as it's use is discouraged.
+	 */
+	if (clk->ops->init)
+		clk->ops->init(clk->hw);
+
+	return 0;
+}
+/**
+ * clk_disable_unused - disable unused clk
+ */
+static void clk_disable_unused(struct clk *clk)
+{
+	unsigned long flags;
+    
+	if (!clk)
+		goto out;
+
+	spin_lock_irqsave(&enable_lock, flags);
+
+	if (clk->enable_count)
+		goto unlock_out;
+
+	if (clk->flags & CLK_IGNORE_UNUSED)
+		goto unlock_out;
+
+	if (__clk_is_enabled(clk) && clk->ops->disable) {
+		clk->ops->disable(clk->hw);
+        printk(KERN_DEBUG "clk %s: start disabled\n",clk->name);
+	}
+
+unlock_out:
+	spin_unlock_irqrestore(&enable_lock, flags);
+
+out:
+	return;
+}
+/**
+ * clk_show - print clock debug info
+ */
+static int clk_show(struct seq_file *s, void *v)
+{
+    struct clk *clk;
+    
+    seq_printf(s, "%-20s %-20s %-9s %-9s\n", "name","parent","enable","rate");
+	mutex_lock(&prepare_lock);
+	list_for_each_entry(clk, &clocks, list) {
+        if(clk->parent)
+	        seq_printf(s, "%-20s %-20s %-9u %-9lu\n", clk->name, clk->parent->name, \
+                        clk->enable_count, clk->rate);
+        else
+	        seq_printf(s, "%-20s %-20s %-9u %-9lu\n", clk->name, "root", \
+                        clk->enable_count, clk->rate);
+	}
+	mutex_unlock(&prepare_lock);
+	return 0;
+}
+
+/**
+ * clk_open
+ */
+static int clk_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, clk_show, inode->i_private);
+}
+
+/**
+ * clock debug fs
+ */
+struct dentry * clk_debugfs = NULL;
+static const struct file_operations clk_debugfs_fops = {
+	.owner		= THIS_MODULE,
+	.open		= clk_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static void clk_debugfs_init(void)
+{
+	clk_debugfs = debugfs_create_file("clocks", S_IRUSR, NULL,NULL,
+				   &clk_debugfs_fops);
+    return ;
+}
+
+/**
+ *  "/sys/zte/test/clk_info" 
+ */
+static ssize_t clk_info_show(struct kobject *kobj, struct kobj_attribute *attr,
+			  char *buf)
+{
+	char *s = buf;
+    struct clk *clk;
+
+    s += sprintf(s, "%-20s %-20s %-9s %-9s\n", "name","parent","enable","rate");
+	mutex_lock(&prepare_lock);
+	list_for_each_entry(clk, &clocks, list) {
+        if(clk->parent)
+	        s += sprintf(s, "%-20s %-20s %-9u %-9lu\n", clk->name, clk->parent->name, \
+                        clk->enable_count, clk->rate);
+        else
+	        s += sprintf(s, "%-20s %-20s %-9u %-9lu\n", clk->name, "root", \
+                        clk->enable_count, clk->rate);
+	}
+	mutex_unlock(&prepare_lock);
+	
+	return (s - buf);
+}
+
+static ssize_t clk_info_store(struct kobject *kobj, struct kobj_attribute *attr,
+			   const char *buf, size_t n)
+{
+
+	return (n);
+}
+
+zte_attr(clk_info);
+
+static struct attribute *g[] = {
+	&clk_info_attr.attr,
+	NULL,
+};
+
+static struct attribute_group zx29_clk_attribute_group = {
+	.attrs = g,
+}; 
+int __init zx_clk_test_init(void)
+{
+	int ret;
+
+    ret = sysfs_create_group(zx_test_kobj, &zx29_clk_attribute_group);
+
+    pr_info("[DEBUG] create test clk sysfs interface OK.\n");
+
+	return 0;
+}
+
+/* zx29 clocks init*/
+
+static void __init __zx29_clock_init(struct clk_lookup *clock_tbl, unsigned num_clocks)
+{
+	unsigned n;
+    struct clk *clk;
+
+	mutex_lock(&prepare_lock);
+    /*register to devlist*/
+	for (n = 0; n < num_clocks; n++) {
+		clkdev_add(&clock_tbl[n]);
+		list_add_tail(&clock_tbl[n].clk->list, &clocks);
+	}
+    /*register to clktree*/
+	for (n = 0; n < num_clocks; n++) {
+        clk = clock_tbl[n].clk;
+        clk_register(clk);
+	}
+	mutex_unlock(&prepare_lock);
+
+    return ;
+}
+
+void __init zx29_clock_init(void)
+{
+	__zx29_clock_init(periph_clocks_lookups, periph_clocks_lookups_num);
+
+    pr_info("[CLK] zx29 tsp clk init ok.\n");
+}
+
+/*
+ * Several unused clocks may be active.  Turn them off.
+ */
+static int __init zx29_disable_unused_clocks(void)
+{
+	struct clk *clk;
+
+	mutex_lock(&prepare_lock);
+	list_for_each_entry(clk, &clocks, list) {
+    printk(KERN_DEBUG "clk %s: rate = %lu\n",clk->name,clk->rate);
+//zxp			clk_disable_unused(clk);
+	}
+	mutex_unlock(&prepare_lock);
+    
+    clk_debugfs_init();
+
+	return 0;
+}
+late_initcall(zx29_disable_unused_clocks);
diff --git a/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk.h b/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk.h
new file mode 100644
index 0000000..0d5a5fb
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/clk/zte/clk.h
@@ -0,0 +1,130 @@
+/*
+ * linux/arch/arm/mach-zx297520v2/mach/clock.h
+ *
+ * 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.
+ */
+#ifndef CLOCK_H
+#define CLOCK_H
+
+#include <linux/clkdev.h>
+#include <mach/iomap.h>
+#include <mach/board.h>
+
+#define name_main_clk_32k   				"main_clk_32k"
+#define name_main_clk_26m   				"main_clk_26m"
+#define name_mpll_clk_12m   				"mpll_clk_12m"
+#define name_mpll_clk_24m   				"mpll_clk_24m"
+#define name_mpll_clk_39m   				"mpll_clk_39m"
+#define name_mpll_clk_52m   				"mpll_clk_52m"
+#define name_mpll_clk_78m   				"mpll_clk_78m"
+#define name_mpll_clk_104m   				"mpll_clk_104m"
+#define name_mpll_clk_124m8   				"mpll_clk_124m8"
+#define name_mpll_clk_156m   				"mpll_clk_156m"
+#define name_mpll_clk_208m   				"mpll_clk_208m"
+#define name_mpll_clk_312m   				"mpll_clk_312m"
+#define name_mpll_clk_624m   				"mpll_clk_624m"
+#define name_dpll_clk_491m52   				"dpll_clk_491m52"
+#define name_dpll_clk_122m88   				"dpll_clk_122m88"
+#define name_dpll_clk_81m92   				"dpll_clk_81m92"
+#define name_upll_clk_480m   				"upll_clk_480m"
+#define name_upll_clk_96m   				"upll_clk_96m"
+#define name_gpll_clk_25m   				"gpll_clk_25m"
+#define name_gpll_clk_50m   				"gpll_clk_50m"
+#define name_gpll_clk_100m   				"gpll_clk_100m"
+#define name_gpll_clk_178m   				"gpll_clk_178m"
+#define name_gpll_clk_200m   				"gpll_clk_200m"
+
+/*
+ * flags used across common struct clk.  these flags should only affect the
+ * top-level framework.  custom flags for dealing with hardware specifics
+ * belong in struct clk_foo
+ */
+#define CLK_IGNORE_UNUSED					BIT(3) /* do not gate even if unused */
+#define CLK_IS_ROOT							BIT(4) /* root clk, has no parent */
+#define CLK_AUTO_ROUND_PARENT				BIT(5) /* auto round parent to select rate */
+#define CLK_NO_ODD_DIV						BIT(6) /* no div or even div */
+
+struct clk;
+
+/**
+ * struct clk_hw - handle for traversing from a struct clk to its corresponding
+ * hardware-specific structure.  struct clk_hw should be declared within struct
+ * clk_foo and then referenced by the struct clk instance that uses struct
+ * clk_foo's clk_ops
+ *
+ * clk: pointer to the struct clk instance that points back to this struct
+ * clk_hw instance
+ */
+struct clk_hw
+{
+	struct clk *clk;
+};
+
+struct clk_ops {
+	int				(*prepare)(struct clk_hw *hw);
+	void			(*unprepare)(struct clk_hw *hw);
+
+	int				(*enable)(struct clk_hw *hw);
+	void			(*disable)(struct clk_hw *hw);
+	int				(*is_enabled)(struct clk_hw *hw);
+
+	unsigned long	(*recalc_rate)(struct clk_hw *hw,
+					unsigned long parent_rate);
+	long			(*round_rate)(struct clk_hw *hw, unsigned long,
+					unsigned long *);
+	int				(*set_rate)(struct clk_hw *hw, unsigned long);
+
+	int				(*set_parent)(struct clk_hw *hw, u8 index);
+	u8				(*get_parent)(struct clk_hw *hw);
+	void			(*init)(struct clk_hw *hw);			/*called when register to clk_dev*/
+	int    			(*set_auto_gate)(struct clk_hw *hw, bool enable);
+};
+struct clk
+{
+	const char				*name;
+	const struct clk_ops	*ops;
+	struct clk_hw			*hw;
+	struct clk				*parent;
+	char					**parent_names;
+	struct clk				**parents;
+	u8						num_parents;
+	unsigned long			rate;
+	unsigned long			new_rate;
+	unsigned long			flags;
+	unsigned int			enable_count;
+	struct list_head 		list;
+};
+
+#define CLK_ZX29_CONFIG(dev, con, ck) 	\
+	{				\
+			.dev_id = dev,	\
+			.con_id = con,	\
+			.clk = ck,	\
+	}
+
+#define NAME_CLK(clk) 		name_##clk
+
+#define DEFINE_ZX29_ROOT_CLK(root_clk,clk_rate) \
+static struct clk root_clk = { \
+	.name 	= NAME_CLK(root_clk), \
+    .rate 	= clk_rate, \
+    .ops  	= &root_clk_ops, \
+    .flags = CLK_IS_ROOT, \
+}
+
+struct zx29_hwclk
+{
+    struct clk_hw   hw;
+    struct zx29_reg_conf     clk_en_reg;
+    struct zx29_reg_conf     clk_sel_reg;
+    struct zx29_reg_conf     clk_div_reg;
+    struct zx29_reg_conf     clk_gate_reg;
+};
+
+#define to_zx29_hwclk(_hw) container_of(_hw, struct zx29_hwclk, hw)
+
+extern struct clk_lookup periph_clocks_lookups[];
+extern unsigned int periph_clocks_lookups_num;
+#endif