diff for duplicates of <4AF9721B.4070203@st.com> diff --git a/a/1.1.hdr b/a/1.1.hdr deleted file mode 100644 index 094af2c..0000000 --- a/a/1.1.hdr +++ /dev/null @@ -1,2 +0,0 @@ -Content-Type: text/plain; charset=ISO-8859-1; format=flowed -Content-Transfer-Encoding: 7bit diff --git a/a/1.2.bin b/a/1.2.bin deleted file mode 100644 index 57bd2c0..0000000 --- a/a/1.2.bin +++ /dev/null @@ -1,67 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> - -<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> -</head> -<body text="#000000" bgcolor="#ffffff"> -<big><big><tt>Hi all<br> -<br> -I'm Francesco and I work in STMicroelectronics<br> -<br> -In the last ELC-E_2009 I spoke on a generic clock framework I'm working -on<br> - (see -<a class="moz-txt-link-freetext" href="http://tree.celinuxforum.org/CelfPubWiki/ELCEurope2009Presentations?action=AttachFile&do=view&target=ELC_E_2009_Generic_Clock_Framework.pdf">http://tree.celinuxforum.org/CelfPubWiki/ELCEurope2009Presentations?action=AttachFile&do=view&target=ELC_E_2009_Generic_Clock_Framework.pdf</a>).<br> -<br> -</tt><tt>I wrote the gcf to manage both clocks the platform_devices -during a clock operation.<br> -<br> -</tt><tt>The main features are:<br> - - it's integrated in the LDM<br> -</tt></big></big><big><big><tt> - it tracks the clock-to-clock -relationship<br> - - it tracks the clock-to-device relationship<br> -<br> -</tt></big></big><big><big><tt> - it has sysfs interface<br> - - - the user can navigate the clock tree under /sys/clocks/...<br> -<br> - - it uses the linux API (<linux/clk.h>) with some extra -functions (to register/unregister a clock<br> - and other utility functions as clk_for_each())<br> -<br> - - it involves the platform_device and the platform_driver in the clock -propagation.<br> - - - basically each clock operation is managed as a transaction which -evolves step by step.<br> - - - </tt><tt>all the clock rates are evaluated (before the clk -operation is actually done)<br> -</tt><tt> - - each platform_device can check (</tt><tt>before the clk -operation is </tt></big></big><big><big><tt>actually</tt></big></big><big><big><tt> -done</tt><tt>) the clk environment<br> - it will have at the end of clock operation and if required it can -reject the operation.<br> - - - each clock operation is </tt></big></big><big><big><tt>actually</tt></big></big><big><big><tt> -executed only if all the </tt><tt>platform_</tt><tt>devices accept the -operation it-self<br> -<br> -<br> -Moreover a common clock framework could be used to avoid a lot of -duplicated and/or similar code<br> - just a grep of 'EXPORT_SYMBOL\(clk_enable' under arch/arm finds 22 -entries.<br> -<br> -The patch is based on a 2.6.30 kernel also if it has a preliminary -integration with the PM_RUNTIME<br> - support.<br> -<br> -It works on our st40 (an sh4 cpu based system) no test/porting was done -on any ARM platform.<br> -<br> -It would be mainly a starting point for a discussion and I'm available -to extend/fix/share it.<br> -<br> -Regards<br> - Francesco</tt></big></big><br> -</body> -</html> diff --git a/a/1.2.hdr b/a/1.2.hdr deleted file mode 100644 index e403a18..0000000 --- a/a/1.2.hdr +++ /dev/null @@ -1,2 +0,0 @@ -Content-Type: text/html; charset=ISO-8859-1 -Content-Transfer-Encoding: 7bit diff --git a/a/1.1.txt b/N1/1.txt similarity index 80% rename from a/1.1.txt rename to N1/1.txt index 1d61c6b..a08e6c7 100644 --- a/a/1.1.txt +++ b/N1/1.txt @@ -52,3 +52,10 @@ to extend/fix/share it. Regards Francesco +-------------- next part -------------- +An HTML attachment was scrubbed... +URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20091110/a197b928/attachment-0001.htm> +-------------- next part -------------- +An embedded and charset-unspecified text was scrubbed... +Name: 0001-generic-clock-framework.patch +URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20091110/a197b928/attachment-0001.el> diff --git a/a/2.hdr b/a/2.hdr deleted file mode 100644 index f9dadb5..0000000 --- a/a/2.hdr +++ /dev/null @@ -1,5 +0,0 @@ -Content-Type: text/plain; - name="0001-generic-clock-framework.patch" -Content-Transfer-Encoding: 7bit -Content-Disposition: attachment; - filename="0001-generic-clock-framework.patch" diff --git a/a/2.txt b/a/2.txt deleted file mode 100644 index 2756354..0000000 --- a/a/2.txt +++ /dev/null @@ -1,3071 +0,0 @@ -From 4e065fb9247ec511bfdc88001f0713977d3f4e89 Mon Sep 17 00:00:00 2001 -From: Francesco Virlinzi <francesco.virlinzi@st.com> -Date: Fri, 23 Oct 2009 15:26:42 +0200 -Subject: [PATCH] generic clock framework - -version: 0.6.2 - -Signed-off-by: Francesco Virlinzi <francesco.virlinzi@st.com> ---- - drivers/base/Makefile | 4 + - drivers/base/base.h | 5 + - drivers/base/clk.c | 1606 +++++++++++++++++++++++++++++++++++++++ - drivers/base/clk.h | 319 ++++++++ - drivers/base/clk_pm.c | 197 +++++ - drivers/base/clk_utils.c | 456 +++++++++++ - drivers/base/init.c | 1 + - drivers/base/platform.c | 27 + - include/linux/clk.h | 251 ++++++ - include/linux/platform_device.h | 9 + - init/Kconfig | 23 + - 11 files changed, 2898 insertions(+), 0 deletions(-) - create mode 100644 drivers/base/clk.c - create mode 100644 drivers/base/clk.h - create mode 100644 drivers/base/clk_pm.c - create mode 100644 drivers/base/clk_utils.c - -diff --git a/drivers/base/Makefile b/drivers/base/Makefile -index b5b8ba5..b78a2bf 100644 ---- a/drivers/base/Makefile -+++ b/drivers/base/Makefile -@@ -16,6 +16,10 @@ ifeq ($(CONFIG_SYSFS),y) - obj-$(CONFIG_MODULES) += module.o - endif - obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o -+ifdef CONFIG_GENERIC_CLK_FM -+obj-y += clk.o clk_utils.o -+obj-$(CONFIG_PM) += clk_pm.o -+endif - - ifeq ($(CONFIG_DEBUG_DRIVER),y) - EXTRA_CFLAGS += -DDEBUG -diff --git a/drivers/base/base.h b/drivers/base/base.h -index b528145..bc5b9e8 100644 ---- a/drivers/base/base.h -+++ b/drivers/base/base.h -@@ -94,6 +94,11 @@ extern int devices_init(void); - extern int buses_init(void); - extern int classes_init(void); - extern int firmware_init(void); -+#ifdef CONFIG_GENERIC_CLK_FM -+extern int clock_init(void); -+#else -+static inline int clock_init(void){ return 0; } -+#endif - #ifdef CONFIG_SYS_HYPERVISOR - extern int hypervisor_init(void); - #else -diff --git a/drivers/base/clk.c b/drivers/base/clk.c -new file mode 100644 -index 0000000..7feae61 ---- /dev/null -+++ b/drivers/base/clk.c -@@ -0,0 +1,1606 @@ -+/* -+ * ------------------------------------------------------------------------- -+ * clk.c -+ * ------------------------------------------------------------------------- -+ * (C) STMicroelectronics 2008 -+ * (C) STMicroelectronics 2009 -+ * Author: Francesco M. Virlinzi <francesco.virlinzi@st.com> -+ * ------------------------------------------------------------------------- -+ * May be copied or modified under the terms of the GNU General Public -+ * License v.2 ONLY. See linux/COPYING for more information. -+ * -+ * ------------------------------------------------------------------------- -+ */ -+ -+#include <linux/platform_device.h> -+#include <linux/clk.h> -+#include <linux/klist.h> -+#include <linux/sysdev.h> -+#include <linux/kref.h> -+#include <linux/kobject.h> -+#include <linux/err.h> -+#include <linux/spinlock.h> -+#include <asm/atomic.h> -+#include "clk.h" -+#include "base.h" -+ -+#define CLK_NAME "Generic Clk Framework" -+#define CLK_VERSION "0.6.2" -+ -+/* #define CLK_SAFE_CODE */ -+ -+klist_entry_support(clock, clk, node) -+klist_entry_support(child_clock, clk, child_node) -+klist_entry_support(dev_info, pdev_clk_info, node) -+ -+#define to_clk(ptr) container_of(ptr, struct clk, kobj) -+#define to_tnode(ptr) container_of(ptr, struct clk_tnode, pnode) -+ -+static int sysfs_clk_attr_show(struct kobject *kobj, -+ struct attribute *attr, char *buf) -+{ -+ ssize_t ret = -EIO; -+ struct kobj_attribute *kattr -+ = container_of(attr, struct kobj_attribute, attr); -+ if (kattr->show) -+ ret = kattr->show(kobj, kattr, buf); -+ return ret; -+} -+ -+static ssize_t -+sysfs_clk_attr_store(struct kobject *kobj, struct attribute *attr, -+ const char *buf, size_t count) -+{ -+ ssize_t ret = -EIO; -+ struct kobj_attribute *kattr -+ = container_of(attr, struct kobj_attribute, attr); -+ if (kattr->store) -+ ret = kattr->store(kobj, kattr, buf, count); -+ return ret; -+} -+ -+static struct sysfs_ops clk_sysfs_ops = { -+ .show = sysfs_clk_attr_show, -+ .store = sysfs_clk_attr_store, -+}; -+ -+static struct kobj_type ktype_clk = { -+ .sysfs_ops = &clk_sysfs_ops, -+}; -+ -+static struct clk *check_clk(struct clk *); -+ -+static struct kobject *clk_kobj; -+static DEFINE_MUTEX(clk_list_sem); -+static atomic_t transaction_counter = ATOMIC_INIT(0); -+struct klist clk_list = KLIST_INIT(clk_list, NULL, NULL); -+ -+klist_function_support(child, clk, child_node, kobj) -+klist_function_support(device, pdev_clk_info, node, pdev->dev.kobj) -+ -+/* -+ * The ___clk_xxx operations doesn't raise propagation -+ * they are used to operate on the real clock -+ */ -+static int -+__clk_operations(struct clk *clk, unsigned long rate, -+ enum clk_ops_id const id_ops) -+{ -+ int ret = 0; -+ unsigned long *ops_fns = (unsigned long *)clk->ops; -+ if (likely(ops_fns && ops_fns[id_ops])) { -+ int (*fns)(struct clk *clk, unsigned long rate) -+ = (void *)ops_fns[id_ops]; -+ unsigned long flags; -+ spin_lock_irqsave(&clk->lock, flags); -+ ret = fns(clk, rate); -+ spin_unlock_irqrestore(&clk->lock, flags); -+ } -+ return ret; -+} -+ -+static inline int __clk_init(struct clk *clk) -+{ -+ pr_debug(": %s\n", clk->name); -+ return __clk_operations(clk, 0, __CLK_INIT); -+} -+static inline int __clk_enable(struct clk *clk) -+{ -+ pr_debug(": %s\n", clk->name); -+ return __clk_operations(clk, 0, __CLK_ENABLE); -+} -+static inline int __clk_disable(struct clk *clk) -+{ -+ pr_debug(": %s\n", clk->name); -+ return __clk_operations(clk, 0, __CLK_DISABLE); -+} -+static inline int __clk_set_rate(struct clk *clk, unsigned long rate) -+{ -+ pr_debug(": %s\n", clk->name); -+ return __clk_operations(clk, rate, __CLK_SET_RATE); -+} -+static inline int __clk_set_parent(struct clk *clk, struct clk *parent) -+{ -+ pr_debug(": %s\n", clk->name); -+ return __clk_operations(clk, (unsigned long)parent, __CLK_SET_PARENT); -+} -+static inline int __clk_recalc_rate(struct clk *clk) -+{ -+ pr_debug(": %s\n", clk->name); -+ return __clk_operations(clk, 0, __CLK_RECALC); -+} -+static inline int __clk_round(struct clk *clk, unsigned long value) -+{ -+ pr_debug(": %s\n", clk->name); -+ return __clk_operations(clk, value, __CLK_ROUND); -+} -+ -+static inline int __clk_eval(struct clk *clk, unsigned long prate) -+{ -+#ifndef CONFIG_CLK_FORCE_GENERIC_EVALUATE -+ pr_debug(": %s\n", clk->name); -+ return __clk_operations(clk, prate, __CLK_EVAL); -+#else -+ unsigned long rate, flags; -+ pr_debug(": %s\n", clk->name); -+ if (likely(clk->ops && clk->ops->eval)) { -+ spin_lock_irqsave(&clk->lock, flags); -+ rate = clk->ops->eval(clk, prate); -+ spin_unlock_irqrestore(&clk->lock, flags); -+ } else -+ rate = clk_generic_evaluate_rate(clk, prate); -+ return rate; -+#endif -+} -+ -+#ifdef CONFIG_PM_RUNTIME -+static int -+clk_pm_runtime_devinfo(enum rpm_status code, struct pdev_clk_info *info) -+{ -+ struct platform_device *pdev = info->pdev; -+ -+ pr_debug("\n"); -+ -+ switch (code) { -+ case RPM_ACTIVE: -+ return clk_notify_child_event(CHILD_DEVICE_ENABLED, info->clk); -+ case RPM_SUSPENDED: -+ return clk_notify_child_event(CHILD_DEVICE_DISABLED, info->clk); -+ } -+ return -EINVAL; -+} -+ -+int clk_pm_runtime_device(enum rpm_status code, struct platform_device *dev) -+{ -+ int idx; -+ int ret = 0; -+ struct pdev_clk_info *info; -+ -+ if (!dev) -+ return -EFAULT; -+ -+ if (!dev->clks || !pdevice_num_clocks(dev)) -+ return 0; -+ -+ pr_debug("\n"); -+/* -+ * Check if the device is under a transaction. -+ * If so the GCFdoesn't raise a 'clk_pm_runtime_devinfo' -+ * all the device change will be notified on 'tnode_transaction_complete' -+ * if required.... -+ */ -+ if (atomic_read((atomic_t *)&dev->clk_flags)) { -+ pr_debug("%s.%d under transaction\n", dev->name, dev->id); -+ return ret; -+ } -+ for (idx = 0, info = dev->clks; idx < pdevice_num_clocks(dev); ++idx) -+ ret |= clk_pm_runtime_devinfo(&info[idx], state, 0); -+ -+ return ret; -+} -+#else -+#define clk_pm_runtime_devinfo(x, y) -+#define clk_pm_runtime_device(x, y) -+#endif -+ -+/** -+ * tnode_malloc -+ * -+ * Allocs the memory for both the transaction and the -+ * clk_event objects -+ */ -+static struct clk_tnode *tnode_malloc(struct clk_tnode *parent, -+ unsigned long nevent) -+{ -+ struct clk_event *evt; -+ struct clk_tnode *node; -+ -+ if (nevent > 32) -+ return NULL; -+ -+ node = kmalloc(sizeof(*node) + nevent * sizeof(*evt), GFP_KERNEL); -+ -+ if (!node) -+ return NULL; -+ -+ evt = (struct clk_event *)(sizeof(struct clk_tnode) + (long)node); -+ -+ node->tid = atomic_inc_return(&transaction_counter); -+ node->parent = parent; -+ node->size = nevent; -+ node->events = evt; -+ node->events_map = 0; -+ INIT_LIST_HEAD(&node->childs); -+ -+ return node; -+} -+ -+/** -+ * tnode_free -+ * -+ * Free the tnode memory -+ */ -+static void tnode_free(struct clk_tnode *node) -+{ -+ if (tnode_get_parent(node)) { -+ list_del(&node->pnode); -+ kfree(node); -+ } -+} -+ -+/** -+ * tnode_check_clock - -+ * -+ * @node: the tnode object -+ * @clk: the clock object -+ * -+ * returns a boolean value -+ * it checks if the clock (clk) is managed by the -+ * tnode (node) or any parent node -+ */ -+static int __must_check -+tnode_check_clock(struct clk_tnode *node, struct clk *clk) -+{ -+ int j; -+ for (; node; node = tnode_get_parent(node)) -+ /* scans all the event */ -+ tnode_for_each_valid_events(node, j) -+ if (tnode_get_clock(node, j) == clk) -+ return 1; /* FOUND!!! */ -+ return 0; -+} -+ -+/** -+ * tnode_lock_clocks - -+ * -+ * @node: the tnode object -+ * -+ * marks all the clocks under transaction to be sure there is no more -+ * than one transaction for each clock -+ */ -+static int __must_check -+tnode_lock_clocks(struct clk_tnode *node) -+{ -+ int i; -+ pr_debug("\n"); -+ -+ /* 1. try to mark all the clocks in transaction */ -+ for (i = 0; i < tnode_get_size(node); ++i) -+ if (clk_set_towner(tnode_get_clock(node, i), node)) { -+ struct clk *clkp = tnode_get_clock(node, i); -+ /* this clock is already locked */ -+ /* we accept that __only__ if it is locked by a -+ * parent tnode!!! -+ */ -+ if (!tnode_get_parent(node)) { -+ pr_debug("Error clk %s locked but " -+ "there is no parent!\n", clkp->name); -+ goto err_0; -+ } -+ pr_debug("clk %s already locked\n", clkp->name); -+ if (tnode_check_clock(tnode_get_parent(node), clkp)) { -+ pr_debug("ok clk %s locked " -+ "by a parent\n", clkp->name); -+ continue; -+ } else -+ goto err_0; -+ } else -+ /* set the event as valid in the bitmap*/ -+ tnode_set_map_id(node, i); -+ -+/* -+ * all the clocks are marked succesfully or all the clock on -+ * this tnode are already managed by parent -+ */ -+ if (!tnode_get_map(node)) { /* check if the bitamp is not zero */ -+ if (tnode_get_parent(node)) -+ kfree(node); -+ return 1; -+ } -+ -+ /* -+ * all the clocks are marked succesfully _and_ there is at least -+ * one clock marked. -+ * Add the tnode to its parent! and return -+ */ -+ if (tnode_get_parent(node)) -+ list_add_tail(&node->pnode, &tnode_get_parent(node)->childs); -+ -+ return 0; -+ -+err_0: -+ pr_debug("Error on clock locking...\n"); -+ for (--i; i >= 0; --i) -+ if (tnode_check_map_id(node, i)) -+ clk_clean_towner(tnode_get_clock(node, i)); -+ -+ if (tnode_get_parent(node)) -+ kfree(node); -+ -+ return -EINVAL; -+} -+ -+/** -+ * tnode_transaction_complete - -+ * -+ * checks the devices status when the transaction is complete. -+ */ -+static void tnode_transaction_complete(struct clk_tnode *node) -+{ -+ struct klist_iter i; -+ struct pdev_clk_info *dev_info; -+ int j; -+ -+ pr_debug("tid: %d\n", (int)tnode_get_id(node)); -+ tnode_for_each_valid_events(node, j) { -+ klist_iter_init(&tnode_get_clock(node, j)->devices, &i); -+ while ((dev_info = next_dev_info(&i))) { -+ /* update the device state */ -+ struct platform_device *dev = dev_info->pdev; -+ switch (dev->clk_state & (DEV_SUSPENDED_ON_TRANSACTION | -+ DEV_RESUMED_ON_TRANSACTION)) { -+ case 0: /* this device doesn't care on the clock transaction */ -+ atomic_clear_mask(DEV_ON_TRANSACTION, -+ (atomic_t *)&dev->clk_state); -+ break; -+ -+ case (DEV_SUSPENDED_ON_TRANSACTION | -+ DEV_RESUMED_ON_TRANSACTION): -+ /* this device was suspended and -+ * resumed therefore no real change -+ */ -+ pr_debug("dev: %s.%d " -+ "Suspended&Resumed (no child event)\n", -+ dev->name, dev->id); -+ atomic_clear_mask(DEV_ON_TRANSACTION | -+ DEV_SUSPENDED_ON_TRANSACTION | -+ DEV_RESUMED_ON_TRANSACTION, -+ (atomic_t *)&dev->clk_state); -+ break; -+ case DEV_SUSPENDED_ON_TRANSACTION: -+ atomic_clear_mask(DEV_ON_TRANSACTION | -+ DEV_SUSPENDED_ON_TRANSACTION, -+ (atomic_t *)&dev->clk_state); -+ pr_debug("dev: %s.%d Suspended\n", -+ dev->name, dev->id); -+ clk_pm_runtime_device(RPM_SUSPENDED, dev); -+ break; -+ case DEV_RESUMED_ON_TRANSACTION: -+ atomic_clear_mask(DEV_ON_TRANSACTION | -+ DEV_RESUMED_ON_TRANSACTION, -+ (atomic_t *)&dev->clk_state); -+ pr_debug("dev: %s.%d Resumed\n", -+ dev->name, dev->id); -+ clk_pm_runtime_device(RPM_ACTIVE, dev); -+ break; -+ -+ default: -+ printk(KERN_ERR "%s: device %s,%d clk_flags _not_ valid %u\n", -+ __func__, dev->name, dev->id, -+ (unsigned int)dev->clk_state); -+ } -+ } -+ klist_iter_exit(&i); -+ clk_clean_towner(tnode_get_clock(node, j)); -+ } -+ pr_debug("tid: %d exit\n", (int)tnode_get_id(node)); -+ return; -+} -+ -+/* -+ * Check if the clk is registered -+ */ -+#ifdef CLK_SAFE_CODE -+static struct clk *check_clk(struct clk *clk) -+{ -+ struct clk *clkp; -+ struct clk *result = NULL; -+ struct klist_iter i; -+ -+ pr_debug("\n"); -+ -+ klist_iter_init(&clk_list, &i); -+ while ((clkp = next_clock(&i))) -+ if (clk == clkp) { -+ result = clk; -+ break; -+ } -+ klist_iter_exit(&i); -+ return result; -+} -+#else -+static inline struct clk *check_clk(struct clk *clk) -+{ -+ return clk; -+} -+#endif -+ -+enum child_event_e { -+ CHILD_CLOCK_ENABLED = 1, -+ CHILD_CLOCK_DISABLED, -+ CHILD_DEVICE_ENABLED, -+ CHILD_DEVICE_DISABLED, -+}; -+ -+static int -+clk_notify_child_event(enum child_event_e const code, struct clk *clk) -+{ -+ if (!clk) -+ return 0; -+ -+ switch (code) { -+ case CHILD_CLOCK_ENABLED: -+ ++clk->nr_active_clocks; -+ break; -+ case CHILD_CLOCK_DISABLED: -+ --clk->nr_active_clocks; -+ break; -+ case CHILD_DEVICE_ENABLED: -+ ++clk->nr_active_devices; -+ break; -+ case CHILD_DEVICE_DISABLED: -+ --clk->nr_active_devices; -+ break; -+ } -+ -+ if (clk_is_auto_switching(clk)) { -+ /* -+ * Check if there are still users -+ */ -+ if (!clk->nr_active_devices && !clk->nr_active_clocks) -+ clk_disable(clk); -+ else if (!clk_get_rate(clk)) /* if off.. turn-on */ -+ clk_enable(clk); -+ } -+ -+ return 0; -+} -+ -+/** -+ * clk_dev_events_malloc - -+ * -+ * builds a struct clk_event array (dev_event). -+ * the array size (how many elements) is based on device_num_clocks(dev) -+ * the contenets of each element is equal to: -+ * - the events array (if the idx-clock is under transaction) -+ * - the current clock setting if the idx-clock isn't under transaction -+ */ -+static struct clk_event * __must_check -+clk_dev_events_malloc(struct platform_device const *dev) -+{ -+ struct clk_event *dev_events; -+ struct clk_tnode *node; -+ int i, j; -+ pr_debug("\n"); -+/* -+ * 1. simple case: -+ * - device_num_clocks(dev) = 1 -+ */ -+ if (pdevice_num_clocks(dev) == 1) { -+ node = (struct clk_tnode *)pdevice_clock(dev, 0)->towner; -+ for (i = 0; i < tnode_get_size(node); ++i) -+ if (tnode_get_clock(node, i) == pdevice_clock(dev, 0)) -+ return tnode_get_event(node, i); -+ } -+/* -+ * 2. - device_num_clocks(dev) > 1 -+ * GCF has to build a dedicated device events (devents) array -+ * for this device! sorted as the device registered it-self! -+ */ -+ dev_events = kmalloc(sizeof(*dev_events) * pdevice_num_clocks(dev), -+ GFP_KERNEL); -+ if (!dev_events) -+ return NULL; -+ -+ for (i = 0; i < pdevice_num_clocks(dev); ++i) { -+ node = (struct clk_tnode *)pdevice_clock(dev, i)->towner; -+ dev_events[i].clk = pdevice_clock(dev, i); -+ if (!node) {/* this means this clocs isn't under transaction */ -+ dev_events[i].old_rate = -+ clk_get_rate(pdevice_clock(dev, i)); -+ dev_events[i].new_rate = -+ clk_get_rate(pdevice_clock(dev, i)); -+ continue; -+ } -+ /* search the right clk_event */ -+ for (j = 0; tnode_get_clock(node, j) != pdevice_clock(dev, i); -+ ++j); -+ -+ dev_events[i].old_rate = tnode_get_event(node, j)->old_rate; -+ dev_events[i].new_rate = tnode_get_event(node, j)->new_rate; -+ } -+ return dev_events; -+} -+ -+/** -+ * clk_devents_free - -+ * free the devent allocated on the device dev. -+ */ -+static inline void -+clk_dev_events_free(struct clk_event *dev_events, struct platform_device *dev) -+{ -+ if (pdevice_num_clocks(dev) == 1) -+ return ; -+ kfree(dev_events); -+} -+ -+/** -+ * clk_trnsc_fsm - -+ * -+ * propagate the transaction to all the childs -+ * each transaction has the following life-time: -+ * -+ * +---------------+ -+ * | ENTER_CLK | The ENTER state only for clocks -+ * +---------------+ - acquires all the clock of the transaction -+ * | - builds the transaction graph -+ * | - for each clock generates a child transaction -+ * | -+ * +---------------------+ -+ * | +---------------+ | -+ * | | ENTER_DEV | | The ENTER state only for devices -+ * | +---------------+ | - >> NOTIFY_CLK_ENTERCHANGE << notified -+ * | | | - - the device could refuse the operation -+ * | | | -+ * | +---------------+ | -+ * | | PRE_DEV | | The PRE state only devices -+ * | +---------------+ | - >> NOTIFY_CLK_PRECHANGE << notified -+ * | | | - - the device could be suspended -+ * +---------------------+ -+ * | -+ * +---------------+ -+ * | CHANGE_CLK | The CHANGE state only for clocks -+ * +---------------+ - updates all the physical clocks -+ * | and relative clk_event_s according to -+ * | the hw value. -+ * +---------------------+ -+ * | | | -+ * | +---------------+ | -+ * | | POST_DEV | | The POST state only for devices -+ * | +---------------+ | - >> NOTIFY_CLK_POSTCHANGE << notified -+ * | | | - - the devices could be resumed -+ * | | | -+ * | +---------------+ | -+ * | | EXIT_DEV | | The EXIT state only for devices -+ * | +---------------+ | - >> NOTIFY_CLK_EXITCHANGE << notified -+ * | | | - - the devices is aware all the other -+ * +---------------------+ devices are resumed. -+ * | -+ * +---------------+ -+ * | EXIT_CLK | The EXIT state only for clocks -+ * +---------------+ (to free all the memory) -+ * - Free all the allocated memory -+ * -+ */ -+ -+static enum notify_ret_e -+clk_trnsc_fsm(enum clk_fsm_e const code, struct clk_tnode *node) -+{ -+ struct pdev_clk_info *dev_info; -+ struct clk_tnode *tchild; -+ struct klist_iter i; -+ int j; -+ enum notify_ret_e tmp, ret_notifier = NOTIFY_EVENT_HANDLED; -+ -+#ifdef CONFIG_CLK_DEBUG -+ switch (code) { -+ case TRNSC_ENTER_CLOCK: -+ case TRNSC_ENTER_DEVICE: -+ printk(KERN_INFO "ENTER_%s ", -+ (code == TRNSC_ENTER_CLOCK ? "CLK" : "DEV")); -+ break; -+ case TRNSC_PRE_DEVICE: -+ printk(KERN_INFO "PRE_DEV "); -+ break; -+ case TRNSC_CHANGE_CLOCK: -+ printk(KERN_INFO "CHANGE_CLK "); -+ break; -+ case TRNSC_POST_DEVICE: -+ printk(KERN_INFO "POST_DEV "); -+ break; -+ case TRNSC_EXIT_DEVICE: -+ case TRNSC_EXIT_CLOCK: -+ printk(KERN_INFO "EXIT_%s ", -+ (code == TRNSC_EXIT_DEVICE ? "DEV" : "CLK")); -+ break; -+ } -+ printk(KERN_INFO"tid:%u ", (unsigned int)tnode_get_id(node)); -+ if (tnode_get_parent(node)) -+ printk(KERN_INFO " (tpid: %d)", -+ (int)tnode_get_id(tnode_get_parent(node))); -+ printk(KERN_INFO " (0x%x/0x%x) ", (unsigned int)tnode_get_size(node), -+ (unsigned int)tnode_get_map(node)); -+ for (j = 0; j < tnode_get_size(node); ++j) { -+ if (tnode_check_map_id(node, j)) -+ /* print only the valid event... */ -+ printk(KERN_INFO"- %s ", -+ tnode_get_clock(node, j)->name); -+ else if (code == TRNSC_ENTER_CLOCK) -+ printk(KERN_INFO"- %s ", -+ tnode_get_clock(node, j)->name); -+ } -+ printk(KERN_INFO"\n"); -+#endif -+ -+ /* -+ * Clk ENTER state -+ */ -+ if (code == TRNSC_ENTER_CLOCK) { -+ unsigned long idx; -+ enum clk_event_e sub_code; -+ struct clk *clkp; -+ struct clk_event *sub_event = NULL; -+ -+ /* first of all the GCF tries to lock the clock of this tnode -+ * and links the tnode to its parent (if any) -+ */ -+ switch (tnode_lock_clocks(node)) { -+ case 0: -+ break; -+ case -EINVAL: -+ return NOTIFY_EVENT_NOTHANDLED; -+ case 1: -+ return NOTIFY_EVENT_HANDLED; -+ } -+ -+ pr_debug("clocks acquired\n"); -+ /* Propagates the events to the sub clks */ -+ tnode_for_each_valid_events(node, j) { -+ -+ if (!clk_allow_propagation(tnode_get_clock(node, j))) { -+ pr_debug("clk: %s doesn't want propagation\n", -+ tnode_get_clock(node, j)->name); -+ continue; -+ } -+ if (!(tnode_get_clock(node, j)->nr_clocks)) -+ continue; -+ -+ tchild = tnode_malloc(node, -+ tnode_get_clock(node, j)->nr_clocks); -+ if (!tchild) { -+ printk(KERN_ERR "No enough memory during a clk " -+ "transaction\n"); -+ ret_notifier |= NOTIFY_EVENT_NOTHANDLED;; -+ return ret_notifier; -+ } -+ -+ pr_debug("memory for child transaction acquired\n"); -+ idx = 0; -+ sub_code = clk_event_decode(tnode_get_event(node, j)); -+ klist_iter_init(&tnode_get_clock(node, j)->childs, &i); -+ while ((clkp = next_child_clock(&i))) { -+ sub_event = tnode_get_event(tchild, idx); -+ clk_event_init(sub_event, clkp, clk_get_rate(clkp), -+ clk_get_rate(clkp)); -+ switch (sub_code) {/* prepare the sub event fields */ -+ case _CLK_CHANGE: -+ case _CLK_ENABLE: -+ sub_event->new_rate = clk_evaluate_rate(clkp, -+ tnode_get_event(node, j)->new_rate); -+ break; -+ case _CLK_DISABLE: -+ sub_event->new_rate = 0; -+ break; -+ case _CLK_NOCHANGE: -+ break; -+ } -+ ++idx; -+ } -+ klist_iter_exit(&i); -+ /* now GCF can araiese the sub transaction */ -+ ret_notifier |= -+ clk_trnsc_fsm(code, tchild); -+ } -+ return ret_notifier; -+ } -+ -+ /* -+ * Clk CHANGE state -+ */ -+ if (code == TRNSC_CHANGE_CLOCK) { -+ /* the clocks on the root node are managed directly in the -+ * clk_set_rate/clk_enable/... functions ... -+ * while all the other clocks have to managed here! -+ */ -+ if (node->parent) -+ tnode_for_each_valid_events(node, j) { -+ struct clk_event *event; -+ long code; -+ event = tnode_get_event(node, j); -+ code = clk_event_decode(event); -+ switch (code) { -+ case _CLK_CHANGE: -+ __clk_recalc_rate(event->clk); -+ event->new_rate = -+ clk_get_rate(event->clk); -+ break; -+ case _CLK_ENABLE: -+ if (clk_follow_parent(event->clk)) { -+ __clk_enable(event->clk); -+ event->new_rate = -+ clk_get_rate(event->clk); -+ } -+ break; -+ case _CLK_DISABLE: -+ if (clk_is_enabled(event->clk)) -+ __clk_disable(event->clk); -+ break; -+ } -+ } -+ -+ list_for_each_entry(tchild, &node->childs, pnode) -+ ret_notifier |= clk_trnsc_fsm(code, tchild); -+ -+ return ret_notifier; -+ } -+ -+ /* -+ * Clk EXIT state -+ */ -+ if (code == TRNSC_EXIT_CLOCK) { -+ struct list_head *ptr, *next; -+ /* scans all the transaction childs */ -+ list_for_each_safe(ptr, next, &node->childs) -+ clk_trnsc_fsm(code, to_tnode(ptr)); -+ -+ /* update the devices/clocks state */ -+ tnode_transaction_complete(node); -+ -+ tnode_free(node); -+ pr_debug("EXIT_CLK complete\n"); -+ -+ return ret_notifier; -+ } -+ -+ /* -+ * Here the devices management -+ */ -+ tnode_for_each_valid_events(node, j) { -+ if (!clk_allow_propagation(tnode_get_clock(node, j))) -+ continue; -+ klist_iter_init(&tnode_get_clock(node, j)->devices, &i); -+ while ((dev_info = next_dev_info(&i))) { -+ struct platform_device *pdev = dev_info->pdev; -+ struct platform_driver *pdrv = container_of( -+ pdev->dev.driver, struct platform_driver, driver); -+ -+ struct clk_event *dev_events; -+ -+ if (!pdrv || !pdrv->notify) { -+ pr_debug( -+ "device %s.%d registered with no notify function\n", -+ pdev->name, pdev->id); -+ continue; -+ } -+ /* check if it already had a 'code' event */ -+ if (pdev_transaction_move_on(pdev, code)) -+ continue; -+ -+ dev_events = clk_dev_events_malloc(pdev); -+ if (!dev_events) { -+ printk(KERN_ERR"%s: No Memory during a clk " -+ "transaction\n", __func__); -+ continue; -+ } -+ -+ /* GCF can use 'code' directly in the .notify function -+ * just because external 'NOTIFY_CLK_xxxCHANGE' code -+ * matchs with the internal 'device' code -+ */ -+ tmp = pdrv->notify(code, pdev, dev_events); -+ clk_dev_events_free(dev_events, pdev); -+ ret_notifier |= tmp; -+#ifdef CONFIG_PM_RUNTIME -+ if (code == TRNSC_PRE_DEVICE && tmp == NOTIFY_EVENT_HANDLED) { -+ printk(KERN_INFO "clk %s on code %u suspends " -+ "device %s.%d\n", -+ transaction_get_clock(node, j)->name, -+ (unsigned int)code, pdev->name, pdev->id); -+ pm_runtime_suspend(&pdev->dev); -+ } else -+ if (code == TRNSC_POST_DEVICE && tmp == NOTIFY_EVENT_HANDLED) { -+ printk(KERN_INFO "clk %s on code %u resumes " -+ "device %s.%d\n", -+ transaction_get_clock(node, j)->name, -+ (unsigned int)code, pdev->name, pdev->id); -+ pm_runtime_resume(&pdev->dev); -+ }; -+#endif -+ } /* while closed */ -+ klist_iter_exit(&i); -+ } /* for closed */ -+ -+ /* -+ *and propagate down... -+ */ -+ list_for_each_entry(tchild, &node->childs, pnode) -+ ret_notifier |= clk_trnsc_fsm(code, tchild); -+ -+ return ret_notifier; -+} -+ -+static void clk_initialize(struct clk *clk) -+{ -+ kobject_init(&clk->kobj, &ktype_clk); -+ kobject_set_name(&clk->kobj, "%s", clk->name); -+ kobject_get(&clk->kobj); -+ -+ clk->nr_clocks = 0; -+ clk->nr_active_clocks = 0; -+ clk->nr_active_devices = 0; -+ clk->towner = NULL; -+ -+ klist_init(&clk->childs, klist_get_child, klist_put_child); -+ klist_init(&clk->devices, klist_get_device, klist_put_device); -+ -+} -+ -+/** -+ * clk_register - -+ * -+ * registers a new clk in the system. -+ * returns zero if success -+ */ -+int clk_register(struct clk *clk) -+{ -+ int ret = 0; -+ if (!clk) -+ return -EFAULT; -+ pr_debug("%s\n", clk->name); -+ -+ clk_initialize(clk); -+ -+ /* Initialize ... */ -+ __clk_init(clk); -+ -+ if (clk->parent) { -+#ifdef CLK_SAFE_CODE -+ /* 1. the parent has to be registered */ -+ if (!check_clk(clk->parent)) -+ return -ENODEV; -+ /* 2. an always enabled child has to sit on a always -+ * enabled parent! -+ */ -+ if (clk->flags & CLK_ALWAYS_ENABLED && -+ !(clk->parent->flags & CLK_ALWAYS_ENABLED)) -+ return -EFAULT; -+ /* 3. a fixed child has to sit on a fixed parent */ -+ if (clk_is_readonly(clk) && !clk_is_readonly(clk->parent)) -+ return -EFAULT; -+#endif -+ klist_add_tail(&clk->child_node, &clk->parent->childs); -+ clk->parent->nr_clocks++; -+ } -+ -+ ret = kobject_add(&clk->kobj, -+ (clk->parent ? &clk->parent->kobj : clk_kobj), clk->name); -+ if (ret) -+ goto err_0; -+ -+ clk->kdevices = kobject_create_and_add("devices", &clk->kobj); -+ if (!clk->kdevices) -+ goto err_1; -+ -+ klist_add_tail(&clk->node, &clk_list); -+ if (clk->flags & CLK_ALWAYS_ENABLED) { -+ __clk_enable(clk); -+ clk_notify_child_event(CHILD_CLOCK_ENABLED, clk->parent); -+ } -+ return ret; -+ -+err_1: -+ /* subsystem_remove_file... removed in the common code... ??? */ -+ kobject_del(&clk->kobj); -+err_0: -+ return ret; -+} -+EXPORT_SYMBOL(clk_register); -+ -+/** -+ * clk_unregister - -+ * unregisters the clock from system -+ */ -+int clk_unregister(struct clk *clk) -+{ -+ pr_debug("\n"); -+ -+ if (!clk) -+ return -EFAULT; -+ -+ if (!list_empty(&clk->devices.k_list)) -+ return -EFAULT; /* somebody is still using this clock */ -+ -+ kobject_del(clk->kdevices); -+ kfree(clk->kdevices); -+ /* subsystem_remove_file... removed in the common code... ??? */ -+ kobject_del(&clk->kobj); -+ klist_del(&clk->node); -+ if (clk->parent) { -+ klist_del(&clk->child_node); -+ clk->parent->nr_clocks--; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(clk_unregister); -+ -+static int clk_add_devinfo(struct pdev_clk_info *info) -+{ -+ int ret = 0; -+ pr_debug("\n"); -+ -+#ifdef CLK_SAFE_CODE -+ if (!info || !info->clk || !check_clk(info->clk)) -+ return -EFAULT; -+#endif -+ ret = sysfs_create_link(info->clk->kdevices, &info->pdev->dev.kobj, -+ dev_name(&info->pdev->dev)); -+ if (ret) { -+ pr_debug(" Error %d\n", ret); -+ return ret; -+ } -+ klist_add_tail(&info->node, &info->clk->devices); -+ -+ return 0; -+} -+ -+static int clk_del_devinfo(struct pdev_clk_info *info) -+{ -+ pr_debug("\n"); -+ -+#ifdef CLK_SAFE_CODE -+ if (!info || !info->clk || !check_clk(info->clk)) -+ return -EFAULT; -+#endif -+ sysfs_remove_link(info->clk->kdevices, dev_name(&info->pdev->dev)); -+ klist_del(&info->node); -+ -+#ifndef CONFIG_PM_RUNTIME -+ /* -+ * Without PM_RUNTIME the GCF assumes the device is -+ * 'not active' when it's removed -+ */ -+ clk_notify_child_event(CHILD_DEVICE_DISABLED, info->clk); -+#endif -+ return 0; -+} -+ -+int clk_probe_device(struct platform_device *dev, enum pdev_probe_state state) -+{ -+ int idx; -+ switch (state) { -+ case PDEV_PROBEING: -+ /* before the .probe function is called the GCF -+ * has to turn-on _all_ the clocks the device uses -+ * to garantee a safe .probe -+ */ -+ for (idx = 0; idx < pdevice_num_clocks(dev); ++idx) -+ if (pdevice_clock(dev, idx)) -+ clk_enable(pdevice_clock(dev, idx)); -+ return 0; -+ case PDEV_PROBED: -+#ifdef CONFIG_PM_RUNTIME -+ /* -+ * Here the GCF should check the device's pm_runtime state -+ * And if the device is suspended the clk_frmwk can turn-off the clocks -+ */ -+#else -+ /* -+ * Without PM_RUNTIME the GCF assumes the device is active -+ */ -+ for (idx = 0; idx < pdevice_num_clocks(dev); ++idx) -+ clk_notify_child_event(CHILD_DEVICE_ENABLED, -+ pdevice_clock(dev, idx)); -+#endif -+ break; -+ case PDEV_PROBE_FAILED: -+ /* -+ * TO DO something... -+ */ -+ break; -+ } -+ return 0; -+} -+ -+int clk_add_device(struct platform_device *dev, enum pdev_add_state state) -+{ -+ int idx; -+ int ret; -+ -+ if (!dev) -+ return -EFAULT; -+ -+ switch (state) { -+ case PDEV_ADDING: -+ case PDEV_ADD_FAILED: -+ /* -+ * TO DO something -+ */ -+ return 0; -+ case PDEV_ADDED: -+ break; -+ } -+ /* case PDEV_ADDED ... */ -+ if (!dev->clks || !pdevice_num_clocks(dev)) -+ return 0; /* this device will not use -+ the clk framework */ -+ -+ pr_debug("%s.%d with %u clocks\n", dev->name, dev->id, -+ (unsigned int)pdevice_num_clocks(dev)); -+ -+ dev->clk_state = 0; -+ for (idx = 0; idx < pdevice_num_clocks(dev); ++idx) { -+ if (!pdevice_clock(dev, idx)) { /* clk can not be NULL... */ -+ pr_debug("Error clock NULL\n"); -+ continue; -+ } -+ pr_debug("->under %s\n", dev->clks[idx].clk->name); -+ dev->clks[idx].pdev = dev; -+ ret = clk_add_devinfo(&dev->clks[idx]); -+ if (ret) -+ goto err_0; -+ } -+ -+ return 0; -+err_0: -+ for (--idx; idx >= 0; --idx) -+ clk_del_devinfo(&dev->clks[idx]); -+ -+ return -EINVAL; -+} -+ -+int clk_del_device(struct platform_device *dev) -+{ -+ int idx; -+ if (!dev) -+ return -EFAULT; -+ -+ for (idx = 0; idx < pdevice_num_clocks(dev); ++idx) -+ clk_del_devinfo(&dev->clks[idx]); -+ -+ return 0; -+} -+ -+void clk_put(struct clk *clk) -+{ -+ if (clk && !IS_ERR(clk)) -+ kobject_put(&clk->kobj); -+} -+ -+static int clk_is_parent(struct clk const *child, struct clk const *parent) -+{ -+ if (!child || !parent) -+ return 0; -+ if (!child->parent) -+ return 0; -+ if (child->parent == parent) -+ return 1; -+ else -+ return clk_is_parent(child->parent, parent); -+} -+ -+int clk_enable(struct clk *clk) -+{ -+ int ret; -+ struct clk_tnode transaction; -+ struct clk_event event; -+ -+ event = EVENT(clk, 0, CLK_UNDEFINED_RATE); -+ transaction = TRANSACTION_ROOT(1, &event); -+ -+ pr_debug("%s\n", clk->name); -+ -+ -+ if (clk->flags & CLK_ALWAYS_ENABLED || clk_is_enabled(clk)) -+ return 0; -+ -+ if (clk->parent) { -+ /* turn-on the parent if the parent is 'auto_switch' */ -+ clk_notify_child_event(CHILD_CLOCK_ENABLED, clk->parent); -+ -+ if (!clk_is_enabled(clk->parent)) { -+ /* the parent is still disabled... */ -+ clk_notify_child_event(CHILD_CLOCK_DISABLED, -+ clk->parent); -+ return -EINVAL; -+ } -+ } -+ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction); -+ if (ret) { -+ ret = -EPERM; -+ goto err_0; -+ } -+ -+ /* if not zero somebody doens't agree the clock update */ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction); -+ if (ret) { -+ ret = -EPERM; -+ goto err_1; -+ } -+ -+ clk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction); -+ -+ ret = __clk_enable(clk); -+ -+ event.new_rate = clk_get_rate(clk); -+ -+ clk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction); -+ -+ clk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction); -+ -+err_1: -+ clk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction); -+ -+err_0: -+ clk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction); -+ -+ if (ret) -+ clk_notify_child_event(CHILD_CLOCK_DISABLED, clk->parent); -+ -+ return ret; -+} -+EXPORT_SYMBOL(clk_enable); -+ -+/** -+ * clk_disable - -+ * disables the clock -+ * Is isn't really good that it's a 'void' function... -+ * but this is common interface -+ */ -+void clk_disable(struct clk *clk) -+{ -+ struct clk_tnode transaction; -+ struct clk_event event; -+ int ret; -+ -+ event = EVENT(clk, clk_get_rate(clk), 0); -+ transaction = TRANSACTION_ROOT(1, &event); -+ -+ pr_debug("\n"); -+ -+ if (clk->flags & CLK_ALWAYS_ENABLED || !clk_is_enabled(clk)) -+ return; -+ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction); -+ if (ret) -+ goto err_0; -+ -+ /* if not zero somebody doens't agree the clock update */ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction); -+ if (ret) -+ goto err_1; -+ -+ clk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction); -+ -+ __clk_disable(clk); -+ -+ clk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction); -+ -+ clk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction); -+ -+err_0: -+ clk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction); -+err_1: -+ clk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction); -+ -+ clk_notify_child_event(CHILD_CLOCK_DISABLED, clk->parent); -+ -+ return ; -+} -+EXPORT_SYMBOL(clk_disable); -+ -+unsigned long clk_get_rate(struct clk *clk) -+{ -+ return clk->rate; -+} -+EXPORT_SYMBOL(clk_get_rate); -+ -+struct clk *clk_get_parent(struct clk *clk) -+{ -+ return clk->parent; -+} -+EXPORT_SYMBOL(clk_get_parent); -+ -+int clk_set_parent(struct clk *clk, struct clk *parent) -+{ -+ int ret = -EOPNOTSUPP; -+ struct clk *old_parent = clk->parent; -+ struct clk_event event; -+ struct clk_tnode transaction; -+ int clk_was_enabled = clk_is_enabled(clk); -+ -+ event = EVENT(clk, clk_get_rate(clk), CLK_UNDEFINED_RATE); -+ transaction = TRANSACTION_ROOT(1, &event); -+ -+ if (!clk || !parent) -+ return -EINVAL; -+ -+ if (clk->parent == parent) -+ return 0; -+ -+ pr_debug("\n"); -+ -+ if (clk_was_enabled && !clk_is_enabled(parent)) -+ /* turn-on parent if possible */ -+ clk_notify_child_event(CHILD_CLOCK_ENABLED, parent); -+ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction); -+ if (ret) { -+ ret = -EPERM; -+ goto err_0; -+ } -+ -+ /* if not zero somebody doens't agree the clock updated */ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction); -+ if (ret) { -+ ret = -EPERM; -+ goto err_1; -+ } -+ -+ clk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction); -+ -+ /* Now we updated the hw */ -+ ret = __clk_set_parent(clk, parent); -+ if (ret) { -+ /* there was a problem... -+ * therefore clk is still on the old parent -+ */ -+ clk->parent = old_parent; /* to be safe ! */ -+ goto err_2; -+ } -+ -+ klist_del(&clk->child_node); -+ -+ clk->parent = parent; -+ -+ ret = kobject_move(&clk->kobj, &clk->parent->kobj); -+ if (ret) -+ ; -+ -+ klist_add_tail(&clk->child_node, &clk->parent->childs); -+ -+ clk->parent->nr_clocks++; -+ old_parent->nr_clocks--; -+ -+err_2: -+ event.new_rate = clk_get_rate(clk); -+ -+ clk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction); -+ -+ clk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction); -+ -+err_1: -+ clk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction); -+err_0: -+ clk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction); -+ -+ if (clk_was_enabled && !ret) { -+ /* 5. to decrease the old_parent nchild counter */ -+ clk_notify_child_event(CHILD_CLOCK_DISABLED, old_parent); -+ /* 5. increase the new_parent nchild counter */ -+ clk_notify_child_event(CHILD_CLOCK_ENABLED, clk->parent); -+ /* 6. to decrease the old_parent nchild counter */ -+ clk_notify_child_event(CHILD_CLOCK_DISABLED, old_parent); -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(clk_set_parent); -+ -+int clk_set_rate(struct clk *clk, unsigned long rate) -+{ -+ int ret = -EOPNOTSUPP; -+ struct clk_event event; -+ struct clk_tnode transaction; -+ -+ event = EVENT(clk, clk_get_rate(clk), clk_round_rate(clk, rate)); -+ transaction = TRANSACTION_ROOT(1, &event); -+ -+ pr_debug("\n"); -+ -+ if (clk_is_readonly(clk)) -+ /* read only clock doesn't have to be "touched" !!!! */ -+ return -EPERM; -+ -+ if (event.new_rate == clk_get_rate(clk)) -+ return 0; -+ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction); -+ if (ret) { -+ ret = -EPERM; -+ goto err_0; -+ } -+ -+ /* if not zero somebody doens't agree the clock updated */ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction); -+ if (ret) { -+ ret = -EPERM; -+ goto err_1; -+ } -+ -+ clk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction); -+ -+ __clk_set_rate(clk, event.new_rate); -+ /* reload new_rate to avoid hw rounding... */ -+ event.new_rate = clk_get_rate(clk); -+ -+ clk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction); -+ clk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction); -+ -+err_1: -+ clk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction); -+err_0: -+ clk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction); -+ -+ return ret; -+} -+EXPORT_SYMBOL(clk_set_rate); -+ -+long clk_round_rate(struct clk *clk, unsigned long rate) -+{ -+ pr_debug("\n"); -+ -+ if (likely(clk->ops && clk->ops->round)) -+ return clk->ops->round(clk, rate); -+ return rate; -+} -+EXPORT_SYMBOL(clk_round_rate); -+ -+unsigned long clk_evaluate_rate(struct clk *clk, unsigned long prate) -+{ -+ pr_debug("\n"); -+ if (!clk->parent)/* without parent this function has no meaning */ -+ return CLK_UNDEFINED_RATE; -+ -+ if (!prate)/* on parent disabled than disable the child */ -+ return 0; -+ -+ if (likely(clk->ops && clk->ops->eval)) -+ return clk->ops->eval(clk, prate); -+ -+ return CLK_UNDEFINED_RATE; -+} -+EXPORT_SYMBOL(clk_evaluate_rate); -+ -+int clk_set_rates(struct clk **clks, unsigned long *rates, unsigned long nclks) -+{ -+ int i, ret = 0; -+ struct clk_event *evt; -+ struct clk_tnode transaction = TRANSACTION_ROOT(nclks, NULL) -+ -+ pr_debug("\n"); -+ -+ if (!clks || !rates || !nclks) -+ return -EINVAL; -+ evt = kmalloc(sizeof(*evt) * -+ tnode_get_size(&transaction), GFP_KERNEL); -+ -+ if (!evt) -+ return -ENOMEM; -+ -+ tnode_set_events(&transaction, evt); -+ -+ for (i = 0; i < tnode_get_size(&transaction); ++i) { -+ tnode_set_clock(&transaction, i, clks[i]); -+ tnode_get_event(&transaction, i)->old_rate = -+ clk_get_rate(clks[i]); -+ tnode_get_event(&transaction, i)->new_rate = -+ clk_round_rate(clks[i], rates[i]); -+ } -+ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction); -+ if (ret) { -+ ret = -EPERM; -+ goto err_0; -+ } -+ -+ /* if not zero somebody doens't agree the clock updated */ -+ ret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction); -+ if (ret) { -+ ret = -EPERM; -+ goto err_1; -+ } -+ -+ clk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction); -+ -+ for (i = 0; i < tnode_get_size(&transaction); ++i) { -+ if (!clk_is_enabled(clks[i]) && rates[i]) -+ ret |= __clk_enable(clks[i]); -+ else if (clk_is_enabled(clks[i]) && !rates[i]) -+ ret |= __clk_disable(clks[i]); -+ else -+ ret |= __clk_set_rate(clks[i], rates[i]); -+ -+ /* reload new_rate to avoid hw rounding... */ -+ tnode_get_event(&transaction, i)->new_rate = -+ clk_get_rate(clks[i]); -+ } -+ -+ clk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction); -+ -+ clk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction); -+ -+err_1: -+ clk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction); -+ -+err_0: -+ clk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction); -+ -+ kfree(evt); -+ return ret; -+} -+EXPORT_SYMBOL(clk_set_rates); -+ -+struct clk *clk_get(struct device *dev, const char *id) -+{ -+ struct clk *clk = NULL; -+ struct clk *clkp; -+ struct klist_iter i; -+ int found = 0, idno; -+ -+ mutex_lock(&clk_list_sem); -+#if 0 -+ if (dev == NULL || dev->bus != &platform_bus_type) -+ idno = -1; -+ else -+ idno = to_platform_device(dev)->id; -+ -+ klist_iter_init(&clk_list, &i); -+ while ((clkp = next_clock(&i)) && !found) -+ if (clk->id == idno && strcmp(id, clk->name) == 0 && -+ try_module_get(clk->owner)) { -+ clk = clkp; -+ found = 1; -+ } -+ klist_iter_exit(&i); -+ -+ if (found) -+ goto _found; -+#endif -+ klist_iter_init(&clk_list, &i); -+ while ((clkp = next_clock(&i))) -+ if (strcmp(id, clkp->name) == 0 -+ && try_module_get(clkp->owner)) { -+ clk = clkp; -+ break; -+ } -+ klist_iter_exit(&i); -+_found: -+ mutex_unlock(&clk_list_sem); -+ return clk; -+} -+EXPORT_SYMBOL(clk_get); -+ -+int clk_for_each(int (*fn) (struct clk *clk, void *data), void *data) -+{ -+ struct clk *clkp; -+ struct klist_iter i; -+ int result = 0; -+ -+ if (!fn) -+ return -EFAULT; -+ -+ pr_debug("\n"); -+ mutex_lock(&clk_list_sem); -+ klist_iter_init(&clk_list, &i); -+ -+ while ((clkp = next_clock(&i))) -+ result |= fn(clkp, data); -+ -+ klist_iter_exit(&i); -+ mutex_unlock(&clk_list_sem); -+ return result; -+} -+EXPORT_SYMBOL(clk_for_each); -+ -+int clk_for_each_child(struct clk *clk, -+ int (*fn) (struct clk *clk, void *data), void *data) -+{ -+ struct clk *clkp; -+ struct klist_iter i; -+ int result = 0; -+ -+ if (!clk || !fn) -+ return -EFAULT; -+ -+ klist_iter_init(&clk->childs, &i); -+ -+ while ((clkp = next_child_clock(&i))) -+ result |= fn(clkp, data); -+ -+ klist_iter_exit(&i); -+ -+ return result; -+} -+EXPORT_SYMBOL(clk_for_each_child); -+ -+static int __init early_clk_complete(struct clk *clk, void *data) -+{ -+ int ret; -+ -+ ret = kobject_add(&clk->kobj, -+ (clk->parent ? &clk->parent->kobj : clk_kobj), -+ clk->name); -+ if (ret) -+ return ret; -+ -+ clk->kdevices = kobject_create_and_add("devices", &clk->kobj); -+ if (!clk->kdevices) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+int __init early_clk_register(struct clk *clk) -+{ -+ int retval = 0; -+ if (!clk) -+ return -EFAULT; -+ pr_debug("%s\n", clk->name); -+ -+ clk_initialize(clk); -+ -+ /* Initialize ... */ -+ __clk_init(clk); -+ -+ if (clk->parent) { -+#ifdef CLK_SAFE_CODE -+ /* 1. the parent has to be registered */ -+ if (!check_clk(clk->parent)) -+ return -ENODEV; -+ /* 2. an always enabled child has to sit on a always -+ * enabled parent! -+ */ -+ if (clk->flags & CLK_ALWAYS_ENABLED && -+ !(clk->parent->flags & CLK_ALWAYS_ENABLED)) -+ return -EFAULT; -+ /* 3. a fixed child has to sit on a fixed parent */ -+ if (clk_is_readonly(clk) && !clk_is_readonly(clk->parent)) -+ return -EFAULT; -+#endif -+ klist_add_tail(&clk->child_node, &clk->parent->childs); -+ clk->parent->nr_clocks++; -+ } -+ -+ klist_add_tail(&clk->node, &clk_list); -+ if (clk->flags & CLK_ALWAYS_ENABLED) { -+ __clk_enable(clk); -+ clk_notify_child_event(CHILD_CLOCK_ENABLED, clk->parent); -+ } -+ return retval; -+} -+ -+int __init clock_init(void) -+{ -+ clk_kobj = kobject_create_and_add("clocks", NULL); -+ if (!clk_kobj) -+ return -EINVAL ; -+ -+ clk_for_each(early_clk_complete, NULL); -+ -+ printk(KERN_INFO CLK_NAME " " CLK_VERSION "\n"); -+ -+ return 0; -+} -+ -diff --git a/drivers/base/clk.h b/drivers/base/clk.h -new file mode 100644 -index 0000000..61672ef ---- /dev/null -+++ b/drivers/base/clk.h -@@ -0,0 +1,319 @@ -+/* -+ ------------------------------------------------------------------------- -+ clk.h -+ ------------------------------------------------------------------------- -+ (C) STMicroelectronics 2008 -+ (C) STMicroelectronics 2009 -+ Author: Francesco M. Virlinzi <francesco.virlinzi@st.com> -+ ---------------------------------------------------------------------------- -+ May be copied or modified under the terms of the GNU General Public -+ License v.2 ONLY. See linux/COPYING for more information. -+ -+ ------------------------------------------------------------------------- */ -+ -+#ifdef CONFIG_GENERIC_CLK_FM -+ -+#include <linux/clk.h> -+#include <linux/platform_device.h> -+#include <linux/kobject.h> -+#include <linux/klist.h> -+#include <linux/list.h> -+#include <linux/notifier.h> -+#include <asm/atomic.h> -+ -+enum clk_ops_id { -+ __CLK_INIT = 0, -+ __CLK_ENABLE, -+ __CLK_DISABLE, -+ __CLK_SET_RATE, -+ __CLK_SET_PARENT, -+ __CLK_RECALC, -+ __CLK_ROUND, -+ __CLK_EVAL, -+}; -+ -+extern struct klist clk_list; -+/** -+ * clk_tnode -+ * it's the internal strucure used to track each node -+ * in the transaction graph. -+ * _NO_ api is showed to the other modules -+ */ -+struct clk_tnode { -+ /** @tid: the tnode id */ -+ unsigned long tid; -+ /** @size: how may clock are involved in this tnode */ -+ unsigned long size; -+ /** @parent: the parent tnode */ -+ struct clk_tnode *parent; -+ /* @events_map: a bitmap to declare the -+ * valid events in this tnode -+ */ -+ unsigned long events_map; -+ /** @events: the event array of this tnode */ -+ struct clk_event *events; -+ /** @child: links the childres tnode */ -+ struct list_head childs; -+ /** @pnode: links the tnode to the parent */ -+ struct list_head pnode; -+}; -+ -+/* -+ * tnode_get_size - -+ * returns the number of events in the transaction -+ */ -+static inline unsigned long -+tnode_get_size(struct clk_tnode *tnode) -+{ -+ return tnode->size; -+} -+ -+static inline unsigned long -+tnode_get_map(struct clk_tnode *tnode) -+{ -+ return tnode->events_map; -+} -+ -+static inline unsigned long -+tnode_check_map_id(struct clk_tnode *node, int id) -+{ -+ return node->events_map & (1 << id); -+} -+ -+static inline void -+tnode_set_map_id(struct clk_tnode *node, int id) -+{ -+ node->events_map |= (1 << id); -+} -+ -+static inline unsigned long -+tnode_get_id(struct clk_tnode *node) -+{ -+ return node->tid; -+} -+ -+static inline struct clk_event* -+tnode_get_event(struct clk_tnode *node, int id) -+{ -+ return &(node->events[id]); -+} -+ -+static inline struct clk_event *tnode_get_events(struct clk_tnode *node) -+{ -+ return tnode_get_event(node, 0); -+} -+ -+static inline void -+tnode_set_events(struct clk_tnode *node, struct clk_event *events) -+{ -+ node->events = events; -+} -+ -+static inline struct clk* -+tnode_get_clock(struct clk_tnode *node, int id) -+{ -+ return tnode_get_event(node, id)->clk; -+} -+ -+static inline void -+tnode_set_clock(struct clk_tnode *node, int id, struct clk *clk) -+{ -+ node->events[id].clk = clk; -+} -+ -+static inline struct clk_tnode *tnode_get_parent(struct clk_tnode *node) -+{ -+ return node->parent; -+} -+ -+#define tnode_for_each_valid_events(node, _j) \ -+ for ((_j) = (ffs(tnode_get_map(node)) - 1); \ -+ (_j) < tnode_get_size((node)); ++(_j)) \ -+ if (tnode_check_map_id((node), (_j))) -+ -+#define EVENT(_clk, _oldrate, _newrate) \ -+ (struct clk_event) \ -+ { \ -+ .clk = (struct clk *)(_clk), \ -+ .old_rate = (unsigned long)(_oldrate), \ -+ .new_rate = (unsigned long)(_newrate), \ -+ }; -+ -+#define TRANSACTION_ROOT(_num, _event) \ -+ (struct clk_tnode) { \ -+ .tid = atomic_inc_return(&transaction_counter), \ -+ .size = (_num), \ -+ .events = (struct clk_event *)(_event), \ -+ .parent = NULL, \ -+ .childs = LIST_HEAD_INIT(transaction.childs), \ -+ .events_map = 0, \ -+ }; -+ -+#define klist_function_support(_name, _type, _field, _kobj) \ -+static void klist_get_##_name(struct klist_node *n) \ -+{ \ -+ struct _type *entry = container_of(n, struct _type, _field); \ -+ kobject_get(&entry->_kobj); \ -+} \ -+static void klist_put_##_name(struct klist_node *n) \ -+{ \ -+ struct _type *entry = container_of(n, struct _type, _field); \ -+ kobject_put(&entry->_kobj); \ -+} -+ -+#define klist_entry_support(name, type, field) \ -+static struct type *next_##name(struct klist_iter *i) \ -+{ struct klist_node *n = klist_next(i); \ -+ return n ? container_of(n, struct type, field) : NULL; \ -+} -+ -+static inline void -+clk_event_init(struct clk_event *evt, struct clk *clk, -+ unsigned long oldrate, unsigned long newrate) -+{ -+ evt->clk = clk; -+ evt->old_rate = oldrate; -+ evt->new_rate = newrate; -+} -+ -+enum clk_fsm_e { -+ TRNSC_ENTER_CLOCK = 0x10, -+ TRNSC_ENTER_DEVICE = NOTIFY_CLK_ENTERCHANGE, /* 0x1 */ -+ TRNSC_PRE_DEVICE = NOTIFY_CLK_PRECHANGE, /* 0x2 */ -+ TRNSC_CHANGE_CLOCK = 0x20, -+ TRNSC_POST_DEVICE = NOTIFY_CLK_POSTCHANGE, /* 0x4 */ -+ TRNSC_EXIT_DEVICE = NOTIFY_CLK_EXITCHANGE, /* 0x8 */ -+ TRNSC_EXIT_CLOCK = 0x40 -+}; -+ -+#define DEV_SUSPENDED_ON_TRANSACTION (0x10) -+#define DEV_RESUMED_ON_TRANSACTION (0x20) -+#define DEV_ON_TRANSACTION (TRNSC_ENTER_DEVICE | \ -+ TRNSC_PRE_DEVICE | \ -+ TRNSC_POST_DEVICE | \ -+ TRNSC_EXIT_DEVICE) -+ -+static inline int -+pdev_transaction_move_on(struct platform_device *dev, unsigned int value) -+{ -+ int ret = -EINVAL; -+ unsigned long flag; -+#ifdef CONFIG_CLK_DEBUG -+ static const char *dev_state[] = { -+ "dev_enter", -+ "dev_pre", -+ "dev_post", -+ "dev_exit" -+ }; -+ -+ unsigned long old = dev->clk_state & DEV_ON_TRANSACTION; -+ int was = 0, is = 0; -+ if ( -+ (old == 0 && value == TRNSC_ENTER_DEVICE) || -+ (old == TRNSC_ENTER_DEVICE && value == TRNSC_EXIT_DEVICE) || -+ (old == TRNSC_ENTER_DEVICE && value == TRNSC_PRE_DEVICE) || -+ (old == TRNSC_PRE_DEVICE && value == TRNSC_POST_DEVICE) || -+ (old == TRNSC_POST_DEVICE && value == TRNSC_EXIT_DEVICE)) -+ goto ok; -+ switch (old) { -+ case TRNSC_ENTER_DEVICE: -+ was = 0; -+ break; -+ case TRNSC_PRE_DEVICE: -+ was = 1; -+ break; -+ case TRNSC_POST_DEVICE: -+ was = 2; -+ break; -+ case TRNSC_EXIT_DEVICE: -+ was = 3; -+ break; -+ } -+ switch (value) { -+ case TRNSC_ENTER_DEVICE: -+ is = 0; -+ break; -+ case TRNSC_PRE_DEVICE: -+ is = 1; -+ break; -+ case TRNSC_POST_DEVICE: -+ is = 2; -+ break; -+ case TRNSC_EXIT_DEVICE: -+ is = 3; -+ break; -+ } -+ printk(KERN_ERR "The device %s.%d shows a wrong evolution during " -+ "a clock transaction\nDev state was %s and moved on %s\n", -+ dev->name, dev->id, dev_state[was], dev_state[is]); -+ok: -+#endif -+ local_irq_save(flag); -+ if ((dev->clk_state & DEV_ON_TRANSACTION) != value) { -+ dev->clk_state &= ~DEV_ON_TRANSACTION; -+ dev->clk_state |= value; -+ ret = 0; -+ } -+ local_irq_restore(flag); -+ return ret; -+} -+ -+static inline int -+clk_set_towner(struct clk *clk, struct clk_tnode *node) -+{ -+ return atomic_cmpxchg((atomic_t *)&clk->towner, 0, (int)node); -+} -+ -+static inline void -+clk_clean_towner(struct clk *clk) -+{ -+ atomic_set((atomic_t *)(&clk->towner), 0); -+} -+ -+static inline int -+clk_is_enabled(struct clk *clk) -+{ -+ return clk->rate != 0; -+} -+ -+static inline int -+clk_is_readonly(struct clk *clk) -+{ -+ return !clk->ops || !clk->ops->set_rate; -+} -+ -+static inline int -+clk_allow_propagation(struct clk *clk) -+{ -+ return !!(clk->flags & CLK_EVENT_PROPAGATES); -+} -+ -+static inline int -+clk_is_auto_switching(struct clk *clk) -+{ -+ return !!(clk->flags & CLK_AUTO_SWITCHING); -+} -+ -+static inline int -+clk_follow_parent(struct clk *clk) -+{ -+ return !!(clk->flags & CLK_FOLLOW_PARENT); -+} -+ -+enum pdev_add_state { -+ PDEV_ADDING, -+ PDEV_ADDED, -+ PDEV_ADD_FAILED, -+}; -+ -+enum pdev_probe_state { -+ PDEV_PROBEING, -+ PDEV_PROBED, -+ PDEV_PROBE_FAILED, -+}; -+ -+int clk_add_device(struct platform_device *dev, enum pdev_add_state state); -+int clk_probe_device(struct platform_device *dev, enum pdev_probe_state state); -+int clk_del_device(struct platform_device *dev); -+ -+#endif -diff --git a/drivers/base/clk_pm.c b/drivers/base/clk_pm.c -new file mode 100644 -index 0000000..56c1760 ---- /dev/null -+++ b/drivers/base/clk_pm.c -@@ -0,0 +1,197 @@ -+/* -+ * ------------------------------------------------------------------------- -+ * clk_pm.c -+ * ------------------------------------------------------------------------- -+ * (C) STMicroelectronics 2008 -+ * (C) STMicroelectronics 2009 -+ * Author: Francesco M. Virlinzi <francesco.virlinzi@st.com> -+ * ------------------------------------------------------------------------- -+ * May be copied or modified under the terms of the GNU General Public -+ * License v.2 ONLY. See linux/COPYING for more information. -+ * -+ * ------------------------------------------------------------------------- -+ */ -+ -+#include <linux/clk.h> -+#include <linux/klist.h> -+#include <linux/list.h> -+#include <linux/sysdev.h> -+#include <linux/device.h> -+#include <linux/kref.h> -+#include <linux/kobject.h> -+#include <linux/err.h> -+#include <linux/spinlock.h> -+#include <linux/proc_fs.h> -+#include "power/power.h" -+#include "clk.h" -+#include "base.h" -+ -+static int -+__clk_operations(struct clk *clk, unsigned long rate, enum clk_ops_id id_ops) -+{ -+ int ret = -EINVAL; -+ unsigned long *ops_fns = (unsigned long *)clk->ops; -+ if (likely(ops_fns && ops_fns[id_ops])) { -+ int (*fns)(struct clk *clk, unsigned long rate) -+ = (void *)ops_fns[id_ops]; -+ unsigned long flags; -+ spin_lock_irqsave(&clk->lock, flags); -+ ret = fns(clk, rate); -+ spin_unlock_irqrestore(&clk->lock, flags); -+ } -+ return ret; -+} -+ -+static inline int __clk_init(struct clk *clk) -+{ -+ return __clk_operations(clk, 0, __CLK_INIT); -+} -+ -+static inline int __clk_enable(struct clk *clk) -+{ -+ return __clk_operations(clk, 0, __CLK_ENABLE); -+} -+ -+static inline int __clk_disable(struct clk *clk) -+{ -+ return __clk_operations(clk, 0, __CLK_DISABLE); -+} -+ -+static inline int __clk_set_rate(struct clk *clk, unsigned long rate) -+{ -+ return __clk_operations(clk, rate, __CLK_SET_RATE); -+} -+ -+static inline int __clk_set_parent(struct clk *clk, struct clk *parent) -+{ -+ return __clk_operations(clk, (unsigned long)parent, __CLK_SET_PARENT); -+} -+ -+static inline int __clk_recalc_rate(struct clk *clk) -+{ -+ return __clk_operations(clk, 0, __CLK_RECALC); -+} -+ -+static inline int pm_clk_ratio(struct clk *clk) -+{ -+ register unsigned int val, exp; -+ -+ val = ((clk->flags >> CLK_PM_RATIO_SHIFT) & -+ ((1 << CLK_PM_RATIO_NRBITS) - 1)) + 1; -+ exp = ((clk->flags >> CLK_PM_EXP_SHIFT) & -+ ((1 << CLK_PM_EXP_NRBITS) - 1)); -+ -+ return val << exp; -+} -+ -+static inline int pm_clk_is_off(struct clk *clk) -+{ -+ return ((clk->flags & CLK_PM_TURNOFF) == CLK_PM_TURNOFF); -+} -+ -+static inline void pm_clk_set(struct clk *clk, int edited) -+{ -+#define CLK_PM_EDITED (1 << CLK_PM_EDIT_SHIFT) -+ clk->flags &= ~CLK_PM_EDITED; -+ clk->flags |= (edited ? CLK_PM_EDITED : 0); -+} -+ -+static inline int pm_clk_is_modified(struct clk *clk) -+{ -+ return ((clk->flags & CLK_PM_EDITED) != 0); -+} -+ -+static int clk_resume_from_standby(struct clk *clk, void *data) -+{ -+ pr_debug("\n"); -+ if (!likely(clk->ops)) -+ return 0; -+ /* check if the pm modified the clock */ -+ if (!pm_clk_is_modified(clk)) -+ return 0;; -+ pm_clk_set(clk, 0); -+ if (pm_clk_is_off(clk)) -+ __clk_enable(clk); -+ else -+ __clk_set_rate(clk, clk->rate * pm_clk_ratio(clk)); -+ return 0; -+} -+ -+static int clk_on_standby(struct clk *clk, void *data) -+{ -+ pr_debug("\n"); -+ -+ if (!clk->ops) -+ return 0; -+ if (!clk->rate) /* already disabled */ -+ return 0; -+ -+ pm_clk_set(clk, 1); /* set as modified */ -+ if (pm_clk_is_off(clk)) /* turn-off */ -+ __clk_disable(clk); -+ else /* reduce */ -+ __clk_set_rate(clk, clk->rate / pm_clk_ratio(clk)); -+ return 0; -+} -+ -+static int clk_resume_from_hibernation(struct clk *clk, void *data) -+{ -+ unsigned long rate = clk->rate; -+ pr_debug("\n"); -+ __clk_set_parent(clk, clk->parent); -+ __clk_set_rate(clk, rate); -+ __clk_recalc_rate(clk); -+ return 0; -+} -+ -+static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) -+{ -+ static pm_message_t prev_state; -+ -+ switch (state.event) { -+ case PM_EVENT_ON: -+ switch (prev_state.event) { -+ case PM_EVENT_FREEZE: /* Resumeing from hibernation */ -+ clk_for_each(clk_resume_from_hibernation, NULL); -+ break; -+ case PM_EVENT_SUSPEND: -+ clk_for_each(clk_resume_from_standby, NULL); -+ break; -+ } -+ case PM_EVENT_SUSPEND: -+ clk_for_each(clk_on_standby, NULL); -+ break; -+ case PM_EVENT_FREEZE: -+ break; -+ } -+ prev_state = state; -+ return 0; -+} -+ -+static int clks_sysdev_resume(struct sys_device *dev) -+{ -+ return clks_sysdev_suspend(dev, PMSG_ON); -+} -+ -+static struct sysdev_class clk_sysdev_class = { -+ .name = "clks", -+}; -+ -+static struct sysdev_driver clks_sysdev_driver = { -+ .suspend = clks_sysdev_suspend, -+ .resume = clks_sysdev_resume, -+}; -+ -+static struct sys_device clks_sysdev_dev = { -+ .cls = &clk_sysdev_class, -+}; -+ -+static int __init clk_sysdev_init(void) -+{ -+ sysdev_class_register(&clk_sysdev_class); -+ sysdev_driver_register(&clk_sysdev_class, &clks_sysdev_driver); -+ sysdev_register(&clks_sysdev_dev); -+ return 0; -+} -+ -+subsys_initcall(clk_sysdev_init); -diff --git a/drivers/base/clk_utils.c b/drivers/base/clk_utils.c -new file mode 100644 -index 0000000..a222aa7 ---- /dev/null -+++ b/drivers/base/clk_utils.c -@@ -0,0 +1,456 @@ -+/* -+ * ------------------------------------------------------------------------- -+ * clk_utils.c -+ * ------------------------------------------------------------------------- -+ * (C) STMicroelectronics 2008 -+ * (C) STMicroelectronics 2009 -+ * Author: Francesco M. Virlinzi <francesco.virlinzi@st.com> -+ * ------------------------------------------------------------------------- -+ * May be copied or modified under the terms of the GNU General Public -+ * License v.2 ONLY. See linux/COPYING for more information. -+ * -+ * ------------------------------------------------------------------------- -+ */ -+ -+#include <linux/platform_device.h> -+#include <linux/clk.h> -+#include <linux/klist.h> -+#include <linux/list.h> -+#include <linux/delay.h> -+#include <linux/sysdev.h> -+#include <linux/kref.h> -+#include <linux/kobject.h> -+#include <linux/err.h> -+#include <linux/spinlock.h> -+#include <asm/atomic.h> -+#include "power/power.h" -+#include "clk.h" -+#include "base.h" -+ -+int clk_generic_notify(unsigned long code, -+ struct platform_device *pdev, void *data) -+{ -+ struct clk_event *event = (struct clk_event *)data; -+ unsigned long event_decode = clk_event_decode(event); -+ -+ switch (code) { -+ case NOTIFY_CLK_ENTERCHANGE: -+ return NOTIFY_EVENT_HANDLED; /* to accept */ -+ -+ case NOTIFY_CLK_PRECHANGE: -+ /* without clock (not still enabled) the device can not work */ -+ if (event_decode == _CLK_ENABLE) -+ return NOTIFY_EVENT_NOTHANDLED; -+ return NOTIFY_EVENT_HANDLED; /* to suspend */ -+ -+ case NOTIFY_CLK_POSTCHANGE: -+ /* without clock (just disabled) the device can not work */ -+ if (event_decode == _CLK_DISABLE) -+ return NOTIFY_EVENT_NOTHANDLED; -+ return NOTIFY_EVENT_HANDLED; /* to resume */ -+ -+ case NOTIFY_CLK_EXITCHANGE: -+ return NOTIFY_EVENT_HANDLED; -+ } -+ -+ return NOTIFY_EVENT_HANDLED; -+} -+EXPORT_SYMBOL(clk_generic_notify); -+ -+unsigned long clk_generic_evaluate_rate(struct clk *clk, unsigned long prate) -+{ -+ unsigned long current_prate; -+ -+ if (!clk->parent) -+ return -EINVAL; -+ -+ if (!prate) /* if zero return zero (on disable: disable!) */ -+ return 0; -+ -+ if (prate == CLK_UNDEFINED_RATE) /* on undefined: undefined */ -+ return CLK_UNDEFINED_RATE; -+ -+ current_prate = clk_get_rate(clk->parent); -+ if (current_prate == prate) -+ return clk_get_rate(clk); -+ -+ if (current_prate > prate) /* down scale */ -+ return (clk_get_rate(clk) * prate) / current_prate; -+ else -+ return (clk_get_rate(clk) / current_prate) * prate; -+} -+EXPORT_SYMBOL(clk_generic_evaluate_rate); -+ -+#ifdef CONFIG_PROC_FS -+/* -+ * The "clocks" file is created under /proc -+ * to list all the clocks registered in the system -+ */ -+#include <linux/proc_fs.h> -+#include <linux/seq_file.h> -+static void *clk_seq_next(struct seq_file *s, void *v, loff_t *pos) -+{ -+ struct list_head *tmp; -+ union { -+ loff_t value; -+ long parts[2]; -+ } ltmp; -+ -+ ltmp.value = *pos; -+ tmp = (struct list_head *)ltmp.parts[0]; -+ tmp = tmp->next; -+ ltmp.parts[0] = (long)tmp; -+ -+ *pos = ltmp.value; -+ -+ if (tmp == &clk_list.k_list) -+ return NULL; /* No more to read */ -+ -+ return pos; -+} -+ -+static void *clk_seq_start(struct seq_file *s, loff_t *pos) -+{ -+ if (!*pos) { /* first call! */ -+ union { -+ loff_t value; -+ long parts[2]; -+ } ltmp; -+ ltmp.parts[0] = (long) clk_list.k_list.next; -+ *pos = ltmp. value; -+ return pos; -+ } -+ --(*pos); /* to realign *pos value! */ -+ -+ return clk_seq_next(s, NULL, pos); -+} -+ -+static int clk_seq_show(struct seq_file *s, void *v) -+{ -+ unsigned long *l = (unsigned long *)v; -+ struct list_head *node = (struct list_head *)(*l); -+ struct clk *clk = container_of(node, struct clk, node.n_node); -+ unsigned long rate = clk_get_rate(clk); -+ -+ if (unlikely(!rate && !clk->parent)) -+ return 0; -+ -+ seq_printf(s, "%-12s\t: %ld.%02ldMHz - ", clk->name, -+ rate / 1000000, (rate % 1000000) / 10000); -+ seq_printf(s, "[0x%p]", clk); -+ if (clk_is_enabled(clk)) -+ seq_printf(s, " - enabled"); -+ -+ if (clk->parent) -+ seq_printf(s, " - [%s]", clk->parent->name); -+ seq_printf(s, "\n"); -+ -+ return 0; -+} -+ -+static void clk_seq_stop(struct seq_file *s, void *v) -+{ -+} -+ -+static const struct seq_operations clk_seq_ops = { -+ .start = clk_seq_start, -+ .next = clk_seq_next, -+ .stop = clk_seq_stop, -+ .show = clk_seq_show, -+}; -+ -+static int clk_proc_open(struct inode *inode, struct file *file) -+{ -+ return seq_open(file, &clk_seq_ops); -+} -+ -+static const struct file_operations clk_proc_ops = { -+ .owner = THIS_MODULE, -+ .open = clk_proc_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+static int __init clk_proc_init(void) -+{ -+ struct proc_dir_entry *p; -+ -+ p = create_proc_entry("clocks", S_IRUGO, NULL); -+ -+ if (unlikely(!p)) -+ return -EINVAL; -+ -+ p->proc_fops = &clk_proc_ops; -+ -+ return 0; -+} -+ -+subsys_initcall(clk_proc_init); -+#endif -+ -+#ifdef CONFIG_SYSFS -+static ssize_t clk_rate_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ struct clk *clk = container_of(kobj, struct clk, kobj); -+ -+ return sprintf(buf, "%u\n", (unsigned int)clk_get_rate(clk)); -+} -+ -+static ssize_t clk_rate_store(struct kobject *kobj, -+ struct kobj_attribute *attr, const char *buf, size_t count) -+{ -+ unsigned long rate = simple_strtoul(buf, NULL, 10); -+ struct clk *clk = container_of(kobj, struct clk, kobj); -+ -+ if (rate) { -+ if (!clk_is_enabled(clk)) -+ clk_enable(clk); -+ if (clk_set_rate(clk, rate) < 0) -+ return -EINVAL; -+ } else -+ clk_disable(clk); -+ return count; -+} -+ -+static const char *clk_ctrl_token[] = { -+ "auto_switching", -+ "no_auto_switching", -+ "allow_propagation", -+ "no_allow_propagation", -+ "follow_parent", -+ "no_follow_parent", -+}; -+static ssize_t clk_state_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ struct clk *clk = container_of(kobj, struct clk, kobj); -+ ssize_t ret; -+ -+ -+ ret = sprintf(buf, "clock name: %s\n", clk->name); -+ if (clk_is_enabled(clk)) -+ ret += sprintf(buf + ret, " + enabled\n"); -+ else -+ ret += sprintf(buf + ret, " + disabled\n"); -+ if (clk_is_readonly(clk)) -+ ret += sprintf(buf + ret, " + rate read only\n"); -+ else -+ ret += sprintf(buf + ret, " + rate writable\n"); -+ ret += -+ sprintf(buf + ret, " + %s\n", -+ clk_ctrl_token[(clk_allow_propagation(clk) ? 2 : 3)]); -+ ret += -+ sprintf(buf + ret, " + %s\n", -+ clk_ctrl_token[(clk_is_auto_switching(clk) ? 0 : 1)]); -+ ret += -+ sprintf(buf + ret, " + %s\n", -+ clk_ctrl_token[(clk_follow_parent(clk) ? 4 : 5)]); -+ ret += -+ sprintf(buf + ret, " + nr_clocks: %u\n", clk->nr_clocks); -+ ret += -+ sprintf(buf + ret, " + nr_active_clocks: %u\n", -+ clk->nr_active_clocks); -+ ret += -+ sprintf(buf + ret, " + nr_active_devices: %u\n", -+ clk->nr_active_devices); -+ ret += -+ sprintf(buf + ret, " + rate: %u\n", -+ (unsigned int)clk_get_rate(clk)); -+ return ret; -+} -+ -+static ssize_t clk_ctrl_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ int idx, ret = 0; -+ -+ ret += sprintf(buf + ret, "Allowed command:\n"); -+ -+ for (idx = 0; idx < ARRAY_SIZE(clk_ctrl_token); ++idx) -+ ret += sprintf(buf + ret, " + %s\n", clk_ctrl_token[idx]); -+ -+ return ret; -+} -+static ssize_t clk_ctrl_store(struct kobject *kobj, -+ struct kobj_attribute *attr, const char *buf, size_t count) -+{ -+ int i, idx_token, ret = -EINVAL; -+ struct clk *clk = container_of(kobj, struct clk, kobj); -+ -+ if (!count) -+ return ret; -+ -+ for (i = 0, idx_token = -1; i < ARRAY_SIZE(clk_ctrl_token); ++i) -+ if (!strcmp(buf, clk_ctrl_token[i])) -+ idx_token = i; -+ -+ if (idx_token == -EINVAL) -+ return ret; /* token not valid... */ -+ -+ switch (idx_token) { -+ case 0: -+ clk->flags |= CLK_EVENT_PROPAGATES; -+ break; -+ case 1: -+ clk->flags &= ~CLK_EVENT_PROPAGATES; -+ break; -+ case 2: -+ clk->flags |= CLK_AUTO_SWITCHING; -+ if (!clk->nr_active_clocks && !clk->nr_active_devices) -+ clk_disable(clk); -+ else if (clk->nr_active_clocks || clk->nr_active_devices) -+ clk_enable(clk); -+ break; -+ case 3: -+ clk->flags &= ~CLK_AUTO_SWITCHING; -+ break; -+ case 4: -+ clk->flags |= CLK_FOLLOW_PARENT; -+ break; -+ case 5: -+ clk->flags &= ~CLK_FOLLOW_PARENT; -+ break; -+ } -+ -+ return count; -+} -+ -+static ssize_t clk_parent_store(struct kobject *kobj, -+ struct kobj_attribute *attr, const char *buf, size_t count) -+{ -+ struct clk *clk = container_of(kobj, struct clk, kobj); -+ struct clk *parent = clk_get(NULL, buf); -+ -+ if (!parent) -+ return -EINVAL; -+ -+ clk_put(parent); -+ clk_set_parent(clk, parent); -+ -+ return count; -+} -+ -+static struct kobj_attribute attributes[] = { -+__ATTR(state, S_IRUSR, clk_state_show, NULL), -+__ATTR(rate, S_IRUSR | S_IWUSR, clk_rate_show, clk_rate_store), -+__ATTR(control, S_IRUSR | S_IWUSR, clk_ctrl_show, clk_ctrl_store), -+__ATTR(parent, S_IWUSR, NULL, clk_parent_store) -+}; -+ -+static struct attribute *clk_attrs[] = { -+ &attributes[0].attr, -+ &attributes[1].attr, -+ &attributes[2].attr, -+ &attributes[3].attr, -+ NULL -+}; -+ -+static struct attribute_group clk_attr_group = { -+ .attrs = clk_attrs, -+ .name = "attributes" -+}; -+ -+#if 0 -+static inline char *_strsep(char **s, const char *d) -+{ -+ int i, len = strlen(d); -+retry: -+ if (!(*s) || !(**s)) -+ return NULL; -+ for (i = 0; i < len; ++i) { -+ if (**s != *(d+i)) -+ continue; -+ ++(*s); -+ goto retry; -+ } -+ return strsep(s, d); -+} -+ -+/** -+ * clk_rates_store -+ * -+ * It parses the buf to create multi clocks transaction -+ * via user space -+ * The buffer has to be something like: -+ * clock_A @ rate_A; clock_B @ rate_b; clock_C @ rate_c -+ */ -+static ssize_t clk_rates_store(struct kobject *kobj, -+ struct kobj_attribute *attr, const char *buf, size_t count) -+{ -+ int i, ret; -+ int nclock = 0; -+ unsigned long *rates; -+ struct clk **clocks; -+ -+ if (!buf) -+ return -1; -+ -+ for (i = 0; i < count; ++i) -+ if (buf[i] == '@') -+ ++nclock; -+ -+ rates = kmalloc(sizeof(long) * nclock, GFP_KERNEL); -+ if (!rates) -+ return -ENOMEM; -+ -+ clocks = kmalloc(sizeof(void *) * nclock, GFP_KERNEL); -+ if (!clocks) { -+ ret = -ENOMEM; -+ goto err_0; -+ } -+ -+ /* Parse the buffer */ -+ for (i = 0; i < nclock; ++i) { -+ char *name; -+ char *nrate; -+ name = _strsep((char **)&buf, "@ "); ++buf; -+ nrate = _strsep((char **)&buf, " ;"); ++buf; -+ if (!name || !nrate) { -+ ret = -EINVAL; -+ goto err_1; -+ } -+ clocks[i] = clk_get(NULL, name); -+ rates[i] = simple_strtoul(nrate, NULL, 10); -+ if (!clocks[i]) { /* the clock doesn't exist! */ -+ ret = -EINVAL; -+ goto err_1; -+ } -+ } -+ -+ ret = clk_set_rates(clocks, rates, nclock); -+ if (ret >= 0) -+ ret = count; /* to say OK */ -+ -+err_1: -+ kfree(clocks); -+err_0: -+ kfree(rates); -+ return ret; -+} -+ -+static struct kobj_attribute clk_rates_attr = -+ __ATTR(rates, S_IWUSR, NULL, clk_rates_store); -+#endif -+ -+static int __init clk_add_attributes(struct clk *clk, void *data) -+{ -+ int ret; -+ -+ ret = sysfs_update_group(&clk->kobj, &clk_attr_group); -+ -+ return ret; -+} -+ -+static int __init clk_late_init(void) -+{ -+ int ret; -+ -+ ret = clk_for_each(clk_add_attributes, NULL); -+ -+ return ret; -+} -+ -+late_initcall(clk_late_init); -+#endif -diff --git a/drivers/base/init.c b/drivers/base/init.c -index 7bd9b6a..2441b26 100644 ---- a/drivers/base/init.c -+++ b/drivers/base/init.c -@@ -24,6 +24,7 @@ void __init driver_init(void) - buses_init(); - classes_init(); - firmware_init(); -+ clock_init(); - hypervisor_init(); - - /* These are also core pieces, but must come after the -diff --git a/drivers/base/platform.c b/drivers/base/platform.c -index 8b4708e..550d993 100644 ---- a/drivers/base/platform.c -+++ b/drivers/base/platform.c -@@ -17,6 +17,8 @@ - #include <linux/bootmem.h> - #include <linux/err.h> - #include <linux/slab.h> -+#include <linux/clk.h> -+#include "clk.h" - - #include "base.h" - -@@ -272,9 +274,20 @@ int platform_device_add(struct platform_device *pdev) - pr_debug("Registering platform device '%s'. Parent at %s\n", - dev_name(&pdev->dev), dev_name(pdev->dev.parent)); - -+#ifdef CONFIG_GENERIC_CLK_FM -+ clk_add_device(pdev, PDEV_ADDING); -+ -+ ret = device_add(&pdev->dev); -+ -+ clk_add_device(pdev, (ret ? PDEV_ADD_FAILED : PDEV_ADDED)); -+ -+ if (ret == 0) -+ return ret; -+#else - ret = device_add(&pdev->dev); - if (ret == 0) - return ret; -+#endif - - failed: - while (--i >= 0) { -@@ -311,6 +324,9 @@ void platform_device_del(struct platform_device *pdev) - if (type == IORESOURCE_MEM || type == IORESOURCE_IO) - release_resource(r); - } -+#ifdef CONFIG_GENERIC_CLK_FM -+ clk_del_device(pdev); -+#endif - } - } - EXPORT_SYMBOL_GPL(platform_device_del); -@@ -445,7 +461,18 @@ static int platform_drv_probe(struct device *_dev) - struct platform_driver *drv = to_platform_driver(_dev->driver); - struct platform_device *dev = to_platform_device(_dev); - -+#ifdef CONFIG_GENERIC_CLK_FM -+ int ret; -+ ret = clk_probe_device(dev, PDEV_PROBEING); -+ if (ret) -+ return ret; -+ ret = drv->probe(dev); -+ -+ clk_probe_device(dev, (ret ? PDEV_PROBE_FAILED : PDEV_PROBED)); -+ return ret; -+#else - return drv->probe(dev); -+#endif - } - - static int platform_drv_probe_fail(struct device *_dev) -diff --git a/include/linux/clk.h b/include/linux/clk.h -index 1db9bbf..e537bcd 100644 ---- a/include/linux/clk.h -+++ b/include/linux/clk.h -@@ -12,6 +12,7 @@ - #define __LINUX_CLK_H - - struct device; -+struct platform_device; - - /* - * The base API. -@@ -142,4 +143,254 @@ struct clk *clk_get_parent(struct clk *clk); - */ - struct clk *clk_get_sys(const char *dev_id, const char *con_id); - -+/** -+ * clk_set_rates - set the clock rates -+ * @clk: clocks source -+ * @rate: desired clock rates in Hz -+ * @nclks: the number of clocks -+ * -+ * Returns success (0) or negative errno. -+ */ -+int clk_set_rates(struct clk **clk, unsigned long *rates, unsigned long nclks); -+ -+#ifndef CONFIG_GENERIC_CLK_FM -+ -+#define bind_clock(_clk) -+#define pdevice_setclock(_dev, _clk) -+#define pdevice_setclock_byname(_dev, _clkname) -+#define pdevice_num_clocks(_dev) -+#define pdevice_clock(dev, idx) -+ -+#else -+ -+#include <linux/kobject.h> -+#include <linux/klist.h> -+#include <linux/notifier.h> -+#include <linux/pm.h> -+#include <linux/spinlock.h> -+#include <asm/atomic.h> -+ -+ -+/** -+ * Clock operation - -+ * -+ * It's a set of function pointer to identify all the capability on a clock -+ */ -+struct clk_ops { -+/** @init initializes the clock */ -+ int (*init)(struct clk *); -+/** @enable enables the clock */ -+ int (*enable)(struct clk *); -+/** @disable disables the clock */ -+ int (*disable)(struct clk *); -+/** @set_rate sets the new frequency rate */ -+ int (*set_rate)(struct clk *, unsigned long value); -+/** @set_parent sets the new parent clock */ -+ int (*set_parent)(struct clk *clk, struct clk *parent); -+/** @recalc updates the clock rate when the parent clock is updated */ -+ void (*recalc)(struct clk *); -+/** @round returns the allowed rate on the required value */ -+ unsigned long (*round)(struct clk *, unsigned long value); -+/** @eval evaluates the clock rate based on a parent_rate but the -+ * real clock rate is __not__ changed -+ */ -+ unsigned long (*eval)(struct clk *, unsigned long parent_rate); -+}; -+ -+/** -+ * struct clk - clock object -+ */ -+struct clk { -+ spinlock_t lock; -+ -+ struct kobject kobj; -+ struct kobject *kdevices; -+ -+ int id; -+ -+ const char *name; -+ struct module *owner; -+ -+ struct clk *parent; -+ struct clk_ops *ops; -+ -+ void *private_data; -+ -+ unsigned long rate; -+ unsigned long flags; -+ -+ unsigned int nr_active_clocks; -+ unsigned int nr_active_devices; -+ unsigned int nr_clocks; -+ -+ void *towner;/* the transaction owner of the clock */ -+ -+ struct klist childs; -+ struct klist devices; -+ -+ struct klist_node node; /* for global link */ -+ struct klist_node child_node; /* for child link */ -+}; -+ -+#define CLK_ALWAYS_ENABLED (0x1 << 0) -+#define CLK_EVENT_PROPAGATES (0x1 << 1) -+#define CLK_RATE_PROPAGATES CLK_EVENT_PROPAGATES -+/* CLK_AUTO_SWITCHING: enable/disable the clock based on the -+ * current active children -+ */ -+#define CLK_AUTO_SWITCHING (0x1 << 2) -+/* CLK_FOLLOW_PARENT: enable/disable the clock as the parent is -+ * enabled/disabled -+ */ -+#define CLK_FOLLOW_PARENT (0x1 << 3) -+ -+/* -+ * Flags to support the system standby -+ */ -+#define CLK_PM_EXP_SHIFT (24) -+#define CLK_PM_EXP_NRBITS (7) -+#define CLK_PM_RATIO_SHIFT (16) -+#define CLK_PM_RATIO_NRBITS (8) -+#define CLK_PM_EDIT_SHIFT (31) -+#define CLK_PM_EDIT_NRBITS (1) -+#define CLK_PM_TURNOFF (((1<<CLK_PM_EXP_NRBITS)-1) << CLK_PM_EXP_SHIFT) -+ -+int early_clk_register(struct clk *); -+/** -+ * Registers a new clock into the system -+ */ -+int clk_register(struct clk *); -+/** -+ * Unregisters a clock into the system -+ */ -+int clk_unregister(struct clk *); -+ -+/** -+ * Returns the clock rate if the parent clock is 'parent_rate' -+ */ -+unsigned long clk_evaluate_rate(struct clk *, unsigned long parent_rate); -+ -+#define CLK_UNDEFINED_RATE (-1UL) -+/** -+ * Utility functions in the clock framework -+ */ -+int clk_for_each(int (*fn)(struct clk *, void *), void *); -+ -+int clk_for_each_child(struct clk *, int (*fn)(struct clk *, void *), void *); -+ -+/** struct pdev_clk_info - -+ * -+ * It's a meta data used to link the device of linux driver model -+ * to the clock framework. -+ * The device driver developers has to set only the clk field -+ * all the other fileds are managed in the clk core code -+ */ -+struct pdev_clk_info { -+ /** the device owner */ -+ struct platform_device *pdev; -+ /** the clock address */ -+ struct clk *clk; -+ /** used by the clock core*/ -+ struct klist_node node; -+}; -+ -+/******************** clk transition notifiers *******************/ -+#define NOTIFY_CLK_ENTERCHANGE 0x1 -+#define NOTIFY_CLK_PRECHANGE 0x2 -+#define NOTIFY_CLK_POSTCHANGE 0x4 -+#define NOTIFY_CLK_EXITCHANGE 0x8 -+ -+/** struct clk_event -+ * -+ * It's the object propagated during a clock transaction. -+ * During a transaction each device will receive an array of 'struct clk_event' -+ * based on the clocks it uses -+ */ -+struct clk_event { -+ /** on which clock the event is */ -+ struct clk *clk; -+ /** the clock rate before the event */ -+ unsigned long old_rate; -+ /** the clock rate after the event */ -+ unsigned long new_rate; -+}; -+ -+enum clk_event_e { -+ _CLK_NOCHANGE, -+ _CLK_ENABLE, -+ _CLK_DISABLE, -+ _CLK_CHANGE -+}; -+ -+/** -+ * clk_event_decode - -+ * -+ * @event: the events has to be decoded -+ * It's an utility function to identify what each clock -+ * is doing -+ */ -+static inline enum clk_event_e clk_event_decode(struct clk_event const *event) -+{ -+ if (event->old_rate == event->new_rate) -+ return _CLK_NOCHANGE; -+ if (!event->old_rate && event->new_rate) -+ return _CLK_ENABLE; -+ if (event->old_rate && !event->new_rate) -+ return _CLK_DISABLE; -+ return _CLK_CHANGE; -+} -+ -+enum notify_ret_e { -+ NOTIFY_EVENT_HANDLED = 0, /* event handled */ -+ NOTIFY_EVENT_NOTHANDLED, /* event not handled */ -+}; -+ -+/* Some macro device oriented static initialization */ -+#define bind_clock(_clk) \ -+ .nr_clks = 1, \ -+ .clks = (struct pdev_clk_info[]) { { \ -+ .clk = (_clk), \ -+ } }, -+ -+#define pdevice_setclock(_dev, _clk) \ -+ (_dev)->clks[0].clk = (_clk); \ -+ (_dev)->nr_clks = 1; -+ -+#define pdevice_setclock_byname(_dev, _clkname) \ -+ (_dev)->clks[0].clk = clk_get(NULL, _clkname); \ -+ (_dev)->nr_clks = 1; -+ -+#define pdevice_num_clocks(_dev) ((_dev)->nr_clks) -+ -+#define pdevice_clock(dev, idx) ((dev)->clks[(idx)].clk) -+ -+/** -+ * clk_generic_notify - -+ * -+ * @code: the code event -+ * @dev: the platform_device under transaction -+ * @data: the clock event descriptor -+ * -+ * it's a generic notify function for devie with _only_ -+ * one clock. It will : -+ * - accept every 'ENTER' state -+ * - suspend on 'PRE' state -+ * - resume on 'POST' state -+ * - do nothing on 'EXIT' state -+ */ -+int clk_generic_notify(unsigned long code, struct platform_device *dev, -+ void *data); -+ -+/* -+ * clk_generic_evaluate_rate -+ * -+ * @clk: the analised clock -+ * @prate: the parent rate -+ * -+ * Evaluate the clock rate (without hardware modification) based on a 'prate' -+ * parent clock rate. It's based on 'divisor' relationship -+ * between parent and child -+ */ -+unsigned long clk_generic_evaluate_rate(struct clk *clk, unsigned long prate); -+#endif - #endif -diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h -index b67bb5d..db1989d 100644 ---- a/include/linux/platform_device.h -+++ b/include/linux/platform_device.h -@@ -12,6 +12,7 @@ - #define _PLATFORM_DEVICE_H_ - - #include <linux/device.h> -+#include <linux/clk.h> - #include <linux/mod_devicetable.h> - - struct platform_device { -@@ -22,6 +23,11 @@ struct platform_device { - struct resource * resource; - - struct platform_device_id *id_entry; -+#ifdef CONFIG_GENERIC_CLK_FM -+ unsigned long clk_state; /* used by the core */ -+ unsigned long nr_clks; -+ struct pdev_clk_info *clks; -+#endif - }; - - #define platform_get_device_id(pdev) ((pdev)->id_entry) -@@ -61,6 +67,9 @@ struct platform_driver { - int (*resume_early)(struct platform_device *); - int (*resume)(struct platform_device *); - struct device_driver driver; -+#ifdef CONFIG_GENERIC_CLK_FM -+ int (*notify)(unsigned long code, struct platform_device *, void *); -+#endif - struct platform_device_id *id_table; - }; - -diff --git a/init/Kconfig b/init/Kconfig -index 0682ecc..4254c5f 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1042,6 +1042,29 @@ config SLOW_WORK - - See Documentation/slow-work.txt. - -+config GENERIC_CLK_FM -+ default n -+ depends on EXPERIMENTAL -+ bool "Generic Clock Framework" -+ help -+ Add the clock framework in the Linux driver model -+ to track the clocks used by each devices and drivers -+ -+config CLK_FORCE_GENERIC_EVALUATE -+ depends on GENERIC_CLK_FM -+ default n -+ bool "Force the clk_generic_evaluate_rate" -+ help -+ Say the if you want use the clk_generic_evaluate_rate on every clock -+ without evaluate_rate -+ -+config CLK_DEBUG -+ depends on GENERIC_CLK_FM -+ default n -+ bool "Debug the Generic Clk Framework" -+ help -+ Prints some message to debug the clock framework -+ - endmenu # General setup - - config HAVE_GENERIC_DMA_COHERENT --- -1.6.2.5 diff --git a/a/3.hdr b/a/3.hdr deleted file mode 100644 index 4b86001..0000000 --- a/a/3.hdr +++ /dev/null @@ -1,4 +0,0 @@ -Content-Type: text/plain; charset="us-ascii" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Content-Disposition: inline diff --git a/a/3.txt b/a/3.txt deleted file mode 100644 index 8133cf0..0000000 --- a/a/3.txt +++ /dev/null @@ -1,4 +0,0 @@ -_______________________________________________ -linux-arm-kernel mailing list -linux-arm-kernel@lists.infradead.org -http://lists.infradead.org/mailman/listinfo/linux-arm-kernel diff --git a/a/content_digest b/N1/content_digest index 0140af8..729cc90 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -1,10 +1,8 @@ - "From\0Francesco VIRLINZI <francesco.virlinzi@st.com>\0" + "From\0francesco.virlinzi@st.com (Francesco VIRLINZI)\0" "Subject\0[Proposal] [PATCH] generic clock framework\0" "Date\0Tue, 10 Nov 2009 15:00:59 +0100\0" - "To\0linux-arm-kernel@lists.infradead.org" - Linux-sh <linux-sh@vger.kernel.org> - " linux-embedded@vger.kernel.org\0" - "\02:1.1\0" + "To\0linux-arm-kernel@lists.infradead.org\0" + "\00:1\0" "b\0" "Hi all\n" "\n" @@ -59,3155 +57,13 @@ "to extend/fix/share it.\n" "\n" "Regards\n" - Francesco - "\02:1.2\0" - "b\0" - "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" - "<html>\n" - "<head>\n" - "\n" - "<meta http-equiv=\"content-type\" content=\"text/html; charset=ISO-8859-1\">\n" - "</head>\n" - "<body text=\"#000000\" bgcolor=\"#ffffff\">\n" - "<big><big><tt>Hi all<br>\n" - "<br>\n" - "I'm Francesco and I work in STMicroelectronics<br>\n" - "<br>\n" - "In the last ELC-E_2009 I spoke on a generic clock framework I'm working\n" - "on<br>\n" - " (see\n" - "<a class=\"moz-txt-link-freetext\" href=\"http://tree.celinuxforum.org/CelfPubWiki/ELCEurope2009Presentations?action=AttachFile&do=view&target=ELC_E_2009_Generic_Clock_Framework.pdf\">http://tree.celinuxforum.org/CelfPubWiki/ELCEurope2009Presentations?action=AttachFile&do=view&target=ELC_E_2009_Generic_Clock_Framework.pdf</a>).<br>\n" - "<br>\n" - "</tt><tt>I wrote the gcf to manage both clocks the platform_devices\n" - "during a clock operation.<br>\n" - "<br>\n" - "</tt><tt>The main features are:<br>\n" - " - it's integrated in the LDM<br>\n" - "</tt></big></big><big><big><tt> - it tracks the clock-to-clock\n" - "relationship<br>\n" - " - it tracks the clock-to-device relationship<br>\n" - "<br>\n" - "</tt></big></big><big><big><tt> - it has sysfs interface<br>\n" - " - - the user can navigate the clock tree under /sys/clocks/...<br>\n" - "<br>\n" - " - it uses the linux API (<linux/clk.h>) with some extra\n" - "functions (to register/unregister a clock<br>\n" - " and other utility functions as clk_for_each())<br>\n" - "<br>\n" - " - it involves the platform_device and the platform_driver in the clock\n" - "propagation.<br>\n" - " - - basically each clock operation is managed as a transaction which\n" - "evolves step by step.<br>\n" - " - - </tt><tt>all the clock rates are evaluated (before the clk\n" - "operation is actually done)<br>\n" - "</tt><tt> - - each platform_device can check (</tt><tt>before the clk\n" - "operation is </tt></big></big><big><big><tt>actually</tt></big></big><big><big><tt>\n" - "done</tt><tt>) the clk environment<br>\n" - " it will have at the end of clock operation and if required it can\n" - "reject the operation.<br>\n" - " - - each clock operation is </tt></big></big><big><big><tt>actually</tt></big></big><big><big><tt>\n" - "executed only if all the </tt><tt>platform_</tt><tt>devices accept the\n" - "operation it-self<br>\n" - "<br>\n" - "<br>\n" - "Moreover a common clock framework could be used to avoid a lot of\n" - "duplicated and/or similar code<br>\n" - " just a grep of 'EXPORT_SYMBOL\\(clk_enable' under arch/arm finds 22\n" - "entries.<br>\n" - "<br>\n" - "The patch is based on a 2.6.30 kernel also if it has a preliminary\n" - "integration with the PM_RUNTIME<br>\n" - " support.<br>\n" - "<br>\n" - "It works on our st40 (an sh4 cpu based system) no test/porting was done\n" - "on any ARM platform.<br>\n" - "<br>\n" - "It would be mainly a starting point for a discussion and I'm available\n" - "to extend/fix/share it.<br>\n" - "<br>\n" - "Regards<br>\n" - " Francesco</tt></big></big><br>\n" - "</body>\n" - "</html>\n" - "\01:2\0" - "fn\00001-generic-clock-framework.patch\0" - "b\0" - "From 4e065fb9247ec511bfdc88001f0713977d3f4e89 Mon Sep 17 00:00:00 2001\n" - "From: Francesco Virlinzi <francesco.virlinzi@st.com>\n" - "Date: Fri, 23 Oct 2009 15:26:42 +0200\n" - "Subject: [PATCH] generic clock framework\n" - "\n" - "version: 0.6.2\n" - "\n" - "Signed-off-by: Francesco Virlinzi <francesco.virlinzi@st.com>\n" - "---\n" - " drivers/base/Makefile | 4 +\n" - " drivers/base/base.h | 5 +\n" - " drivers/base/clk.c | 1606 +++++++++++++++++++++++++++++++++++++++\n" - " drivers/base/clk.h | 319 ++++++++\n" - " drivers/base/clk_pm.c | 197 +++++\n" - " drivers/base/clk_utils.c | 456 +++++++++++\n" - " drivers/base/init.c | 1 +\n" - " drivers/base/platform.c | 27 +\n" - " include/linux/clk.h | 251 ++++++\n" - " include/linux/platform_device.h | 9 +\n" - " init/Kconfig | 23 +\n" - " 11 files changed, 2898 insertions(+), 0 deletions(-)\n" - " create mode 100644 drivers/base/clk.c\n" - " create mode 100644 drivers/base/clk.h\n" - " create mode 100644 drivers/base/clk_pm.c\n" - " create mode 100644 drivers/base/clk_utils.c\n" - "\n" - "diff --git a/drivers/base/Makefile b/drivers/base/Makefile\n" - "index b5b8ba5..b78a2bf 100644\n" - "--- a/drivers/base/Makefile\n" - "+++ b/drivers/base/Makefile\n" - "@@ -16,6 +16,10 @@ ifeq ($(CONFIG_SYSFS),y)\n" - " obj-$(CONFIG_MODULES)\t+= module.o\n" - " endif\n" - " obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o\n" - "+ifdef CONFIG_GENERIC_CLK_FM\n" - "+obj-y\t\t\t+= clk.o clk_utils.o\n" - "+obj-$(CONFIG_PM)\t+= clk_pm.o\n" - "+endif\n" - " \n" - " ifeq ($(CONFIG_DEBUG_DRIVER),y)\n" - " EXTRA_CFLAGS += -DDEBUG\n" - "diff --git a/drivers/base/base.h b/drivers/base/base.h\n" - "index b528145..bc5b9e8 100644\n" - "--- a/drivers/base/base.h\n" - "+++ b/drivers/base/base.h\n" - "@@ -94,6 +94,11 @@ extern int devices_init(void);\n" - " extern int buses_init(void);\n" - " extern int classes_init(void);\n" - " extern int firmware_init(void);\n" - "+#ifdef CONFIG_GENERIC_CLK_FM\n" - "+extern int clock_init(void);\n" - "+#else\n" - "+static inline int clock_init(void){ return 0; }\n" - "+#endif\n" - " #ifdef CONFIG_SYS_HYPERVISOR\n" - " extern int hypervisor_init(void);\n" - " #else\n" - "diff --git a/drivers/base/clk.c b/drivers/base/clk.c\n" - "new file mode 100644\n" - "index 0000000..7feae61\n" - "--- /dev/null\n" - "+++ b/drivers/base/clk.c\n" - "@@ -0,0 +1,1606 @@\n" - "+/*\n" - "+ * -------------------------------------------------------------------------\n" - "+ * clk.c\n" - "+ * -------------------------------------------------------------------------\n" - "+ * (C) STMicroelectronics 2008\n" - "+ * (C) STMicroelectronics 2009\n" - "+ * Author: Francesco M. Virlinzi <francesco.virlinzi@st.com>\n" - "+ * -------------------------------------------------------------------------\n" - "+ * May be copied or modified under the terms of the GNU General Public\n" - "+ * License v.2 ONLY. See linux/COPYING for more information.\n" - "+ *\n" - "+ * -------------------------------------------------------------------------\n" - "+ */\n" - "+\n" - "+#include <linux/platform_device.h>\n" - "+#include <linux/clk.h>\n" - "+#include <linux/klist.h>\n" - "+#include <linux/sysdev.h>\n" - "+#include <linux/kref.h>\n" - "+#include <linux/kobject.h>\n" - "+#include <linux/err.h>\n" - "+#include <linux/spinlock.h>\n" - "+#include <asm/atomic.h>\n" - "+#include \"clk.h\"\n" - "+#include \"base.h\"\n" - "+\n" - "+#define CLK_NAME\t\t\"Generic Clk Framework\"\n" - "+#define CLK_VERSION\t\t\"0.6.2\"\n" - "+\n" - "+/* #define CLK_SAFE_CODE */\n" - "+\n" - "+klist_entry_support(clock, clk, node)\n" - "+klist_entry_support(child_clock, clk, child_node)\n" - "+klist_entry_support(dev_info, pdev_clk_info, node)\n" - "+\n" - "+#define to_clk(ptr)\tcontainer_of(ptr, struct clk, kobj)\n" - "+#define to_tnode(ptr)\tcontainer_of(ptr, struct clk_tnode, pnode)\n" - "+\n" - "+static int sysfs_clk_attr_show(struct kobject *kobj,\n" - "+\t\t\t\tstruct attribute *attr, char *buf)\n" - "+{\n" - "+\tssize_t ret = -EIO;\n" - "+\tstruct kobj_attribute *kattr\n" - "+\t = container_of(attr, struct kobj_attribute, attr);\n" - "+\tif (kattr->show)\n" - "+\t\tret = kattr->show(kobj, kattr, buf);\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+static ssize_t\n" - "+sysfs_clk_attr_store(struct kobject *kobj, struct attribute *attr,\n" - "+\t\t\tconst char *buf, size_t count)\n" - "+{\n" - "+\tssize_t ret = -EIO;\n" - "+\tstruct kobj_attribute *kattr\n" - "+\t = container_of(attr, struct kobj_attribute, attr);\n" - "+\tif (kattr->store)\n" - "+\t\tret = kattr->store(kobj, kattr, buf, count);\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+static struct sysfs_ops clk_sysfs_ops = {\n" - "+\t.show = sysfs_clk_attr_show,\n" - "+\t.store = sysfs_clk_attr_store,\n" - "+};\n" - "+\n" - "+static struct kobj_type ktype_clk = {\n" - "+\t.sysfs_ops = &clk_sysfs_ops,\n" - "+};\n" - "+\n" - "+static struct clk *check_clk(struct clk *);\n" - "+\n" - "+static struct kobject *clk_kobj;\n" - "+static DEFINE_MUTEX(clk_list_sem);\n" - "+static atomic_t transaction_counter = ATOMIC_INIT(0);\n" - "+struct klist clk_list = KLIST_INIT(clk_list, NULL, NULL);\n" - "+\n" - "+klist_function_support(child, clk, child_node, kobj)\n" - "+klist_function_support(device, pdev_clk_info, node, pdev->dev.kobj)\n" - "+\n" - "+/*\n" - "+ * The ___clk_xxx operations doesn't raise propagation\n" - "+ * they are used to operate on the real clock\n" - "+ */\n" - "+static int\n" - "+__clk_operations(struct clk *clk, unsigned long rate,\n" - "+\tenum clk_ops_id const id_ops)\n" - "+{\n" - "+\tint ret = 0;\n" - "+\tunsigned long *ops_fns = (unsigned long *)clk->ops;\n" - "+\tif (likely(ops_fns && ops_fns[id_ops])) {\n" - "+\t\tint (*fns)(struct clk *clk, unsigned long rate)\n" - "+\t\t\t= (void *)ops_fns[id_ops];\n" - "+\t\tunsigned long flags;\n" - "+\t\tspin_lock_irqsave(&clk->lock, flags);\n" - "+\t\tret = fns(clk, rate);\n" - "+\t\tspin_unlock_irqrestore(&clk->lock, flags);\n" - "+\t}\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+static inline int __clk_init(struct clk *clk)\n" - "+{\n" - "+\tpr_debug(\": %s\\n\", clk->name);\n" - "+\treturn __clk_operations(clk, 0, __CLK_INIT);\n" - "+}\n" - "+static inline int __clk_enable(struct clk *clk)\n" - "+{\n" - "+\tpr_debug(\": %s\\n\", clk->name);\n" - "+\treturn __clk_operations(clk, 0, __CLK_ENABLE);\n" - "+}\n" - "+static inline int __clk_disable(struct clk *clk)\n" - "+{\n" - "+\tpr_debug(\": %s\\n\", clk->name);\n" - "+\treturn __clk_operations(clk, 0, __CLK_DISABLE);\n" - "+}\n" - "+static inline int __clk_set_rate(struct clk *clk, unsigned long rate)\n" - "+{\n" - "+\tpr_debug(\": %s\\n\", clk->name);\n" - "+\treturn __clk_operations(clk, rate, __CLK_SET_RATE);\n" - "+}\n" - "+static inline int __clk_set_parent(struct clk *clk, struct clk *parent)\n" - "+{\n" - "+\tpr_debug(\": %s\\n\", clk->name);\n" - "+\treturn __clk_operations(clk, (unsigned long)parent, __CLK_SET_PARENT);\n" - "+}\n" - "+static inline int __clk_recalc_rate(struct clk *clk)\n" - "+{\n" - "+\tpr_debug(\": %s\\n\", clk->name);\n" - "+\treturn __clk_operations(clk, 0, __CLK_RECALC);\n" - "+}\n" - "+static inline int __clk_round(struct clk *clk, unsigned long value)\n" - "+{\n" - "+\tpr_debug(\": %s\\n\", clk->name);\n" - "+\treturn __clk_operations(clk, value, __CLK_ROUND);\n" - "+}\n" - "+\n" - "+static inline int __clk_eval(struct clk *clk, unsigned long prate)\n" - "+{\n" - "+#ifndef CONFIG_CLK_FORCE_GENERIC_EVALUATE\n" - "+\tpr_debug(\": %s\\n\", clk->name);\n" - "+\treturn\t__clk_operations(clk, prate, __CLK_EVAL);\n" - "+#else\n" - "+\tunsigned long rate, flags;\n" - "+\tpr_debug(\": %s\\n\", clk->name);\n" - "+\tif (likely(clk->ops && clk->ops->eval)) {\n" - "+\t\tspin_lock_irqsave(&clk->lock, flags);\n" - "+\t\trate = clk->ops->eval(clk, prate);\n" - "+\t\tspin_unlock_irqrestore(&clk->lock, flags);\n" - "+\t} else\n" - "+\t\trate = clk_generic_evaluate_rate(clk, prate);\n" - "+\treturn rate;\n" - "+#endif\n" - "+}\n" - "+\n" - "+#ifdef CONFIG_PM_RUNTIME\n" - "+static int\n" - "+clk_pm_runtime_devinfo(enum rpm_status code, struct pdev_clk_info *info)\n" - "+{\n" - "+\tstruct platform_device *pdev = info->pdev;\n" - "+\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\tswitch (code) {\n" - "+\tcase RPM_ACTIVE:\n" - "+\t\treturn clk_notify_child_event(CHILD_DEVICE_ENABLED, info->clk);\n" - "+\tcase RPM_SUSPENDED:\n" - "+\t\treturn clk_notify_child_event(CHILD_DEVICE_DISABLED, info->clk);\n" - "+\t}\n" - "+\treturn -EINVAL;\n" - "+}\n" - "+\n" - "+int clk_pm_runtime_device(enum rpm_status code, struct platform_device *dev)\n" - "+{\n" - "+\tint idx;\n" - "+\tint ret = 0;\n" - "+\tstruct pdev_clk_info *info;\n" - "+\n" - "+\tif (!dev)\n" - "+\t\treturn -EFAULT;\n" - "+\n" - "+\tif (!dev->clks || !pdevice_num_clocks(dev))\n" - "+\t\treturn 0;\n" - "+\n" - "+\tpr_debug(\"\\n\");\n" - "+/*\n" - "+ *\tCheck if the device is under a transaction.\n" - "+ * \tIf so the GCFdoesn't raise a 'clk_pm_runtime_devinfo'\n" - "+ *\tall the device change will be notified on 'tnode_transaction_complete'\n" - "+ *\tif required....\n" - "+ */\n" - "+\tif (atomic_read((atomic_t *)&dev->clk_flags)) {\n" - "+\t\tpr_debug(\"%s.%d under transaction\\n\", dev->name, dev->id);\n" - "+\t\treturn ret;\n" - "+\t}\n" - "+\tfor (idx = 0, info = dev->clks; idx < pdevice_num_clocks(dev); ++idx)\n" - "+\t\tret |= clk_pm_runtime_devinfo(&info[idx], state, 0);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+#else\n" - "+#define clk_pm_runtime_devinfo(x, y)\n" - "+#define clk_pm_runtime_device(x, y)\n" - "+#endif\n" - "+\n" - "+/**\n" - "+ * tnode_malloc\n" - "+ *\n" - "+ * Allocs the memory for both the transaction and the\n" - "+ * clk_event objects\n" - "+ */\n" - "+static struct clk_tnode *tnode_malloc(struct clk_tnode *parent,\n" - "+\tunsigned long nevent)\n" - "+{\n" - "+\tstruct clk_event *evt;\n" - "+\tstruct clk_tnode *node;\n" - "+\n" - "+\tif (nevent > 32)\n" - "+\t\treturn NULL;\n" - "+\n" - "+\tnode = kmalloc(sizeof(*node) + nevent *\tsizeof(*evt), GFP_KERNEL);\n" - "+\n" - "+\tif (!node)\n" - "+\t\treturn NULL;\n" - "+\n" - "+\tevt = (struct clk_event *)(sizeof(struct clk_tnode) + (long)node);\n" - "+\n" - "+\tnode->tid = atomic_inc_return(&transaction_counter);\n" - "+\tnode->parent = parent;\n" - "+\tnode->size = nevent;\n" - "+\tnode->events = evt;\n" - "+\tnode->events_map = 0;\n" - "+\tINIT_LIST_HEAD(&node->childs);\n" - "+\n" - "+\treturn node;\n" - "+}\n" - "+\n" - "+/**\n" - "+ * tnode_free\n" - "+ *\n" - "+ * Free the tnode memory\n" - "+ */\n" - "+static void tnode_free(struct clk_tnode *node)\n" - "+{\n" - "+\tif (tnode_get_parent(node)) {\n" - "+\t\tlist_del(&node->pnode);\n" - "+\t\tkfree(node);\n" - "+\t}\n" - "+}\n" - "+\n" - "+/**\n" - "+ * tnode_check_clock -\n" - "+ *\n" - "+ * @node: the tnode object\n" - "+ * @clk: the clock object\n" - "+ *\n" - "+ * returns a boolean value\n" - "+ * it checks if the clock (clk) is managed by the\n" - "+ * tnode (node) or any parent node\n" - "+ */\n" - "+static int __must_check\n" - "+tnode_check_clock(struct clk_tnode *node, struct clk *clk)\n" - "+{\n" - "+\tint j;\n" - "+\tfor (; node; node = tnode_get_parent(node))\n" - "+\t\t/* scans all the event */\n" - "+\t\ttnode_for_each_valid_events(node, j)\n" - "+\t\t\tif (tnode_get_clock(node, j) == clk)\n" - "+\t\t\t\t\treturn 1; /* FOUND!!! */\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+/**\n" - "+ * tnode_lock_clocks -\n" - "+ *\n" - "+ * @node: the tnode object\n" - "+ *\n" - "+ * marks all the clocks under transaction to be sure there is no more\n" - "+ * than one transaction for each clock\n" - "+ */\n" - "+static int __must_check\n" - "+tnode_lock_clocks(struct clk_tnode *node)\n" - "+{\n" - "+\tint i;\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\t/* 1. try to mark all the clocks in transaction */\n" - "+\tfor (i = 0; i < tnode_get_size(node); ++i)\n" - "+\t\tif (clk_set_towner(tnode_get_clock(node, i), node)) {\n" - "+\t\t\tstruct clk *clkp = tnode_get_clock(node, i);\n" - "+\t\t\t/* this clock is already locked */\n" - "+\t\t\t/* we accept that __only__ if it is locked by a\n" - "+\t\t\t * parent tnode!!!\n" - "+\t\t\t */\n" - "+\t\t\tif (!tnode_get_parent(node)) {\n" - "+\t\t\t\tpr_debug(\"Error clk %s locked but \"\n" - "+\t\t\t\t\t \"there is no parent!\\n\", clkp->name);\n" - "+\t\t\t\tgoto err_0;\n" - "+\t\t\t}\n" - "+\t\t\tpr_debug(\"clk %s already locked\\n\", clkp->name);\n" - "+\t\t\tif (tnode_check_clock(tnode_get_parent(node), clkp)) {\n" - "+\t\t\t\tpr_debug(\"ok clk %s locked \"\n" - "+\t\t\t\t\t \"by a parent\\n\", clkp->name);\n" - "+\t\t\t\tcontinue;\n" - "+\t\t\t} else\n" - "+\t\t\t\tgoto err_0;\n" - "+\t\t} else\n" - "+\t\t\t/* set the event as valid in the bitmap*/\n" - "+\t\t\ttnode_set_map_id(node, i);\n" - "+\n" - "+/*\n" - "+ * all the clocks are marked succesfully or all the clock on\n" - "+ * this tnode are already managed by parent\n" - "+ */\n" - "+\tif (!tnode_get_map(node)) { /* check if the bitamp is not zero */\n" - "+\t\tif (tnode_get_parent(node))\n" - "+\t\t\tkfree(node);\n" - "+\t\treturn 1;\n" - "+\t}\n" - "+\n" - "+ /*\n" - "+ * all the clocks are marked succesfully _and_ there is at least\n" - "+ * one clock marked.\n" - "+ * Add the tnode to its parent! and return\n" - "+ */\n" - "+\tif (tnode_get_parent(node))\n" - "+\t\tlist_add_tail(&node->pnode, &tnode_get_parent(node)->childs);\n" - "+\n" - "+\treturn 0;\n" - "+\n" - "+err_0:\n" - "+\tpr_debug(\"Error on clock locking...\\n\");\n" - "+\tfor (--i; i >= 0; --i)\n" - "+\t\tif (tnode_check_map_id(node, i))\n" - "+\t\t\tclk_clean_towner(tnode_get_clock(node, i));\n" - "+\n" - "+\tif (tnode_get_parent(node))\n" - "+\t\tkfree(node);\n" - "+\n" - "+\treturn -EINVAL;\n" - "+}\n" - "+\n" - "+/**\n" - "+ * tnode_transaction_complete -\n" - "+ *\n" - "+ * checks the devices status when the transaction is complete.\n" - "+ */\n" - "+static void tnode_transaction_complete(struct clk_tnode *node)\n" - "+{\n" - "+\tstruct klist_iter i;\n" - "+\tstruct pdev_clk_info *dev_info;\n" - "+\tint j;\n" - "+\n" - "+\tpr_debug(\"tid: %d\\n\", (int)tnode_get_id(node));\n" - "+\ttnode_for_each_valid_events(node, j) {\n" - "+\tklist_iter_init(&tnode_get_clock(node, j)->devices, &i);\n" - "+\twhile ((dev_info = next_dev_info(&i))) {\n" - "+\t\t/* update the device state */\n" - "+\t\tstruct platform_device *dev = dev_info->pdev;\n" - "+\t\tswitch (dev->clk_state & (DEV_SUSPENDED_ON_TRANSACTION |\n" - "+\t\t\t\t\t DEV_RESUMED_ON_TRANSACTION)) {\n" - "+\t\tcase 0: /* this device doesn't care on the clock transaction */\n" - "+\t\t\tatomic_clear_mask(DEV_ON_TRANSACTION,\n" - "+\t\t\t\t(atomic_t *)&dev->clk_state);\n" - "+\t\t\tbreak;\n" - "+\n" - "+\t\tcase (DEV_SUSPENDED_ON_TRANSACTION |\n" - "+\t\t\tDEV_RESUMED_ON_TRANSACTION):\n" - "+\t\t\t/* this device was suspended and\n" - "+\t\t\t * resumed therefore no real change\n" - "+\t\t\t */\n" - "+\t\t\tpr_debug(\"dev: %s.%d \"\n" - "+\t\t\t\t\"Suspended&Resumed (no child event)\\n\",\n" - "+\t\t\t\tdev->name, dev->id);\n" - "+\t\t\tatomic_clear_mask(DEV_ON_TRANSACTION |\n" - "+\t\t\t\t\t DEV_SUSPENDED_ON_TRANSACTION |\n" - "+\t\t\t\t\t DEV_RESUMED_ON_TRANSACTION,\n" - "+\t\t\t\t\t (atomic_t *)&dev->clk_state);\n" - "+\t\t\tbreak;\n" - "+\t\tcase DEV_SUSPENDED_ON_TRANSACTION:\n" - "+\t\t\tatomic_clear_mask(DEV_ON_TRANSACTION |\n" - "+\t\t\t\tDEV_SUSPENDED_ON_TRANSACTION,\n" - "+\t\t\t\t(atomic_t *)&dev->clk_state);\n" - "+\t\t\tpr_debug(\"dev: %s.%d Suspended\\n\",\n" - "+\t\t\t\tdev->name, dev->id);\n" - "+\t\t\tclk_pm_runtime_device(RPM_SUSPENDED, dev);\n" - "+\t\t\tbreak;\n" - "+\t\tcase DEV_RESUMED_ON_TRANSACTION:\n" - "+\t\t\tatomic_clear_mask(DEV_ON_TRANSACTION |\n" - "+\t\t\t\tDEV_RESUMED_ON_TRANSACTION,\n" - "+\t\t\t\t(atomic_t *)&dev->clk_state);\n" - "+\t\t\tpr_debug(\"dev: %s.%d Resumed\\n\",\n" - "+\t\t\t\tdev->name, dev->id);\n" - "+\t\t\tclk_pm_runtime_device(RPM_ACTIVE, dev);\n" - "+\t\t\tbreak;\n" - "+\n" - "+\t\tdefault:\n" - "+\t\t\tprintk(KERN_ERR \"%s: device %s,%d clk_flags _not_ valid %u\\n\",\n" - "+\t\t\t\t__func__, dev->name, dev->id,\n" - "+\t\t\t\t(unsigned int)dev->clk_state);\n" - "+\t\t}\n" - "+\t}\n" - "+\tklist_iter_exit(&i);\n" - "+\tclk_clean_towner(tnode_get_clock(node, j));\n" - "+\t}\n" - "+\tpr_debug(\"tid: %d exit\\n\", (int)tnode_get_id(node));\n" - "+\treturn;\n" - "+}\n" - "+\n" - "+/*\n" - "+ * Check if the clk is registered\n" - "+ */\n" - "+#ifdef CLK_SAFE_CODE\n" - "+static struct clk *check_clk(struct clk *clk)\n" - "+{\n" - "+\tstruct clk *clkp;\n" - "+\tstruct clk *result = NULL;\n" - "+\tstruct klist_iter i;\n" - "+\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\tklist_iter_init(&clk_list, &i);\n" - "+\twhile ((clkp = next_clock(&i)))\n" - "+\t\tif (clk == clkp) {\n" - "+\t\t\tresult = clk;\n" - "+\t\t\tbreak;\n" - "+\t\t}\n" - "+\tklist_iter_exit(&i);\n" - "+\treturn result;\n" - "+}\n" - "+#else\n" - "+static inline struct clk *check_clk(struct clk *clk)\n" - "+{\n" - "+\treturn clk;\n" - "+}\n" - "+#endif\n" - "+\n" - "+enum child_event_e {\n" - "+\tCHILD_CLOCK_ENABLED = 1,\n" - "+\tCHILD_CLOCK_DISABLED,\n" - "+\tCHILD_DEVICE_ENABLED,\n" - "+\tCHILD_DEVICE_DISABLED,\n" - "+};\n" - "+\n" - "+static int\n" - "+clk_notify_child_event(enum child_event_e const code, struct clk *clk)\n" - "+{\n" - "+\tif (!clk)\n" - "+\t\treturn 0;\n" - "+\n" - "+\tswitch (code) {\n" - "+\tcase CHILD_CLOCK_ENABLED:\n" - "+\t\t++clk->nr_active_clocks;\n" - "+\t\tbreak;\n" - "+\tcase CHILD_CLOCK_DISABLED:\n" - "+\t\t--clk->nr_active_clocks;\n" - "+\t\tbreak;\n" - "+\tcase CHILD_DEVICE_ENABLED:\n" - "+\t\t++clk->nr_active_devices;\n" - "+\t\tbreak;\n" - "+\tcase CHILD_DEVICE_DISABLED:\n" - "+\t\t--clk->nr_active_devices;\n" - "+\t\tbreak;\n" - "+\t}\n" - "+\n" - "+\tif (clk_is_auto_switching(clk)) {\n" - "+\t\t/*\n" - "+\t\t * Check if there are still users\n" - "+\t\t */\n" - "+\t\tif (!clk->nr_active_devices && !clk->nr_active_clocks)\n" - "+\t\t\tclk_disable(clk);\n" - "+\t\telse if (!clk_get_rate(clk)) /* if off.. turn-on */\n" - "+\t\t\tclk_enable(clk);\n" - "+\t}\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+/**\n" - "+ * clk_dev_events_malloc -\n" - "+ *\n" - "+ * builds a struct clk_event array (dev_event).\n" - "+ * the array size (how many elements) is based on device_num_clocks(dev)\n" - "+ * the contenets of each element is equal to:\n" - "+ * - the events array (if the idx-clock is under transaction)\n" - "+ * - the current clock setting if the idx-clock isn't under transaction\n" - "+ */\n" - "+static struct clk_event * __must_check\n" - "+clk_dev_events_malloc(struct platform_device const *dev)\n" - "+{\n" - "+\tstruct clk_event *dev_events;\n" - "+\tstruct clk_tnode *node;\n" - "+\tint i, j;\n" - "+\tpr_debug(\"\\n\");\n" - "+/*\n" - "+ * 1. simple case:\n" - "+ *\t- device_num_clocks(dev) = 1\n" - "+ */\n" - "+\tif (pdevice_num_clocks(dev) == 1) {\n" - "+\t\tnode = (struct clk_tnode *)pdevice_clock(dev, 0)->towner;\n" - "+\t\tfor (i = 0; i < tnode_get_size(node); ++i)\n" - "+\t\t\tif (tnode_get_clock(node, i) == pdevice_clock(dev, 0))\n" - "+\t\t\t\treturn tnode_get_event(node, i);\n" - "+\t}\n" - "+/*\n" - "+ * 2. - device_num_clocks(dev) > 1\n" - "+ *\tGCF has to build a dedicated device events (devents) array\n" - "+ *\tfor this device! sorted as the device registered it-self!\n" - "+ */\n" - "+\tdev_events = kmalloc(sizeof(*dev_events) * pdevice_num_clocks(dev),\n" - "+\t\t\tGFP_KERNEL);\n" - "+\tif (!dev_events)\n" - "+\t\treturn NULL;\n" - "+\n" - "+\tfor (i = 0; i < pdevice_num_clocks(dev); ++i) {\n" - "+\t\tnode = (struct clk_tnode *)pdevice_clock(dev, i)->towner;\n" - "+\t\tdev_events[i].clk = pdevice_clock(dev, i);\n" - "+\t\tif (!node) {/* this means this clocs isn't under transaction */\n" - "+\t\t dev_events[i].old_rate =\n" - "+\t\t\t\tclk_get_rate(pdevice_clock(dev, i));\n" - "+\t\t dev_events[i].new_rate =\n" - "+\t\t\t\tclk_get_rate(pdevice_clock(dev, i));\n" - "+\t\t continue;\n" - "+\t\t}\n" - "+\t\t/* search the right clk_event */\n" - "+\t\tfor (j = 0; tnode_get_clock(node, j) != pdevice_clock(dev, i);\n" - "+\t\t ++j);\n" - "+\n" - "+\t\tdev_events[i].old_rate = tnode_get_event(node, j)->old_rate;\n" - "+\t\tdev_events[i].new_rate = tnode_get_event(node, j)->new_rate;\n" - "+\t}\n" - "+\treturn dev_events;\n" - "+}\n" - "+\n" - "+/**\n" - "+ * clk_devents_free -\n" - "+ * free the devent allocated on the device dev.\n" - "+ */\n" - "+static inline void\n" - "+clk_dev_events_free(struct clk_event *dev_events, struct platform_device *dev)\n" - "+{\n" - "+\tif (pdevice_num_clocks(dev) == 1)\n" - "+\t\treturn ;\n" - "+\tkfree(dev_events);\n" - "+}\n" - "+\n" - "+/**\n" - "+ * clk_trnsc_fsm -\n" - "+ *\n" - "+ * propagate the transaction to all the childs\n" - "+ * each transaction has the following life-time:\n" - "+ *\n" - "+ *\t+---------------+\n" - "+ *\t| ENTER_CLK\t| The ENTER state only for clocks\n" - "+ *\t+---------------+ - acquires all the clock of the transaction\n" - "+ *\t\t|\t - builds the transaction graph\n" - "+ *\t\t|\t - for each clock generates a child transaction\n" - "+ *\t\t|\n" - "+ * +---------------------+\n" - "+ * |\t+---------------+ |\n" - "+ * |\t| ENTER_DEV \t| | The ENTER state only for devices\n" - "+ * | +---------------+ | - >> NOTIFY_CLK_ENTERCHANGE << notified\n" - "+ * |\t\t|\t | - - the device could refuse the operation\n" - "+ * |\t\t|\t |\n" - "+ * |\t+---------------+ |\n" - "+ * |\t| PRE_DEV\t| | The PRE state only devices\n" - "+ * |\t+---------------+ | - >> NOTIFY_CLK_PRECHANGE << notified\n" - "+ * |\t\t|\t | - - the device could be suspended\n" - "+ * +---------------------+\n" - "+ *\t\t|\n" - "+ *\t+---------------+\n" - "+ * \t| CHANGE_CLK\t| The CHANGE state only for clocks\n" - "+ *\t+---------------+ - updates all the physical clocks\n" - "+ *\t\t|\t and relative clk_event_s according to\n" - "+ *\t\t|\t the hw value.\n" - "+ * +---------------------+\n" - "+ * |\t\t|\t |\n" - "+ * |\t+---------------+ |\n" - "+ * |\t| POST_DEV\t| | The POST state only for devices\n" - "+ * | +---------------+ | - >> NOTIFY_CLK_POSTCHANGE << notified\n" - "+ * |\t\t|\t | - - the devices could be resumed\n" - "+ * |\t\t|\t |\n" - "+ * |\t+---------------+ |\n" - "+ * |\t| EXIT_DEV\t| | The EXIT state only for devices\n" - "+ * | +---------------+ | - >> NOTIFY_CLK_EXITCHANGE << notified\n" - "+ * |\t\t|\t | - - the devices is aware all the other\n" - "+ * +---------------------+\t devices are resumed.\n" - "+ *\t\t|\n" - "+ *\t+---------------+\n" - "+ *\t| EXIT_CLK\t| The EXIT state only for clocks\n" - "+ *\t+---------------+ (to free all the memory)\n" - "+ *\t\t\t\t- Free all the allocated memory\n" - "+ *\n" - "+ */\n" - "+\n" - "+static enum notify_ret_e\n" - "+clk_trnsc_fsm(enum clk_fsm_e const code, struct clk_tnode *node)\n" - "+{\n" - "+\tstruct pdev_clk_info *dev_info;\n" - "+\tstruct clk_tnode *tchild;\n" - "+\tstruct klist_iter i;\n" - "+\tint j;\n" - "+\tenum notify_ret_e tmp, ret_notifier = NOTIFY_EVENT_HANDLED;\n" - "+\n" - "+#ifdef CONFIG_CLK_DEBUG\n" - "+\tswitch (code) {\n" - "+\tcase TRNSC_ENTER_CLOCK:\n" - "+\tcase TRNSC_ENTER_DEVICE:\n" - "+\t\tprintk(KERN_INFO \"ENTER_%s \",\n" - "+\t\t\t(code == TRNSC_ENTER_CLOCK ? \"CLK\" : \"DEV\"));\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_PRE_DEVICE:\n" - "+\t\tprintk(KERN_INFO \"PRE_DEV \");\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_CHANGE_CLOCK:\n" - "+\t\tprintk(KERN_INFO \"CHANGE_CLK \");\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_POST_DEVICE:\n" - "+\t\tprintk(KERN_INFO \"POST_DEV \");\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_EXIT_DEVICE:\n" - "+\tcase TRNSC_EXIT_CLOCK:\n" - "+\t\tprintk(KERN_INFO \"EXIT_%s \",\n" - "+\t\t\t(code == TRNSC_EXIT_DEVICE ? \"DEV\" : \"CLK\"));\n" - "+\t\t\tbreak;\n" - "+\t}\n" - "+\tprintk(KERN_INFO\"tid:%u \", (unsigned int)tnode_get_id(node));\n" - "+\tif (tnode_get_parent(node))\n" - "+\t\tprintk(KERN_INFO \" (tpid: %d)\",\n" - "+\t\t\t(int)tnode_get_id(tnode_get_parent(node)));\n" - "+\tprintk(KERN_INFO \" (0x%x/0x%x) \", (unsigned int)tnode_get_size(node),\n" - "+\t\t\t(unsigned int)tnode_get_map(node));\n" - "+\tfor (j = 0; j < tnode_get_size(node); ++j) {\n" - "+\t\tif (tnode_check_map_id(node, j))\n" - "+\t\t\t/* print only the valid event... */\n" - "+\t\t\tprintk(KERN_INFO\"- %s \",\n" - "+\t\t\t\ttnode_get_clock(node, j)->name);\n" - "+\t\telse if (code == TRNSC_ENTER_CLOCK)\n" - "+\t\t\tprintk(KERN_INFO\"- %s \",\n" - "+\t\t\t\ttnode_get_clock(node, j)->name);\n" - "+\t}\n" - "+\tprintk(KERN_INFO\"\\n\");\n" - "+#endif\n" - "+\n" - "+\t/* \n" - "+\t * Clk ENTER state\n" - "+\t */\n" - "+\tif (code == TRNSC_ENTER_CLOCK) {\n" - "+\t\tunsigned long idx;\n" - "+\t\tenum clk_event_e sub_code;\n" - "+\t\tstruct clk *clkp;\n" - "+\t\tstruct clk_event *sub_event = NULL;\n" - "+\n" - "+\t\t/* first of all the GCF tries to lock the clock of this tnode\n" - "+\t\t * and links the tnode to its parent (if any)\n" - "+\t\t */\n" - "+\t\tswitch (tnode_lock_clocks(node)) {\n" - "+\t\tcase 0:\n" - "+\t\t\tbreak;\n" - "+\t\tcase -EINVAL:\n" - "+\t\t\treturn NOTIFY_EVENT_NOTHANDLED;\n" - "+\t\tcase 1:\n" - "+\t\t\treturn NOTIFY_EVENT_HANDLED;\n" - "+\t\t}\n" - "+\n" - "+\t\tpr_debug(\"clocks acquired\\n\");\n" - "+\t\t/* Propagates the events to the sub clks */\n" - "+\t\ttnode_for_each_valid_events(node, j) {\n" - "+\n" - "+\t\tif (!clk_allow_propagation(tnode_get_clock(node, j))) {\n" - "+\t\t\tpr_debug(\"clk: %s doesn't want propagation\\n\",\n" - "+\t\t\t\ttnode_get_clock(node, j)->name);\n" - "+\t\t\tcontinue;\n" - "+\t\t}\n" - "+\t\tif (!(tnode_get_clock(node, j)->nr_clocks))\n" - "+\t\t\tcontinue;\n" - "+\n" - "+\t\ttchild = tnode_malloc(node,\n" - "+\t\t\ttnode_get_clock(node, j)->nr_clocks);\n" - "+\t\tif (!tchild) {\n" - "+\t\t\tprintk(KERN_ERR \"No enough memory during a clk \"\n" - "+\t\t\t\t\t\"transaction\\n\");\n" - "+\t\t\tret_notifier |= NOTIFY_EVENT_NOTHANDLED;;\n" - "+\t\t\treturn ret_notifier;\n" - "+\t\t}\n" - "+\n" - "+\t\tpr_debug(\"memory for child transaction acquired\\n\");\n" - "+\t\tidx = 0;\n" - "+\t\tsub_code = clk_event_decode(tnode_get_event(node, j));\n" - "+\t\tklist_iter_init(&tnode_get_clock(node, j)->childs, &i);\n" - "+\t\twhile ((clkp = next_child_clock(&i))) {\n" - "+\t\t\tsub_event = tnode_get_event(tchild, idx);\n" - "+\t\t\tclk_event_init(sub_event, clkp, clk_get_rate(clkp),\n" - "+\t\t\t\tclk_get_rate(clkp));\n" - "+\t\t\tswitch (sub_code) {/* prepare the sub event fields */\n" - "+\t\t\tcase _CLK_CHANGE:\n" - "+\t\t\tcase _CLK_ENABLE:\n" - "+\t\t\t\tsub_event->new_rate = clk_evaluate_rate(clkp,\n" - "+\t\t\t\t\ttnode_get_event(node, j)->new_rate);\n" - "+\t\t\t\tbreak;\n" - "+\t\t\tcase _CLK_DISABLE:\n" - "+\t\t\t\tsub_event->new_rate = 0;\n" - "+\t\t\t\tbreak;\n" - "+\t\t\tcase _CLK_NOCHANGE:\n" - "+\t\t\t\tbreak;\n" - "+\t\t\t}\n" - "+\t\t\t++idx;\n" - "+\t\t\t}\n" - "+\t\tklist_iter_exit(&i);\n" - "+\t\t/* now GCF can araiese the sub transaction */\n" - "+\t\tret_notifier |=\n" - "+\t\t\tclk_trnsc_fsm(code, tchild);\n" - "+\t\t}\n" - "+\t\treturn ret_notifier;\n" - "+\t}\n" - "+\n" - "+\t/*\n" - "+\t * Clk CHANGE state\n" - "+\t */\n" - "+\tif (code == TRNSC_CHANGE_CLOCK) {\n" - "+\t\t/* the clocks on the root node are managed directly in the\n" - "+\t\t * clk_set_rate/clk_enable/... functions ...\n" - "+\t\t * while all the other clocks have to managed here!\n" - "+\t\t */\n" - "+\t\tif (node->parent)\n" - "+\t\t\ttnode_for_each_valid_events(node, j) {\n" - "+\t\t\t\tstruct clk_event *event;\n" - "+\t\t\t\tlong code;\n" - "+\t\t\t\tevent = tnode_get_event(node, j);\n" - "+\t\t\t\tcode = clk_event_decode(event);\n" - "+\t\t\t\tswitch (code) {\n" - "+\t\t\t\tcase _CLK_CHANGE:\n" - "+\t\t\t\t\t__clk_recalc_rate(event->clk);\n" - "+\t\t\t\t\tevent->new_rate =\n" - "+\t\t\t\t\t\tclk_get_rate(event->clk);\n" - "+\t\t\t\t\tbreak;\n" - "+\t\t\t\tcase _CLK_ENABLE:\n" - "+\t\t\t\t\tif (clk_follow_parent(event->clk)) {\n" - "+\t\t\t\t\t\t__clk_enable(event->clk);\n" - "+\t\t\t\t\t\tevent->new_rate =\n" - "+\t\t\t\t\t\tclk_get_rate(event->clk);\n" - "+\t\t\t\t\t}\n" - "+\t\t\t\t\tbreak;\n" - "+\t\t\t\tcase _CLK_DISABLE:\n" - "+\t\t\t\t\tif (clk_is_enabled(event->clk))\n" - "+\t\t\t\t\t\t__clk_disable(event->clk);\n" - "+\t\t\t\t\tbreak;\n" - "+\t\t\t\t}\n" - "+\t\t\t}\n" - "+\n" - "+\t\tlist_for_each_entry(tchild, &node->childs, pnode)\n" - "+\t\t\tret_notifier |= clk_trnsc_fsm(code, tchild);\n" - "+\n" - "+\t\treturn ret_notifier;\n" - "+\t}\n" - "+\n" - "+\t/*\n" - "+\t * Clk EXIT state\n" - "+\t */\n" - "+\tif (code == TRNSC_EXIT_CLOCK) {\n" - "+\t\tstruct list_head *ptr, *next;\n" - "+\t\t/* scans all the transaction childs */\n" - "+\t\tlist_for_each_safe(ptr, next, &node->childs)\n" - "+\t\t\tclk_trnsc_fsm(code, to_tnode(ptr));\n" - "+\n" - "+\t\t/* update the devices/clocks state */\n" - "+\t\ttnode_transaction_complete(node);\n" - "+\n" - "+\t\ttnode_free(node);\n" - "+\t\tpr_debug(\"EXIT_CLK complete\\n\");\n" - "+\n" - "+\t\treturn ret_notifier;\n" - "+\t}\n" - "+\n" - "+\t/*\n" - "+\t * Here the devices management\n" - "+\t */\n" - "+\ttnode_for_each_valid_events(node, j) {\n" - "+\t\tif (!clk_allow_propagation(tnode_get_clock(node, j)))\n" - "+\t\t\tcontinue;\n" - "+\tklist_iter_init(&tnode_get_clock(node, j)->devices, &i);\n" - "+\twhile ((dev_info = next_dev_info(&i))) {\n" - "+\t\tstruct platform_device *pdev = dev_info->pdev;\n" - "+\t\tstruct platform_driver *pdrv = \tcontainer_of(\n" - "+\t\t\tpdev->dev.driver, struct platform_driver, driver);\n" - "+\n" - "+\t\tstruct clk_event *dev_events;\n" - "+\n" - "+\t\tif (!pdrv || !pdrv->notify) {\n" - "+\t\t\tpr_debug(\n" - "+\t\t\t\"device %s.%d registered with no notify function\\n\",\n" - "+\t\t\t\tpdev->name, pdev->id);\n" - "+\t\t\tcontinue;\n" - "+\t\t}\n" - "+\t\t/* check if it already had a 'code' event */\n" - "+\t\tif (pdev_transaction_move_on(pdev, code))\n" - "+\t\t\tcontinue;\n" - "+\n" - "+\t\tdev_events = clk_dev_events_malloc(pdev);\n" - "+\t\tif (!dev_events) {\n" - "+\t\t\tprintk(KERN_ERR\"%s: No Memory during a clk \"\n" - "+\t\t\t\t\"transaction\\n\", __func__);\n" - "+\t\t\tcontinue;\n" - "+\t\t}\n" - "+\n" - "+\t\t/* GCF can use 'code' directly in the .notify function\n" - "+\t\t * just because external 'NOTIFY_CLK_xxxCHANGE' code\n" - "+\t\t * matchs with the internal 'device' code\n" - "+\t\t */\n" - "+\t\ttmp = pdrv->notify(code, pdev, dev_events);\n" - "+\t\tclk_dev_events_free(dev_events, pdev);\n" - "+\t\tret_notifier |= tmp;\n" - "+#ifdef CONFIG_PM_RUNTIME\n" - "+\t\tif (code == TRNSC_PRE_DEVICE && tmp == NOTIFY_EVENT_HANDLED) {\n" - "+\t\t\tprintk(KERN_INFO \"clk %s on code %u suspends \"\n" - "+\t\t\t\t\"device %s.%d\\n\",\n" - "+\t\t\t\ttransaction_get_clock(node, j)->name,\n" - "+\t\t\t\t(unsigned int)code, pdev->name, pdev->id);\n" - "+\t\t\tpm_runtime_suspend(&pdev->dev);\n" - "+\t\t} else\n" - "+\t\tif (code == TRNSC_POST_DEVICE && tmp == NOTIFY_EVENT_HANDLED) {\n" - "+\t\t\tprintk(KERN_INFO \"clk %s on code %u resumes \"\n" - "+\t\t\t\t\"device %s.%d\\n\",\n" - "+\t\t\t\ttransaction_get_clock(node, j)->name,\n" - "+\t\t\t\t(unsigned int)code, pdev->name, pdev->id);\n" - "+\t\t\tpm_runtime_resume(&pdev->dev);\n" - "+\t\t};\n" - "+#endif\n" - "+\t} /* while closed */\n" - "+\tklist_iter_exit(&i);\n" - "+\t} /* for closed */\n" - "+\n" - "+\t/*\n" - "+\t *and propagate down...\n" - "+\t */\n" - "+\tlist_for_each_entry(tchild, &node->childs, pnode)\n" - "+\t\t\tret_notifier |= clk_trnsc_fsm(code, tchild);\n" - "+\n" - "+\treturn ret_notifier;\n" - "+}\n" - "+\n" - "+static void clk_initialize(struct clk *clk)\n" - "+{\n" - "+\tkobject_init(&clk->kobj, &ktype_clk);\n" - "+\tkobject_set_name(&clk->kobj, \"%s\", clk->name);\n" - "+\tkobject_get(&clk->kobj);\n" - "+\n" - "+\tclk->nr_clocks = 0;\n" - "+\tclk->nr_active_clocks = 0;\n" - "+\tclk->nr_active_devices = 0;\n" - "+\tclk->towner = NULL;\n" - "+\n" - "+\tklist_init(&clk->childs, klist_get_child, klist_put_child);\n" - "+\tklist_init(&clk->devices, klist_get_device, klist_put_device);\n" - "+\n" - "+}\n" - "+\n" - "+/**\n" - "+ * clk_register -\n" - "+ *\n" - "+ * registers a new clk in the system.\n" - "+ * returns zero if success\n" - "+ */\n" - "+int clk_register(struct clk *clk)\n" - "+{\n" - "+\tint ret = 0;\n" - "+\tif (!clk)\n" - "+\t\treturn -EFAULT;\n" - "+\tpr_debug(\"%s\\n\", clk->name);\n" - "+\n" - "+\tclk_initialize(clk);\n" - "+\n" - "+\t/* Initialize ... */\n" - "+\t__clk_init(clk);\n" - "+\n" - "+\tif (clk->parent) {\n" - "+#ifdef CLK_SAFE_CODE\n" - "+\t\t/* 1. the parent has to be registered */\n" - "+\t\tif (!check_clk(clk->parent))\n" - "+\t\t\treturn -ENODEV;\n" - "+\t\t/* 2. an always enabled child has to sit on a always\n" - "+\t\t * enabled parent!\n" - "+\t\t */\n" - "+\t\tif (clk->flags & CLK_ALWAYS_ENABLED &&\n" - "+\t\t\t!(clk->parent->flags & CLK_ALWAYS_ENABLED))\n" - "+\t\t\treturn -EFAULT;\n" - "+\t\t/* 3. a fixed child has to sit on a fixed parent */\n" - "+\t\tif (clk_is_readonly(clk) && !clk_is_readonly(clk->parent))\n" - "+\t\t\treturn -EFAULT;\n" - "+#endif\n" - "+\t\tklist_add_tail(&clk->child_node, &clk->parent->childs);\n" - "+\t\tclk->parent->nr_clocks++;\n" - "+\t}\n" - "+\n" - "+\tret = kobject_add(&clk->kobj,\n" - "+\t\t(clk->parent ? &clk->parent->kobj : clk_kobj), clk->name);\n" - "+\tif (ret)\n" - "+\t\tgoto err_0;\n" - "+\n" - "+\tclk->kdevices =\tkobject_create_and_add(\"devices\", &clk->kobj);\n" - "+\tif (!clk->kdevices)\n" - "+\t\tgoto err_1;\n" - "+\n" - "+\tklist_add_tail(&clk->node, &clk_list);\n" - "+\tif (clk->flags & CLK_ALWAYS_ENABLED) {\n" - "+\t\t__clk_enable(clk);\n" - "+\t\tclk_notify_child_event(CHILD_CLOCK_ENABLED, clk->parent);\n" - "+\t}\n" - "+\treturn ret;\n" - "+\n" - "+err_1:\n" - "+\t/* subsystem_remove_file... removed in the common code... ??? */\n" - "+\tkobject_del(&clk->kobj);\n" - "+err_0:\n" - "+\treturn ret;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_register);\n" - "+\n" - "+/**\n" - "+ * clk_unregister -\n" - "+ * unregisters the clock from system\n" - "+ */\n" - "+int clk_unregister(struct clk *clk)\n" - "+{\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\tif (!clk)\n" - "+\t\treturn -EFAULT;\n" - "+\n" - "+\tif (!list_empty(&clk->devices.k_list))\n" - "+\t\treturn -EFAULT; /* somebody is still using this clock */\n" - "+\n" - "+\tkobject_del(clk->kdevices);\n" - "+\tkfree(clk->kdevices);\n" - "+\t/* subsystem_remove_file... removed in the common code... ??? */\n" - "+\tkobject_del(&clk->kobj);\n" - "+\tklist_del(&clk->node);\n" - "+\tif (clk->parent) {\n" - "+\t\tklist_del(&clk->child_node);\n" - "+\t\tclk->parent->nr_clocks--;\n" - "+\t}\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_unregister);\n" - "+\n" - "+static int clk_add_devinfo(struct pdev_clk_info *info)\n" - "+{\n" - "+\tint ret = 0;\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+#ifdef CLK_SAFE_CODE\n" - "+\tif (!info || !info->clk || !check_clk(info->clk))\n" - "+\t\treturn -EFAULT;\n" - "+#endif\n" - "+\tret = sysfs_create_link(info->clk->kdevices, &info->pdev->dev.kobj,\n" - "+\t\tdev_name(&info->pdev->dev));\n" - "+\tif (ret) {\n" - "+\t\tpr_debug(\" Error %d\\n\", ret);\n" - "+\t\treturn ret;\n" - "+\t}\n" - "+\tklist_add_tail(&info->node, &info->clk->devices);\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+static int clk_del_devinfo(struct pdev_clk_info *info)\n" - "+{\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+#ifdef CLK_SAFE_CODE\n" - "+\tif (!info || !info->clk || !check_clk(info->clk))\n" - "+\t\treturn -EFAULT;\n" - "+#endif\n" - "+\tsysfs_remove_link(info->clk->kdevices, dev_name(&info->pdev->dev));\n" - "+\tklist_del(&info->node);\n" - "+\n" - "+#ifndef CONFIG_PM_RUNTIME\n" - "+\t/*\n" - "+\t * Without PM_RUNTIME the GCF assumes the device is\n" - "+\t * 'not active' when it's removed\n" - "+\t */\n" - "+\tclk_notify_child_event(CHILD_DEVICE_DISABLED, info->clk);\n" - "+#endif\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+int clk_probe_device(struct platform_device *dev, enum pdev_probe_state state)\n" - "+{\n" - "+\tint idx;\n" - "+\tswitch (state) {\n" - "+\tcase PDEV_PROBEING:\n" - "+\t\t/* before the .probe function is called the GCF\n" - "+\t\t * has to turn-on _all_ the clocks the device uses\n" - "+\t\t * to garantee a safe .probe\n" - "+\t\t */\n" - "+\t\tfor (idx = 0; idx < pdevice_num_clocks(dev); ++idx)\n" - "+\t\t\tif (pdevice_clock(dev, idx))\n" - "+\t\t\t\tclk_enable(pdevice_clock(dev, idx));\n" - "+\t\treturn 0;\n" - "+\tcase PDEV_PROBED:\n" - "+#ifdef CONFIG_PM_RUNTIME\n" - "+\t/*\n" - "+\t * Here the GCF should check the device's pm_runtime state\n" - "+\t * And if the device is suspended the clk_frmwk can turn-off the clocks\n" - "+\t */\n" - "+#else\n" - "+\t/*\n" - "+\t * Without PM_RUNTIME the GCF assumes the device is active\n" - "+\t */\n" - "+\tfor (idx = 0; idx < pdevice_num_clocks(dev); ++idx)\n" - "+\t\tclk_notify_child_event(CHILD_DEVICE_ENABLED,\n" - "+\t\t\tpdevice_clock(dev, idx));\n" - "+#endif\n" - "+\tbreak;\n" - "+\tcase PDEV_PROBE_FAILED:\n" - "+\t/*\n" - "+\t * TO DO something...\n" - "+\t */\n" - "+\t\tbreak;\n" - "+\t}\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+int clk_add_device(struct platform_device *dev, enum pdev_add_state state)\n" - "+{\n" - "+\tint idx;\n" - "+\tint ret;\n" - "+\n" - "+\tif (!dev)\n" - "+\t\treturn -EFAULT;\n" - "+\n" - "+\tswitch (state) {\n" - "+\tcase PDEV_ADDING:\n" - "+\tcase PDEV_ADD_FAILED:\n" - "+\t\t/*\n" - "+\t\t * TO DO something\n" - "+\t\t */\n" - "+\t\treturn 0;\n" - "+\tcase PDEV_ADDED:\n" - "+\t\tbreak;\n" - "+\t}\n" - "+\t/* case PDEV_ADDED ... */\n" - "+\tif (!dev->clks || !pdevice_num_clocks(dev))\n" - "+\t\treturn 0;\t/* this device will not use\n" - "+\t\t\t\t the clk framework */\n" - "+\n" - "+\tpr_debug(\"%s.%d with %u clocks\\n\", dev->name, dev->id,\n" - "+\t\t(unsigned int)pdevice_num_clocks(dev));\n" - "+\n" - "+\tdev->clk_state = 0;\n" - "+\tfor (idx = 0; idx < pdevice_num_clocks(dev); ++idx) {\n" - "+\t\tif (!pdevice_clock(dev, idx)) {\t/* clk can not be NULL... */\n" - "+\t\t\tpr_debug(\"Error clock NULL\\n\");\n" - "+\t\t\tcontinue;\n" - "+\t\t}\n" - "+\t\tpr_debug(\"->under %s\\n\", dev->clks[idx].clk->name);\n" - "+\t\tdev->clks[idx].pdev = dev;\n" - "+\t\tret = clk_add_devinfo(&dev->clks[idx]);\n" - "+\t\tif (ret)\n" - "+\t\t\tgoto err_0;\n" - "+\t}\n" - "+\n" - "+\treturn 0;\n" - "+err_0:\n" - "+\tfor (--idx; idx >= 0; --idx)\n" - "+\t\tclk_del_devinfo(&dev->clks[idx]);\n" - "+\n" - "+\treturn -EINVAL;\n" - "+}\n" - "+\n" - "+int clk_del_device(struct platform_device *dev)\n" - "+{\n" - "+\tint idx;\n" - "+\tif (!dev)\n" - "+\t\treturn -EFAULT;\n" - "+\n" - "+\tfor (idx = 0; idx < pdevice_num_clocks(dev); ++idx)\n" - "+\t\tclk_del_devinfo(&dev->clks[idx]);\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+void clk_put(struct clk *clk)\n" - "+{\n" - "+\tif (clk && !IS_ERR(clk))\n" - "+\t\tkobject_put(&clk->kobj);\n" - "+}\n" - "+\n" - "+static int clk_is_parent(struct clk const *child, struct clk const *parent)\n" - "+{\n" - "+\tif (!child || !parent)\n" - "+\t\treturn 0;\n" - "+\tif (!child->parent)\n" - "+\t\treturn 0;\n" - "+\tif (child->parent == parent)\n" - "+\t\treturn 1;\n" - "+\telse\n" - "+\t\treturn clk_is_parent(child->parent, parent);\n" - "+}\n" - "+\n" - "+int clk_enable(struct clk *clk)\n" - "+{\n" - "+\tint ret;\n" - "+\tstruct clk_tnode transaction;\n" - "+\tstruct clk_event event;\n" - "+\n" - "+\tevent = EVENT(clk, 0, CLK_UNDEFINED_RATE);\n" - "+\ttransaction = TRANSACTION_ROOT(1, &event);\n" - "+\n" - "+\tpr_debug(\"%s\\n\", clk->name);\n" - "+\n" - "+\n" - "+\tif (clk->flags & CLK_ALWAYS_ENABLED || clk_is_enabled(clk))\n" - "+\t\treturn 0;\n" - "+\n" - "+\tif (clk->parent) {\n" - "+\t\t/* turn-on the parent if the parent is 'auto_switch' */\n" - "+\t\tclk_notify_child_event(CHILD_CLOCK_ENABLED, clk->parent);\n" - "+\n" - "+\t\tif (!clk_is_enabled(clk->parent)) {\n" - "+\t\t\t/* the parent is still disabled... */\n" - "+\t\t\tclk_notify_child_event(CHILD_CLOCK_DISABLED,\n" - "+\t\t\t\tclk->parent);\n" - "+\t\t\treturn -EINVAL;\n" - "+\t\t}\n" - "+\t}\n" - "+\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction);\n" - "+\tif (ret) {\n" - "+\t\tret = -EPERM;\n" - "+\t\tgoto err_0;\n" - "+\t}\n" - "+\n" - "+\t/* if not zero somebody doens't agree the clock update */\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction);\n" - "+\tif (ret) {\n" - "+\t\tret = -EPERM;\n" - "+\t\tgoto err_1;\n" - "+\t\t}\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction);\n" - "+\n" - "+\tret = __clk_enable(clk);\n" - "+\n" - "+\tevent.new_rate = clk_get_rate(clk);\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction);\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction);\n" - "+\n" - "+err_1:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction);\n" - "+\n" - "+err_0:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction);\n" - "+\n" - "+\tif (ret)\n" - "+\t\tclk_notify_child_event(CHILD_CLOCK_DISABLED, clk->parent);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_enable);\n" - "+\n" - "+/**\n" - "+ * clk_disable -\n" - "+ * disables the clock\n" - "+ * Is isn't really good that it's a 'void' function...\n" - "+ * but this is common interface\n" - "+ */\n" - "+void clk_disable(struct clk *clk)\n" - "+{\n" - "+\tstruct clk_tnode transaction;\n" - "+\tstruct clk_event event;\n" - "+\tint ret;\n" - "+\n" - "+\tevent = EVENT(clk, clk_get_rate(clk), 0);\n" - "+\ttransaction = TRANSACTION_ROOT(1, &event);\n" - "+\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\tif (clk->flags & CLK_ALWAYS_ENABLED || !clk_is_enabled(clk))\n" - "+\t\treturn;\n" - "+\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction);\n" - "+\tif (ret)\n" - "+\t\tgoto err_0;\n" - "+\n" - "+\t/* if not zero somebody doens't agree the clock update */\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction);\n" - "+\tif (ret)\n" - "+\t\tgoto err_1;\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction);\n" - "+\n" - "+\t__clk_disable(clk);\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction);\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction);\n" - "+\n" - "+err_0:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction);\n" - "+err_1:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction);\n" - "+\n" - "+\tclk_notify_child_event(CHILD_CLOCK_DISABLED, clk->parent);\n" - "+\n" - "+\treturn ;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_disable);\n" - "+\n" - "+unsigned long clk_get_rate(struct clk *clk)\n" - "+{\n" - "+\treturn clk->rate;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_get_rate);\n" - "+\n" - "+struct clk *clk_get_parent(struct clk *clk)\n" - "+{\n" - "+\treturn clk->parent;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_get_parent);\n" - "+\n" - "+int clk_set_parent(struct clk *clk, struct clk *parent)\n" - "+{\n" - "+\tint ret = -EOPNOTSUPP;\n" - "+\tstruct clk *old_parent = clk->parent;\n" - "+\tstruct clk_event event;\n" - "+\tstruct clk_tnode transaction;\n" - "+\tint clk_was_enabled = clk_is_enabled(clk);\n" - "+\n" - "+\tevent = EVENT(clk, clk_get_rate(clk), CLK_UNDEFINED_RATE);\n" - "+\ttransaction = TRANSACTION_ROOT(1, &event);\n" - "+\n" - "+\tif (!clk || !parent)\n" - "+\t\treturn -EINVAL;\n" - "+\n" - "+\tif (clk->parent == parent)\n" - "+\t\treturn 0;\n" - "+\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\tif (clk_was_enabled && !clk_is_enabled(parent))\n" - "+\t\t/* turn-on parent if possible */\n" - "+\t\tclk_notify_child_event(CHILD_CLOCK_ENABLED, parent);\n" - "+\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction);\n" - "+\tif (ret) {\n" - "+\t\tret = -EPERM;\n" - "+\t\tgoto err_0;\n" - "+\t}\n" - "+\n" - "+\t/* if not zero somebody doens't agree the clock updated */\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction);\n" - "+\tif (ret) {\n" - "+\t\tret = -EPERM;\n" - "+\t\tgoto err_1;\n" - "+\t}\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction);\n" - "+\n" - "+\t/* Now we updated the hw */\n" - "+\tret = __clk_set_parent(clk, parent);\n" - "+\tif (ret) {\n" - "+\t\t/* there was a problem...\n" - "+\t\t * therefore clk is still on the old parent\n" - "+\t\t */\n" - "+\t\tclk->parent = old_parent; /* to be safe ! */\n" - "+\t\tgoto err_2;\n" - "+\t}\n" - "+\n" - "+\tklist_del(&clk->child_node);\n" - "+\n" - "+\tclk->parent = parent;\n" - "+\n" - "+\tret = kobject_move(&clk->kobj, &clk->parent->kobj);\n" - "+\tif (ret)\n" - "+\t\t;\n" - "+\n" - "+\tklist_add_tail(&clk->child_node, &clk->parent->childs);\n" - "+\n" - "+\tclk->parent->nr_clocks++;\n" - "+\told_parent->nr_clocks--;\n" - "+\n" - "+err_2:\n" - "+\tevent.new_rate = clk_get_rate(clk);\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction);\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction);\n" - "+\n" - "+err_1:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction);\n" - "+err_0:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction);\n" - "+\n" - "+\tif (clk_was_enabled && !ret) {\n" - "+\t\t/* 5. to decrease the old_parent nchild counter */\n" - "+\t\tclk_notify_child_event(CHILD_CLOCK_DISABLED, old_parent);\n" - "+\t\t/* 5. increase the new_parent nchild counter */\n" - "+\t\tclk_notify_child_event(CHILD_CLOCK_ENABLED, clk->parent);\n" - "+\t\t/* 6. to decrease the old_parent nchild counter */\n" - "+\t\tclk_notify_child_event(CHILD_CLOCK_DISABLED, old_parent);\n" - "+\t\t}\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_set_parent);\n" - "+\n" - "+int clk_set_rate(struct clk *clk, unsigned long rate)\n" - "+{\n" - "+\tint ret = -EOPNOTSUPP;\n" - "+\tstruct clk_event event;\n" - "+\tstruct clk_tnode transaction;\n" - "+\n" - "+\tevent = EVENT(clk, clk_get_rate(clk), clk_round_rate(clk, rate));\n" - "+\ttransaction = TRANSACTION_ROOT(1, &event);\n" - "+\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\tif (clk_is_readonly(clk))\n" - "+\t\t/* read only clock doesn't have to be \"touched\" !!!! */\n" - "+\t\treturn -EPERM;\n" - "+\n" - "+\tif (event.new_rate == clk_get_rate(clk))\n" - "+\t\treturn 0;\n" - "+\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction);\n" - "+\tif (ret) {\n" - "+\t\tret = -EPERM;\n" - "+\t\tgoto err_0;\n" - "+\t}\n" - "+\n" - "+\t/* if not zero somebody doens't agree the clock updated */\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction);\n" - "+\tif (ret) {\n" - "+\t\tret = -EPERM;\n" - "+\t\tgoto err_1;\n" - "+\t}\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction);\n" - "+\n" - "+\t__clk_set_rate(clk, event.new_rate);\n" - "+\t/* reload new_rate to avoid hw rounding... */\n" - "+\tevent.new_rate = clk_get_rate(clk);\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction);\n" - "+\tclk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction);\n" - "+\n" - "+err_1:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction);\n" - "+err_0:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_set_rate);\n" - "+\n" - "+long clk_round_rate(struct clk *clk, unsigned long rate)\n" - "+{\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\tif (likely(clk->ops && clk->ops->round))\n" - "+\t\treturn clk->ops->round(clk, rate);\n" - "+\treturn rate;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_round_rate);\n" - "+\n" - "+unsigned long clk_evaluate_rate(struct clk *clk, unsigned long prate)\n" - "+{\n" - "+\tpr_debug(\"\\n\");\n" - "+\tif (!clk->parent)/* without parent this function has no meaning */\n" - "+\t\treturn CLK_UNDEFINED_RATE;\n" - "+\n" - "+\tif (!prate)/* on parent disabled than disable the child */\n" - "+\t\treturn 0;\n" - "+\n" - "+\tif (likely(clk->ops && clk->ops->eval))\n" - "+\t\treturn clk->ops->eval(clk, prate);\n" - "+\n" - "+\treturn CLK_UNDEFINED_RATE;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_evaluate_rate);\n" - "+\n" - "+int clk_set_rates(struct clk **clks, unsigned long *rates, unsigned long nclks)\n" - "+{\n" - "+\tint i, ret = 0;\n" - "+\tstruct clk_event *evt;\n" - "+\tstruct clk_tnode transaction = TRANSACTION_ROOT(nclks, NULL)\n" - "+\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\tif (!clks || !rates || !nclks)\n" - "+\t\treturn -EINVAL;\n" - "+\tevt = kmalloc(sizeof(*evt) *\n" - "+\t\ttnode_get_size(&transaction), GFP_KERNEL);\n" - "+\n" - "+\tif (!evt)\n" - "+\t\treturn -ENOMEM;\n" - "+\n" - "+\ttnode_set_events(&transaction, evt);\n" - "+\n" - "+\tfor (i = 0; i < tnode_get_size(&transaction); ++i) {\n" - "+\t\ttnode_set_clock(&transaction, i, clks[i]);\n" - "+\t\ttnode_get_event(&transaction, i)->old_rate =\n" - "+\t\t\tclk_get_rate(clks[i]);\n" - "+\t\ttnode_get_event(&transaction, i)->new_rate =\n" - "+\t\t\tclk_round_rate(clks[i], rates[i]);\n" - "+\t}\n" - "+\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_CLOCK, &transaction);\n" - "+\tif (ret) {\n" - "+\t\tret = -EPERM;\n" - "+\t\tgoto err_0;\n" - "+\t}\n" - "+\n" - "+\t/* if not zero somebody doens't agree the clock updated */\n" - "+\tret = clk_trnsc_fsm(TRNSC_ENTER_DEVICE, &transaction);\n" - "+\tif (ret) {\n" - "+\t\tret = -EPERM;\n" - "+\t\tgoto err_1;\n" - "+\t}\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_PRE_DEVICE, &transaction);\n" - "+\n" - "+\tfor (i = 0; i < tnode_get_size(&transaction); ++i) {\n" - "+\t\tif (!clk_is_enabled(clks[i]) && rates[i])\n" - "+\t\t\tret |= __clk_enable(clks[i]);\n" - "+\t\telse if (clk_is_enabled(clks[i]) && !rates[i])\n" - "+\t\t\tret |= __clk_disable(clks[i]);\n" - "+\t\telse\n" - "+\t\t\tret |= __clk_set_rate(clks[i], rates[i]);\n" - "+\n" - "+\t\t/* reload new_rate to avoid hw rounding... */\n" - "+\t\ttnode_get_event(&transaction, i)->new_rate =\n" - "+\t\t\tclk_get_rate(clks[i]);\n" - "+\t}\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_CHANGE_CLOCK, &transaction);\n" - "+\n" - "+\tclk_trnsc_fsm(TRNSC_POST_DEVICE, &transaction);\n" - "+\n" - "+err_1:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_DEVICE, &transaction);\n" - "+\n" - "+err_0:\n" - "+\tclk_trnsc_fsm(TRNSC_EXIT_CLOCK, &transaction);\n" - "+\n" - "+\tkfree(evt);\n" - "+\treturn ret;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_set_rates);\n" - "+\n" - "+struct clk *clk_get(struct device *dev, const char *id)\n" - "+{\n" - "+\tstruct clk *clk = NULL;\n" - "+\tstruct clk *clkp;\n" - "+\tstruct klist_iter i;\n" - "+\tint found = 0, idno;\n" - "+\n" - "+\tmutex_lock(&clk_list_sem);\n" - "+#if 0\n" - "+\tif (dev == NULL || dev->bus != &platform_bus_type)\n" - "+\t\tidno = -1;\n" - "+\telse\n" - "+\t\tidno = to_platform_device(dev)->id;\n" - "+\n" - "+\tklist_iter_init(&clk_list, &i);\n" - "+\twhile ((clkp = next_clock(&i)) && !found)\n" - "+\t\tif (clk->id == idno && strcmp(id, clk->name) == 0 &&\n" - "+\t\t\ttry_module_get(clk->owner)) {\n" - "+\t\t\t\tclk = clkp;\n" - "+\t\t\t\tfound = 1;\n" - "+\t\t}\n" - "+\tklist_iter_exit(&i);\n" - "+\n" - "+\tif (found)\n" - "+\t\tgoto _found;\n" - "+#endif\n" - "+\tklist_iter_init(&clk_list, &i);\n" - "+\twhile ((clkp = next_clock(&i)))\n" - "+\t\tif (strcmp(id, clkp->name) == 0\n" - "+\t\t && try_module_get(clkp->owner)) {\n" - "+\t\t\tclk = clkp;\n" - "+\t\t\tbreak;\n" - "+\t\t}\n" - "+\tklist_iter_exit(&i);\n" - "+_found:\n" - "+\tmutex_unlock(&clk_list_sem);\n" - "+\treturn clk;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_get);\n" - "+\n" - "+int clk_for_each(int (*fn) (struct clk *clk, void *data), void *data)\n" - "+{\n" - "+\tstruct clk *clkp;\n" - "+\tstruct klist_iter i;\n" - "+\tint result = 0;\n" - "+\n" - "+\tif (!fn)\n" - "+\t\treturn -EFAULT;\n" - "+\n" - "+\tpr_debug(\"\\n\");\n" - "+\tmutex_lock(&clk_list_sem);\n" - "+\tklist_iter_init(&clk_list, &i);\n" - "+\n" - "+\twhile ((clkp = next_clock(&i)))\n" - "+\t\tresult |= fn(clkp, data);\n" - "+\n" - "+\tklist_iter_exit(&i);\n" - "+\tmutex_unlock(&clk_list_sem);\n" - "+\treturn result;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_for_each);\n" - "+\n" - "+int clk_for_each_child(struct clk *clk,\n" - "+\tint (*fn) (struct clk *clk, void *data), void *data)\n" - "+{\n" - "+\tstruct clk *clkp;\n" - "+\tstruct klist_iter i;\n" - "+\tint result = 0;\n" - "+\n" - "+\tif (!clk || !fn)\n" - "+\t\treturn -EFAULT;\n" - "+\n" - "+\tklist_iter_init(&clk->childs, &i);\n" - "+\n" - "+\twhile ((clkp = next_child_clock(&i)))\n" - "+\t\tresult |= fn(clkp, data);\n" - "+\n" - "+\tklist_iter_exit(&i);\n" - "+\n" - "+\treturn result;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_for_each_child);\n" - "+\n" - "+static int __init early_clk_complete(struct clk *clk, void *data)\n" - "+{\n" - "+\tint ret;\n" - "+\n" - "+\tret = kobject_add(&clk->kobj,\n" - "+\t\t(clk->parent ? &clk->parent->kobj : clk_kobj),\n" - "+\t\tclk->name);\n" - "+\tif (ret)\n" - "+\t\treturn ret;\n" - "+\n" - "+\tclk->kdevices = kobject_create_and_add(\"devices\", &clk->kobj);\n" - "+\tif (!clk->kdevices)\n" - "+\t\treturn -EINVAL;\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+int __init early_clk_register(struct clk *clk)\n" - "+{\n" - "+\tint retval = 0;\n" - "+\tif (!clk)\n" - "+\t\treturn -EFAULT;\n" - "+\tpr_debug(\"%s\\n\", clk->name);\n" - "+\n" - "+\tclk_initialize(clk);\n" - "+\n" - "+\t/* Initialize ... */\n" - "+\t__clk_init(clk);\n" - "+\n" - "+\tif (clk->parent) {\n" - "+#ifdef CLK_SAFE_CODE\n" - "+\t\t/* 1. the parent has to be registered */\n" - "+\t\tif (!check_clk(clk->parent))\n" - "+\t\t\treturn -ENODEV;\n" - "+\t\t/* 2. an always enabled child has to sit on a always\n" - "+\t\t * enabled parent!\n" - "+\t\t */\n" - "+\t\tif (clk->flags & CLK_ALWAYS_ENABLED &&\n" - "+\t\t\t!(clk->parent->flags & CLK_ALWAYS_ENABLED))\n" - "+\t\t\treturn -EFAULT;\n" - "+\t\t/* 3. a fixed child has to sit on a fixed parent */\n" - "+\t\tif (clk_is_readonly(clk) && !clk_is_readonly(clk->parent))\n" - "+\t\t\treturn -EFAULT;\n" - "+#endif\n" - "+\t\tklist_add_tail(&clk->child_node, &clk->parent->childs);\n" - "+\t\tclk->parent->nr_clocks++;\n" - "+\t}\n" - "+\n" - "+\tklist_add_tail(&clk->node, &clk_list);\n" - "+\tif (clk->flags & CLK_ALWAYS_ENABLED) {\n" - "+\t\t__clk_enable(clk);\n" - "+\t\tclk_notify_child_event(CHILD_CLOCK_ENABLED, clk->parent);\n" - "+\t}\n" - "+\treturn retval;\n" - "+}\n" - "+\n" - "+int __init clock_init(void)\n" - "+{\n" - "+\tclk_kobj = kobject_create_and_add(\"clocks\", NULL);\n" - "+\tif (!clk_kobj)\n" - "+\t\treturn -EINVAL ;\n" - "+\n" - "+\tclk_for_each(early_clk_complete, NULL);\n" - "+\n" - "+\tprintk(KERN_INFO CLK_NAME \" \" CLK_VERSION \"\\n\");\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "diff --git a/drivers/base/clk.h b/drivers/base/clk.h\n" - "new file mode 100644\n" - "index 0000000..61672ef\n" - "--- /dev/null\n" - "+++ b/drivers/base/clk.h\n" - "@@ -0,0 +1,319 @@\n" - "+/*\n" - "+ -------------------------------------------------------------------------\n" - "+ clk.h\n" - "+ -------------------------------------------------------------------------\n" - "+ (C) STMicroelectronics 2008\n" - "+ (C) STMicroelectronics 2009\n" - "+ Author: Francesco M. Virlinzi <francesco.virlinzi@st.com>\n" - "+ ----------------------------------------------------------------------------\n" - "+ May be copied or modified under the terms of the GNU General Public\n" - "+ License v.2 ONLY. See linux/COPYING for more information.\n" - "+\n" - "+ ------------------------------------------------------------------------- */\n" - "+\n" - "+#ifdef CONFIG_GENERIC_CLK_FM\n" - "+\n" - "+#include <linux/clk.h>\n" - "+#include <linux/platform_device.h>\n" - "+#include <linux/kobject.h>\n" - "+#include <linux/klist.h>\n" - "+#include <linux/list.h>\n" - "+#include <linux/notifier.h>\n" - "+#include <asm/atomic.h>\n" - "+\n" - "+enum clk_ops_id {\n" - "+\t__CLK_INIT = 0,\n" - "+\t__CLK_ENABLE,\n" - "+\t__CLK_DISABLE,\n" - "+\t__CLK_SET_RATE,\n" - "+\t__CLK_SET_PARENT,\n" - "+\t__CLK_RECALC,\n" - "+\t__CLK_ROUND,\n" - "+\t__CLK_EVAL,\n" - "+};\n" - "+\n" - "+extern struct klist clk_list;\n" - "+/**\n" - "+ * clk_tnode\n" - "+ * it's the internal strucure used to track each node\n" - "+ * in the transaction graph.\n" - "+ * _NO_ api is showed to the other modules\n" - "+ */\n" - "+struct clk_tnode {\n" - "+\t/** @tid: the tnode id */\n" - "+\tunsigned long tid;\n" - "+\t/** @size: how may clock are involved in this tnode */\n" - "+\tunsigned long size;\n" - "+\t/** @parent: the parent tnode */\n" - "+\tstruct clk_tnode *parent;\n" - "+\t/* @events_map: a bitmap to declare the\n" - "+\t * valid events in this tnode\n" - "+\t */\n" - "+\tunsigned long events_map;\n" - "+\t/** @events: the event array of this tnode */\n" - "+\tstruct clk_event *events;\n" - "+\t/** @child: links the childres tnode */\n" - "+\tstruct list_head childs;\n" - "+\t/** @pnode: links the tnode to the parent */\n" - "+\tstruct list_head pnode;\n" - "+};\n" - "+\n" - "+/*\n" - "+ * tnode_get_size -\n" - "+ * returns the number of events in the transaction\n" - "+ */\n" - "+static inline unsigned long\n" - "+tnode_get_size(struct clk_tnode *tnode)\n" - "+{\n" - "+\treturn tnode->size;\n" - "+}\n" - "+\n" - "+static inline unsigned long\n" - "+tnode_get_map(struct clk_tnode *tnode)\n" - "+{\n" - "+\treturn tnode->events_map;\n" - "+}\n" - "+\n" - "+static inline unsigned long\n" - "+tnode_check_map_id(struct clk_tnode *node, int id)\n" - "+{\n" - "+\treturn node->events_map & (1 << id);\n" - "+}\n" - "+\n" - "+static inline void\n" - "+tnode_set_map_id(struct clk_tnode *node, int id)\n" - "+{\n" - "+\tnode->events_map |= (1 << id);\n" - "+}\n" - "+\n" - "+static inline unsigned long\n" - "+tnode_get_id(struct clk_tnode *node)\n" - "+{\n" - "+\treturn node->tid;\n" - "+}\n" - "+\n" - "+static inline struct clk_event*\n" - "+tnode_get_event(struct clk_tnode *node, int id)\n" - "+{\n" - "+\treturn &(node->events[id]);\n" - "+}\n" - "+\n" - "+static inline struct clk_event *tnode_get_events(struct clk_tnode *node)\n" - "+{\n" - "+\treturn tnode_get_event(node, 0);\n" - "+}\n" - "+\n" - "+static inline void\n" - "+tnode_set_events(struct clk_tnode *node, struct clk_event *events)\n" - "+{\n" - "+\tnode->events = events;\n" - "+}\n" - "+\n" - "+static inline struct clk*\n" - "+tnode_get_clock(struct clk_tnode *node, int id)\n" - "+{\n" - "+\treturn tnode_get_event(node, id)->clk;\n" - "+}\n" - "+\n" - "+static inline void\n" - "+tnode_set_clock(struct clk_tnode *node, int id, struct clk *clk)\n" - "+{\n" - "+\tnode->events[id].clk = clk;\n" - "+}\n" - "+\n" - "+static inline struct clk_tnode *tnode_get_parent(struct clk_tnode *node)\n" - "+{\n" - "+\treturn node->parent;\n" - "+}\n" - "+\n" - "+#define tnode_for_each_valid_events(node, _j)\t\t\t\\\n" - "+\tfor ((_j) = (ffs(tnode_get_map(node)) - 1);\t\t\\\n" - "+\t (_j) < tnode_get_size((node)); ++(_j))\t\t\\\n" - "+\t\t\tif (tnode_check_map_id((node), (_j)))\n" - "+\n" - "+#define EVENT(_clk, _oldrate, _newrate)\t\t\\\n" - "+\t(struct clk_event)\t\t\t\t\\\n" - "+\t{\t\t\t\t\t\t\\\n" - "+\t\t.clk = (struct clk *)(_clk),\t\t\\\n" - "+\t\t.old_rate = (unsigned long)(_oldrate),\t\\\n" - "+\t\t.new_rate = (unsigned long)(_newrate),\t\\\n" - "+\t};\n" - "+\n" - "+#define TRANSACTION_ROOT(_num, _event)\t\t\t\t\t\\\n" - "+\t(struct clk_tnode) {\t\t\t\t\t\t\\\n" - "+\t\t.tid = atomic_inc_return(&transaction_counter),\t\\\n" - "+\t\t.size = (_num),\t\t\t\t\t\\\n" - "+\t\t.events = (struct clk_event *)(_event),\t\t\t\\\n" - "+\t\t.parent = NULL,\t\t\t\t\t\t\\\n" - "+\t\t.childs = LIST_HEAD_INIT(transaction.childs),\t\t\\\n" - "+\t\t.events_map = 0,\t\t\t\t\t\\\n" - "+\t\t};\n" - "+\n" - "+#define klist_function_support(_name, _type, _field, _kobj)\t\t\\\n" - "+static void klist_get_##_name(struct klist_node *n)\t\t\t\\\n" - "+{\t\t\t\t\t\t\t\t\t\\\n" - "+\tstruct _type *entry = container_of(n, struct _type, _field);\t\\\n" - "+\tkobject_get(&entry->_kobj);\t\t\t\t\t\\\n" - "+}\t\t\t\t\t\t\t\t\t\\\n" - "+static void klist_put_##_name(struct klist_node *n)\t\t\t\\\n" - "+{\t\t\t\t\t\t\t\t\t\\\n" - "+\tstruct _type *entry = container_of(n, struct _type, _field);\t\\\n" - "+\tkobject_put(&entry->_kobj);\t\t\t\t\t\\\n" - "+}\n" - "+\n" - "+#define klist_entry_support(name, type, field)\t\t\t\t\\\n" - "+static struct type *next_##name(struct klist_iter *i)\t\t\t\\\n" - "+{\tstruct klist_node *n = klist_next(i);\t\t\t\t\\\n" - "+\treturn n ? container_of(n, struct type, field) : NULL;\t\t\\\n" - "+}\n" - "+\n" - "+static inline void\n" - "+clk_event_init(struct clk_event *evt, struct clk *clk,\n" - "+\t\tunsigned long oldrate, unsigned long newrate)\n" - "+{\n" - "+\tevt->clk = clk;\n" - "+\tevt->old_rate = oldrate;\n" - "+\tevt->new_rate = newrate;\n" - "+}\n" - "+\n" - "+enum clk_fsm_e {\n" - "+\tTRNSC_ENTER_CLOCK\t= 0x10,\n" - "+\tTRNSC_ENTER_DEVICE\t= NOTIFY_CLK_ENTERCHANGE,\t/* 0x1 */\n" - "+\tTRNSC_PRE_DEVICE\t= NOTIFY_CLK_PRECHANGE,\t\t/* 0x2 */\n" - "+\tTRNSC_CHANGE_CLOCK\t= 0x20,\n" - "+\tTRNSC_POST_DEVICE\t= NOTIFY_CLK_POSTCHANGE,\t/* 0x4 */\n" - "+\tTRNSC_EXIT_DEVICE\t= NOTIFY_CLK_EXITCHANGE,\t/* 0x8 */\n" - "+\tTRNSC_EXIT_CLOCK\t= 0x40\n" - "+};\n" - "+\n" - "+#define DEV_SUSPENDED_ON_TRANSACTION\t(0x10)\n" - "+#define DEV_RESUMED_ON_TRANSACTION\t(0x20)\n" - "+#define DEV_ON_TRANSACTION\t(TRNSC_ENTER_DEVICE\t|\t\\\n" - "+\t\t\t\tTRNSC_PRE_DEVICE\t|\t\\\n" - "+\t\t\t\tTRNSC_POST_DEVICE\t|\t\\\n" - "+\t\t\t\tTRNSC_EXIT_DEVICE)\n" - "+\n" - "+static inline int\n" - "+pdev_transaction_move_on(struct platform_device *dev, unsigned int value)\n" - "+{\n" - "+\tint ret = -EINVAL;\n" - "+\tunsigned long flag;\n" - "+#ifdef CONFIG_CLK_DEBUG\n" - "+\tstatic const char *dev_state[] = {\n" - "+\t\t\"dev_enter\",\n" - "+\t\t\"dev_pre\",\n" - "+\t\t\"dev_post\",\n" - "+\t\t\"dev_exit\"\n" - "+\t};\n" - "+\n" - "+\tunsigned long old = dev->clk_state & DEV_ON_TRANSACTION;\n" - "+\tint was = 0, is = 0;\n" - "+\tif (\n" - "+\t (old == 0 && value == TRNSC_ENTER_DEVICE) ||\n" - "+\t (old == TRNSC_ENTER_DEVICE && value == TRNSC_EXIT_DEVICE) ||\n" - "+\t (old == TRNSC_ENTER_DEVICE && value == TRNSC_PRE_DEVICE) ||\n" - "+\t (old == TRNSC_PRE_DEVICE && value == TRNSC_POST_DEVICE) ||\n" - "+\t (old == TRNSC_POST_DEVICE && value == TRNSC_EXIT_DEVICE))\n" - "+\t\tgoto ok;\n" - "+\tswitch (old) {\n" - "+\tcase TRNSC_ENTER_DEVICE:\n" - "+\t\twas = 0;\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_PRE_DEVICE:\n" - "+\t\twas = 1;\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_POST_DEVICE:\n" - "+\t\twas = 2;\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_EXIT_DEVICE:\n" - "+\t\twas = 3;\n" - "+\t\tbreak;\n" - "+\t}\n" - "+\tswitch (value) {\n" - "+\tcase TRNSC_ENTER_DEVICE:\n" - "+\t\tis = 0;\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_PRE_DEVICE:\n" - "+\t\tis = 1;\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_POST_DEVICE:\n" - "+\t\tis = 2;\n" - "+\t\tbreak;\n" - "+\tcase TRNSC_EXIT_DEVICE:\n" - "+\t\tis = 3;\n" - "+\t\tbreak;\n" - "+\t}\n" - "+\tprintk(KERN_ERR \"The device %s.%d shows a wrong evolution during \"\n" - "+\t\t\"a clock transaction\\nDev state was %s and moved on %s\\n\",\n" - "+\t\tdev->name, dev->id, dev_state[was], dev_state[is]);\n" - "+ok:\n" - "+#endif\n" - "+\tlocal_irq_save(flag);\n" - "+\tif ((dev->clk_state & DEV_ON_TRANSACTION) != value) {\n" - "+\t\tdev->clk_state &= ~DEV_ON_TRANSACTION;\n" - "+\t\tdev->clk_state |= value;\n" - "+\t\tret = 0;\n" - "+\t}\n" - "+\tlocal_irq_restore(flag);\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+static inline int\n" - "+clk_set_towner(struct clk *clk, struct clk_tnode *node)\n" - "+{\n" - "+\treturn atomic_cmpxchg((atomic_t *)&clk->towner, 0, (int)node);\n" - "+}\n" - "+\n" - "+static inline void\n" - "+clk_clean_towner(struct clk *clk)\n" - "+{\n" - "+\tatomic_set((atomic_t *)(&clk->towner), 0);\n" - "+}\n" - "+\n" - "+static inline int\n" - "+clk_is_enabled(struct clk *clk)\n" - "+{\n" - "+\treturn clk->rate != 0;\n" - "+}\n" - "+\n" - "+static inline int\n" - "+clk_is_readonly(struct clk *clk)\n" - "+{\n" - "+\treturn !clk->ops || !clk->ops->set_rate;\n" - "+}\n" - "+\n" - "+static inline int\n" - "+clk_allow_propagation(struct clk *clk)\n" - "+{\n" - "+\treturn !!(clk->flags & CLK_EVENT_PROPAGATES);\n" - "+}\n" - "+\n" - "+static inline int\n" - "+clk_is_auto_switching(struct clk *clk)\n" - "+{\n" - "+\treturn !!(clk->flags & CLK_AUTO_SWITCHING);\n" - "+}\n" - "+\n" - "+static inline int\n" - "+clk_follow_parent(struct clk *clk)\n" - "+{\n" - "+\treturn !!(clk->flags & CLK_FOLLOW_PARENT);\n" - "+}\n" - "+\n" - "+enum pdev_add_state {\n" - "+\tPDEV_ADDING,\n" - "+\tPDEV_ADDED,\n" - "+\tPDEV_ADD_FAILED,\n" - "+};\n" - "+\n" - "+enum pdev_probe_state {\n" - "+\tPDEV_PROBEING,\n" - "+\tPDEV_PROBED,\n" - "+\tPDEV_PROBE_FAILED,\n" - "+};\n" - "+\n" - "+int clk_add_device(struct platform_device *dev, enum pdev_add_state state);\n" - "+int clk_probe_device(struct platform_device *dev, enum pdev_probe_state state);\n" - "+int clk_del_device(struct platform_device *dev);\n" - "+\n" - "+#endif\n" - "diff --git a/drivers/base/clk_pm.c b/drivers/base/clk_pm.c\n" - "new file mode 100644\n" - "index 0000000..56c1760\n" - "--- /dev/null\n" - "+++ b/drivers/base/clk_pm.c\n" - "@@ -0,0 +1,197 @@\n" - "+/*\n" - "+ * -------------------------------------------------------------------------\n" - "+ * clk_pm.c\n" - "+ * -------------------------------------------------------------------------\n" - "+ * (C) STMicroelectronics 2008\n" - "+ * (C) STMicroelectronics 2009\n" - "+ * Author: Francesco M. Virlinzi <francesco.virlinzi@st.com>\n" - "+ * -------------------------------------------------------------------------\n" - "+ * May be copied or modified under the terms of the GNU General Public\n" - "+ * License v.2 ONLY. See linux/COPYING for more information.\n" - "+ *\n" - "+ * -------------------------------------------------------------------------\n" - "+ */\n" - "+\n" - "+#include <linux/clk.h>\n" - "+#include <linux/klist.h>\n" - "+#include <linux/list.h>\n" - "+#include <linux/sysdev.h>\n" - "+#include <linux/device.h>\n" - "+#include <linux/kref.h>\n" - "+#include <linux/kobject.h>\n" - "+#include <linux/err.h>\n" - "+#include <linux/spinlock.h>\n" - "+#include <linux/proc_fs.h>\n" - "+#include \"power/power.h\"\n" - "+#include \"clk.h\"\n" - "+#include \"base.h\"\n" - "+\n" - "+static int\n" - "+__clk_operations(struct clk *clk, unsigned long rate, enum clk_ops_id id_ops)\n" - "+{\n" - "+\tint ret = -EINVAL;\n" - "+\tunsigned long *ops_fns = (unsigned long *)clk->ops;\n" - "+\tif (likely(ops_fns && ops_fns[id_ops])) {\n" - "+\t\tint (*fns)(struct clk *clk, unsigned long rate)\n" - "+\t\t\t= (void *)ops_fns[id_ops];\n" - "+\t\tunsigned long flags;\n" - "+\t\tspin_lock_irqsave(&clk->lock, flags);\n" - "+\t\tret = fns(clk, rate);\n" - "+\t\tspin_unlock_irqrestore(&clk->lock, flags);\n" - "+\t}\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+static inline int __clk_init(struct clk *clk)\n" - "+{\n" - "+\treturn __clk_operations(clk, 0, __CLK_INIT);\n" - "+}\n" - "+\n" - "+static inline int __clk_enable(struct clk *clk)\n" - "+{\n" - "+\treturn __clk_operations(clk, 0, __CLK_ENABLE);\n" - "+}\n" - "+\n" - "+static inline int __clk_disable(struct clk *clk)\n" - "+{\n" - "+\treturn __clk_operations(clk, 0, __CLK_DISABLE);\n" - "+}\n" - "+\n" - "+static inline int __clk_set_rate(struct clk *clk, unsigned long rate)\n" - "+{\n" - "+\treturn __clk_operations(clk, rate, __CLK_SET_RATE);\n" - "+}\n" - "+\n" - "+static inline int __clk_set_parent(struct clk *clk, struct clk *parent)\n" - "+{\n" - "+\treturn __clk_operations(clk, (unsigned long)parent, __CLK_SET_PARENT);\n" - "+}\n" - "+\n" - "+static inline int __clk_recalc_rate(struct clk *clk)\n" - "+{\n" - "+\treturn __clk_operations(clk, 0, __CLK_RECALC);\n" - "+}\n" - "+\n" - "+static inline int pm_clk_ratio(struct clk *clk)\n" - "+{\n" - "+\tregister unsigned int val, exp;\n" - "+\n" - "+\tval = ((clk->flags >> CLK_PM_RATIO_SHIFT) &\n" - "+\t\t((1 << CLK_PM_RATIO_NRBITS) - 1)) + 1;\n" - "+\texp = ((clk->flags >> CLK_PM_EXP_SHIFT) &\n" - "+\t\t((1 << CLK_PM_EXP_NRBITS) - 1));\n" - "+\n" - "+\treturn val << exp;\n" - "+}\n" - "+\n" - "+static inline int pm_clk_is_off(struct clk *clk)\n" - "+{\n" - "+\treturn ((clk->flags & CLK_PM_TURNOFF) == CLK_PM_TURNOFF);\n" - "+}\n" - "+\n" - "+static inline void pm_clk_set(struct clk *clk, int edited)\n" - "+{\n" - "+#define CLK_PM_EDITED (1 << CLK_PM_EDIT_SHIFT)\n" - "+\tclk->flags &= ~CLK_PM_EDITED;\n" - "+\tclk->flags |= (edited ? CLK_PM_EDITED : 0);\n" - "+}\n" - "+\n" - "+static inline int pm_clk_is_modified(struct clk *clk)\n" - "+{\n" - "+\treturn ((clk->flags & CLK_PM_EDITED) != 0);\n" - "+}\n" - "+\n" - "+static int clk_resume_from_standby(struct clk *clk, void *data)\n" - "+{\n" - "+\tpr_debug(\"\\n\");\n" - "+\tif (!likely(clk->ops))\n" - "+\t\treturn 0;\n" - "+\t/* check if the pm modified the clock */\n" - "+\tif (!pm_clk_is_modified(clk))\n" - "+\t\treturn 0;;\n" - "+\tpm_clk_set(clk, 0);\n" - "+\tif (pm_clk_is_off(clk))\n" - "+\t\t__clk_enable(clk);\n" - "+\telse\n" - "+\t\t__clk_set_rate(clk, clk->rate * pm_clk_ratio(clk));\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+static int clk_on_standby(struct clk *clk, void *data)\n" - "+{\n" - "+\tpr_debug(\"\\n\");\n" - "+\n" - "+\tif (!clk->ops)\n" - "+\t\treturn 0;\n" - "+\tif (!clk->rate) /* already disabled */\n" - "+\t\treturn 0;\n" - "+\n" - "+\tpm_clk_set(clk, 1);\t/* set as modified */\n" - "+\tif (pm_clk_is_off(clk))\t\t/* turn-off */\n" - "+\t\t__clk_disable(clk);\n" - "+\telse /* reduce */\n" - "+\t\t__clk_set_rate(clk, clk->rate / pm_clk_ratio(clk));\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+static int clk_resume_from_hibernation(struct clk *clk, void *data)\n" - "+{\n" - "+\tunsigned long rate = clk->rate;\n" - "+\tpr_debug(\"\\n\");\n" - "+\t__clk_set_parent(clk, clk->parent);\n" - "+\t__clk_set_rate(clk, rate);\n" - "+\t__clk_recalc_rate(clk);\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)\n" - "+{\n" - "+\tstatic pm_message_t prev_state;\n" - "+\n" - "+\tswitch (state.event) {\n" - "+\tcase PM_EVENT_ON:\n" - "+\t\tswitch (prev_state.event) {\n" - "+\t\tcase PM_EVENT_FREEZE: /* Resumeing from hibernation */\n" - "+\t\t\tclk_for_each(clk_resume_from_hibernation, NULL);\n" - "+\t\t\tbreak;\n" - "+\t\tcase PM_EVENT_SUSPEND:\n" - "+\t\t\tclk_for_each(clk_resume_from_standby, NULL);\n" - "+\t\t\tbreak;\n" - "+\t\t}\n" - "+\tcase PM_EVENT_SUSPEND:\n" - "+\t\tclk_for_each(clk_on_standby, NULL);\n" - "+\t\tbreak;\n" - "+\tcase PM_EVENT_FREEZE:\n" - "+\t\tbreak;\n" - "+\t}\n" - "+\tprev_state = state;\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+static int clks_sysdev_resume(struct sys_device *dev)\n" - "+{\n" - "+\treturn clks_sysdev_suspend(dev, PMSG_ON);\n" - "+}\n" - "+\n" - "+static struct sysdev_class clk_sysdev_class = {\n" - "+\t.name = \"clks\",\n" - "+};\n" - "+\n" - "+static struct sysdev_driver clks_sysdev_driver = {\n" - "+\t.suspend = clks_sysdev_suspend,\n" - "+\t.resume = clks_sysdev_resume,\n" - "+};\n" - "+\n" - "+static struct sys_device clks_sysdev_dev = {\n" - "+\t.cls = &clk_sysdev_class,\n" - "+};\n" - "+\n" - "+static int __init clk_sysdev_init(void)\n" - "+{\n" - "+\tsysdev_class_register(&clk_sysdev_class);\n" - "+\tsysdev_driver_register(&clk_sysdev_class, &clks_sysdev_driver);\n" - "+\tsysdev_register(&clks_sysdev_dev);\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+subsys_initcall(clk_sysdev_init);\n" - "diff --git a/drivers/base/clk_utils.c b/drivers/base/clk_utils.c\n" - "new file mode 100644\n" - "index 0000000..a222aa7\n" - "--- /dev/null\n" - "+++ b/drivers/base/clk_utils.c\n" - "@@ -0,0 +1,456 @@\n" - "+/*\n" - "+ * -------------------------------------------------------------------------\n" - "+ * clk_utils.c\n" - "+ * -------------------------------------------------------------------------\n" - "+ * (C) STMicroelectronics 2008\n" - "+ * (C) STMicroelectronics 2009\n" - "+ * Author: Francesco M. Virlinzi <francesco.virlinzi@st.com>\n" - "+ * -------------------------------------------------------------------------\n" - "+ * May be copied or modified under the terms of the GNU General Public\n" - "+ * License v.2 ONLY. See linux/COPYING for more information.\n" - "+ *\n" - "+ * -------------------------------------------------------------------------\n" - "+ */\n" - "+\n" - "+#include <linux/platform_device.h>\n" - "+#include <linux/clk.h>\n" - "+#include <linux/klist.h>\n" - "+#include <linux/list.h>\n" - "+#include <linux/delay.h>\n" - "+#include <linux/sysdev.h>\n" - "+#include <linux/kref.h>\n" - "+#include <linux/kobject.h>\n" - "+#include <linux/err.h>\n" - "+#include <linux/spinlock.h>\n" - "+#include <asm/atomic.h>\n" - "+#include \"power/power.h\"\n" - "+#include \"clk.h\"\n" - "+#include \"base.h\"\n" - "+\n" - "+int clk_generic_notify(unsigned long code,\n" - "+\tstruct platform_device *pdev, void *data)\n" - "+{\n" - "+\tstruct clk_event *event = (struct clk_event *)data;\n" - "+\tunsigned long event_decode = clk_event_decode(event);\n" - "+\n" - "+\tswitch (code) {\n" - "+\tcase NOTIFY_CLK_ENTERCHANGE:\n" - "+\t\treturn NOTIFY_EVENT_HANDLED;\t/* to accept */\n" - "+\n" - "+\tcase NOTIFY_CLK_PRECHANGE:\n" - "+\t\t/* without clock (not still enabled) the device can not work */\n" - "+\t\tif (event_decode == _CLK_ENABLE)\n" - "+\t\t\treturn NOTIFY_EVENT_NOTHANDLED;\n" - "+\t\treturn NOTIFY_EVENT_HANDLED;\t/* to suspend */\n" - "+\n" - "+\tcase NOTIFY_CLK_POSTCHANGE:\n" - "+\t\t/* without clock (just disabled) the device can not work */\n" - "+\t\tif (event_decode == _CLK_DISABLE)\n" - "+\t\t\treturn NOTIFY_EVENT_NOTHANDLED;\n" - "+\t\treturn NOTIFY_EVENT_HANDLED;\t/* to resume */\n" - "+\n" - "+\tcase NOTIFY_CLK_EXITCHANGE:\n" - "+\t\treturn NOTIFY_EVENT_HANDLED;\n" - "+\t}\n" - "+\n" - "+\treturn NOTIFY_EVENT_HANDLED;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_generic_notify);\n" - "+\n" - "+unsigned long clk_generic_evaluate_rate(struct clk *clk, unsigned long prate)\n" - "+{\n" - "+\tunsigned long current_prate;\n" - "+\n" - "+\tif (!clk->parent)\n" - "+\t\treturn -EINVAL;\n" - "+\n" - "+\tif (!prate)\t/* if zero return zero (on disable: disable!) */\n" - "+\t\treturn 0;\n" - "+\n" - "+\tif (prate == CLK_UNDEFINED_RATE) /* on undefined: undefined */\n" - "+\t\treturn CLK_UNDEFINED_RATE;\n" - "+\n" - "+\tcurrent_prate = clk_get_rate(clk->parent);\n" - "+\tif (current_prate == prate)\n" - "+\t\treturn clk_get_rate(clk);\n" - "+\n" - "+\tif (current_prate > prate) /* down scale */\n" - "+\t\treturn (clk_get_rate(clk) * prate) / current_prate;\n" - "+\telse\n" - "+\t\treturn (clk_get_rate(clk) / current_prate) * prate;\n" - "+}\n" - "+EXPORT_SYMBOL(clk_generic_evaluate_rate);\n" - "+\n" - "+#ifdef CONFIG_PROC_FS\n" - "+/*\n" - "+ * The \"clocks\" file is created under /proc\n" - "+ * to list all the clocks registered in the system\n" - "+ */\n" - "+#include <linux/proc_fs.h>\n" - "+#include <linux/seq_file.h>\n" - "+static void *clk_seq_next(struct seq_file *s, void *v, loff_t *pos)\n" - "+{\n" - "+\tstruct list_head *tmp;\n" - "+\tunion {\n" - "+\t\tloff_t value;\n" - "+\t\tlong parts[2];\n" - "+\t} ltmp;\n" - "+\n" - "+\tltmp.value = *pos;\n" - "+\ttmp = (struct list_head *)ltmp.parts[0];\n" - "+\ttmp = tmp->next;\n" - "+\tltmp.parts[0] = (long)tmp;\n" - "+\n" - "+\t*pos = ltmp.value;\n" - "+\n" - "+\tif (tmp == &clk_list.k_list)\n" - "+\t\treturn NULL; /* No more to read */\n" - "+\n" - "+\treturn pos;\n" - "+}\n" - "+\n" - "+static void *clk_seq_start(struct seq_file *s, loff_t *pos)\n" - "+{\n" - "+\tif (!*pos) { /* first call! */\n" - "+\t\tunion {\n" - "+\t\t\tloff_t value;\n" - "+\t\t\tlong parts[2];\n" - "+\t\t} ltmp;\n" - "+\t\tltmp.parts[0] = (long) clk_list.k_list.next;\n" - "+\t\t*pos = ltmp. value;\n" - "+\t\treturn pos;\n" - "+\t}\n" - "+\t--(*pos); /* to realign *pos value! */\n" - "+\n" - "+\treturn clk_seq_next(s, NULL, pos);\n" - "+}\n" - "+\n" - "+static int clk_seq_show(struct seq_file *s, void *v)\n" - "+{\n" - "+\tunsigned long *l = (unsigned long *)v;\n" - "+\tstruct list_head *node = (struct list_head *)(*l);\n" - "+\tstruct clk *clk = container_of(node, struct clk, node.n_node);\n" - "+\tunsigned long rate = clk_get_rate(clk);\n" - "+\n" - "+\tif (unlikely(!rate && !clk->parent))\n" - "+\t\treturn 0;\n" - "+\n" - "+\tseq_printf(s, \"%-12s\\t: %ld.%02ldMHz - \", clk->name,\n" - "+\t rate / 1000000, (rate % 1000000) / 10000);\n" - "+\tseq_printf(s, \"[0x%p]\", clk);\n" - "+\tif (clk_is_enabled(clk))\n" - "+\t\tseq_printf(s, \" - enabled\");\n" - "+\n" - "+\tif (clk->parent)\n" - "+\t\tseq_printf(s, \" - [%s]\", clk->parent->name);\n" - "+\tseq_printf(s, \"\\n\");\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+static void clk_seq_stop(struct seq_file *s, void *v)\n" - "+{\n" - "+}\n" - "+\n" - "+static const struct seq_operations clk_seq_ops = {\n" - "+\t.start = clk_seq_start,\n" - "+\t.next = clk_seq_next,\n" - "+\t.stop = clk_seq_stop,\n" - "+\t.show = clk_seq_show,\n" - "+};\n" - "+\n" - "+static int clk_proc_open(struct inode *inode, struct file *file)\n" - "+{\n" - "+\treturn seq_open(file, &clk_seq_ops);\n" - "+}\n" - "+\n" - "+static const struct file_operations clk_proc_ops = {\n" - "+\t.owner = THIS_MODULE,\n" - "+\t.open = clk_proc_open,\n" - "+\t.read = seq_read,\n" - "+\t.llseek = seq_lseek,\n" - "+\t.release = seq_release,\n" - "+};\n" - "+\n" - "+static int __init clk_proc_init(void)\n" - "+{\n" - "+\tstruct proc_dir_entry *p;\n" - "+\n" - "+\tp = create_proc_entry(\"clocks\", S_IRUGO, NULL);\n" - "+\n" - "+\tif (unlikely(!p))\n" - "+\t\treturn -EINVAL;\n" - "+\n" - "+\tp->proc_fops = &clk_proc_ops;\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+subsys_initcall(clk_proc_init);\n" - "+#endif\n" - "+\n" - "+#ifdef CONFIG_SYSFS\n" - "+static ssize_t clk_rate_show(struct kobject *kobj,\n" - "+\t\tstruct kobj_attribute *attr, char *buf)\n" - "+{\n" - "+\tstruct clk *clk = container_of(kobj, struct clk, kobj);\n" - "+\n" - "+\treturn sprintf(buf, \"%u\\n\", (unsigned int)clk_get_rate(clk));\n" - "+}\n" - "+\n" - "+static ssize_t clk_rate_store(struct kobject *kobj,\n" - "+\t\tstruct kobj_attribute *attr, const char *buf, size_t count)\n" - "+{\n" - "+\tunsigned long rate = simple_strtoul(buf, NULL, 10);\n" - "+\tstruct clk *clk = container_of(kobj, struct clk, kobj);\n" - "+\n" - "+\tif (rate) {\n" - "+\t\tif (!clk_is_enabled(clk))\n" - "+\t\t\tclk_enable(clk);\n" - "+\t\tif (clk_set_rate(clk, rate) < 0)\n" - "+\t\t\treturn -EINVAL;\n" - "+\t} else\n" - "+\t\tclk_disable(clk);\n" - "+\treturn count;\n" - "+}\n" - "+\n" - "+static const char *clk_ctrl_token[] = {\n" - "+\t\"auto_switching\",\n" - "+\t\"no_auto_switching\",\n" - "+\t\"allow_propagation\",\n" - "+\t\"no_allow_propagation\",\n" - "+\t\"follow_parent\",\n" - "+\t\"no_follow_parent\",\n" - "+};\n" - "+static ssize_t clk_state_show(struct kobject *kobj,\n" - "+\t\tstruct kobj_attribute *attr, char *buf)\n" - "+{\n" - "+\tstruct clk *clk = container_of(kobj, struct clk, kobj);\n" - "+\tssize_t ret;\n" - "+\n" - "+\n" - "+\tret = sprintf(buf, \"clock name: %s\\n\", clk->name);\n" - "+\tif (clk_is_enabled(clk))\n" - "+\t\tret += sprintf(buf + ret, \" + enabled\\n\");\n" - "+\telse\n" - "+\t\tret += sprintf(buf + ret, \" + disabled\\n\");\n" - "+\tif (clk_is_readonly(clk))\n" - "+\t\tret += sprintf(buf + ret, \" + rate read only\\n\");\n" - "+\telse\n" - "+\t\tret += sprintf(buf + ret, \" + rate writable\\n\");\n" - "+\tret +=\n" - "+\t sprintf(buf + ret, \" + %s\\n\",\n" - "+\t\t clk_ctrl_token[(clk_allow_propagation(clk) ? 2 : 3)]);\n" - "+\tret +=\n" - "+\t sprintf(buf + ret, \" + %s\\n\",\n" - "+\t\t clk_ctrl_token[(clk_is_auto_switching(clk) ? 0 : 1)]);\n" - "+\tret +=\n" - "+\t sprintf(buf + ret, \" + %s\\n\",\n" - "+\t\t clk_ctrl_token[(clk_follow_parent(clk) ? 4 : 5)]);\n" - "+\tret +=\n" - "+\t sprintf(buf + ret, \" + nr_clocks: %u\\n\", clk->nr_clocks);\n" - "+\tret +=\n" - "+\t sprintf(buf + ret, \" + nr_active_clocks: %u\\n\",\n" - "+\t\tclk->nr_active_clocks);\n" - "+\tret +=\n" - "+\t sprintf(buf + ret, \" + nr_active_devices: %u\\n\",\n" - "+\t\tclk->nr_active_devices);\n" - "+\tret +=\n" - "+\t sprintf(buf + ret, \" + rate: %u\\n\",\n" - "+\t\t (unsigned int)clk_get_rate(clk));\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+static ssize_t clk_ctrl_show(struct kobject *kobj,\n" - "+\t\tstruct kobj_attribute *attr, char *buf)\n" - "+{\n" - "+\tint idx, ret = 0;\n" - "+\n" - "+\tret += sprintf(buf + ret, \"Allowed command:\\n\");\n" - "+\n" - "+\tfor (idx = 0; idx < ARRAY_SIZE(clk_ctrl_token); ++idx)\n" - "+\t\tret += sprintf(buf + ret, \" + %s\\n\", clk_ctrl_token[idx]);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+static ssize_t clk_ctrl_store(struct kobject *kobj,\n" - "+\t\tstruct kobj_attribute *attr, const char *buf, size_t count)\n" - "+{\n" - "+\tint i, idx_token, ret = -EINVAL;\n" - "+\tstruct clk *clk = container_of(kobj, struct clk, kobj);\n" - "+\n" - "+\tif (!count)\n" - "+\t\treturn ret;\n" - "+\n" - "+\tfor (i = 0, idx_token = -1; i < ARRAY_SIZE(clk_ctrl_token); ++i)\n" - "+\t\tif (!strcmp(buf, clk_ctrl_token[i]))\n" - "+\t\t\tidx_token = i;\n" - "+\n" - "+\tif (idx_token == -EINVAL)\n" - "+\t\treturn ret; /* token not valid... */\n" - "+\n" - "+\tswitch (idx_token) {\n" - "+\tcase 0:\n" - "+\t\tclk->flags |= CLK_EVENT_PROPAGATES;\n" - "+\t\tbreak;\n" - "+\tcase 1:\n" - "+\t\tclk->flags &= ~CLK_EVENT_PROPAGATES;\n" - "+\t\tbreak;\n" - "+\tcase 2:\n" - "+\t\tclk->flags |= CLK_AUTO_SWITCHING;\n" - "+\t\tif (!clk->nr_active_clocks && !clk->nr_active_devices)\n" - "+\t\t\tclk_disable(clk);\n" - "+\t\telse if (clk->nr_active_clocks || clk->nr_active_devices)\n" - "+\t\t\tclk_enable(clk);\n" - "+\t\tbreak;\n" - "+\tcase 3:\n" - "+\t\tclk->flags &= ~CLK_AUTO_SWITCHING;\n" - "+\t\tbreak;\n" - "+\tcase 4:\n" - "+\t\tclk->flags |= CLK_FOLLOW_PARENT;\n" - "+\t\tbreak;\n" - "+\tcase 5:\n" - "+\t\tclk->flags &= ~CLK_FOLLOW_PARENT;\n" - "+\t\tbreak;\n" - "+\t}\n" - "+\n" - "+\treturn count;\n" - "+}\n" - "+\n" - "+static ssize_t clk_parent_store(struct kobject *kobj,\n" - "+\t\tstruct kobj_attribute *attr, const char *buf, size_t count)\n" - "+{\n" - "+\tstruct clk *clk = container_of(kobj, struct clk, kobj);\n" - "+\tstruct clk *parent = clk_get(NULL, buf);\n" - "+\n" - "+\tif (!parent)\n" - "+\t\treturn -EINVAL;\n" - "+\n" - "+\tclk_put(parent);\n" - "+\tclk_set_parent(clk, parent);\n" - "+\n" - "+\treturn count;\n" - "+}\n" - "+\n" - "+static struct kobj_attribute attributes[] = {\n" - "+__ATTR(state, S_IRUSR, clk_state_show, NULL),\n" - "+__ATTR(rate, S_IRUSR | S_IWUSR, clk_rate_show, clk_rate_store),\n" - "+__ATTR(control, S_IRUSR | S_IWUSR, clk_ctrl_show, clk_ctrl_store),\n" - "+__ATTR(parent, S_IWUSR, NULL, clk_parent_store)\n" - "+};\n" - "+\n" - "+static struct attribute *clk_attrs[] = {\n" - "+\t&attributes[0].attr,\n" - "+\t&attributes[1].attr,\n" - "+\t&attributes[2].attr,\n" - "+\t&attributes[3].attr,\n" - "+\tNULL\n" - "+};\n" - "+\n" - "+static struct attribute_group clk_attr_group = {\n" - "+\t.attrs = clk_attrs,\n" - "+\t.name = \"attributes\"\n" - "+};\n" - "+\n" - "+#if 0\n" - "+static inline char *_strsep(char **s, const char *d)\n" - "+{\n" - "+\tint i, len = strlen(d);\n" - "+retry:\n" - "+\tif (!(*s) || !(**s))\n" - "+\t\treturn NULL;\n" - "+\tfor (i = 0; i < len; ++i) {\n" - "+\t\tif (**s != *(d+i))\n" - "+\t\t\tcontinue;\n" - "+\t\t++(*s);\n" - "+\t\tgoto retry;\n" - "+\t}\n" - "+\treturn strsep(s, d);\n" - "+}\n" - "+\n" - "+/**\n" - "+ * clk_rates_store\n" - "+ *\n" - "+ * It parses the buf to create multi clocks transaction\n" - "+ * via user space\n" - "+ * The buffer has to be something like:\n" - "+ * clock_A @ rate_A; clock_B @ rate_b; clock_C @ rate_c\n" - "+ */\n" - "+static ssize_t clk_rates_store(struct kobject *kobj,\n" - "+\t\tstruct kobj_attribute *attr, const char *buf, size_t count)\n" - "+{\n" - "+\tint i, ret;\n" - "+\tint nclock = 0;\n" - "+\tunsigned long *rates;\n" - "+\tstruct clk **clocks;\n" - "+\n" - "+\tif (!buf)\n" - "+\t\treturn -1;\n" - "+\n" - "+\tfor (i = 0; i < count; ++i)\n" - "+\t\tif (buf[i] == '@')\n" - "+\t\t\t++nclock;\n" - "+\n" - "+\trates = kmalloc(sizeof(long) * nclock, GFP_KERNEL);\n" - "+\tif (!rates)\n" - "+\t\treturn -ENOMEM;\n" - "+\n" - "+\tclocks = kmalloc(sizeof(void *) * nclock, GFP_KERNEL);\n" - "+\tif (!clocks) {\n" - "+\t\tret = -ENOMEM;\n" - "+\t\tgoto err_0;\n" - "+\t}\n" - "+\n" - "+\t/* Parse the buffer */\n" - "+\tfor (i = 0; i < nclock; ++i) {\n" - "+\t\tchar *name;\n" - "+\t\tchar *nrate;\n" - "+\t\tname = _strsep((char **)&buf, \"@ \"); ++buf;\n" - "+\t\tnrate = _strsep((char **)&buf, \" ;\"); ++buf;\n" - "+\t\tif (!name || !nrate) {\n" - "+\t\t\tret = -EINVAL;\n" - "+\t\t\tgoto err_1;\n" - "+\t\t\t}\n" - "+\t\tclocks[i] = clk_get(NULL, name);\n" - "+\t\trates[i] = simple_strtoul(nrate, NULL, 10);\n" - "+\t\tif (!clocks[i]) { /* the clock doesn't exist! */\n" - "+\t\t\tret = -EINVAL;\n" - "+\t\t\tgoto err_1;\n" - "+\t\t\t}\n" - "+\t}\n" - "+\n" - "+\tret = clk_set_rates(clocks, rates, nclock);\n" - "+\tif (ret >= 0)\n" - "+\t\tret = count; /* to say OK */\n" - "+\n" - "+err_1:\n" - "+\tkfree(clocks);\n" - "+err_0:\n" - "+\tkfree(rates);\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+static struct kobj_attribute clk_rates_attr =\n" - "+\t__ATTR(rates, S_IWUSR, NULL, clk_rates_store);\n" - "+#endif\n" - "+\n" - "+static int __init clk_add_attributes(struct clk *clk, void *data)\n" - "+{\n" - "+\tint ret;\n" - "+\n" - "+\tret = sysfs_update_group(&clk->kobj, &clk_attr_group);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+static int __init clk_late_init(void)\n" - "+{\n" - "+\tint ret;\n" - "+\n" - "+\tret = clk_for_each(clk_add_attributes, NULL);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+late_initcall(clk_late_init);\n" - "+#endif\n" - "diff --git a/drivers/base/init.c b/drivers/base/init.c\n" - "index 7bd9b6a..2441b26 100644\n" - "--- a/drivers/base/init.c\n" - "+++ b/drivers/base/init.c\n" - "@@ -24,6 +24,7 @@ void __init driver_init(void)\n" - " \tbuses_init();\n" - " \tclasses_init();\n" - " \tfirmware_init();\n" - "+\tclock_init();\n" - " \thypervisor_init();\n" - " \n" - " \t/* These are also core pieces, but must come after the\n" - "diff --git a/drivers/base/platform.c b/drivers/base/platform.c\n" - "index 8b4708e..550d993 100644\n" - "--- a/drivers/base/platform.c\n" - "+++ b/drivers/base/platform.c\n" - "@@ -17,6 +17,8 @@\n" - " #include <linux/bootmem.h>\n" - " #include <linux/err.h>\n" - " #include <linux/slab.h>\n" - "+#include <linux/clk.h>\n" - "+#include \"clk.h\"\n" - " \n" - " #include \"base.h\"\n" - " \n" - "@@ -272,9 +274,20 @@ int platform_device_add(struct platform_device *pdev)\n" - " \tpr_debug(\"Registering platform device '%s'. Parent at %s\\n\",\n" - " \t\t dev_name(&pdev->dev), dev_name(pdev->dev.parent));\n" - " \n" - "+#ifdef CONFIG_GENERIC_CLK_FM\n" - "+\tclk_add_device(pdev, PDEV_ADDING);\n" - "+\n" - "+\tret = device_add(&pdev->dev);\n" - "+\n" - "+\tclk_add_device(pdev, (ret ? PDEV_ADD_FAILED : PDEV_ADDED));\n" - "+\n" - "+\tif (ret == 0)\n" - "+\t\treturn ret;\n" - "+#else\n" - " \tret = device_add(&pdev->dev);\n" - " \tif (ret == 0)\n" - " \t\treturn ret;\n" - "+#endif\n" - " \n" - " failed:\n" - " \twhile (--i >= 0) {\n" - "@@ -311,6 +324,9 @@ void platform_device_del(struct platform_device *pdev)\n" - " \t\t\tif (type == IORESOURCE_MEM || type == IORESOURCE_IO)\n" - " \t\t\t\trelease_resource(r);\n" - " \t\t}\n" - "+#ifdef CONFIG_GENERIC_CLK_FM\n" - "+\tclk_del_device(pdev);\n" - "+#endif\n" - " \t}\n" - " }\n" - " EXPORT_SYMBOL_GPL(platform_device_del);\n" - "@@ -445,7 +461,18 @@ static int platform_drv_probe(struct device *_dev)\n" - " \tstruct platform_driver *drv = to_platform_driver(_dev->driver);\n" - " \tstruct platform_device *dev = to_platform_device(_dev);\n" - " \n" - "+#ifdef CONFIG_GENERIC_CLK_FM\n" - "+\tint ret;\n" - "+\tret = clk_probe_device(dev, PDEV_PROBEING);\n" - "+\tif (ret)\n" - "+\t\treturn ret;\n" - "+\tret = drv->probe(dev);\n" - "+\n" - "+\tclk_probe_device(dev, (ret ? PDEV_PROBE_FAILED : PDEV_PROBED));\n" - "+\treturn ret;\n" - "+#else\n" - " \treturn drv->probe(dev);\n" - "+#endif\n" - " }\n" - " \n" - " static int platform_drv_probe_fail(struct device *_dev)\n" - "diff --git a/include/linux/clk.h b/include/linux/clk.h\n" - "index 1db9bbf..e537bcd 100644\n" - "--- a/include/linux/clk.h\n" - "+++ b/include/linux/clk.h\n" - "@@ -12,6 +12,7 @@\n" - " #define __LINUX_CLK_H\n" - " \n" - " struct device;\n" - "+struct platform_device;\n" - " \n" - " /*\n" - " * The base API.\n" - "@@ -142,4 +143,254 @@ struct clk *clk_get_parent(struct clk *clk);\n" - " */\n" - " struct clk *clk_get_sys(const char *dev_id, const char *con_id);\n" - " \n" - "+/**\n" - "+ * clk_set_rates - set the clock rates\n" - "+ * @clk: clocks source\n" - "+ * @rate: desired clock rates in Hz\n" - "+ * @nclks: the number of clocks\n" - "+ *\n" - "+ * Returns success (0) or negative errno.\n" - "+ */\n" - "+int clk_set_rates(struct clk **clk, unsigned long *rates, unsigned long nclks);\n" - "+\n" - "+#ifndef CONFIG_GENERIC_CLK_FM\n" - "+\n" - "+#define bind_clock(_clk)\n" - "+#define pdevice_setclock(_dev, _clk)\n" - "+#define pdevice_setclock_byname(_dev, _clkname)\n" - "+#define pdevice_num_clocks(_dev)\n" - "+#define pdevice_clock(dev, idx)\n" - "+\n" - "+#else\n" - "+\n" - "+#include <linux/kobject.h>\n" - "+#include <linux/klist.h>\n" - "+#include <linux/notifier.h>\n" - "+#include <linux/pm.h>\n" - "+#include <linux/spinlock.h>\n" - "+#include <asm/atomic.h>\n" - "+\n" - "+\n" - "+/**\n" - "+ * Clock operation -\n" - "+ *\n" - "+ * It's a set of function pointer to identify all the capability on a clock\n" - "+ */\n" - "+struct clk_ops {\n" - "+/** @init initializes the clock\t*/\n" - "+\tint (*init)(struct clk *);\n" - "+/** @enable enables the clock\t*/\n" - "+\tint (*enable)(struct clk *);\n" - "+/** @disable disables the clock\t*/\n" - "+\tint (*disable)(struct clk *);\n" - "+/** @set_rate sets the new frequency rate */\n" - "+\tint (*set_rate)(struct clk *, unsigned long value);\n" - "+/** @set_parent sets the new parent clock */\n" - "+\tint (*set_parent)(struct clk *clk, struct clk *parent);\n" - "+/** @recalc updates the clock rate when the parent clock is updated\t */\n" - "+\tvoid (*recalc)(struct clk *);\n" - "+/** @round returns the allowed rate on the required value\t*/\n" - "+\tunsigned long (*round)(struct clk *, unsigned long value);\n" - "+/** @eval evaluates the clock rate based on a parent_rate but the\n" - "+ * real clock rate is __not__ changed\n" - "+ */\n" - "+\tunsigned long (*eval)(struct clk *, unsigned long parent_rate);\n" - "+};\n" - "+\n" - "+/**\n" - "+ * struct clk - clock object\n" - "+ */\n" - "+struct clk {\n" - "+\tspinlock_t\t\tlock;\n" - "+\n" - "+\tstruct kobject\t\tkobj;\n" - "+\tstruct kobject\t\t*kdevices;\n" - "+\n" - "+\tint\t\t\tid;\n" - "+\n" - "+\tconst char\t\t*name;\n" - "+\tstruct module\t\t*owner;\n" - "+\n" - "+\tstruct clk\t\t*parent;\n" - "+\tstruct clk_ops\t\t*ops;\n" - "+\n" - "+\tvoid\t\t\t*private_data;\n" - "+\n" - "+\tunsigned long\t\trate;\n" - "+\tunsigned long\t\tflags;\n" - "+\n" - "+\tunsigned int\t\tnr_active_clocks;\n" - "+\tunsigned int\t\tnr_active_devices;\n" - "+\tunsigned int\t\tnr_clocks;\n" - "+\n" - "+\tvoid\t\t\t*towner;/* the transaction owner of the clock */\n" - "+\n" - "+\tstruct klist\t\tchilds;\n" - "+\tstruct klist\t\tdevices;\n" - "+\n" - "+\tstruct klist_node\tnode;\t\t/* for global link\t*/\n" - "+\tstruct klist_node\tchild_node;\t/* for child link\t*/\n" - "+};\n" - "+\n" - "+#define CLK_ALWAYS_ENABLED\t\t(0x1 << 0)\n" - "+#define CLK_EVENT_PROPAGATES\t\t(0x1 << 1)\n" - "+#define CLK_RATE_PROPAGATES\t\tCLK_EVENT_PROPAGATES\n" - "+/* CLK_AUTO_SWITCHING: enable/disable the clock based on the\n" - "+ * current active children\n" - "+ */\n" - "+#define CLK_AUTO_SWITCHING\t\t(0x1 << 2)\n" - "+/* CLK_FOLLOW_PARENT: enable/disable the clock as the parent is\n" - "+ * enabled/disabled\n" - "+ */\n" - "+#define CLK_FOLLOW_PARENT\t\t(0x1 << 3)\n" - "+\n" - "+/*\n" - "+ * Flags to support the system standby\n" - "+ */\n" - "+#define CLK_PM_EXP_SHIFT\t(24)\n" - "+#define CLK_PM_EXP_NRBITS\t(7)\n" - "+#define CLK_PM_RATIO_SHIFT\t(16)\n" - "+#define CLK_PM_RATIO_NRBITS\t(8)\n" - "+#define CLK_PM_EDIT_SHIFT\t(31)\n" - "+#define CLK_PM_EDIT_NRBITS\t(1)\n" - "+#define CLK_PM_TURNOFF\t\t(((1<<CLK_PM_EXP_NRBITS)-1) << CLK_PM_EXP_SHIFT)\n" - "+\n" - "+int early_clk_register(struct clk *);\n" - "+/**\n" - "+ * Registers a new clock into the system\n" - "+ */\n" - "+int clk_register(struct clk *);\n" - "+/**\n" - "+ * Unregisters a clock into the system\n" - "+ */\n" - "+int clk_unregister(struct clk *);\n" - "+\n" - "+/**\n" - "+ * Returns the clock rate if the parent clock is 'parent_rate'\n" - "+ */\n" - "+unsigned long clk_evaluate_rate(struct clk *, unsigned long parent_rate);\n" - "+\n" - "+#define CLK_UNDEFINED_RATE\t(-1UL)\n" - "+/**\n" - "+ * Utility functions in the clock framework\n" - "+ */\n" - "+int clk_for_each(int (*fn)(struct clk *, void *), void *);\n" - "+\n" - "+int clk_for_each_child(struct clk *, int (*fn)(struct clk *, void *), void *);\n" - "+\n" - "+/** struct pdev_clk_info -\n" - "+ *\n" - "+ * It's a meta data used to link the device of linux driver model\n" - "+ * to the clock framework.\n" - "+ * The device driver developers has to set only the clk field\n" - "+ * all the other fileds are managed in the clk core code\n" - "+ */\n" - "+struct pdev_clk_info {\n" - "+\t/** the device owner */\n" - "+\tstruct platform_device *pdev;\n" - "+\t/** the clock address\t*/\n" - "+\tstruct clk\t\t*clk;\n" - "+\t/** used by the clock core*/\n" - "+\tstruct klist_node\tnode;\n" - "+};\n" - "+\n" - "+/******************** clk transition notifiers *******************/\n" - "+#define\tNOTIFY_CLK_ENTERCHANGE\t0x1\n" - "+#define\tNOTIFY_CLK_PRECHANGE\t0x2\n" - "+#define\tNOTIFY_CLK_POSTCHANGE\t0x4\n" - "+#define NOTIFY_CLK_EXITCHANGE\t0x8\n" - "+\n" - "+/** struct clk_event\n" - "+ *\n" - "+ * It's the object propagated during a clock transaction.\n" - "+ * During a transaction each device will receive an array of 'struct clk_event'\n" - "+ * based on the clocks it uses\n" - "+ */\n" - "+struct clk_event {\n" - "+\t/** on which clock the event is\t\t*/\n" - "+\tstruct clk *clk;\n" - "+\t/** the clock rate before the event\t*/\n" - "+\tunsigned long old_rate;\n" - "+\t/** the clock rate after the event\t*/\n" - "+\tunsigned long new_rate;\n" - "+};\n" - "+\n" - "+enum clk_event_e {\n" - "+\t_CLK_NOCHANGE,\n" - "+\t_CLK_ENABLE,\n" - "+\t_CLK_DISABLE,\n" - "+\t_CLK_CHANGE\n" - "+};\n" - "+\n" - "+/**\n" - "+ * clk_event_decode -\n" - "+ *\n" - "+ * @event: the events has to be decoded\n" - "+ * It's an utility function to identify what each clock\n" - "+ * is doing\n" - "+ */\n" - "+static inline enum clk_event_e clk_event_decode(struct clk_event const *event)\n" - "+{\n" - "+\tif (event->old_rate == event->new_rate)\n" - "+\t\treturn _CLK_NOCHANGE;\n" - "+\tif (!event->old_rate && event->new_rate)\n" - "+\t\treturn _CLK_ENABLE;\n" - "+\tif (event->old_rate && !event->new_rate)\n" - "+\t\treturn _CLK_DISABLE;\n" - "+\treturn _CLK_CHANGE;\n" - "+}\n" - "+\n" - "+enum notify_ret_e {\n" - "+\tNOTIFY_EVENT_HANDLED = 0,\t\t/* event handled\t*/\n" - "+\tNOTIFY_EVENT_NOTHANDLED,\t\t/* event not handled\t*/\n" - "+};\n" - "+\n" - "+/* Some macro device oriented static initialization */\n" - "+#define bind_clock(_clk)\t\t\t\t\t\\\n" - "+\t.nr_clks = 1,\t\t\t\t\t\t\\\n" - "+\t.clks = (struct pdev_clk_info[]) { {\t\t\t\\\n" - "+\t\t.clk = (_clk),\t\t\t\t\t\\\n" - "+\t\t} },\n" - "+\n" - "+#define pdevice_setclock(_dev, _clk)\t\t\t\t\\\n" - "+\t(_dev)->clks[0].clk = (_clk);\t\t\t\t\\\n" - "+\t(_dev)->nr_clks = 1;\n" - "+\n" - "+#define pdevice_setclock_byname(_dev, _clkname)\t\t\t\\\n" - "+\t(_dev)->clks[0].clk = clk_get(NULL, _clkname);\t\t\\\n" - "+\t(_dev)->nr_clks = 1;\n" - "+\n" - "+#define pdevice_num_clocks(_dev)\t((_dev)->nr_clks)\n" - "+\n" - "+#define pdevice_clock(dev, idx)\t\t((dev)->clks[(idx)].clk)\n" - "+\n" - "+/**\n" - "+ * clk_generic_notify -\n" - "+ *\n" - "+ * @code: the code event\n" - "+ * @dev: the platform_device under transaction\n" - "+ * @data: the clock event descriptor\n" - "+ *\n" - "+ * it's a generic notify function for devie with _only_\n" - "+ * one clock. It will :\n" - "+ * - accept every 'ENTER' state\n" - "+ * - suspend on 'PRE' state\n" - "+ * - resume on 'POST' state\n" - "+ * - do nothing on 'EXIT' state\n" - "+ */\n" - "+int clk_generic_notify(unsigned long code, struct platform_device *dev,\n" - "+\tvoid *data);\n" - "+\n" - "+/*\n" - "+ * clk_generic_evaluate_rate\n" - "+ *\n" - "+ * @clk: the analised clock\n" - "+ * @prate: the parent rate\n" - "+ *\n" - "+ * Evaluate the clock rate (without hardware modification) based on a 'prate'\n" - "+ * parent clock rate. It's based on 'divisor' relationship\n" - "+ * between parent and child\n" - "+ */\n" - "+unsigned long clk_generic_evaluate_rate(struct clk *clk, unsigned long prate);\n" - "+#endif\n" - " #endif\n" - "diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h\n" - "index b67bb5d..db1989d 100644\n" - "--- a/include/linux/platform_device.h\n" - "+++ b/include/linux/platform_device.h\n" - "@@ -12,6 +12,7 @@\n" - " #define _PLATFORM_DEVICE_H_\n" - " \n" - " #include <linux/device.h>\n" - "+#include <linux/clk.h>\n" - " #include <linux/mod_devicetable.h>\n" - " \n" - " struct platform_device {\n" - "@@ -22,6 +23,11 @@ struct platform_device {\n" - " \tstruct resource\t* resource;\n" - " \n" - " \tstruct platform_device_id\t*id_entry;\n" - "+#ifdef CONFIG_GENERIC_CLK_FM\n" - "+\tunsigned long\tclk_state; /* used by the core */\n" - "+\tunsigned long\tnr_clks;\n" - "+\tstruct pdev_clk_info *clks;\n" - "+#endif\n" - " };\n" - " \n" - " #define platform_get_device_id(pdev)\t((pdev)->id_entry)\n" - "@@ -61,6 +67,9 @@ struct platform_driver {\n" - " \tint (*resume_early)(struct platform_device *);\n" - " \tint (*resume)(struct platform_device *);\n" - " \tstruct device_driver driver;\n" - "+#ifdef CONFIG_GENERIC_CLK_FM\n" - "+\tint (*notify)(unsigned long code, struct platform_device *, void *);\n" - "+#endif\n" - " \tstruct platform_device_id *id_table;\n" - " };\n" - " \n" - "diff --git a/init/Kconfig b/init/Kconfig\n" - "index 0682ecc..4254c5f 100644\n" - "--- a/init/Kconfig\n" - "+++ b/init/Kconfig\n" - "@@ -1042,6 +1042,29 @@ config SLOW_WORK\n" - " \n" - " \t See Documentation/slow-work.txt.\n" - " \n" - "+config GENERIC_CLK_FM\n" - "+ default n\n" - "+\tdepends on EXPERIMENTAL\n" - "+ bool \"Generic Clock Framework\"\n" - "+ help\n" - "+ Add the clock framework in the Linux driver model\n" - "+ to track the clocks used by each devices and drivers\n" - "+\n" - "+config CLK_FORCE_GENERIC_EVALUATE\n" - "+ depends on GENERIC_CLK_FM\n" - "+ default n\n" - "+ bool \"Force the clk_generic_evaluate_rate\"\n" - "+ help\n" - "+ Say the if you want use the clk_generic_evaluate_rate on every clock\n" - "+ without evaluate_rate\n" - "+\n" - "+config CLK_DEBUG\n" - "+ depends on GENERIC_CLK_FM\n" - "+ default n\n" - "+ bool \"Debug the Generic Clk Framework\"\n" - "+ help\n" - "+ Prints some message to debug the clock framework\n" - "+\n" - " endmenu\t\t# General setup\n" - " \n" - " config HAVE_GENERIC_DMA_COHERENT\n" - "-- \n" - 1.6.2.5 - "\01:3\0" - "b\0" - "_______________________________________________\n" - "linux-arm-kernel mailing list\n" - "linux-arm-kernel@lists.infradead.org\n" - http://lists.infradead.org/mailman/listinfo/linux-arm-kernel + " Francesco\n" + "-------------- next part --------------\n" + "An HTML attachment was scrubbed...\n" + "URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20091110/a197b928/attachment-0001.htm>\n" + "-------------- next part --------------\n" + "An embedded and charset-unspecified text was scrubbed...\n" + "Name: 0001-generic-clock-framework.patch\n" + URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20091110/a197b928/attachment-0001.el> -722b6b97e358e49c261c236cffa3973e57a9e77fbafce148cb2d13547051f6d3 +8ee3db8167487feb3806c9b36ca0cbd707f648353f6abd185eac353d5493546a
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.