All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jarkko Lavinen <jarkko.lavinen@nokia.com>
To: linux-omap-open-source@linux.omap.com
Subject: [PATCH] OMAP: Asynchronous clock disable
Date: Fri, 5 Oct 2007 15:50:28 +0300	[thread overview]
Message-ID: <20071005125028.GA32101@angel.research.nokia.com> (raw)

[-- 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 --]



             reply	other threads:[~2007-10-05 12:50 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-10-05 12:50 Jarkko Lavinen [this message]
2007-10-05 13:25 ` [PATCH] OMAP: Asynchronous clock disable Igor Stoppa
2007-10-05 13:27 ` Woodruff, Richard
2007-10-08  3:51   ` Tony Lindgren
2007-10-09 22:17     ` Woodruff, Richard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20071005125028.GA32101@angel.research.nokia.com \
    --to=jarkko.lavinen@nokia.com \
    --cc=linux-omap-open-source@linux.omap.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.