summaryrefslogtreecommitdiff
path: root/recipes/kexecboot/linux-kexecboot-2.6.24/tosa/0039-Add-generic-framework-for-managing-clocks.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/kexecboot/linux-kexecboot-2.6.24/tosa/0039-Add-generic-framework-for-managing-clocks.patch')
-rw-r--r--recipes/kexecboot/linux-kexecboot-2.6.24/tosa/0039-Add-generic-framework-for-managing-clocks.patch446
1 files changed, 446 insertions, 0 deletions
diff --git a/recipes/kexecboot/linux-kexecboot-2.6.24/tosa/0039-Add-generic-framework-for-managing-clocks.patch b/recipes/kexecboot/linux-kexecboot-2.6.24/tosa/0039-Add-generic-framework-for-managing-clocks.patch
new file mode 100644
index 0000000000..c09c208c6a
--- /dev/null
+++ b/recipes/kexecboot/linux-kexecboot-2.6.24/tosa/0039-Add-generic-framework-for-managing-clocks.patch
@@ -0,0 +1,446 @@
+From 62c9a23cfa7181369637d0b61a8e90c83c562f03 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Mon, 4 Feb 2008 03:01:06 +0300
+Subject: [PATCH 39/64] Add generic framework for managing clocks.
+
+Provide a generic framework that platform may choose
+to support clocks api. In particular this provides
+platform-independant struct clk definition, a full
+implementation of clocks api and a set of functions
+for registering and unregistering clocks in a safe way.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ include/linux/clklib.h | 85 ++++++++++++++
+ init/Kconfig | 7 +
+ kernel/Makefile | 1 +
+ kernel/clklib.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 388 insertions(+), 0 deletions(-)
+ create mode 100644 include/linux/clklib.h
+ create mode 100644 kernel/clklib.c
+
+diff --git a/include/linux/clklib.h b/include/linux/clklib.h
+new file mode 100644
+index 0000000..4bd9b4a
+--- /dev/null
++++ b/include/linux/clklib.h
+@@ -0,0 +1,85 @@
++/*
++ * Copyright (C) 2008 Dmitry Baryshkov
++ *
++ * This file is released under the GPL v2.
++ */
++
++#ifndef CLKLIB_H
++#define CLKLIB_H
++
++#include <linux/list.h>
++
++struct clk {
++ struct list_head node;
++ struct clk *parent;
++
++ const char *name;
++ struct module *owner;
++
++ int users;
++ unsigned long rate;
++ int delay;
++
++ int (*can_get) (struct clk *, struct device *);
++ int (*set_parent) (struct clk *, struct clk *);
++ int (*enable) (struct clk *);
++ void (*disable) (struct clk *);
++ unsigned long (*getrate) (struct clk*);
++ int (*setrate) (struct clk *, unsigned long);
++ long (*roundrate) (struct clk *, unsigned long);
++
++ void *priv;
++};
++
++int clk_register(struct clk *clk);
++void clk_unregister(struct clk *clk);
++static void __maybe_unused clks_register(struct clk *clks, size_t num)
++{
++ int i;
++ for (i = 0; i < num; i++) {
++ clk_register(&clks[i]);
++ }
++}
++
++
++int clk_alloc_function(const char *parent, struct clk *clk);
++
++struct clk_function {
++ const char *parent;
++ struct clk *clk;
++};
++
++#define CLK_FUNC(_clock, _function, _can_get, _data, _format) \
++ { \
++ .parent = _clock, \
++ .clk = &(struct clk) { \
++ .name= _function, \
++ .owner = THIS_MODULE, \
++ .can_get = _can_get, \
++ .priv = _data, \
++ .format = _format, \
++ }, \
++ }
++
++static int __maybe_unused clk_alloc_functions(
++ struct clk_function *funcs,
++ int num)
++{
++ int i;
++ int rc;
++
++ for (i = 0; i < num; i++) {
++ rc = clk_alloc_function(funcs[i].parent, funcs[i].clk);
++
++ if (rc) {
++ printk(KERN_ERR "Error allocating %s.%s function.\n",
++ funcs[i].parent,
++ funcs[i].clk->name);
++ return rc;
++ }
++ }
++
++ return 0;
++}
++
++#endif
+diff --git a/init/Kconfig b/init/Kconfig
+index b9d11a8..05b62ba 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -435,6 +435,13 @@ config CC_OPTIMIZE_FOR_SIZE
+ config SYSCTL
+ bool
+
++config HAVE_CLOCK_LIB
++ bool
++ help
++ Platforms select clocklib if they use this infrastructure
++ for managing their clocks both built into SoC and provided
++ by external devices.
++
+ menuconfig EMBEDDED
+ bool "Configure standard kernel features (for small systems)"
+ help
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 6d9a87c..0b2ade7 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -58,6 +58,7 @@ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
+ obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
+ obj-$(CONFIG_MARKERS) += marker.o
+ obj-$(CONFIG_LATENCYTOP) += latencytop.o
++obj-$(CONFIG_HAVE_CLOCK_LIB) += clklib.o
+
+ ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
+ # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+diff --git a/kernel/clklib.c b/kernel/clklib.c
+new file mode 100644
+index 0000000..203af3d
+--- /dev/null
++++ b/kernel/clklib.c
+@@ -0,0 +1,295 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/clklib.h>
++#include <linux/spinlock.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++
++static LIST_HEAD(clocks);
++static DEFINE_SPINLOCK(clocks_lock);
++
++static int __clk_register(struct clk *clk)
++{
++ if (clk->parent &&
++ !try_module_get(clk->parent->owner))
++ return -EINVAL;
++
++ list_add_tail(&clk->node, &clocks);
++
++ return 0;
++}
++
++int clk_register(struct clk *clk)
++{
++ unsigned long flags;
++ int rc;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ rc = __clk_register(clk);
++
++ spin_unlock_irqrestore(&clocks_lock, flags);
++
++ return rc;
++}
++EXPORT_SYMBOL(clk_register);
++
++void clk_unregister(struct clk *clk)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++ list_del(&clk->node);
++ if (clk->parent)
++ module_put(clk->parent->owner);
++ spin_unlock_irqrestore(&clocks_lock, flags);
++}
++EXPORT_SYMBOL(clk_unregister);
++
++struct clk *clk_get(struct device *dev, const char *id)
++{
++ struct clk *p, *clk = ERR_PTR(-ENOENT);
++ unsigned long flags;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ list_for_each_entry(p, &clocks, node) {
++ if (strcmp(id, p->name) == 0 &&
++ (!p->can_get || p->can_get(p, dev)) &&
++ try_module_get(p->owner)) {
++ clk = p;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&clocks_lock, flags);
++
++ return clk;
++}
++EXPORT_SYMBOL(clk_get);
++
++void clk_put(struct clk *clk)
++{
++ unsigned long flags;
++
++ if (!clk || IS_ERR(clk))
++ return;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ module_put(clk->owner);
++
++ spin_unlock_irqrestore(&clocks_lock, flags);
++}
++EXPORT_SYMBOL(clk_put);
++
++int clk_set_parent(struct clk *clk, struct clk *parent)
++{
++ int rc;
++ unsigned long flags;
++
++ if (!clk || IS_ERR(clk))
++ return -EINVAL;
++
++ if (!clk->set_parent)
++ return -EINVAL;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ rc = clk->set_parent(clk, parent);
++ if (!rc)
++ clk->parent = parent;
++
++ spin_unlock_irqrestore(&clocks_lock, flags);
++
++ return rc;
++}
++EXPORT_SYMBOL(clk_set_parent);
++
++static int __clk_enable(struct clk *clk)
++{
++ int rc = 0;
++
++ if (clk->parent) {
++ rc = __clk_enable(clk->parent);
++
++ if (rc)
++ return rc;
++ }
++
++ if (clk->users++ == 0)
++ if (clk->enable)
++ rc = clk->enable(clk);
++
++ if (clk->delay)
++ udelay(clk->delay);
++
++ return rc;
++}
++
++int clk_enable(struct clk *clk)
++{
++ unsigned long flags;
++ int rc;
++
++ if (!clk || IS_ERR(clk))
++ return -EINVAL;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ rc = __clk_enable(clk);
++
++ spin_unlock_irqrestore(&clocks_lock, flags);
++
++ return rc;
++}
++EXPORT_SYMBOL(clk_enable);
++
++static void __clk_disable(struct clk *clk)
++{
++ if (clk->users <= 0) {
++ WARN_ON(1);
++ return;
++ }
++
++ if (--clk->users == 0)
++ if (clk->disable)
++ clk->disable(clk);
++
++ if (clk->parent)
++ __clk_disable(clk->parent);
++}
++
++void clk_disable(struct clk *clk)
++{
++ unsigned long flags;
++
++ if (!clk || IS_ERR(clk))
++ return;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ __clk_disable(clk);
++
++ spin_unlock_irqrestore(&clocks_lock, flags);
++}
++EXPORT_SYMBOL(clk_disable);
++
++static unsigned long __clk_get_rate(struct clk *clk)
++{
++ unsigned long rate = 0;
++
++ for (;;) {
++ if (rate || !clk)
++ return rate;
++
++ if (clk->getrate)
++ rate = clk->getrate(clk);
++ else if (clk->rate)
++ rate = clk->rate;
++ else
++ clk = clk->parent;
++ }
++}
++
++unsigned long clk_get_rate(struct clk *clk)
++{
++ unsigned long rate = 0;
++ unsigned long flags;
++
++ if (!clk || IS_ERR(clk))
++ return -EINVAL;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ rate = __clk_get_rate(clk);
++
++ spin_unlock_irqrestore(&clocks_lock, flags);
++
++ return rate;
++}
++EXPORT_SYMBOL(clk_get_rate);
++
++long clk_round_rate(struct clk *clk, unsigned long rate)
++{
++ long res;
++ unsigned long flags;
++
++ if (!clk || IS_ERR(clk))
++ return -EINVAL;
++
++ if (!clk->roundrate)
++ return -EINVAL;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ res = clk->roundrate(clk, rate);
++
++ spin_unlock_irqrestore(&clocks_lock, flags);
++
++ return res;
++}
++EXPORT_SYMBOL(clk_round_rate);
++
++int clk_set_rate(struct clk *clk, unsigned long rate)
++{
++ int rc;
++ unsigned long flags;
++
++ if (!clk || IS_ERR(clk))
++ return -EINVAL;
++
++ if (!clk->setrate)
++ return -EINVAL;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ rc = clk->setrate(clk, rate);
++
++ spin_unlock_irqrestore(&clocks_lock, flags);
++
++ return rc;
++}
++EXPORT_SYMBOL(clk_set_rate);
++
++int clk_alloc_function(const char *parent, struct clk *clk)
++{
++ int rc = 0;
++ unsigned long flags;
++ struct clk *pclk;
++ bool found = false;
++
++ spin_lock_irqsave(&clocks_lock, flags);
++
++ list_for_each_entry(pclk, &clocks, node) {
++ if (strcmp(parent, pclk->name) == 0 &&
++ try_module_get(pclk->owner)) {
++ found = true;
++ break;
++ }
++ }
++
++ if (!found) {
++ rc = -ENODEV;
++ goto out;
++ }
++
++ clk->parent = pclk;
++
++ __clk_register(clk);
++ /*
++ * We locked parent owner during search
++ * and also in __clk_register. Free one reference
++ */
++ module_put(pclk->owner);
++
++out:
++ if (rc) {
++ kfree(clk);
++ }
++ spin_unlock_irqrestore(&clocks_lock, flags);
++
++ return rc;
++}
++EXPORT_SYMBOL(clk_alloc_function);
+--
+1.5.3.8
+