zte's code,first commit
Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
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);