rk30: move clock.h/clock.c to plat-rk
author黄涛 <huangtao@rock-chips.com>
Tue, 11 Sep 2012 05:40:14 +0000 (13:40 +0800)
committer黄涛 <huangtao@rock-chips.com>
Tue, 11 Sep 2012 05:50:58 +0000 (13:50 +0800)
arch/arm/mach-rk30/Makefile
arch/arm/mach-rk30/clock.c [deleted file]
arch/arm/mach-rk30/clock.h [deleted file]
arch/arm/mach-rk30/clock_data-rk3066b.c
arch/arm/mach-rk30/clock_data.c
arch/arm/mach-rk30/dvfs.c
arch/arm/mach-rk30/include/mach/clock.h
arch/arm/plat-rk/clock.c [new file with mode: 0755]
arch/arm/plat-rk/include/plat/clock.h [new file with mode: 0644]

index 11b2f7fe594abb458aea8246fb6a1bfbd9eeeac0..71a2aa7ef01b451f1789b38b422cc3115e6ba270 100755 (executable)
@@ -1,6 +1,6 @@
 EXTRA_CFLAGS += -Os
 ifneq ($(CONFIG_RK_FPGA),y)
-obj-y += clock.o
+obj-y += ../plat-rk/clock.o
 obj-$(CONFIG_ARCH_RK30XX) += clock_data.o
 obj-$(CONFIG_ARCH_RK3066B) += clock_data-rk3066b.o
 endif
diff --git a/arch/arm/mach-rk30/clock.c b/arch/arm/mach-rk30/clock.c
deleted file mode 100755 (executable)
index a763cc7..0000000
+++ /dev/null
@@ -1,751 +0,0 @@
-/* linux/arch/arm/mach-rk30/clock.c
- *
- * Copyright (C) 2012 ROCKCHIP, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/clk.h>
-#include <linux/clkdev.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/hardirq.h>
-#include <linux/delay.h>
-#include <mach/clock.h>
-#include "clock.h"
-#include <mach/dvfs.h>
-#include <linux/delay.h>
-
-#define CLOCK_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args);
-#define CLOCK_PRINTK_ERR(fmt, args...) pr_err(fmt, ## args);
-#define CLOCK_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args);
-
-/* Clock flags */
-/* bit 0 is free */
-#define RATE_FIXED             (1 << 1)        /* Fixed clock rate */
-#define CONFIG_PARTICIPANT     (1 << 10)       /* Fundamental clock */
-
-#define MHZ                    (1000*1000)
-#define KHZ                    (1000)
-
-static void __clk_recalc(struct clk *clk);
-static void __propagate_rate(struct clk *tclk);
-static void __clk_reparent(struct clk *child, struct clk *parent);
-
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-static DEFINE_SPINLOCK(clockfw_lock);
-static LIST_HEAD(root_clks);
-static void clk_notify(struct clk *clk, unsigned long msg,
-                      unsigned long old_rate, unsigned long new_rate);
-
-#define LOCK() do { WARN_ON(in_irq()); if (!irqs_disabled()) spin_lock_bh(&clockfw_lock); } while (0)
-#define UNLOCK() do { if (!irqs_disabled()) spin_unlock_bh(&clockfw_lock); } while (0)
-/**********************************************for clock data****************************************************/
-static struct clk *def_ops_clk=NULL;
-
-void clk_register_default_ops_clk(struct clk *clk)
-{
-       def_ops_clk=clk;
-}
-
-static struct clk *clk_default_get_parent(struct clk *clk)
-{
-       if(def_ops_clk&&def_ops_clk->get_parent)
-               return def_ops_clk->get_parent(clk);
-       else return NULL;
-
-
-
-}
-static int clk_default_set_parent(struct clk *clk, struct clk *parent)
-{
-       if(def_ops_clk&&def_ops_clk->set_parent)
-               return def_ops_clk->set_parent(clk,parent);
-       else
-               return -EINVAL;
-}
-
-int __init clk_disable_unused(void)
-{
-       struct clk *ck;
-       list_for_each_entry(ck, &clocks, node) {
-       if (ck->usecount > 0 || ck->mode == NULL || (ck->flags & IS_PD))
-               continue;
-               LOCK();
-               clk_enable_nolock(ck);
-               clk_disable_nolock(ck);
-               UNLOCK();
-       }
-       return 0;
-}
-/**
- * recalculate_root_clocks - recalculate and propagate all root clocks
- *
- * Recalculates all root clocks (clocks with no parent), which if the
- * clock's .recalc is set correctly, should also propagate their rates.
- * Called at init.
- */
-void clk_recalculate_root_clocks_nolock(void)
-{
-       struct clk *clkp;
-
-       list_for_each_entry(clkp, &root_clks, sibling) {
-               __clk_recalc(clkp);
-               __propagate_rate(clkp);
-       }
-}
-/*
-void clk_recalculate_root_clocks(void)
-{
-       LOCK();
-       clk_recalculate_root_clocks_nolock();
-       UNLOCK();
-}*/
-       
-/**
- * clk_preinit - initialize any fields in the struct clk before clk init
- * @clk: struct clk * to initialize
- *
- * Initialize any struct clk fields needed before normal clk initialization
- * can run.  No return value.
- */
-int clk_register(struct clk *clk)
-{
-       if (clk == NULL || IS_ERR(clk))
-               return -EINVAL;
-       //INIT_LIST_HEAD(&clk->sibling);
-       INIT_LIST_HEAD(&clk->children);
-
-       /*
-        * trap out already registered clocks
-        */
-       if (clk->node.next || clk->node.prev)
-               return 0;
-
-       mutex_lock(&clocks_mutex);
-       if (clk->get_parent)
-               clk->parent = clk->get_parent(clk);
-       else if (clk->parents)
-               clk->parent =clk_default_get_parent(clk);
-       
-       if (clk->parent)
-               list_add(&clk->sibling, &clk->parent->children);
-       else
-               list_add(&clk->sibling, &root_clks);
-       list_add(&clk->node, &clocks);
-       mutex_unlock(&clocks_mutex);    
-       return 0;
-}
-
-/************************************************************/
-static void __clk_recalc(struct clk *clk)
-{
-       if (unlikely(clk->flags & RATE_FIXED))
-               return;
-       if (clk->recalc)
-               clk->rate = clk->recalc(clk);
-       else if (clk->parent)
-               clk->rate = clk->parent->rate;
-}
-static void __clk_reparent(struct clk *child, struct clk *parent)
-{
-       if (child->parent == parent)
-               return;
-       //CLOCK_PRINTK_DBG("%s reparent to %s (was %s)\n", child->name, parent->name, ((child->parent) ? child->parent->name : "NULL"));
-
-       list_del_init(&child->sibling);
-       if (parent)
-               list_add(&child->sibling, &parent->children);
-       child->parent = parent;
-}
-
-/* Propagate rate to children */
-static void __propagate_rate(struct clk *tclk)
-{
-       struct clk *clkp;
-       
-       //CLOCK_PRINTK_DBG("propagate_rate clk %s\n",clkp->name);
-       
-       list_for_each_entry(clkp, &tclk->children, sibling) {
-               __clk_recalc(clkp);
-               __propagate_rate(clkp);
-       }
-       //CLOCK_PRINTK_DBG("propagate_rate clk %s end\n",clkp->name);
-}
-
-int clk_enable_nolock(struct clk *clk)
-{
-       int ret = 0;
-
-       if (clk->usecount == 0) {
-               if (clk->parent) {
-                       ret = clk_enable_nolock(clk->parent);
-                       if (ret)
-                               return ret;
-               }
-
-               if (clk->notifier_count)
-                       clk_notify(clk, CLK_PRE_ENABLE, clk->rate, clk->rate);
-               if (clk->mode)
-                       ret = clk->mode(clk, 1);
-               if (clk->notifier_count)
-                       clk_notify(clk, ret ? CLK_ABORT_ENABLE : CLK_POST_ENABLE, clk->rate, clk->rate);
-               if (ret) {
-                       if (clk->parent)
-                               clk_disable_nolock(clk->parent);
-                       return ret;
-               }
-               pr_debug("%s enabled\n", clk->name);
-       }
-       clk->usecount++;
-
-       return ret;
-}
-void clk_disable_nolock(struct clk *clk)
-{
-       if (clk->usecount == 0) {
-               CLOCK_PRINTK_ERR(KERN_ERR "Trying disable clock %s with 0 usecount\n", clk->name);
-               WARN_ON(1);
-               return;
-       }
-       if (--clk->usecount == 0) {
-               int ret = 0;
-               if (clk->notifier_count)
-                       clk_notify(clk, CLK_PRE_DISABLE, clk->rate, clk->rate);
-               if (clk->mode)
-                       ret = clk->mode(clk, 0);
-               if (clk->notifier_count)
-                       clk_notify(clk, ret ? CLK_ABORT_DISABLE : CLK_POST_DISABLE, clk->rate, clk->rate);
-               pr_debug("%s disabled\n", clk->name);
-               if (ret == 0 && clk->parent)
-                       clk_disable_nolock(clk->parent);
-       }
-}
-/* Given a clock and a rate apply a clock specific rounding function */
-long clk_round_rate_nolock(struct clk *clk, unsigned long rate)
-{
-       if (clk->round_rate)
-               return clk->round_rate(clk, rate);
-
-       if (clk->flags & RATE_FIXED)
-               CLOCK_PRINTK_ERR("clock: clk_round_rate called on fixed-rate clock %s\n", clk->name);
-
-       return clk->rate;
-}
-int is_suport_round_rate(struct clk *clk)
-{
-       return (clk->round_rate) ? 0:(-1);
-}
-
-int clk_set_rate_nolock(struct clk *clk, unsigned long rate)
-{
-       int ret;
-       unsigned long old_rate;
-
-       if (rate == clk->rate)
-               return 0;
-       if (clk->flags & CONFIG_PARTICIPANT)
-               return -EINVAL;
-
-       if (!clk->set_rate)
-               return -EINVAL;
-       
-       //CLOCK_PRINTK_LOG("**will set %s rate %lu\n", clk->name, rate);
-
-       old_rate = clk->rate;
-       if (clk->notifier_count)
-               clk_notify(clk, CLK_PRE_RATE_CHANGE, old_rate, rate);
-
-       ret = clk->set_rate(clk, rate);
-
-       if (ret == 0) {
-               __clk_recalc(clk);
-               CLOCK_PRINTK_LOG("**set %s rate recalc=%lu\n",clk->name,clk->rate);
-               __propagate_rate(clk);
-       }
-
-       if (clk->notifier_count)
-               clk_notify(clk, ret ? CLK_ABORT_RATE_CHANGE : CLK_POST_RATE_CHANGE, old_rate, clk->rate);
-
-       return ret;
-}
-int clk_set_parent_nolock(struct clk *clk, struct clk *parent)
-{
-       int ret;
-       int enabled = clk->usecount > 0;
-       struct clk *old_parent = clk->parent;
-
-       if (clk->parent == parent)
-               return 0;
-
-       /* if clk is already enabled, enable new parent first and disable old parent later. */
-       if (enabled)
-               clk_enable_nolock(parent);
-
-       if (clk->set_parent)
-               ret = clk->set_parent(clk, parent);
-       else
-               ret = clk_default_set_parent(clk,parent);
-
-       if (ret == 0) {
-               /* OK */
-               
-               //CLOCK_PRINTK_DBG("set_parent %s reparent\n",clk->name,parent->name);
-               __clk_reparent(clk, parent);
-               __clk_recalc(clk);
-               __propagate_rate(clk);
-               if (enabled)
-                       clk_disable_nolock(old_parent);
-       } else {
-               //CLOCK_PRINTK_DBG("set_parent err\n",clk->name,parent->name);
-               if (enabled)
-                       clk_disable_nolock(parent);
-       }
-
-       return ret;
-}
-/**********************************dvfs****************************************************/
-
-struct clk_node *clk_get_dvfs_info(struct clk *clk)
-{
-    return clk->dvfs_info;
-}
-
-int clk_set_rate_locked(struct clk * clk,unsigned long rate)
-{
-       int ret;
-       //CLOCK_PRINTK_DBG("%s dvfs clk_set_locked\n",clk->name);
-       LOCK();
-    ret=clk_set_rate_nolock(clk, rate);;
-    UNLOCK();
-       return ret;
-       
-}
-void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk)
-{
-    clk->dvfs_info = dvfs_clk;
-}
-
-
-/*-------------------------------------------------------------------------
- * Optional clock functions defined in include/linux/clk.h
- *-------------------------------------------------------------------------*/
-#ifdef RK30_CLK_OFFBOARD_TEST
-long rk30_clk_round_rate(struct clk *clk, unsigned long rate)
-#else
-long clk_round_rate(struct clk *clk, unsigned long rate)
-#endif
-{
-       long ret = 0;
-
-       if (clk == NULL || IS_ERR(clk))
-               return ret;
-
-       LOCK();
-       ret = clk_round_rate_nolock(clk, rate);
-       UNLOCK();
-
-       return ret;
-}
-
-#ifdef RK30_CLK_OFFBOARD_TEST
-EXPORT_SYMBOL(rk30_clk_round_rate);
-#else
-EXPORT_SYMBOL(clk_round_rate);
-#endif
-
-#ifdef RK30_CLK_OFFBOARD_TEST
-unsigned long rk30_clk_get_rate(struct clk *clk)
-#else
-unsigned long clk_get_rate(struct clk *clk)
-#endif
-{
-       if (clk == NULL || IS_ERR(clk))
-               return 0;
-
-       return clk->rate;
-}
-#ifdef RK30_CLK_OFFBOARD_TEST
-EXPORT_SYMBOL(rk30_clk_get_rate);
-#else
-EXPORT_SYMBOL(clk_get_rate);
-#endif
-
-
-/* Set the clock rate for a clock source */
-#ifdef RK30_CLK_OFFBOARD_TEST
-int rk30_clk_set_rate(struct clk *clk, unsigned long rate)
-#else
-int clk_set_rate(struct clk *clk, unsigned long rate)
-#endif
-{
-       int ret = -EINVAL;
-       if (clk == NULL || IS_ERR(clk)){
-               return ret;
-       }
-       if (rate == clk->rate)
-               return 0;
-       if (clk->dvfs_info!=NULL&&is_support_dvfs(clk->dvfs_info))
-               return dvfs_set_rate(clk, rate);
-
-       LOCK();
-       ret = clk_set_rate_nolock(clk, rate);
-       UNLOCK();
-
-       return ret;
-}
-#ifdef RK30_CLK_OFFBOARD_TEST
-EXPORT_SYMBOL(rk30_clk_set_rate);
-#else
-EXPORT_SYMBOL(clk_set_rate);
-#endif
-
-
-#ifdef RK30_CLK_OFFBOARD_TEST
-int rk30_clk_set_parent(struct clk *clk, struct clk *parent)
-#else
-int clk_set_parent(struct clk *clk, struct clk *parent)
-#endif
-{
-       int ret = -EINVAL;
-
-       if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
-               return ret;
-
-       if (clk->set_parent==NULL||clk->parents == NULL)
-               return ret;
-
-       LOCK();
-       if (clk->usecount == 0)
-               ret = clk_set_parent_nolock(clk, parent);
-       else
-               ret = -EBUSY;
-       UNLOCK();
-
-       return ret;
-}
-int clk_set_parent_force(struct clk *clk, struct clk *parent)
-{
-       int ret = -EINVAL;
-
-       if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
-               return ret;
-
-       if (clk->set_parent==NULL||clk->parents == NULL)
-               return ret;
-       LOCK();
-               ret = clk_set_parent_nolock(clk, parent);       
-       UNLOCK();
-       return ret;
-}
-
-#ifdef RK30_CLK_OFFBOARD_TEST
-EXPORT_SYMBOL(rk30_clk_set_parent);
-#else
-EXPORT_SYMBOL(clk_set_parent);
-#endif
-
-#ifdef RK30_CLK_OFFBOARD_TEST
-struct clk *rk30_clk_get_parent(struct clk *clk)
-#else
-struct clk *clk_get_parent(struct clk *clk)
-#endif
-{
-       if (clk == NULL || IS_ERR(clk)) {
-               return ERR_PTR(-EINVAL);
-       }
-       return clk->parent;
-}
-
-#ifdef RK30_CLK_OFFBOARD_TEST
-EXPORT_SYMBOL(rk30_clk_get_parent);
-#else
-EXPORT_SYMBOL(clk_get_parent);
-#endif
-
-#ifdef RK30_CLK_OFFBOARD_TEST
-void rk30_clk_disable(struct clk *clk)
-#else
-void clk_disable(struct clk *clk)
-#endif
-{
-       if (clk == NULL || IS_ERR(clk))
-               return;
-
-       LOCK();
-       clk_disable_nolock(clk);
-       UNLOCK();
-}
-#ifdef RK30_CLK_OFFBOARD_TEST
-EXPORT_SYMBOL(rk30_clk_disable);
-#else
-EXPORT_SYMBOL(clk_disable);
-#endif
-
-#ifdef RK30_CLK_OFFBOARD_TEST
-int rk30_clk_enable(struct clk *clk)
-#else
-int  clk_enable(struct clk *clk)
-#endif
-{
-       int ret = 0;
-
-       if (clk == NULL || IS_ERR(clk))
-               return -EINVAL;
-
-       LOCK();
-       ret = clk_enable_nolock(clk);
-       UNLOCK();
-
-       return ret;
-}
-#ifdef RK30_CLK_OFFBOARD_TEST
-EXPORT_SYMBOL(rk30_clk_enable);
-#else
-EXPORT_SYMBOL(clk_enable);
-#endif
-
-/* Clk notifier implementation */
-
-/**
- * struct clk_notifier - associate a clk with a notifier
- * @clk: struct clk * to associate the notifier with
- * @notifier_head: a raw_notifier_head for this clk
- * @node: linked list pointers
- *
- * A list of struct clk_notifier is maintained by the notifier code.
- * An entry is created whenever code registers the first notifier on a
- * particular @clk.  Future notifiers on that @clk are added to the
- * @notifier_head.
- */
-struct clk_notifier {
-       struct clk                      *clk;
-       struct raw_notifier_head        notifier_head;
-       struct list_head                node;
-};
-static LIST_HEAD(clk_notifier_list);
-/**
- * _clk_free_notifier_chain - safely remove struct clk_notifier
- * @cn: struct clk_notifier *
- *
- * Removes the struct clk_notifier @cn from the clk_notifier_list and
- * frees it.
- */
-static void _clk_free_notifier_chain(struct clk_notifier *cn)
-{
-       list_del(&cn->node);
-       kfree(cn);
-}
-
-/**
- * clk_notify - call clk notifier chain
- * @clk: struct clk * that is changing rate
- * @msg: clk notifier type (i.e., CLK_POST_RATE_CHANGE; see mach/clock.h)
- * @old_rate: old rate
- * @new_rate: new rate
- *
- * Triggers a notifier call chain on the post-clk-rate-change notifier
- * for clock '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.  No return value.
- */
-static void 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;
-
-       cnd.clk = clk;
-       cnd.old_rate = old_rate;
-       cnd.new_rate = new_rate;
-
-       UNLOCK();
-       list_for_each_entry(cn, &clk_notifier_list, node) {
-               if (cn->clk == clk) {
-                       pr_debug("%s msg %lu rate %lu -> %lu\n", clk->name, msg, old_rate, new_rate);
-                       raw_notifier_call_chain(&cn->notifier_head, msg, &cnd);
-                       break;
-               }
-       }
-       LOCK();
-}
-
-/**
- * clk_notifier_register - add a clock parameter change notifier
- * @clk: struct clk * to watch
- * @nb: struct notifier_block * with callback info
- *
- * Request notification for changes to the clock 'clk'.  This uses a
- * blocking notifier.  Callback code must not call into the clock
- * framework, as clocks_mutex is held.  Pre-notifier callbacks will be
- * passed the previous and new rate of the clock.
- *
- * clk_notifier_register() must be called from process
- * context.  Returns -EINVAL if called with null arguments, -ENOMEM
- * upon allocation failure; otherwise, passes along the return value
- * of blocking_notifier_chain_register().
- */
-int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb)
-{
-       struct clk_notifier *cn = NULL, *cn_new = NULL;
-       int r;
-       struct clk *clkp;
-
-       if (!clk || IS_ERR(clk) || !nb)
-               return -EINVAL;
-
-       mutex_lock(&clocks_mutex);
-
-       list_for_each_entry(cn, &clk_notifier_list, node)
-               if (cn->clk == clk)
-                       break;
-
-       if (cn->clk != clk) {
-               cn_new = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
-               if (!cn_new) {
-                       r = -ENOMEM;
-                       goto cnr_out;
-               };
-
-               cn_new->clk = clk;
-               RAW_INIT_NOTIFIER_HEAD(&cn_new->notifier_head);
-
-               list_add(&cn_new->node, &clk_notifier_list);
-               cn = cn_new;
-       }
-
-       r = raw_notifier_chain_register(&cn->notifier_head, nb);
-       if (!IS_ERR_VALUE(r)) {
-               clkp = clk;
-               do {
-                       clkp->notifier_count++;
-               } while ((clkp = clkp->parent));
-       } else {
-               if (cn_new)
-                       _clk_free_notifier_chain(cn);
-       }
-
-cnr_out:
-       mutex_unlock(&clocks_mutex);
-
-       return r;
-}
-EXPORT_SYMBOL(rk30_clk_notifier_register);
-
-/**
- * clk_notifier_unregister - remove a clock change notifier
- * @clk: struct clk *
- * @nb: struct notifier_block * with callback info
- *
- * Request no further notification for changes to clock 'clk'.
- * Returns -EINVAL if called with null arguments; otherwise, passes
- * along the return value of blocking_notifier_chain_unregister().
- */
-int rk30_clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
-{
-       struct clk_notifier *cn = NULL;
-       struct clk *clkp;
-       int r = -EINVAL;
-
-       if (!clk || IS_ERR(clk) || !nb)
-               return -EINVAL;
-
-       mutex_lock(&clocks_mutex);
-
-       list_for_each_entry(cn, &clk_notifier_list, node)
-               if (cn->clk == clk)
-                       break;
-
-       if (cn->clk != clk) {
-               r = -ENOENT;
-               goto cnu_out;
-       };
-
-       r = raw_notifier_chain_unregister(&cn->notifier_head, nb);
-       if (!IS_ERR_VALUE(r)) {
-               clkp = clk;
-               do {
-                       clkp->notifier_count--;
-               } while ((clkp = clkp->parent));
-       }
-
-       /*
-        * XXX ugh, layering violation.  There should be some
-        * support in the notifier code for this.
-        */
-       if (!cn->notifier_head.head)
-               _clk_free_notifier_chain(cn);
-
-cnu_out:
-       mutex_unlock(&clocks_mutex);
-
-       return r;
-}
-EXPORT_SYMBOL(rk30_clk_notifier_unregister);
-
-static struct clk_dump_ops *dump_def_ops;
-
-void clk_register_dump_ops(struct clk_dump_ops *ops)
-{
-       dump_def_ops=ops;
-}
-
-#ifdef CONFIG_RK_CLOCK_PROC
-static int proc_clk_show(struct seq_file *s, void *v)
-{
-       struct clk* clk;
-       
-       if(!dump_def_ops)
-               return 0;
-
-       if(dump_def_ops->dump_clk)
-       {
-               mutex_lock(&clocks_mutex);
-               list_for_each_entry(clk, &clocks, node) {
-                       if (!clk->parent)
-                       {
-                               dump_def_ops->dump_clk(s, clk, 0,&clocks);
-                       }
-               }
-               mutex_unlock(&clocks_mutex);
-       }
-       if(dump_def_ops->dump_regs)
-               dump_def_ops->dump_regs(s);
-       return 0;
-}
-
-
-static int proc_clk_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, proc_clk_show, NULL);
-}
-
-static const struct file_operations proc_clk_fops = {
-       .open           = proc_clk_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int __init clk_proc_init(void)
-{
-       proc_create("clocks", 0, NULL, &proc_clk_fops);
-       return 0;
-
-}
-late_initcall(clk_proc_init);
-#endif /* CONFIG_RK_CLOCK_PROC */
-
diff --git a/arch/arm/mach-rk30/clock.h b/arch/arm/mach-rk30/clock.h
deleted file mode 100644 (file)
index fdecd15..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef __MACH_CLOCK_H__
-#define __MACH_CLOCK_H__
-
-#ifndef CONFIG_ARCH_RK30
-#define RK30_CLK_OFFBOARD_TEST
-#endif
-
-
-/* Clock flags */
-/* bit 0 is free */
-#define RATE_FIXED             (1 << 1)        /* Fixed clock rate */
-#define CONFIG_PARTICIPANT     (1 << 10)       /* Fundamental clock */
-#define IS_PD                  (1 << 2)        /* Power Domain */
-
-enum _clk_i2s_rate_support {
-       i2s_8192khz = 8192000,
-       i2s_11289_6khz = 11289600,
-       i2s_12288khz = 12288000,
-       i2s_22579_2khz = 22579200,
-       i2s_24576khz = 24576000,//HDMI
-       i2s_49152khz = 24576000,//HDMI
-};
-
-struct _pll_data{
-       u8 id;
-       void *table;
-};
-//struct clk_node;
-struct clk {
-       struct list_head        node;
-       const char              *name;
-       struct clk              *parent;
-       struct list_head        children;
-       struct list_head        sibling;        /* node for children */
-       
-       int                     (*mode)(struct clk *clk, int on);
-       unsigned long           (*recalc)(struct clk *);        /* if null, follow parent */
-       int                     (*set_rate)(struct clk *, unsigned long);
-       long                    (*round_rate)(struct clk *, unsigned long);
-       struct clk*             (*get_parent)(struct clk *);    /* get clk's parent from the hardware. default is clksel_get_parent if parents present */
-       int                     (*set_parent)(struct clk *, struct clk *);      /* default is clksel_set_parent if parents present */
-
-       unsigned long           rate;
-       u32                     flags;
-       s16                     usecount;
-       u16                     notifier_count;
-       u8                      gate_idx;
-       struct _pll_data *pll;
-       u32                     clksel_con;
-       u32                     div_mask;
-       u32                     div_shift;
-       u32                     div_max;
-       u32                     src_mask;
-       u32                     src_shift;
-       
-       struct clk      **parents;
-       u8      parents_num;
-       struct clk_node *dvfs_info;
-       
-};
-
-int __init clk_disable_unused(void);
-void clk_recalculate_root_clocks_nolock(void);
-void clk_recalculate_root_clocks(void);
-int clk_register(struct clk *clk);
-void clk_register_default_ops_clk(struct clk *clk);
-
-int clk_enable_nolock(struct clk *clk);
-void clk_disable_nolock(struct clk *clk);
-long clk_round_rate_nolock(struct clk *clk, unsigned long rate);
-int clk_set_rate_nolock(struct clk *clk, unsigned long rate);
-int clk_set_parent_nolock(struct clk *clk, struct clk *parent);
-int clk_set_rate_locked(struct clk * clk,unsigned long rate);
-void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk);
-struct clk_node *clk_get_dvfs_info(struct clk *clk);
-int is_suport_round_rate(struct clk *clk);
-
-#ifdef RK30_CLK_OFFBOARD_TEST
-#include <linux/device.h>
-struct clk *rk30_clk_get(struct device *dev, const char *con_id);
-#endif
-
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
-struct clk_dump_ops {
-       void (*dump_clk)(struct seq_file *s, struct clk *clk, int deep,const struct list_head *root_clocks);
-       void (*dump_regs)(struct seq_file *s);
-};
-
-void clk_register_dump_ops(struct clk_dump_ops *ops);
-#else
-static void clk_register_dump_ops(struct clk_dump_ops *ops){
-}
-
-#endif
-
-#endif
index e0b57663173e078064dabb12c3c8f0cb47c5f3ad..70c0671d23d7bfd5b40717c2f9c293babeb22b4e 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/hardirq.h>
 #include <mach/cru.h>
 #include <mach/iomux.h>
-#include "clock.h"
+#include <mach/clock.h>
 #include <mach/pmu.h>
 #include <mach/dvfs.h>
 #include <mach/ddr.h>
index fe432f068cee76e743142148d119912d5b0d2cea..7b9e563e45ec809ad12c7f2014d215d70f4c71a8 100755 (executable)
@@ -23,7 +23,7 @@
 #include <linux/hardirq.h>
 #include <mach/cru.h>
 #include <mach/iomux.h>
-#include "clock.h"
+#include <mach/clock.h>
 #include <mach/pmu.h>
 #include <mach/dvfs.h>
 #include <mach/ddr.h>
index 4bc6752ca626ab966160646c7d87121c71668699..ebe038dd92cf3b57999f2b008e3b5a53c2740a84 100755 (executable)
@@ -20,7 +20,6 @@
 #include <linux/slab.h>\r
 #include <linux/clk.h>\r
 #include <linux/cpufreq.h>\r
-#include "clock.h"\r
 #include <mach/dvfs.h>\r
 #include <mach/clock.h>\r
 #include <linux/regulator/consumer.h>\r
index a94d6c851e3de0b92133980e753cb23b8052bec1..94b35428fd3c660b03e53a2b030de4a7455d5937 100755 (executable)
@@ -1,81 +1 @@
-/* arch/arm/mach-rk29/include/mach/clock.h
- *
- * Copyright (C) 2011 ROCKCHIP, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __ASM_ARCH_RK30_CLOCK_H
-#define __ASM_ARCH_RK30_CLOCK_H
-
-/**
- * struct clk_notifier_data - rate data to pass to the notifier callback
- * @clk: struct clk * being changed
- * @old_rate: previous rate of this clock
- * @new_rate: new rate of this clock
- *
- * For a pre-notifier, old_rate is the clock's rate before this rate
- * change, and new_rate is what the rate will be in the future.  For a
- * post-notifier, old_rate and new_rate are both set to the clock's
- * current rate (this was done to optimize the implementation).
- */
-struct clk_notifier_data {
-       struct clk              *clk;
-       unsigned long           old_rate;
-       unsigned long           new_rate;
-};
-
-/*
- * Clk notifier callback types
- *
- * Since the notifier is called with interrupts disabled, any actions
- * taken by callbacks must be extremely fast and lightweight.
- *
- * CLK_PRE_RATE_CHANGE - called after all callbacks have approved the
- *     rate change, immediately before the clock rate is changed, to
- *     indicate that the rate change will proceed.  Drivers must
- *     immediately terminate any operations that will be affected by
- *     the rate change.  Callbacks must always return NOTIFY_DONE.
- *
- * CLK_ABORT_RATE_CHANGE: called if the rate change failed for some
- *     reason after CLK_PRE_RATE_CHANGE.  In this case, all registered
- *     notifiers on the clock will be called with
- *     CLK_ABORT_RATE_CHANGE. Callbacks must always return
- *     NOTIFY_DONE.
- *
- * CLK_POST_RATE_CHANGE - called after the clock rate change has
- *     successfully completed.  Callbacks must always return
- *     NOTIFY_DONE.
- *
- */
-#define CLK_PRE_RATE_CHANGE            1
-#define CLK_POST_RATE_CHANGE           2
-#define CLK_ABORT_RATE_CHANGE          3
-
-#define CLK_PRE_ENABLE                 4
-#define CLK_POST_ENABLE                        5
-#define CLK_ABORT_ENABLE               6
-
-#define CLK_PRE_DISABLE                        7
-#define CLK_POST_DISABLE               8
-#define CLK_ABORT_DISABLE              9
-
-struct notifier_block;
-
-extern int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
-extern int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
-
-#endif
-
-
-
-
-
+#include <plat/clock.h>
diff --git a/arch/arm/plat-rk/clock.c b/arch/arm/plat-rk/clock.c
new file mode 100755 (executable)
index 0000000..42f2c7f
--- /dev/null
@@ -0,0 +1,750 @@
+/* linux/arch/arm/mach-rk30/clock.c
+ *
+ * Copyright (C) 2012 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/delay.h>
+#include <mach/clock.h>
+#include <mach/dvfs.h>
+#include <linux/delay.h>
+
+#define CLOCK_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args);
+#define CLOCK_PRINTK_ERR(fmt, args...) pr_err(fmt, ## args);
+#define CLOCK_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args);
+
+/* Clock flags */
+/* bit 0 is free */
+#define RATE_FIXED             (1 << 1)        /* Fixed clock rate */
+#define CONFIG_PARTICIPANT     (1 << 10)       /* Fundamental clock */
+
+#define MHZ                    (1000*1000)
+#define KHZ                    (1000)
+
+static void __clk_recalc(struct clk *clk);
+static void __propagate_rate(struct clk *tclk);
+static void __clk_reparent(struct clk *child, struct clk *parent);
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+static DEFINE_SPINLOCK(clockfw_lock);
+static LIST_HEAD(root_clks);
+static void clk_notify(struct clk *clk, unsigned long msg,
+                      unsigned long old_rate, unsigned long new_rate);
+
+#define LOCK() do { WARN_ON(in_irq()); if (!irqs_disabled()) spin_lock_bh(&clockfw_lock); } while (0)
+#define UNLOCK() do { if (!irqs_disabled()) spin_unlock_bh(&clockfw_lock); } while (0)
+/**********************************************for clock data****************************************************/
+static struct clk *def_ops_clk=NULL;
+
+void clk_register_default_ops_clk(struct clk *clk)
+{
+       def_ops_clk=clk;
+}
+
+static struct clk *clk_default_get_parent(struct clk *clk)
+{
+       if(def_ops_clk&&def_ops_clk->get_parent)
+               return def_ops_clk->get_parent(clk);
+       else return NULL;
+
+
+
+}
+static int clk_default_set_parent(struct clk *clk, struct clk *parent)
+{
+       if(def_ops_clk&&def_ops_clk->set_parent)
+               return def_ops_clk->set_parent(clk,parent);
+       else
+               return -EINVAL;
+}
+
+int __init clk_disable_unused(void)
+{
+       struct clk *ck;
+       list_for_each_entry(ck, &clocks, node) {
+       if (ck->usecount > 0 || ck->mode == NULL || (ck->flags & IS_PD))
+               continue;
+               LOCK();
+               clk_enable_nolock(ck);
+               clk_disable_nolock(ck);
+               UNLOCK();
+       }
+       return 0;
+}
+/**
+ * recalculate_root_clocks - recalculate and propagate all root clocks
+ *
+ * Recalculates all root clocks (clocks with no parent), which if the
+ * clock's .recalc is set correctly, should also propagate their rates.
+ * Called at init.
+ */
+void clk_recalculate_root_clocks_nolock(void)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &root_clks, sibling) {
+               __clk_recalc(clkp);
+               __propagate_rate(clkp);
+       }
+}
+/*
+void clk_recalculate_root_clocks(void)
+{
+       LOCK();
+       clk_recalculate_root_clocks_nolock();
+       UNLOCK();
+}*/
+       
+/**
+ * clk_preinit - initialize any fields in the struct clk before clk init
+ * @clk: struct clk * to initialize
+ *
+ * Initialize any struct clk fields needed before normal clk initialization
+ * can run.  No return value.
+ */
+int clk_register(struct clk *clk)
+{
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+       //INIT_LIST_HEAD(&clk->sibling);
+       INIT_LIST_HEAD(&clk->children);
+
+       /*
+        * trap out already registered clocks
+        */
+       if (clk->node.next || clk->node.prev)
+               return 0;
+
+       mutex_lock(&clocks_mutex);
+       if (clk->get_parent)
+               clk->parent = clk->get_parent(clk);
+       else if (clk->parents)
+               clk->parent =clk_default_get_parent(clk);
+       
+       if (clk->parent)
+               list_add(&clk->sibling, &clk->parent->children);
+       else
+               list_add(&clk->sibling, &root_clks);
+       list_add(&clk->node, &clocks);
+       mutex_unlock(&clocks_mutex);    
+       return 0;
+}
+
+/************************************************************/
+static void __clk_recalc(struct clk *clk)
+{
+       if (unlikely(clk->flags & RATE_FIXED))
+               return;
+       if (clk->recalc)
+               clk->rate = clk->recalc(clk);
+       else if (clk->parent)
+               clk->rate = clk->parent->rate;
+}
+static void __clk_reparent(struct clk *child, struct clk *parent)
+{
+       if (child->parent == parent)
+               return;
+       //CLOCK_PRINTK_DBG("%s reparent to %s (was %s)\n", child->name, parent->name, ((child->parent) ? child->parent->name : "NULL"));
+
+       list_del_init(&child->sibling);
+       if (parent)
+               list_add(&child->sibling, &parent->children);
+       child->parent = parent;
+}
+
+/* Propagate rate to children */
+static void __propagate_rate(struct clk *tclk)
+{
+       struct clk *clkp;
+       
+       //CLOCK_PRINTK_DBG("propagate_rate clk %s\n",clkp->name);
+       
+       list_for_each_entry(clkp, &tclk->children, sibling) {
+               __clk_recalc(clkp);
+               __propagate_rate(clkp);
+       }
+       //CLOCK_PRINTK_DBG("propagate_rate clk %s end\n",clkp->name);
+}
+
+int clk_enable_nolock(struct clk *clk)
+{
+       int ret = 0;
+
+       if (clk->usecount == 0) {
+               if (clk->parent) {
+                       ret = clk_enable_nolock(clk->parent);
+                       if (ret)
+                               return ret;
+               }
+
+               if (clk->notifier_count)
+                       clk_notify(clk, CLK_PRE_ENABLE, clk->rate, clk->rate);
+               if (clk->mode)
+                       ret = clk->mode(clk, 1);
+               if (clk->notifier_count)
+                       clk_notify(clk, ret ? CLK_ABORT_ENABLE : CLK_POST_ENABLE, clk->rate, clk->rate);
+               if (ret) {
+                       if (clk->parent)
+                               clk_disable_nolock(clk->parent);
+                       return ret;
+               }
+               pr_debug("%s enabled\n", clk->name);
+       }
+       clk->usecount++;
+
+       return ret;
+}
+void clk_disable_nolock(struct clk *clk)
+{
+       if (clk->usecount == 0) {
+               CLOCK_PRINTK_ERR(KERN_ERR "Trying disable clock %s with 0 usecount\n", clk->name);
+               WARN_ON(1);
+               return;
+       }
+       if (--clk->usecount == 0) {
+               int ret = 0;
+               if (clk->notifier_count)
+                       clk_notify(clk, CLK_PRE_DISABLE, clk->rate, clk->rate);
+               if (clk->mode)
+                       ret = clk->mode(clk, 0);
+               if (clk->notifier_count)
+                       clk_notify(clk, ret ? CLK_ABORT_DISABLE : CLK_POST_DISABLE, clk->rate, clk->rate);
+               pr_debug("%s disabled\n", clk->name);
+               if (ret == 0 && clk->parent)
+                       clk_disable_nolock(clk->parent);
+       }
+}
+/* Given a clock and a rate apply a clock specific rounding function */
+long clk_round_rate_nolock(struct clk *clk, unsigned long rate)
+{
+       if (clk->round_rate)
+               return clk->round_rate(clk, rate);
+
+       if (clk->flags & RATE_FIXED)
+               CLOCK_PRINTK_ERR("clock: clk_round_rate called on fixed-rate clock %s\n", clk->name);
+
+       return clk->rate;
+}
+int is_suport_round_rate(struct clk *clk)
+{
+       return (clk->round_rate) ? 0:(-1);
+}
+
+int clk_set_rate_nolock(struct clk *clk, unsigned long rate)
+{
+       int ret;
+       unsigned long old_rate;
+
+       if (rate == clk->rate)
+               return 0;
+       if (clk->flags & CONFIG_PARTICIPANT)
+               return -EINVAL;
+
+       if (!clk->set_rate)
+               return -EINVAL;
+       
+       //CLOCK_PRINTK_LOG("**will set %s rate %lu\n", clk->name, rate);
+
+       old_rate = clk->rate;
+       if (clk->notifier_count)
+               clk_notify(clk, CLK_PRE_RATE_CHANGE, old_rate, rate);
+
+       ret = clk->set_rate(clk, rate);
+
+       if (ret == 0) {
+               __clk_recalc(clk);
+               CLOCK_PRINTK_LOG("**set %s rate recalc=%lu\n",clk->name,clk->rate);
+               __propagate_rate(clk);
+       }
+
+       if (clk->notifier_count)
+               clk_notify(clk, ret ? CLK_ABORT_RATE_CHANGE : CLK_POST_RATE_CHANGE, old_rate, clk->rate);
+
+       return ret;
+}
+int clk_set_parent_nolock(struct clk *clk, struct clk *parent)
+{
+       int ret;
+       int enabled = clk->usecount > 0;
+       struct clk *old_parent = clk->parent;
+
+       if (clk->parent == parent)
+               return 0;
+
+       /* if clk is already enabled, enable new parent first and disable old parent later. */
+       if (enabled)
+               clk_enable_nolock(parent);
+
+       if (clk->set_parent)
+               ret = clk->set_parent(clk, parent);
+       else
+               ret = clk_default_set_parent(clk,parent);
+
+       if (ret == 0) {
+               /* OK */
+               
+               //CLOCK_PRINTK_DBG("set_parent %s reparent\n",clk->name,parent->name);
+               __clk_reparent(clk, parent);
+               __clk_recalc(clk);
+               __propagate_rate(clk);
+               if (enabled)
+                       clk_disable_nolock(old_parent);
+       } else {
+               //CLOCK_PRINTK_DBG("set_parent err\n",clk->name,parent->name);
+               if (enabled)
+                       clk_disable_nolock(parent);
+       }
+
+       return ret;
+}
+/**********************************dvfs****************************************************/
+
+struct clk_node *clk_get_dvfs_info(struct clk *clk)
+{
+    return clk->dvfs_info;
+}
+
+int clk_set_rate_locked(struct clk * clk,unsigned long rate)
+{
+       int ret;
+       //CLOCK_PRINTK_DBG("%s dvfs clk_set_locked\n",clk->name);
+       LOCK();
+    ret=clk_set_rate_nolock(clk, rate);;
+    UNLOCK();
+       return ret;
+       
+}
+void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk)
+{
+    clk->dvfs_info = dvfs_clk;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Optional clock functions defined in include/linux/clk.h
+ *-------------------------------------------------------------------------*/
+#ifdef RK30_CLK_OFFBOARD_TEST
+long rk30_clk_round_rate(struct clk *clk, unsigned long rate)
+#else
+long clk_round_rate(struct clk *clk, unsigned long rate)
+#endif
+{
+       long ret = 0;
+
+       if (clk == NULL || IS_ERR(clk))
+               return ret;
+
+       LOCK();
+       ret = clk_round_rate_nolock(clk, rate);
+       UNLOCK();
+
+       return ret;
+}
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_round_rate);
+#else
+EXPORT_SYMBOL(clk_round_rate);
+#endif
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+unsigned long rk30_clk_get_rate(struct clk *clk)
+#else
+unsigned long clk_get_rate(struct clk *clk)
+#endif
+{
+       if (clk == NULL || IS_ERR(clk))
+               return 0;
+
+       return clk->rate;
+}
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_get_rate);
+#else
+EXPORT_SYMBOL(clk_get_rate);
+#endif
+
+
+/* Set the clock rate for a clock source */
+#ifdef RK30_CLK_OFFBOARD_TEST
+int rk30_clk_set_rate(struct clk *clk, unsigned long rate)
+#else
+int clk_set_rate(struct clk *clk, unsigned long rate)
+#endif
+{
+       int ret = -EINVAL;
+       if (clk == NULL || IS_ERR(clk)){
+               return ret;
+       }
+       if (rate == clk->rate)
+               return 0;
+       if (clk->dvfs_info!=NULL&&is_support_dvfs(clk->dvfs_info))
+               return dvfs_set_rate(clk, rate);
+
+       LOCK();
+       ret = clk_set_rate_nolock(clk, rate);
+       UNLOCK();
+
+       return ret;
+}
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_set_rate);
+#else
+EXPORT_SYMBOL(clk_set_rate);
+#endif
+
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+int rk30_clk_set_parent(struct clk *clk, struct clk *parent)
+#else
+int clk_set_parent(struct clk *clk, struct clk *parent)
+#endif
+{
+       int ret = -EINVAL;
+
+       if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
+               return ret;
+
+       if (clk->set_parent==NULL||clk->parents == NULL)
+               return ret;
+
+       LOCK();
+       if (clk->usecount == 0)
+               ret = clk_set_parent_nolock(clk, parent);
+       else
+               ret = -EBUSY;
+       UNLOCK();
+
+       return ret;
+}
+int clk_set_parent_force(struct clk *clk, struct clk *parent)
+{
+       int ret = -EINVAL;
+
+       if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
+               return ret;
+
+       if (clk->set_parent==NULL||clk->parents == NULL)
+               return ret;
+       LOCK();
+               ret = clk_set_parent_nolock(clk, parent);       
+       UNLOCK();
+       return ret;
+}
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_set_parent);
+#else
+EXPORT_SYMBOL(clk_set_parent);
+#endif
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+struct clk *rk30_clk_get_parent(struct clk *clk)
+#else
+struct clk *clk_get_parent(struct clk *clk)
+#endif
+{
+       if (clk == NULL || IS_ERR(clk)) {
+               return ERR_PTR(-EINVAL);
+       }
+       return clk->parent;
+}
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_get_parent);
+#else
+EXPORT_SYMBOL(clk_get_parent);
+#endif
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+void rk30_clk_disable(struct clk *clk)
+#else
+void clk_disable(struct clk *clk)
+#endif
+{
+       if (clk == NULL || IS_ERR(clk))
+               return;
+
+       LOCK();
+       clk_disable_nolock(clk);
+       UNLOCK();
+}
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_disable);
+#else
+EXPORT_SYMBOL(clk_disable);
+#endif
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+int rk30_clk_enable(struct clk *clk)
+#else
+int  clk_enable(struct clk *clk)
+#endif
+{
+       int ret = 0;
+
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       LOCK();
+       ret = clk_enable_nolock(clk);
+       UNLOCK();
+
+       return ret;
+}
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_enable);
+#else
+EXPORT_SYMBOL(clk_enable);
+#endif
+
+/* Clk notifier implementation */
+
+/**
+ * struct clk_notifier - associate a clk with a notifier
+ * @clk: struct clk * to associate the notifier with
+ * @notifier_head: a raw_notifier_head for this clk
+ * @node: linked list pointers
+ *
+ * A list of struct clk_notifier is maintained by the notifier code.
+ * An entry is created whenever code registers the first notifier on a
+ * particular @clk.  Future notifiers on that @clk are added to the
+ * @notifier_head.
+ */
+struct clk_notifier {
+       struct clk                      *clk;
+       struct raw_notifier_head        notifier_head;
+       struct list_head                node;
+};
+static LIST_HEAD(clk_notifier_list);
+/**
+ * _clk_free_notifier_chain - safely remove struct clk_notifier
+ * @cn: struct clk_notifier *
+ *
+ * Removes the struct clk_notifier @cn from the clk_notifier_list and
+ * frees it.
+ */
+static void _clk_free_notifier_chain(struct clk_notifier *cn)
+{
+       list_del(&cn->node);
+       kfree(cn);
+}
+
+/**
+ * clk_notify - call clk notifier chain
+ * @clk: struct clk * that is changing rate
+ * @msg: clk notifier type (i.e., CLK_POST_RATE_CHANGE; see mach/clock.h)
+ * @old_rate: old rate
+ * @new_rate: new rate
+ *
+ * Triggers a notifier call chain on the post-clk-rate-change notifier
+ * for clock '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.  No return value.
+ */
+static void 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;
+
+       cnd.clk = clk;
+       cnd.old_rate = old_rate;
+       cnd.new_rate = new_rate;
+
+       UNLOCK();
+       list_for_each_entry(cn, &clk_notifier_list, node) {
+               if (cn->clk == clk) {
+                       pr_debug("%s msg %lu rate %lu -> %lu\n", clk->name, msg, old_rate, new_rate);
+                       raw_notifier_call_chain(&cn->notifier_head, msg, &cnd);
+                       break;
+               }
+       }
+       LOCK();
+}
+
+/**
+ * clk_notifier_register - add a clock parameter change notifier
+ * @clk: struct clk * to watch
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request notification for changes to the clock 'clk'.  This uses a
+ * blocking notifier.  Callback code must not call into the clock
+ * framework, as clocks_mutex is held.  Pre-notifier callbacks will be
+ * passed the previous and new rate of the clock.
+ *
+ * clk_notifier_register() must be called from process
+ * context.  Returns -EINVAL if called with null arguments, -ENOMEM
+ * upon allocation failure; otherwise, passes along the return value
+ * of blocking_notifier_chain_register().
+ */
+int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb)
+{
+       struct clk_notifier *cn = NULL, *cn_new = NULL;
+       int r;
+       struct clk *clkp;
+
+       if (!clk || IS_ERR(clk) || !nb)
+               return -EINVAL;
+
+       mutex_lock(&clocks_mutex);
+
+       list_for_each_entry(cn, &clk_notifier_list, node)
+               if (cn->clk == clk)
+                       break;
+
+       if (cn->clk != clk) {
+               cn_new = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
+               if (!cn_new) {
+                       r = -ENOMEM;
+                       goto cnr_out;
+               };
+
+               cn_new->clk = clk;
+               RAW_INIT_NOTIFIER_HEAD(&cn_new->notifier_head);
+
+               list_add(&cn_new->node, &clk_notifier_list);
+               cn = cn_new;
+       }
+
+       r = raw_notifier_chain_register(&cn->notifier_head, nb);
+       if (!IS_ERR_VALUE(r)) {
+               clkp = clk;
+               do {
+                       clkp->notifier_count++;
+               } while ((clkp = clkp->parent));
+       } else {
+               if (cn_new)
+                       _clk_free_notifier_chain(cn);
+       }
+
+cnr_out:
+       mutex_unlock(&clocks_mutex);
+
+       return r;
+}
+EXPORT_SYMBOL(rk30_clk_notifier_register);
+
+/**
+ * clk_notifier_unregister - remove a clock change notifier
+ * @clk: struct clk *
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request no further notification for changes to clock 'clk'.
+ * Returns -EINVAL if called with null arguments; otherwise, passes
+ * along the return value of blocking_notifier_chain_unregister().
+ */
+int rk30_clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
+{
+       struct clk_notifier *cn = NULL;
+       struct clk *clkp;
+       int r = -EINVAL;
+
+       if (!clk || IS_ERR(clk) || !nb)
+               return -EINVAL;
+
+       mutex_lock(&clocks_mutex);
+
+       list_for_each_entry(cn, &clk_notifier_list, node)
+               if (cn->clk == clk)
+                       break;
+
+       if (cn->clk != clk) {
+               r = -ENOENT;
+               goto cnu_out;
+       };
+
+       r = raw_notifier_chain_unregister(&cn->notifier_head, nb);
+       if (!IS_ERR_VALUE(r)) {
+               clkp = clk;
+               do {
+                       clkp->notifier_count--;
+               } while ((clkp = clkp->parent));
+       }
+
+       /*
+        * XXX ugh, layering violation.  There should be some
+        * support in the notifier code for this.
+        */
+       if (!cn->notifier_head.head)
+               _clk_free_notifier_chain(cn);
+
+cnu_out:
+       mutex_unlock(&clocks_mutex);
+
+       return r;
+}
+EXPORT_SYMBOL(rk30_clk_notifier_unregister);
+
+static struct clk_dump_ops *dump_def_ops;
+
+void clk_register_dump_ops(struct clk_dump_ops *ops)
+{
+       dump_def_ops=ops;
+}
+
+#ifdef CONFIG_RK_CLOCK_PROC
+static int proc_clk_show(struct seq_file *s, void *v)
+{
+       struct clk* clk;
+       
+       if(!dump_def_ops)
+               return 0;
+
+       if(dump_def_ops->dump_clk)
+       {
+               mutex_lock(&clocks_mutex);
+               list_for_each_entry(clk, &clocks, node) {
+                       if (!clk->parent)
+                       {
+                               dump_def_ops->dump_clk(s, clk, 0,&clocks);
+                       }
+               }
+               mutex_unlock(&clocks_mutex);
+       }
+       if(dump_def_ops->dump_regs)
+               dump_def_ops->dump_regs(s);
+       return 0;
+}
+
+
+static int proc_clk_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, proc_clk_show, NULL);
+}
+
+static const struct file_operations proc_clk_fops = {
+       .open           = proc_clk_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init clk_proc_init(void)
+{
+       proc_create("clocks", 0, NULL, &proc_clk_fops);
+       return 0;
+
+}
+late_initcall(clk_proc_init);
+#endif /* CONFIG_RK_CLOCK_PROC */
+
diff --git a/arch/arm/plat-rk/include/plat/clock.h b/arch/arm/plat-rk/include/plat/clock.h
new file mode 100644 (file)
index 0000000..09286d4
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef __PLAT_CLOCK_H__
+#define __PLAT_CLOCK_H__
+
+#ifndef CONFIG_ARCH_RK30
+#define RK30_CLK_OFFBOARD_TEST
+#endif
+
+
+/* Clock flags */
+/* bit 0 is free */
+#define RATE_FIXED             (1 << 1)        /* Fixed clock rate */
+#define CONFIG_PARTICIPANT     (1 << 10)       /* Fundamental clock */
+#define IS_PD                  (1 << 2)        /* Power Domain */
+
+enum _clk_i2s_rate_support {
+       i2s_8192khz = 8192000,
+       i2s_11289_6khz = 11289600,
+       i2s_12288khz = 12288000,
+       i2s_22579_2khz = 22579200,
+       i2s_24576khz = 24576000,//HDMI
+       i2s_49152khz = 24576000,//HDMI
+};
+
+struct _pll_data{
+       u8 id;
+       void *table;
+};
+//struct clk_node;
+struct clk {
+       struct list_head        node;
+       const char              *name;
+       struct clk              *parent;
+       struct list_head        children;
+       struct list_head        sibling;        /* node for children */
+       
+       int                     (*mode)(struct clk *clk, int on);
+       unsigned long           (*recalc)(struct clk *);        /* if null, follow parent */
+       int                     (*set_rate)(struct clk *, unsigned long);
+       long                    (*round_rate)(struct clk *, unsigned long);
+       struct clk*             (*get_parent)(struct clk *);    /* get clk's parent from the hardware. default is clksel_get_parent if parents present */
+       int                     (*set_parent)(struct clk *, struct clk *);      /* default is clksel_set_parent if parents present */
+
+       unsigned long           rate;
+       u32                     flags;
+       s16                     usecount;
+       u16                     notifier_count;
+       u8                      gate_idx;
+       struct _pll_data *pll;
+       u32                     clksel_con;
+       u32                     div_mask;
+       u32                     div_shift;
+       u32                     div_max;
+       u32                     src_mask;
+       u32                     src_shift;
+       
+       struct clk      **parents;
+       u8      parents_num;
+       struct clk_node *dvfs_info;
+       
+};
+
+int __init clk_disable_unused(void);
+void clk_recalculate_root_clocks_nolock(void);
+void clk_recalculate_root_clocks(void);
+int clk_register(struct clk *clk);
+void clk_register_default_ops_clk(struct clk *clk);
+
+int clk_enable_nolock(struct clk *clk);
+void clk_disable_nolock(struct clk *clk);
+long clk_round_rate_nolock(struct clk *clk, unsigned long rate);
+int clk_set_rate_nolock(struct clk *clk, unsigned long rate);
+int clk_set_parent_nolock(struct clk *clk, struct clk *parent);
+int clk_set_rate_locked(struct clk * clk,unsigned long rate);
+void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk);
+struct clk_node *clk_get_dvfs_info(struct clk *clk);
+int is_suport_round_rate(struct clk *clk);
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+#include <linux/device.h>
+struct clk *rk30_clk_get(struct device *dev, const char *con_id);
+#endif
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+struct clk_dump_ops {
+       void (*dump_clk)(struct seq_file *s, struct clk *clk, int deep,const struct list_head *root_clocks);
+       void (*dump_regs)(struct seq_file *s);
+};
+
+void clk_register_dump_ops(struct clk_dump_ops *ops);
+#else
+static inline void clk_register_dump_ops(struct clk_dump_ops *ops) {}
+#endif
+
+/**
+ * struct clk_notifier_data - rate data to pass to the notifier callback
+ * @clk: struct clk * being changed
+ * @old_rate: previous rate of this clock
+ * @new_rate: new rate of this clock
+ *
+ * For a pre-notifier, old_rate is the clock's rate before this rate
+ * change, and new_rate is what the rate will be in the future.  For a
+ * post-notifier, old_rate and new_rate are both set to the clock's
+ * current rate (this was done to optimize the implementation).
+ */
+struct clk_notifier_data {
+       struct clk              *clk;
+       unsigned long           old_rate;
+       unsigned long           new_rate;
+};
+
+/*
+ * Clk notifier callback types
+ *
+ * Since the notifier is called with interrupts disabled, any actions
+ * taken by callbacks must be extremely fast and lightweight.
+ *
+ * CLK_PRE_RATE_CHANGE - called after all callbacks have approved the
+ *     rate change, immediately before the clock rate is changed, to
+ *     indicate that the rate change will proceed.  Drivers must
+ *     immediately terminate any operations that will be affected by
+ *     the rate change.  Callbacks must always return NOTIFY_DONE.
+ *
+ * CLK_ABORT_RATE_CHANGE: called if the rate change failed for some
+ *     reason after CLK_PRE_RATE_CHANGE.  In this case, all registered
+ *     notifiers on the clock will be called with
+ *     CLK_ABORT_RATE_CHANGE. Callbacks must always return
+ *     NOTIFY_DONE.
+ *
+ * CLK_POST_RATE_CHANGE - called after the clock rate change has
+ *     successfully completed.  Callbacks must always return
+ *     NOTIFY_DONE.
+ *
+ */
+#define CLK_PRE_RATE_CHANGE            1
+#define CLK_POST_RATE_CHANGE           2
+#define CLK_ABORT_RATE_CHANGE          3
+
+#define CLK_PRE_ENABLE                 4
+#define CLK_POST_ENABLE                        5
+#define CLK_ABORT_ENABLE               6
+
+#define CLK_PRE_DISABLE                        7
+#define CLK_POST_DISABLE               8
+#define CLK_ABORT_DISABLE              9
+
+struct notifier_block;
+
+extern int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
+extern int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
+
+#endif