public inbox for linux-omap@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] OMAP: Asynchronous clock disable
@ 2007-10-05 12:50 Jarkko Lavinen
  2007-10-05 13:25 ` Igor Stoppa
  2007-10-05 13:27 ` Woodruff, Richard
  0 siblings, 2 replies; 5+ messages in thread
From: Jarkko Lavinen @ 2007-10-05 12:50 UTC (permalink / raw)
  To: linux-omap-open-source

[-- Attachment #1: Type: text/plain, Size: 1507 bytes --]

Hi

In N800 mmc driver we enable and disable mmc clock in a continous
cycle with small delays.

I wonder if asynchronou clock disable has been suggested before?

I would like to be able to disable clocks asynchronously with a
small delay so that when doing repetitive clk enable/disable
cycle, the clock would just stay up and only shut down when
the continuos stream of requests is over.

What I would like to do is:

     clk_enable(clk):
     ... process the request
     clk_disable_async(clk, 2);

This would leave clock running for 2 ticks after returning from
clk_disable_async() and only then disable it. In mmc driver the
delay could be close to 50 ms.

If clk_disable_async() would be reapplies, the latter call would
stay in effect since it is done using mod_timer().  For example here 
the clock would be disabled 1 tick after the second call to 
clk_disable_async():

     clk_enable(clk);
     clk_disable_async(clk, HZ);
     clk_enable(clk);
     clk_disable_async(clk, 1);


If clk_disable() and clk_disable_async() would be mixed, clk_disable()
would not cancel pending clk disable since the usecount would still
be bigger than 0 after calling clk_disable():

     clk_enable(clk);
     clk_disable_async(clk, HZ);
     clk_enable(clk);
     clk_disable(clk);

For clearing up pending clock disables I use clk_flush_disable(clk)
clears out any pending disable immediately.

     clk_enable(clk);
     clk_disable_async(clk, HZ);
     ... later
     clk_flush_disable(clk)


Jarkko Lavinen

[-- Attachment #2: 0001-OMAP-Add-asynchronous-clock-disable.patch --]
[-- Type: text/x-diff, Size: 4550 bytes --]

>From 557e94d0a43efbc7e312ab7c1d8a568d65a9310a Mon Sep 17 00:00:00 2001
From: Jarkko Lavinen <jarkko.lavinen@nokia.com>
Date: Fri, 5 Oct 2007 15:39:46 +0300
Subject: [PATCH] OMAP: Add asynchronous clock disable

Asynchronouse clock disable is useful for repetitive request processing,
where clock is enabled and disabled continuosly.

Signed-off-by: Jarkko Lavinen <jarkko.lavinen@nokia.com>
---
 arch/arm/plat-omap/clock.c        |   56 +++++++++++++++++++++++++++++++++++--
 include/asm-arm/arch-omap/clock.h |    4 ++
 include/linux/clk.h               |   16 ++++++++++
 3 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 70f2311..a94b122 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -127,7 +127,7 @@ int clk_enable(struct clk *clk)
 }
 EXPORT_SYMBOL(clk_enable);
 
-void clk_disable(struct clk *clk)
+void clk_disable_async(struct clk *clk, int ticks)
 {
 	unsigned long flags;
 
@@ -142,14 +142,61 @@ void clk_disable(struct clk *clk)
 		goto out;
 	}
 
-	if (arch_clock->clk_disable)
-		arch_clock->clk_disable(clk);
+	if (ticks > 0) {
+		if ((clk->flags & CLOCK_ASYNC_DISABLE) == 0) {
+			printk(KERN_ERR "Trying to disable clock %s "
+			       "asynchronousely without proper "
+			       "initialization\n", clk->name);
+			WARN_ON(1);
+		} else {
+			if (timer_pending(&clk->disable_timer))
+				clk->usecount--;
+
+			mod_timer(&clk->disable_timer, jiffies + ticks);
+		}
+	} else
+		if (arch_clock->clk_disable)
+			arch_clock->clk_disable(clk);
+out:
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable_async);
+
+void clk_flush_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if ((clk->flags & CLOCK_ASYNC_DISABLE) == 0) {
+		printk(KERN_ERR "Trying to disable clock %s asynchronousely "
+		       "without timer initialization\n", clk->name);
+		WARN_ON(1);
+		goto out;
+	}
 
+	if (timer_pending(&clk->disable_timer)) {
+		del_timer(&clk->disable_timer);
+		if (arch_clock->clk_disable)
+			arch_clock->clk_disable(clk);
+	}
 out:
 	spin_unlock_irqrestore(&clockfw_lock, flags);
 }
+EXPORT_SYMBOL(clk_flush_disable);
+
+void clk_disable(struct clk *clk)
+{
+	clk_disable_async(clk, 0);
+}
 EXPORT_SYMBOL(clk_disable);
 
+static void clk_disable_timer(unsigned long data)
+{
+	struct clk *clk = (struct clk *) data;
+
+	clk_disable_async(clk, 0);
+}
+
 int clk_get_usecount(struct clk *clk)
 {
 	unsigned long flags;
@@ -336,6 +383,9 @@ int clk_register(struct clk *clk)
 
 	mutex_lock(&clocks_mutex);
 	list_add(&clk->node, &clocks);
+	if (clk->flags & CLOCK_ASYNC_DISABLE)
+		setup_timer(&clk->disable_timer, clk_disable_timer,
+			    (unsigned long) clk);
 	if (clk->init)
 		clk->init(clk);
 	mutex_unlock(&clocks_mutex);
diff --git a/include/asm-arm/arch-omap/clock.h b/include/asm-arm/arch-omap/clock.h
index cb7a301..aa95aac 100644
--- a/include/asm-arm/arch-omap/clock.h
+++ b/include/asm-arm/arch-omap/clock.h
@@ -13,6 +13,8 @@
 #ifndef __ARCH_ARM_OMAP_CLOCK_H
 #define __ARCH_ARM_OMAP_CLOCK_H
 
+#include <linux/timer.h>
+
 struct module;
 struct clk;
 
@@ -57,6 +59,7 @@ struct clk {
 	void __iomem		*enable_reg;
 	__u8			enable_bit;
 	__s8			usecount;
+	struct timer_list	disable_timer;
 	void			(*recalc)(struct clk *);
 	int			(*set_rate)(struct clk *, unsigned long);
 	long			(*round_rate)(struct clk *, unsigned long);
@@ -123,6 +126,7 @@ extern void clk_enable_init_clocks(void);
 #define CLOCK_IN_OMAP243X	(1 << 26)
 #define CLOCK_IN_OMAP343X	(1 << 27)
 #define PARENT_CONTROLS_CLOCK	(1 << 28)
+#define CLOCK_ASYNC_DISABLE	(1 << 29)
 
 /* Clksel_rate flags */
 #define DEFAULT_RATE            (1 << 0)
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 5ca8c6f..c922f79 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -63,6 +63,22 @@ int clk_enable(struct clk *clk);
 void clk_disable(struct clk *clk);
 
 /**
+ * clk_disable_async - disable the clock after a delay
+ * @clk:   clock source
+ * @ticks: delay
+ *
+ * Asyncronous clock disable is implemented with a timer which runs
+ * clk_disable when the timer expires.
+ */
+void clk_disable_async(struct clk *clk, int ticks);
+
+/**
+ * clk_sync_disable - Finish pending clock disable immediately
+ * @clk: clock source
+ */
+void clk_flush_disable(struct clk *clk);
+
+/**
  * clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
  *		  This is only valid once the clock source has been enabled.
  * @clk: clock source
-- 
1.5.3.1


[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-10-09 22:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-10-05 12:50 [PATCH] OMAP: Asynchronous clock disable Jarkko Lavinen
2007-10-05 13:25 ` Igor Stoppa
2007-10-05 13:27 ` Woodruff, Richard
2007-10-08  3:51   ` Tony Lindgren
2007-10-09 22:17     ` Woodruff, Richard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox