All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] Add a common struct clk
  2011-01-05  3:51 ` Jeremy Kerr
@ 2011-01-05  3:51   ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-05  3:51 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel; +Cc: Ben Herrenchmidt, Uwe Kleine-König

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	int			flags;
	union {
		struct mutex	mutex;
		spinlock_t	spinlock;
	} lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
Acked-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>

---
 arch/Kconfig        |    3 
 include/linux/clk.h |  164 +++++++++++++++++++++++++++++++++++++++++---
 kernel/Makefile     |    1 
 kernel/clk.c        |  102 +++++++++++++++++++++++++++
 4 files changed, 261 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8bf0fa6..212bd3c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -165,6 +165,9 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 config HAVE_PERF_EVENTS_NMI
 	bool
 	help
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..95c49b1 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,169 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+#define CLK_ATOMIC	0x1
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @flags:		platform-independent flags
+ * @lock:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @lock member provides either a spinlock or a mutex to protect (at least)
+ * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
+ * set, then the core clock code will use a spinlock, otherwise a mutex. This
+ * lock will be acquired during clk_enable and clk_disable, so for atomic
+ * clocks, these ops callbacks must not sleep.
+ *
+ * The choice of atomic or non-atomic clock depends on how the clock is enabled.
+ * Typically, you'll want to use a non-atomic clock. For clocks that need to be
+ * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
+ * clocks with parents will typically cascade enable/disable operations to
+ * their parent, so the parent of an atomic clock *must* be atomic too.
+ */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	int			flags;
+	union {
+		struct mutex	mutex;
+		spinlock_t	spinlock;
+	} lock;
+};
+
+/* static initialiser for non-atomic clocks */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= 0,						\
+	.lock.mutex	= __MUTEX_INITIALIZER(name.lock.mutex),		\
+}
+
+/* static initialiser for atomic clocks */
+#define INIT_CLK_ATOMIC(name, o) {					\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= CLK_ATOMIC,					\
+	.lock.spinlock	= __SPIN_LOCK_UNLOCKED(name.lock.spinlock),	\
+}
+
+/**
+ * struct clk_ops -  Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @enable:	Enable the clock. This must not return until the clock is
+ *		generating a valid clock signal, usable by consumer devices.
+ *		Called with clk->lock held.
+ *
+ * @disable:	Disable the clock. Called with clk->lock held.
+ *
+ * @get:	Called by the core clock code when a device driver acquires a
+ *		clock via clk_get(). Optional.
+ *
+ * @put:	Called by the core clock code when a devices driver releases a
+ *		clock via clk_put(). Optional.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see kernel/clk.c for implementation details. All are optional.
  */
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
 
+static inline void __clk_lock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock(&clk->lock.spinlock);
+	else
+		mutex_lock(&clk->lock.mutex);
+}
+
+static inline void __clk_unlock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_unlock(&clk->lock.spinlock);
+	else
+		mutex_unlock(&clk->lock.mutex);
+}
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = 0;
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock_init(&clk->lock.spinlock);
+	else
+		mutex_init(&clk->lock.mutex);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 0b5ff08..01383a0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..8de8fe3
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	__clk_lock(clk);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	__clk_unlock(clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	__clk_lock(clk);
+
+	WARN_ON(!clk->enable_count);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	__clk_unlock(clk);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* [PATCH 2/2] clk: Generic support for fixed-rate clocks
  2011-01-05  3:51 ` Jeremy Kerr
@ 2011-01-05  3:51   ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-05  3:51 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel; +Cc: Ben Herrenchmidt, Uwe Kleine-König

Since most platforms will need a fixed-rate clock, add one. This will
also serve as a basic example of an implementation of struct clk.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 include/linux/clk.h |   16 ++++++++++++++++
 kernel/clk.c        |   14 ++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/include/linux/clk.h b/include/linux/clk.h
index 95c49b1..6cef9fe 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -164,6 +164,22 @@ static inline void clk_common_init(struct clk *clk)
 		mutex_init(&clk->lock.mutex);
 }
 
+/* Simple fixed-rate clock */
+struct clk_fixed {
+	struct clk	clk;
+	unsigned long	rate;
+};
+
+extern struct clk_ops clk_fixed_ops;
+
+#define INIT_CLK_FIXED(name, r) { \
+	.clk = INIT_CLK(name.clk, clk_fixed_ops), \
+	.rate = (r) \
+}
+
+#define DEFINE_CLK_FIXED(name, r) \
+	struct clk_fixed name = INIT_CLK_FIXED(name, r)
+
 #else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
diff --git a/kernel/clk.c b/kernel/clk.c
index 8de8fe3..6c38cc0 100644
--- a/kernel/clk.c
+++ b/kernel/clk.c
@@ -100,3 +100,17 @@ struct clk *clk_get_parent(struct clk *clk)
 	return ERR_PTR(-ENOSYS);
 }
 EXPORT_SYMBOL_GPL(clk_get_parent);
+
+/* clk_fixed support */
+
+#define to_clk_fixed(clk) (container_of(clk, struct clk_fixed, clk))
+
+static unsigned long clk_fixed_get_rate(struct clk *clk)
+{
+	return to_clk_fixed(clk)->rate;
+}
+
+struct clk_ops clk_fixed_ops = {
+	.get_rate = clk_fixed_get_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_ops);

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

* [PATCH 0/2] Common struct clk implementation, v10
@ 2011-01-05  3:51 ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-05  3:51 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel; +Cc: Ben Herrenchmidt, Uwe Kleine-König

Hi all,

These patches are an attempt to allow platforms to share clock code. At
present, the definitions of 'struct clk' are local to platform code,
which makes allocating and initialising cross-platform clock sources
difficult, and makes it impossible to compile a single image containing
support for two ARM platforms with different struct clks.

The two patches are for the architecture-independent kernel code,
introducing the common clk infrastructure. The changelog for the first
patch includes details about the new clock definitions.

As requested by rmk, I've put together a small series of patches
illustrating the usage of the common struct clock on the ARM imx51
platform. These are available in my git tree:

 git://kernel.ubuntu.com/jk/dt/linux-2.6

in the clk-common-mx51 branch (clk-common..clk-common-mx51). There is
also a port for versatile (clk-common-versatile) in this tree too.

The approach I've taken with the imx51 port is to temporarly duplicate
the platform-common clock code (ie, for all mxc-based boards) to enable
usage of the common struct clk on one machine (imx51), while leaving the
others as-is. For a proper platform-wide usage of the common struct clk,
we'd be better off doing the whole platform at once. However, mx51 is
the only mxc-based HW I have, hence the duplicated example port.

In the example port, the first change simply converts the mxc's struct
clk to a struct clk_mxc, using the new API.  The subsequent patches move
certain clocks to more specific data structures (eg clk_fixed and
clk_pll) where possible.

Also, Yong Shen has contributed a patch to export a tree of clock data
(currently the clock rate and enable_count) through debugfs; this is in
the clk-common-debug branch.

Ben Herrenschmidt is looking at using common struct clk code for powerpc
too, hence the kernel-wide approach.

Many thanks to the following for their input:
 * Ben Dooks <ben-linux@fluff.org>
 * Baruch Siach <baruch@tkos.co.il>
 * Russell King <linux@arm.linux.org.uk>
 * Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
 * Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com>
 * Vincent Guittot <vincent.guittot@linaro.org>
 * Sascha Hauer <s.hauer@pengutronix.de>

Russell - now that we've had a few platforms ported to the common clk
infrastructure, I believe it's ready to merge. If so, do you want this
in the patch tracker? Otherwise, let me know what needs changing.

Cheers,


Jeremy

--
v10:
 * comment fixups, from Uwe's review
 * added DEFINE_CLK_FIXED

v9:
 * comment improvements
 * kerneldoc fixups
 * add WARN_ON to clk_disable

v8:
 * add atomic clocks, and locking wrappers
 * expand comments on clk and clk_ops

v7:
 * change CLK_INIT to initialise clk->mutex statically

v6:
 * fixed up references to 'clk_operations' in the changelog

v5:
 * uninline main API, and share definitions with !USE_COMMON_STRUCT_CLK
 * add __clk_get
 * delay mutex init
 * kerneldoc for struct clk

v4:
 * use mutex for enable/disable locking
 * DEFINE_CLK -> INIT_CLK, and pass the clk name for mutex init
 * struct clk_operations -> struct clk_ops

v3:
 * do clock usage refcounting in common code
 * provide sample port

v2:
 * no longer ARM-specific
 * use clk_operations

---
Jeremy Kerr (2):
      Add a common struct clk
      clk: Generic support for fixed-rate clocks


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

* [PATCH 0/2] Common struct clk implementation, v10
@ 2011-01-05  3:51 ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-05  3:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi all,

These patches are an attempt to allow platforms to share clock code. At
present, the definitions of 'struct clk' are local to platform code,
which makes allocating and initialising cross-platform clock sources
difficult, and makes it impossible to compile a single image containing
support for two ARM platforms with different struct clks.

The two patches are for the architecture-independent kernel code,
introducing the common clk infrastructure. The changelog for the first
patch includes details about the new clock definitions.

As requested by rmk, I've put together a small series of patches
illustrating the usage of the common struct clock on the ARM imx51
platform. These are available in my git tree:

 git://kernel.ubuntu.com/jk/dt/linux-2.6

in the clk-common-mx51 branch (clk-common..clk-common-mx51). There is
also a port for versatile (clk-common-versatile) in this tree too.

The approach I've taken with the imx51 port is to temporarly duplicate
the platform-common clock code (ie, for all mxc-based boards) to enable
usage of the common struct clk on one machine (imx51), while leaving the
others as-is. For a proper platform-wide usage of the common struct clk,
we'd be better off doing the whole platform at once. However, mx51 is
the only mxc-based HW I have, hence the duplicated example port.

In the example port, the first change simply converts the mxc's struct
clk to a struct clk_mxc, using the new API.  The subsequent patches move
certain clocks to more specific data structures (eg clk_fixed and
clk_pll) where possible.

Also, Yong Shen has contributed a patch to export a tree of clock data
(currently the clock rate and enable_count) through debugfs; this is in
the clk-common-debug branch.

Ben Herrenschmidt is looking at using common struct clk code for powerpc
too, hence the kernel-wide approach.

Many thanks to the following for their input:
 * Ben Dooks <ben-linux@fluff.org>
 * Baruch Siach <baruch@tkos.co.il>
 * Russell King <linux@arm.linux.org.uk>
 * Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
 * Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com>
 * Vincent Guittot <vincent.guittot@linaro.org>
 * Sascha Hauer <s.hauer@pengutronix.de>

Russell - now that we've had a few platforms ported to the common clk
infrastructure, I believe it's ready to merge. If so, do you want this
in the patch tracker? Otherwise, let me know what needs changing.

Cheers,


Jeremy

--
v10:
 * comment fixups, from Uwe's review
 * added DEFINE_CLK_FIXED

v9:
 * comment improvements
 * kerneldoc fixups
 * add WARN_ON to clk_disable

v8:
 * add atomic clocks, and locking wrappers
 * expand comments on clk and clk_ops

v7:
 * change CLK_INIT to initialise clk->mutex statically

v6:
 * fixed up references to 'clk_operations' in the changelog

v5:
 * uninline main API, and share definitions with !USE_COMMON_STRUCT_CLK
 * add __clk_get
 * delay mutex init
 * kerneldoc for struct clk

v4:
 * use mutex for enable/disable locking
 * DEFINE_CLK -> INIT_CLK, and pass the clk name for mutex init
 * struct clk_operations -> struct clk_ops

v3:
 * do clock usage refcounting in common code
 * provide sample port

v2:
 * no longer ARM-specific
 * use clk_operations

---
Jeremy Kerr (2):
      Add a common struct clk
      clk: Generic support for fixed-rate clocks

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-05  3:51   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-05  3:51 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	int			flags;
	union {
		struct mutex	mutex;
		spinlock_t	spinlock;
	} lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
Acked-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>

---
 arch/Kconfig        |    3 
 include/linux/clk.h |  164 +++++++++++++++++++++++++++++++++++++++++---
 kernel/Makefile     |    1 
 kernel/clk.c        |  102 +++++++++++++++++++++++++++
 4 files changed, 261 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8bf0fa6..212bd3c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -165,6 +165,9 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 config HAVE_PERF_EVENTS_NMI
 	bool
 	help
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..95c49b1 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,169 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+#define CLK_ATOMIC	0x1
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @flags:		platform-independent flags
+ * @lock:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @lock member provides either a spinlock or a mutex to protect (at least)
+ * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
+ * set, then the core clock code will use a spinlock, otherwise a mutex. This
+ * lock will be acquired during clk_enable and clk_disable, so for atomic
+ * clocks, these ops callbacks must not sleep.
+ *
+ * The choice of atomic or non-atomic clock depends on how the clock is enabled.
+ * Typically, you'll want to use a non-atomic clock. For clocks that need to be
+ * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
+ * clocks with parents will typically cascade enable/disable operations to
+ * their parent, so the parent of an atomic clock *must* be atomic too.
+ */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	int			flags;
+	union {
+		struct mutex	mutex;
+		spinlock_t	spinlock;
+	} lock;
+};
+
+/* static initialiser for non-atomic clocks */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= 0,						\
+	.lock.mutex	= __MUTEX_INITIALIZER(name.lock.mutex),		\
+}
+
+/* static initialiser for atomic clocks */
+#define INIT_CLK_ATOMIC(name, o) {					\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= CLK_ATOMIC,					\
+	.lock.spinlock	= __SPIN_LOCK_UNLOCKED(name.lock.spinlock),	\
+}
+
+/**
+ * struct clk_ops -  Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @enable:	Enable the clock. This must not return until the clock is
+ *		generating a valid clock signal, usable by consumer devices.
+ *		Called with clk->lock held.
+ *
+ * @disable:	Disable the clock. Called with clk->lock held.
+ *
+ * @get:	Called by the core clock code when a device driver acquires a
+ *		clock via clk_get(). Optional.
+ *
+ * @put:	Called by the core clock code when a devices driver releases a
+ *		clock via clk_put(). Optional.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see kernel/clk.c for implementation details. All are optional.
  */
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
 
+static inline void __clk_lock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock(&clk->lock.spinlock);
+	else
+		mutex_lock(&clk->lock.mutex);
+}
+
+static inline void __clk_unlock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_unlock(&clk->lock.spinlock);
+	else
+		mutex_unlock(&clk->lock.mutex);
+}
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = 0;
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock_init(&clk->lock.spinlock);
+	else
+		mutex_init(&clk->lock.mutex);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 0b5ff08..01383a0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..8de8fe3
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	__clk_lock(clk);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	__clk_unlock(clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	__clk_lock(clk);
+
+	WARN_ON(!clk->enable_count);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	__clk_unlock(clk);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* [PATCH 2/2] clk: Generic support for fixed-rate clocks
@ 2011-01-05  3:51   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-05  3:51 UTC (permalink / raw)
  To: linux-arm-kernel

Since most platforms will need a fixed-rate clock, add one. This will
also serve as a basic example of an implementation of struct clk.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 include/linux/clk.h |   16 ++++++++++++++++
 kernel/clk.c        |   14 ++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/include/linux/clk.h b/include/linux/clk.h
index 95c49b1..6cef9fe 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -164,6 +164,22 @@ static inline void clk_common_init(struct clk *clk)
 		mutex_init(&clk->lock.mutex);
 }
 
+/* Simple fixed-rate clock */
+struct clk_fixed {
+	struct clk	clk;
+	unsigned long	rate;
+};
+
+extern struct clk_ops clk_fixed_ops;
+
+#define INIT_CLK_FIXED(name, r) { \
+	.clk = INIT_CLK(name.clk, clk_fixed_ops), \
+	.rate = (r) \
+}
+
+#define DEFINE_CLK_FIXED(name, r) \
+	struct clk_fixed name = INIT_CLK_FIXED(name, r)
+
 #else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
diff --git a/kernel/clk.c b/kernel/clk.c
index 8de8fe3..6c38cc0 100644
--- a/kernel/clk.c
+++ b/kernel/clk.c
@@ -100,3 +100,17 @@ struct clk *clk_get_parent(struct clk *clk)
 	return ERR_PTR(-ENOSYS);
 }
 EXPORT_SYMBOL_GPL(clk_get_parent);
+
+/* clk_fixed support */
+
+#define to_clk_fixed(clk) (container_of(clk, struct clk_fixed, clk))
+
+static unsigned long clk_fixed_get_rate(struct clk *clk)
+{
+	return to_clk_fixed(clk)->rate;
+}
+
+struct clk_ops clk_fixed_ops = {
+	.get_rate = clk_fixed_get_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_ops);

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

* [PATCH 0/2] Common struct clk implementation, v10
  2011-01-05  3:51 ` Jeremy Kerr
                   ` (2 preceding siblings ...)
  (?)
@ 2011-01-05  3:55 ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-05  3:55 UTC (permalink / raw)
  To: linux-arm-kernel

Sorry about the repost, folks - lkml bounced my badly-encoded headers.

Cheers,


Jeremy

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-05  3:51   ` Jeremy Kerr
@ 2011-01-06 16:07     ` Richard Cochran
  -1 siblings, 0 replies; 86+ messages in thread
From: Richard Cochran @ 2011-01-06 16:07 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: linux-kernel, linux-arm-kernel, Ben Herrenchmidt, Uwe Kleine-König

On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:

> + * The @lock member provides either a spinlock or a mutex to protect (at least)
> + * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
> + * set, then the core clock code will use a spinlock, otherwise a mutex. This
> + * lock will be acquired during clk_enable and clk_disable, so for atomic
> + * clocks, these ops callbacks must not sleep.
> + *
> + * The choice of atomic or non-atomic clock depends on how the clock is enabled.
> + * Typically, you'll want to use a non-atomic clock. For clocks that need to be
> + * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
> + * clocks with parents will typically cascade enable/disable operations to
> + * their parent, so the parent of an atomic clock *must* be atomic too.

...

> +struct clk {
> +	const struct clk_ops	*ops;
> +	unsigned int		enable_count;
> +	int			flags;
> +	union {
> +		struct mutex	mutex;
> +		spinlock_t	spinlock;
> +	} lock;
> +};

Here you have a "polymorphic" lock, where the clock instance knows
which type it is supposed to be.  I got flak from David Miller and
others trying to do the same thing with the mdio_bus:

   http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618

The criticism, applied to your case, is that the clk_enable() caller
cannot know whether it is safe to make the call or not. I was told,
"there has got to be a better way."

Richard


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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-06 16:07     ` Richard Cochran
  0 siblings, 0 replies; 86+ messages in thread
From: Richard Cochran @ 2011-01-06 16:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:

> + * The @lock member provides either a spinlock or a mutex to protect (at least)
> + * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
> + * set, then the core clock code will use a spinlock, otherwise a mutex. This
> + * lock will be acquired during clk_enable and clk_disable, so for atomic
> + * clocks, these ops callbacks must not sleep.
> + *
> + * The choice of atomic or non-atomic clock depends on how the clock is enabled.
> + * Typically, you'll want to use a non-atomic clock. For clocks that need to be
> + * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
> + * clocks with parents will typically cascade enable/disable operations to
> + * their parent, so the parent of an atomic clock *must* be atomic too.

...

> +struct clk {
> +	const struct clk_ops	*ops;
> +	unsigned int		enable_count;
> +	int			flags;
> +	union {
> +		struct mutex	mutex;
> +		spinlock_t	spinlock;
> +	} lock;
> +};

Here you have a "polymorphic" lock, where the clock instance knows
which type it is supposed to be.  I got flak from David Miller and
others trying to do the same thing with the mdio_bus:

   http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618

The criticism, applied to your case, is that the clk_enable() caller
cannot know whether it is safe to make the call or not. I was told,
"there has got to be a better way."

Richard

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-06 16:07     ` Richard Cochran
@ 2011-01-06 20:11       ` Uwe Kleine-König
  -1 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2011-01-06 20:11 UTC (permalink / raw)
  To: Richard Cochran
  Cc: Jeremy Kerr, linux-kernel, linux-arm-kernel, Ben Herrenchmidt

On Thu, Jan 06, 2011 at 05:07:52PM +0100, Richard Cochran wrote:
> On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:
> 
> > + * The @lock member provides either a spinlock or a mutex to protect (at least)
> > + * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
> > + * set, then the core clock code will use a spinlock, otherwise a mutex. This
> > + * lock will be acquired during clk_enable and clk_disable, so for atomic
> > + * clocks, these ops callbacks must not sleep.
> > + *
> > + * The choice of atomic or non-atomic clock depends on how the clock is enabled.
> > + * Typically, you'll want to use a non-atomic clock. For clocks that need to be
> > + * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
> > + * clocks with parents will typically cascade enable/disable operations to
> > + * their parent, so the parent of an atomic clock *must* be atomic too.
> 
> ...
> 
> > +struct clk {
> > +	const struct clk_ops	*ops;
> > +	unsigned int		enable_count;
> > +	int			flags;
> > +	union {
> > +		struct mutex	mutex;
> > +		spinlock_t	spinlock;
> > +	} lock;
> > +};
> 
> Here you have a "polymorphic" lock, where the clock instance knows
> which type it is supposed to be.  I got flak from David Miller and
> others trying to do the same thing with the mdio_bus:
> 
>    http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618
> 
> The criticism, applied to your case, is that the clk_enable() caller
> cannot know whether it is safe to make the call or not. I was told,
> "there has got to be a better way."
Note that this is not "new".  Currently there is no convention available
if clk_enable sleeps or not.  See e.g.
http://thread.gmane.org/gmane.linux.ports.arm.kernel/100744

So if there is no consent and you want to introduce common code there is
no choice.

I don't like it, too.  IMHO clk_enable should be allowed to sleep, but I
see the concerns of the other camp, too.  If you know the better way
that has to exists, please tell us.

(Hmm, the way the gpio api does it comes to mind:

	clk_enable_atomic
	clk_enable_cansleep

(where one of these can be named clk_enable).)

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-06 20:11       ` Uwe Kleine-König
  0 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2011-01-06 20:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 06, 2011 at 05:07:52PM +0100, Richard Cochran wrote:
> On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:
> 
> > + * The @lock member provides either a spinlock or a mutex to protect (at least)
> > + * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
> > + * set, then the core clock code will use a spinlock, otherwise a mutex. This
> > + * lock will be acquired during clk_enable and clk_disable, so for atomic
> > + * clocks, these ops callbacks must not sleep.
> > + *
> > + * The choice of atomic or non-atomic clock depends on how the clock is enabled.
> > + * Typically, you'll want to use a non-atomic clock. For clocks that need to be
> > + * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
> > + * clocks with parents will typically cascade enable/disable operations to
> > + * their parent, so the parent of an atomic clock *must* be atomic too.
> 
> ...
> 
> > +struct clk {
> > +	const struct clk_ops	*ops;
> > +	unsigned int		enable_count;
> > +	int			flags;
> > +	union {
> > +		struct mutex	mutex;
> > +		spinlock_t	spinlock;
> > +	} lock;
> > +};
> 
> Here you have a "polymorphic" lock, where the clock instance knows
> which type it is supposed to be.  I got flak from David Miller and
> others trying to do the same thing with the mdio_bus:
> 
>    http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618
> 
> The criticism, applied to your case, is that the clk_enable() caller
> cannot know whether it is safe to make the call or not. I was told,
> "there has got to be a better way."
Note that this is not "new".  Currently there is no convention available
if clk_enable sleeps or not.  See e.g.
http://thread.gmane.org/gmane.linux.ports.arm.kernel/100744

So if there is no consent and you want to introduce common code there is
no choice.

I don't like it, too.  IMHO clk_enable should be allowed to sleep, but I
see the concerns of the other camp, too.  If you know the better way
that has to exists, please tell us.

(Hmm, the way the gpio api does it comes to mind:

	clk_enable_atomic
	clk_enable_cansleep

(where one of these can be named clk_enable).)

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-06 20:11       ` Uwe Kleine-König
@ 2011-01-07  0:10         ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-07  0:10 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Richard Cochran, linux-kernel, linux-arm-kernel, Ben Herrenchmidt

Hi Richard,

> > > +struct clk {
> > > +	const struct clk_ops	*ops;
> > > +	unsigned int		enable_count;
> > > +	int			flags;
> > > +	union {
> > > +		struct mutex	mutex;
> > > +		spinlock_t	spinlock;
> > > +	} lock;
> > > +};
> > 
> > Here you have a "polymorphic" lock, where the clock instance knows
> > which type it is supposed to be.  I got flak from David Miller and
> > 
> > others trying to do the same thing with the mdio_bus:
> >    http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618
> > 
> > The criticism, applied to your case, is that the clk_enable() caller
> > cannot know whether it is safe to make the call or not. I was told,
> > "there has got to be a better way."
> 
> Note that this is not "new".  Currently there is no convention available
> if clk_enable sleeps or not.  See e.g.
> http://thread.gmane.org/gmane.linux.ports.arm.kernel/100744

As Uwe says, the common clock does not change these semantics; I would prefer 
to keep the driver API changes at a minimum with these patches.

But yes, it would be a good idea to:

 * introduce clk_enable_atomic, which requires clk->flags & CLK_ATOMIC

 * add might_sleep to clk_enable(), encouraging clk uses in atomic contexts
   to switch to clk_enable_atomic.

We'd still be able to handle CLK_ATOMIC clocks in clk_enable(), so the 
enforcement only needs to be one-way.

However, I think these would be better as separate changes.

Cheers,


Jeremy

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-07  0:10         ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-07  0:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Richard,

> > > +struct clk {
> > > +	const struct clk_ops	*ops;
> > > +	unsigned int		enable_count;
> > > +	int			flags;
> > > +	union {
> > > +		struct mutex	mutex;
> > > +		spinlock_t	spinlock;
> > > +	} lock;
> > > +};
> > 
> > Here you have a "polymorphic" lock, where the clock instance knows
> > which type it is supposed to be.  I got flak from David Miller and
> > 
> > others trying to do the same thing with the mdio_bus:
> >    http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618
> > 
> > The criticism, applied to your case, is that the clk_enable() caller
> > cannot know whether it is safe to make the call or not. I was told,
> > "there has got to be a better way."
> 
> Note that this is not "new".  Currently there is no convention available
> if clk_enable sleeps or not.  See e.g.
> http://thread.gmane.org/gmane.linux.ports.arm.kernel/100744

As Uwe says, the common clock does not change these semantics; I would prefer 
to keep the driver API changes at a minimum with these patches.

But yes, it would be a good idea to:

 * introduce clk_enable_atomic, which requires clk->flags & CLK_ATOMIC

 * add might_sleep to clk_enable(), encouraging clk uses in atomic contexts
   to switch to clk_enable_atomic.

We'd still be able to handle CLK_ATOMIC clocks in clk_enable(), so the 
enforcement only needs to be one-way.

However, I think these would be better as separate changes.

Cheers,


Jeremy

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-07  0:10         ` Jeremy Kerr
@ 2011-01-07  0:32           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2011-01-07  0:32 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: Uwe Kleine-König, Ben Herrenchmidt, Richard Cochran,
	linux-kernel, linux-arm-kernel

On Fri, Jan 07, 2011 at 08:10:20AM +0800, Jeremy Kerr wrote:
> Hi Richard,
> 
> > > > +struct clk {
> > > > +	const struct clk_ops	*ops;
> > > > +	unsigned int		enable_count;
> > > > +	int			flags;
> > > > +	union {
> > > > +		struct mutex	mutex;
> > > > +		spinlock_t	spinlock;
> > > > +	} lock;
> > > > +};
> > > 
> > > Here you have a "polymorphic" lock, where the clock instance knows
> > > which type it is supposed to be.  I got flak from David Miller and
> > > 
> > > others trying to do the same thing with the mdio_bus:
> > >    http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618
> > > 
> > > The criticism, applied to your case, is that the clk_enable() caller
> > > cannot know whether it is safe to make the call or not. I was told,
> > > "there has got to be a better way."
> > 
> > Note that this is not "new".  Currently there is no convention available
> > if clk_enable sleeps or not.  See e.g.
> > http://thread.gmane.org/gmane.linux.ports.arm.kernel/100744
> 
> As Uwe says, the common clock does not change these semantics; I would prefer 
> to keep the driver API changes at a minimum with these patches.
> 
> But yes, it would be a good idea to:
> 
>  * introduce clk_enable_atomic, which requires clk->flags & CLK_ATOMIC
> 
>  * add might_sleep to clk_enable(), encouraging clk uses in atomic contexts
>    to switch to clk_enable_atomic.
> 
> We'd still be able to handle CLK_ATOMIC clocks in clk_enable(), so the 
> enforcement only needs to be one-way.

I think the atomic stuff should be the norm through and through - otherwise
we're going to end up with problems in drivers where they use the _atomic()
stuff, but the clocks behind are coded to sleep.

I hate the GPIO APIs for doing this _cansleep crap as the decision of
whether to use the _cansleep or normal APIs normally can't be made at
the time when the API is used, but sometime later.  Many people just use
the non-_cansleep versions irrespective of the context they're in -
which is unnecessarily restrictive - consider what happens if you then
have that driver use a GPIO on an I2C peripheral...

By inventing two interfaces, you're asking for the same thing to happen
with clocks.

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-07  0:32           ` Russell King - ARM Linux
  0 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2011-01-07  0:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 07, 2011 at 08:10:20AM +0800, Jeremy Kerr wrote:
> Hi Richard,
> 
> > > > +struct clk {
> > > > +	const struct clk_ops	*ops;
> > > > +	unsigned int		enable_count;
> > > > +	int			flags;
> > > > +	union {
> > > > +		struct mutex	mutex;
> > > > +		spinlock_t	spinlock;
> > > > +	} lock;
> > > > +};
> > > 
> > > Here you have a "polymorphic" lock, where the clock instance knows
> > > which type it is supposed to be.  I got flak from David Miller and
> > > 
> > > others trying to do the same thing with the mdio_bus:
> > >    http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618
> > > 
> > > The criticism, applied to your case, is that the clk_enable() caller
> > > cannot know whether it is safe to make the call or not. I was told,
> > > "there has got to be a better way."
> > 
> > Note that this is not "new".  Currently there is no convention available
> > if clk_enable sleeps or not.  See e.g.
> > http://thread.gmane.org/gmane.linux.ports.arm.kernel/100744
> 
> As Uwe says, the common clock does not change these semantics; I would prefer 
> to keep the driver API changes at a minimum with these patches.
> 
> But yes, it would be a good idea to:
> 
>  * introduce clk_enable_atomic, which requires clk->flags & CLK_ATOMIC
> 
>  * add might_sleep to clk_enable(), encouraging clk uses in atomic contexts
>    to switch to clk_enable_atomic.
> 
> We'd still be able to handle CLK_ATOMIC clocks in clk_enable(), so the 
> enforcement only needs to be one-way.

I think the atomic stuff should be the norm through and through - otherwise
we're going to end up with problems in drivers where they use the _atomic()
stuff, but the clocks behind are coded to sleep.

I hate the GPIO APIs for doing this _cansleep crap as the decision of
whether to use the _cansleep or normal APIs normally can't be made at
the time when the API is used, but sometime later.  Many people just use
the non-_cansleep versions irrespective of the context they're in -
which is unnecessarily restrictive - consider what happens if you then
have that driver use a GPIO on an I2C peripheral...

By inventing two interfaces, you're asking for the same thing to happen
with clocks.

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

* [PATCH 0/2] Common struct clk implementation, v10
  2011-01-05  3:51 ` Jeremy Kerr
                   ` (3 preceding siblings ...)
  (?)
@ 2011-01-07  1:33 ` Ben Dooks
  2011-01-07  9:49   ` Uwe Kleine-König
  -1 siblings, 1 reply; 86+ messages in thread
From: Ben Dooks @ 2011-01-07  1:33 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/01/11 03:51, Jeremy Kerr wrote:
> Hi all,
> 
> These patches are an attempt to allow platforms to share clock code. At
> present, the definitions of 'struct clk' are local to platform code,
> which makes allocating and initialising cross-platform clock sources
> difficult, and makes it impossible to compile a single image containing
> support for two ARM platforms with different struct clks.

no, it doesn't actually. you could do run-time link and select
the right arch support.

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-07  0:32           ` Russell King - ARM Linux
@ 2011-01-07  9:40             ` Uwe Kleine-König
  -1 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2011-01-07  9:40 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Jeremy Kerr, Ben Herrenchmidt, Richard Cochran, linux-kernel,
	linux-arm-kernel

Hello Russell,

On Fri, Jan 07, 2011 at 12:32:05AM +0000, Russell King - ARM Linux wrote:
> On Fri, Jan 07, 2011 at 08:10:20AM +0800, Jeremy Kerr wrote:
> > Hi Richard,
> > 
> > > > > +struct clk {
> > > > > +	const struct clk_ops	*ops;
> > > > > +	unsigned int		enable_count;
> > > > > +	int			flags;
> > > > > +	union {
> > > > > +		struct mutex	mutex;
> > > > > +		spinlock_t	spinlock;
> > > > > +	} lock;
> > > > > +};
> > > > 
> > > > Here you have a "polymorphic" lock, where the clock instance knows
> > > > which type it is supposed to be.  I got flak from David Miller and
> > > > 
> > > > others trying to do the same thing with the mdio_bus:
> > > >    http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618
> > > > 
> > > > The criticism, applied to your case, is that the clk_enable() caller
> > > > cannot know whether it is safe to make the call or not. I was told,
> > > > "there has got to be a better way."
> > > 
> > > Note that this is not "new".  Currently there is no convention available
> > > if clk_enable sleeps or not.  See e.g.
> > > http://thread.gmane.org/gmane.linux.ports.arm.kernel/100744
> > 
> > As Uwe says, the common clock does not change these semantics; I would prefer 
> > to keep the driver API changes at a minimum with these patches.
> > 
> > But yes, it would be a good idea to:
> > 
> >  * introduce clk_enable_atomic, which requires clk->flags & CLK_ATOMIC
> > 
> >  * add might_sleep to clk_enable(), encouraging clk uses in atomic contexts
> >    to switch to clk_enable_atomic.
> > 
> > We'd still be able to handle CLK_ATOMIC clocks in clk_enable(), so the 
> > enforcement only needs to be one-way.
> 
> I think the atomic stuff should be the norm through and through - otherwise
> we're going to end up with problems in drivers where they use the _atomic()
> stuff, but the clocks behind are coded to sleep.
> 
> I hate the GPIO APIs for doing this _cansleep crap as the decision of
> whether to use the _cansleep or normal APIs normally can't be made at
> the time when the API is used, but sometime later.  Many people just use
> the non-_cansleep versions irrespective of the context they're in -
> which is unnecessarily restrictive - consider what happens if you then
> have that driver use a GPIO on an I2C peripheral...
I'd prefer it the other way around, too.  (That is an atomic
gpio_set_value_atomic and a sleeping gpio_set_value.)  So if someone
uses the wrong one it's more likely that (s)he notices it.  Other than
that I agree that not having to do this would be preferable.

When applying the clk_enable_atomic stuff to the amba-pl011 driver (see
link above), I would just get a different error (clk_enable_atomic would
return -ESOMETHING instead of a backtrace about sleeping in atomic
context).  Hmm, not very useful.

On the other hand fixing the clk API to the sleeping or non-sleeping
approach has disadvantages, too:

 - sleeping
   doesn't allow enabling a clk in atomic context which (e.g. in the
   case of amba-pl011) provides maximal power saving.
 - atomic
   some clocks need long to become enabled, so long critical sections
   are introduced

Having a maxtracer for the clk_enable/disable functions would be great
to get some numbers.  I volunteer to try to add something like that to
the common clk thing when it is merged.  (Yes, I still think that
merging Jeremy's patches for .38 is good.)

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-07  9:40             ` Uwe Kleine-König
  0 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2011-01-07  9:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Russell,

On Fri, Jan 07, 2011 at 12:32:05AM +0000, Russell King - ARM Linux wrote:
> On Fri, Jan 07, 2011 at 08:10:20AM +0800, Jeremy Kerr wrote:
> > Hi Richard,
> > 
> > > > > +struct clk {
> > > > > +	const struct clk_ops	*ops;
> > > > > +	unsigned int		enable_count;
> > > > > +	int			flags;
> > > > > +	union {
> > > > > +		struct mutex	mutex;
> > > > > +		spinlock_t	spinlock;
> > > > > +	} lock;
> > > > > +};
> > > > 
> > > > Here you have a "polymorphic" lock, where the clock instance knows
> > > > which type it is supposed to be.  I got flak from David Miller and
> > > > 
> > > > others trying to do the same thing with the mdio_bus:
> > > >    http://kerneltrap.org/mailarchive/linux-netdev/2010/7/6/6280618
> > > > 
> > > > The criticism, applied to your case, is that the clk_enable() caller
> > > > cannot know whether it is safe to make the call or not. I was told,
> > > > "there has got to be a better way."
> > > 
> > > Note that this is not "new".  Currently there is no convention available
> > > if clk_enable sleeps or not.  See e.g.
> > > http://thread.gmane.org/gmane.linux.ports.arm.kernel/100744
> > 
> > As Uwe says, the common clock does not change these semantics; I would prefer 
> > to keep the driver API changes at a minimum with these patches.
> > 
> > But yes, it would be a good idea to:
> > 
> >  * introduce clk_enable_atomic, which requires clk->flags & CLK_ATOMIC
> > 
> >  * add might_sleep to clk_enable(), encouraging clk uses in atomic contexts
> >    to switch to clk_enable_atomic.
> > 
> > We'd still be able to handle CLK_ATOMIC clocks in clk_enable(), so the 
> > enforcement only needs to be one-way.
> 
> I think the atomic stuff should be the norm through and through - otherwise
> we're going to end up with problems in drivers where they use the _atomic()
> stuff, but the clocks behind are coded to sleep.
> 
> I hate the GPIO APIs for doing this _cansleep crap as the decision of
> whether to use the _cansleep or normal APIs normally can't be made at
> the time when the API is used, but sometime later.  Many people just use
> the non-_cansleep versions irrespective of the context they're in -
> which is unnecessarily restrictive - consider what happens if you then
> have that driver use a GPIO on an I2C peripheral...
I'd prefer it the other way around, too.  (That is an atomic
gpio_set_value_atomic and a sleeping gpio_set_value.)  So if someone
uses the wrong one it's more likely that (s)he notices it.  Other than
that I agree that not having to do this would be preferable.

When applying the clk_enable_atomic stuff to the amba-pl011 driver (see
link above), I would just get a different error (clk_enable_atomic would
return -ESOMETHING instead of a backtrace about sleeping in atomic
context).  Hmm, not very useful.

On the other hand fixing the clk API to the sleeping or non-sleeping
approach has disadvantages, too:

 - sleeping
   doesn't allow enabling a clk in atomic context which (e.g. in the
   case of amba-pl011) provides maximal power saving.
 - atomic
   some clocks need long to become enabled, so long critical sections
   are introduced

Having a maxtracer for the clk_enable/disable functions would be great
to get some numbers.  I volunteer to try to add something like that to
the common clk thing when it is merged.  (Yes, I still think that
merging Jeremy's patches for .38 is good.)

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 0/2] Common struct clk implementation, v10
  2011-01-07  1:33 ` Ben Dooks
@ 2011-01-07  9:49   ` Uwe Kleine-König
  0 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2011-01-07  9:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ben,

On Fri, Jan 07, 2011 at 01:33:32AM +0000, Ben Dooks wrote:
> On 05/01/11 03:51, Jeremy Kerr wrote:
> > Hi all,
> > 
> > These patches are an attempt to allow platforms to share clock code. At
> > present, the definitions of 'struct clk' are local to platform code,
> > which makes allocating and initialising cross-platform clock sources
> > difficult, and makes it impossible to compile a single image containing
> > support for two ARM platforms with different struct clks.
> 
> no, it doesn't actually. you could do run-time link and select
> the right arch support.
does that mean you're against the patch set?

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-05  3:51   ` Jeremy Kerr
@ 2011-01-08 13:15     ` Sascha Hauer
  -1 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-08 13:15 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: linux-kernel, linux-arm-kernel, Ben Herrenchmidt, Uwe Kleine-König

Hi Jeremy,

On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
> 
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
> 
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
> 
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
> 
> struct clk {
> 	const struct clk_ops	*ops;
> 	unsigned int		enable_count;
> 	int			flags;
> 	union {
> 		struct mutex	mutex;
> 		spinlock_t	spinlock;
> 	} lock;
> };

I'm currently thinking about how to get the locking right with this
approach. In the current i.MX implementation we have a global lock which
protects the clock enable counter and also the register accesses in the
clock code. With the common struct clock we have a lock per clock which
only protects the enable counter, so we have to introduce a second lock
to protect the register accesses.
The problem comes with nested calls to for example clk_enable which
happens when the parent clock gets enabled. currently we do this with
clk->enable(clk->parent) which results in an unlocked clk_enable of the
parent. With common struct clk we would have to call
clk_enable(clk_get_parent(clk) which results in taking the lock a second
time.
Any ideas how to solve this?

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-08 13:15     ` Sascha Hauer
  0 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-08 13:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jeremy,

On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
> 
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
> 
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
> 
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
> 
> struct clk {
> 	const struct clk_ops	*ops;
> 	unsigned int		enable_count;
> 	int			flags;
> 	union {
> 		struct mutex	mutex;
> 		spinlock_t	spinlock;
> 	} lock;
> };

I'm currently thinking about how to get the locking right with this
approach. In the current i.MX implementation we have a global lock which
protects the clock enable counter and also the register accesses in the
clock code. With the common struct clock we have a lock per clock which
only protects the enable counter, so we have to introduce a second lock
to protect the register accesses.
The problem comes with nested calls to for example clk_enable which
happens when the parent clock gets enabled. currently we do this with
clk->enable(clk->parent) which results in an unlocked clk_enable of the
parent. With common struct clk we would have to call
clk_enable(clk_get_parent(clk) which results in taking the lock a second
time.
Any ideas how to solve this?

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-08 13:15     ` Sascha Hauer
@ 2011-01-10  2:43       ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-10  2:43 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-kernel, linux-arm-kernel, Ben Herrenchmidt, Uwe Kleine-König

Hi Sascha,

> I'm currently thinking about how to get the locking right with this
> approach. In the current i.MX implementation we have a global lock which
> protects the clock enable counter and also the register accesses in the
> clock code. With the common struct clock we have a lock per clock which
> only protects the enable counter, so we have to introduce a second lock
> to protect the register accesses.

Are the registers shared between clocks? If not, you can just use the existing 
per-clk lock. Otherwise it'd be reasonable to add a global register lock, 
protecting accesses to the shared register set (and *only* protecting these 
registers).

> The problem comes with nested calls to for example clk_enable which
> happens when the parent clock gets enabled. currently we do this with
> clk->enable(clk->parent) which results in an unlocked clk_enable of the
> parent. With common struct clk we would have to call
> clk_enable(clk_get_parent(clk) which results in taking the lock a second
> time.
> Any ideas how to solve this?

With the shared register lock, you just need to make sure that you don't 
recurse to the parent while holding the lock.

For clocks with a shared register set, the general pattern would be something 
like:

struct clk_foo {
	struct clk clk;
	u32        enable_reg;
	u32        enable_mask;
	struct clk *parent;
};

static DEFINE_SPINLOCK(clk_foo_register_lock);

/* called with _clk->lock held */
static int clk_foo_enable(struct clk *_clk)
{
	struct clk_foo *clk = to_clk_foo(_clk);
	int reg, rc;

	/* enable parent - will acquire and release the parent's per-clk lock */
	rc = clk_enable(clk->parent);
	if (rc)
		return rc;

	/* do register update, under global register lock */
	spin_lock(&clk_foo_register_lock);

	reg = __raw_readl(clk->reg);
	__raw_writel(clk->reg, reg | clk->enable_mask);

	spin_unlock(&clk_foo_register_lock);

	return 0;
}

struct clk_foo_ops = {
	.enable = clk_foo_enable;
	[...]
};

However, because clk_mxc introduces its own set of abstractions, there may be 
some merging to do here. For my work on mx51, I've done a very basic port:

 * changed plat-mxc's struct clk to struct clk_mxc
 * embedded struct clk into struct clk_mxc (ie, making it use the common API)
 * separated some of the simpler clocks to separate types (eg clk_fixed,
   clk_pll, clk_ccgr).

The goal here is to separate all of the clocks into their most basic types, 
leaving no clk_mxc clocks remaining, then the locking should be much simpler.

Cheers,


Jeremy



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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-10  2:43       ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-10  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Sascha,

> I'm currently thinking about how to get the locking right with this
> approach. In the current i.MX implementation we have a global lock which
> protects the clock enable counter and also the register accesses in the
> clock code. With the common struct clock we have a lock per clock which
> only protects the enable counter, so we have to introduce a second lock
> to protect the register accesses.

Are the registers shared between clocks? If not, you can just use the existing 
per-clk lock. Otherwise it'd be reasonable to add a global register lock, 
protecting accesses to the shared register set (and *only* protecting these 
registers).

> The problem comes with nested calls to for example clk_enable which
> happens when the parent clock gets enabled. currently we do this with
> clk->enable(clk->parent) which results in an unlocked clk_enable of the
> parent. With common struct clk we would have to call
> clk_enable(clk_get_parent(clk) which results in taking the lock a second
> time.
> Any ideas how to solve this?

With the shared register lock, you just need to make sure that you don't 
recurse to the parent while holding the lock.

For clocks with a shared register set, the general pattern would be something 
like:

struct clk_foo {
	struct clk clk;
	u32        enable_reg;
	u32        enable_mask;
	struct clk *parent;
};

static DEFINE_SPINLOCK(clk_foo_register_lock);

/* called with _clk->lock held */
static int clk_foo_enable(struct clk *_clk)
{
	struct clk_foo *clk = to_clk_foo(_clk);
	int reg, rc;

	/* enable parent - will acquire and release the parent's per-clk lock */
	rc = clk_enable(clk->parent);
	if (rc)
		return rc;

	/* do register update, under global register lock */
	spin_lock(&clk_foo_register_lock);

	reg = __raw_readl(clk->reg);
	__raw_writel(clk->reg, reg | clk->enable_mask);

	spin_unlock(&clk_foo_register_lock);

	return 0;
}

struct clk_foo_ops = {
	.enable = clk_foo_enable;
	[...]
};

However, because clk_mxc introduces its own set of abstractions, there may be 
some merging to do here. For my work on mx51, I've done a very basic port:

 * changed plat-mxc's struct clk to struct clk_mxc
 * embedded struct clk into struct clk_mxc (ie, making it use the common API)
 * separated some of the simpler clocks to separate types (eg clk_fixed,
   clk_pll, clk_ccgr).

The goal here is to separate all of the clocks into their most basic types, 
leaving no clk_mxc clocks remaining, then the locking should be much simpler.

Cheers,


Jeremy

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-10  2:43       ` Jeremy Kerr
@ 2011-01-10 10:41         ` Sascha Hauer
  -1 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-10 10:41 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: linux-kernel, linux-arm-kernel, Ben Herrenchmidt, Uwe Kleine-König

On Mon, Jan 10, 2011 at 10:43:04AM +0800, Jeremy Kerr wrote:
> Hi Sascha,
> 
> > I'm currently thinking about how to get the locking right with this
> > approach. In the current i.MX implementation we have a global lock which
> > protects the clock enable counter and also the register accesses in the
> > clock code. With the common struct clock we have a lock per clock which
> > only protects the enable counter, so we have to introduce a second lock
> > to protect the register accesses.
> 
> Are the registers shared between clocks? If not, you can just use the existing 
> per-clk lock. Otherwise it'd be reasonable to add a global register lock, 
> protecting accesses to the shared register set (and *only* protecting these 
> registers).

Yes, the registers are shared between clocks.

> 
> > The problem comes with nested calls to for example clk_enable which
> > happens when the parent clock gets enabled. currently we do this with
> > clk->enable(clk->parent) which results in an unlocked clk_enable of the
> > parent. With common struct clk we would have to call
> > clk_enable(clk_get_parent(clk) which results in taking the lock a second
> > time.
> > Any ideas how to solve this?
> 
> With the shared register lock, you just need to make sure that you don't 
> recurse to the parent while holding the lock.
> 
> For clocks with a shared register set, the general pattern would be something 
> like:
> 
> struct clk_foo {
> 	struct clk clk;
> 	u32        enable_reg;
> 	u32        enable_mask;
> 	struct clk *parent;
> };
> 
> static DEFINE_SPINLOCK(clk_foo_register_lock);
> 
> /* called with _clk->lock held */
> static int clk_foo_enable(struct clk *_clk)
> {
> 	struct clk_foo *clk = to_clk_foo(_clk);
> 	int reg, rc;
> 
> 	/* enable parent - will acquire and release the parent's per-clk lock */
> 	rc = clk_enable(clk->parent);
> 	if (rc)
> 		return rc;
> 
> 	/* do register update, under global register lock */
> 	spin_lock(&clk_foo_register_lock);
> 
> 	reg = __raw_readl(clk->reg);
> 	__raw_writel(clk->reg, reg | clk->enable_mask);
> 
> 	spin_unlock(&clk_foo_register_lock);
> 
> 	return 0;
> }
> 
> struct clk_foo_ops = {
> 	.enable = clk_foo_enable;
> 	[...]
> };

Ok, that should do it. Unfortunately this requires pushing the lock down
to the individual functions instead of taking it in some global place.

> 
> However, because clk_mxc introduces its own set of abstractions, there may be 
> some merging to do here. For my work on mx51, I've done a very basic port:
> 
>  * changed plat-mxc's struct clk to struct clk_mxc
>  * embedded struct clk into struct clk_mxc (ie, making it use the common API)
>  * separated some of the simpler clocks to separate types (eg clk_fixed,
>    clk_pll, clk_ccgr).
> 
> The goal here is to separate all of the clocks into their most basic types, 
> leaving no clk_mxc clocks remaining, then the locking should be much simpler.

I am aware of your work. In fact, I already did some work upon this. See

git://git.pengutronix.de/git/imx/linux-2.6.git clk-common

and

git://git.pengutronix.de/git/imx/linux-2.6.git clk-common-wip

The first branch converts the whole i.MX architecture to clk-common.
The second branch converts i.MX51 into the basic building blocks. See
how i.MX51 clock support looks like after the conversion:

http://git.pengutronix.de/?p=imx/linux-2.6.git;a=blob;f=arch/arm/mach-mx5/clock-mx51-mx53.c;h=60c05c9b8916ebcb856f1e3f4e8c419f878c13a3;hb=refs/heads/clk-common-wip

The following shows the basic building blocks I used:

http://git.pengutronix.de/?p=imx/linux-2.6.git;a=commitdiff;h=b2f7ef29c8d56ef3574a5040890ea0edc14dae7f

This branch must be reworked because the correct locking is missing, but
the first branch should be ready for merging once your clk-common
patches are merged. I'll post the patches for review soon. I hope it's
clear soon that your clk-common patches get merged.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-10 10:41         ` Sascha Hauer
  0 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-10 10:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 10, 2011 at 10:43:04AM +0800, Jeremy Kerr wrote:
> Hi Sascha,
> 
> > I'm currently thinking about how to get the locking right with this
> > approach. In the current i.MX implementation we have a global lock which
> > protects the clock enable counter and also the register accesses in the
> > clock code. With the common struct clock we have a lock per clock which
> > only protects the enable counter, so we have to introduce a second lock
> > to protect the register accesses.
> 
> Are the registers shared between clocks? If not, you can just use the existing 
> per-clk lock. Otherwise it'd be reasonable to add a global register lock, 
> protecting accesses to the shared register set (and *only* protecting these 
> registers).

Yes, the registers are shared between clocks.

> 
> > The problem comes with nested calls to for example clk_enable which
> > happens when the parent clock gets enabled. currently we do this with
> > clk->enable(clk->parent) which results in an unlocked clk_enable of the
> > parent. With common struct clk we would have to call
> > clk_enable(clk_get_parent(clk) which results in taking the lock a second
> > time.
> > Any ideas how to solve this?
> 
> With the shared register lock, you just need to make sure that you don't 
> recurse to the parent while holding the lock.
> 
> For clocks with a shared register set, the general pattern would be something 
> like:
> 
> struct clk_foo {
> 	struct clk clk;
> 	u32        enable_reg;
> 	u32        enable_mask;
> 	struct clk *parent;
> };
> 
> static DEFINE_SPINLOCK(clk_foo_register_lock);
> 
> /* called with _clk->lock held */
> static int clk_foo_enable(struct clk *_clk)
> {
> 	struct clk_foo *clk = to_clk_foo(_clk);
> 	int reg, rc;
> 
> 	/* enable parent - will acquire and release the parent's per-clk lock */
> 	rc = clk_enable(clk->parent);
> 	if (rc)
> 		return rc;
> 
> 	/* do register update, under global register lock */
> 	spin_lock(&clk_foo_register_lock);
> 
> 	reg = __raw_readl(clk->reg);
> 	__raw_writel(clk->reg, reg | clk->enable_mask);
> 
> 	spin_unlock(&clk_foo_register_lock);
> 
> 	return 0;
> }
> 
> struct clk_foo_ops = {
> 	.enable = clk_foo_enable;
> 	[...]
> };

Ok, that should do it. Unfortunately this requires pushing the lock down
to the individual functions instead of taking it in some global place.

> 
> However, because clk_mxc introduces its own set of abstractions, there may be 
> some merging to do here. For my work on mx51, I've done a very basic port:
> 
>  * changed plat-mxc's struct clk to struct clk_mxc
>  * embedded struct clk into struct clk_mxc (ie, making it use the common API)
>  * separated some of the simpler clocks to separate types (eg clk_fixed,
>    clk_pll, clk_ccgr).
> 
> The goal here is to separate all of the clocks into their most basic types, 
> leaving no clk_mxc clocks remaining, then the locking should be much simpler.

I am aware of your work. In fact, I already did some work upon this. See

git://git.pengutronix.de/git/imx/linux-2.6.git clk-common

and

git://git.pengutronix.de/git/imx/linux-2.6.git clk-common-wip

The first branch converts the whole i.MX architecture to clk-common.
The second branch converts i.MX51 into the basic building blocks. See
how i.MX51 clock support looks like after the conversion:

http://git.pengutronix.de/?p=imx/linux-2.6.git;a=blob;f=arch/arm/mach-mx5/clock-mx51-mx53.c;h=60c05c9b8916ebcb856f1e3f4e8c419f878c13a3;hb=refs/heads/clk-common-wip

The following shows the basic building blocks I used:

http://git.pengutronix.de/?p=imx/linux-2.6.git;a=commitdiff;h=b2f7ef29c8d56ef3574a5040890ea0edc14dae7f

This branch must be reworked because the correct locking is missing, but
the first branch should be ready for merging once your clk-common
patches are merged. I'll post the patches for review soon. I hope it's
clear soon that your clk-common patches get merged.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-10 10:41         ` Sascha Hauer
@ 2011-01-10 11:00           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2011-01-10 11:00 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Jeremy Kerr, Ben Herrenchmidt, linux-kernel, linux-arm-kernel,
	Uwe Kleine-König

On Mon, Jan 10, 2011 at 11:41:22AM +0100, Sascha Hauer wrote:
> This branch must be reworked because the correct locking is missing, but
> the first branch should be ready for merging once your clk-common
> patches are merged. I'll post the patches for review soon. I hope it's
> clear soon that your clk-common patches get merged.

Unless the locking problems can be resolved, the patches aren't ready.

>From what I've seen there's still quite a problem with what kind of
lock to use in the clock - mutex or spinlock.

I don't see that having some clocks be one and others another is really
acceptable - think about the resulting mess if you end up with some
parent mux'd clocks which are a mutex and others which are a spinlock.
Can a driver use an atomic call for that?  Sometimes depending on the
mux, sometimes depending on whether a parent clock is already enabled.

What if your clock was enabled while the mux selected another spinlock-
locked clk, but then you switched to a different operating point and the
mux then selected the mutex-locked clock.

We could say that this is illegal - but then we need to have the code
explicitly check this otherwise such situations will be created.

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-10 11:00           ` Russell King - ARM Linux
  0 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2011-01-10 11:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 10, 2011 at 11:41:22AM +0100, Sascha Hauer wrote:
> This branch must be reworked because the correct locking is missing, but
> the first branch should be ready for merging once your clk-common
> patches are merged. I'll post the patches for review soon. I hope it's
> clear soon that your clk-common patches get merged.

Unless the locking problems can be resolved, the patches aren't ready.

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-10 11:00           ` Russell King - ARM Linux
@ 2011-01-11  0:54             ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-11  0:54 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Sascha Hauer, Ben Herrenchmidt, linux-kernel, linux-arm-kernel,
	Uwe Kleine-König

Hi Russell,

> Unless the locking problems can be resolved, the patches aren't ready.
> 
> From what I've seen there's still quite a problem with what kind of
> lock to use in the clock - mutex or spinlock.

Yes, the clock driver may either use a spinlock or mutex.

However, this exactly the same as the current clock code, my patches do not 
alter what we currently have.

I do agree that we should define some specific semantics for the clock API 
with regards to sleeping, and I'll start a new thread about that. But we 
should definitely separate that issue from the problem of having multiple 
definitions for struct clk, which is what these patches address.

Cheers,


Jeremy

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-11  0:54             ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-11  0:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell,

> Unless the locking problems can be resolved, the patches aren't ready.
> 
> From what I've seen there's still quite a problem with what kind of
> lock to use in the clock - mutex or spinlock.

Yes, the clock driver may either use a spinlock or mutex.

However, this exactly the same as the current clock code, my patches do not 
alter what we currently have.

I do agree that we should define some specific semantics for the clock API 
with regards to sleeping, and I'll start a new thread about that. But we 
should definitely separate that issue from the problem of having multiple 
definitions for struct clk, which is what these patches address.

Cheers,


Jeremy

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-05  3:51   ` Jeremy Kerr
@ 2011-01-11 10:16     ` Sascha Hauer
  -1 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-11 10:16 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: linux-kernel, linux-arm-kernel, Ben Herrenchmidt, Uwe Kleine-König

On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:
> diff --git a/kernel/clk.c b/kernel/clk.c
> new file mode 100644
> index 0000000..8de8fe3
> --- /dev/null
> +++ b/kernel/clk.c
> @@ -0,0 +1,102 @@
> +/*
> + * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +

...

> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> +	if (clk->ops->set_parent)
> +		return clk->ops->set_parent(clk, parent);
> +	return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);

The i.MX clk implementation disables the old parent if clk is enabled
and enables the new parent if clk is enabled (modulo bugs). Shouldn't
we do this here aswell? Otherwise at least the enable_count of both the
old and the new parent will be wrong after calling clk_set_parent for an
enabled clk.

I thought about returning -EBUSY if clk_set_parent is called for an
enabled clk, but this way we could never reparent the cpu clock which I
think is done in the Freescale BSP for power saving.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-11 10:16     ` Sascha Hauer
  0 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-11 10:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:
> diff --git a/kernel/clk.c b/kernel/clk.c
> new file mode 100644
> index 0000000..8de8fe3
> --- /dev/null
> +++ b/kernel/clk.c
> @@ -0,0 +1,102 @@
> +/*
> + * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +

...

> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> +	if (clk->ops->set_parent)
> +		return clk->ops->set_parent(clk, parent);
> +	return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);

The i.MX clk implementation disables the old parent if clk is enabled
and enables the new parent if clk is enabled (modulo bugs). Shouldn't
we do this here aswell? Otherwise at least the enable_count of both the
old and the new parent will be wrong after calling clk_set_parent for an
enabled clk.

I thought about returning -EBUSY if clk_set_parent is called for an
enabled clk, but this way we could never reparent the cpu clock which I
think is done in the Freescale BSP for power saving.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-11 10:16     ` Sascha Hauer
@ 2011-01-11 10:27       ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-11 10:27 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-kernel, linux-arm-kernel, Ben Herrenchmidt, Uwe Kleine-König

Hi Sascha,
 
> The i.MX clk implementation disables the old parent if clk is enabled
> and enables the new parent if clk is enabled (modulo bugs). Shouldn't
> we do this here aswell?

Sounds reasonable, yes.

> I thought about returning -EBUSY if clk_set_parent is called for an
> enabled clk, but this way we could never reparent the cpu clock which I
> think is done in the Freescale BSP for power saving.

I think that the possibility for changing the parent really depends on the 
implementation; in some cases we may want to disallow it, in others it might 
be fine.

Related: do we really need globally-accessible clk_{get,set}_parent in the clk 
API? For cases where we need to set the parent, we probably need details about 
the platform clock configuration (eg, which clocks are possible parents). In 
this case, we could just call into the clock driver directly.

Cheers,


Jeremy

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-11 10:27       ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-11 10:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Sascha,
 
> The i.MX clk implementation disables the old parent if clk is enabled
> and enables the new parent if clk is enabled (modulo bugs). Shouldn't
> we do this here aswell?

Sounds reasonable, yes.

> I thought about returning -EBUSY if clk_set_parent is called for an
> enabled clk, but this way we could never reparent the cpu clock which I
> think is done in the Freescale BSP for power saving.

I think that the possibility for changing the parent really depends on the 
implementation; in some cases we may want to disallow it, in others it might 
be fine.

Related: do we really need globally-accessible clk_{get,set}_parent in the clk 
API? For cases where we need to set the parent, we probably need details about 
the platform clock configuration (eg, which clocks are possible parents). In 
this case, we could just call into the clock driver directly.

Cheers,


Jeremy

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-11 10:27       ` Jeremy Kerr
@ 2011-01-11 11:22         ` Sascha Hauer
  -1 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-11 11:22 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: linux-kernel, linux-arm-kernel, Ben Herrenchmidt, Uwe Kleine-König

On Tue, Jan 11, 2011 at 06:27:11PM +0800, Jeremy Kerr wrote:
> Hi Sascha,
>  
> > The i.MX clk implementation disables the old parent if clk is enabled
> > and enables the new parent if clk is enabled (modulo bugs). Shouldn't
> > we do this here aswell?
> 
> Sounds reasonable, yes.
> 
> > I thought about returning -EBUSY if clk_set_parent is called for an
> > enabled clk, but this way we could never reparent the cpu clock which I
> > think is done in the Freescale BSP for power saving.
> 
> I think that the possibility for changing the parent really depends on the 
> implementation; in some cases we may want to disallow it, in others it might 
> be fine.
> 
> Related: do we really need globally-accessible clk_{get,set}_parent in the clk 
> API? For cases where we need to set the parent, we probably need details about 
> the platform clock configuration (eg, which clocks are possible parents). In 
> this case, we could just call into the clock driver directly.

I agree that drivers have no business calling clk_{get,set}_parent, this
is purely platform specific.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-11 11:22         ` Sascha Hauer
  0 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-11 11:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 11, 2011 at 06:27:11PM +0800, Jeremy Kerr wrote:
> Hi Sascha,
>  
> > The i.MX clk implementation disables the old parent if clk is enabled
> > and enables the new parent if clk is enabled (modulo bugs). Shouldn't
> > we do this here aswell?
> 
> Sounds reasonable, yes.
> 
> > I thought about returning -EBUSY if clk_set_parent is called for an
> > enabled clk, but this way we could never reparent the cpu clock which I
> > think is done in the Freescale BSP for power saving.
> 
> I think that the possibility for changing the parent really depends on the 
> implementation; in some cases we may want to disallow it, in others it might 
> be fine.
> 
> Related: do we really need globally-accessible clk_{get,set}_parent in the clk 
> API? For cases where we need to set the parent, we probably need details about 
> the platform clock configuration (eg, which clocks are possible parents). In 
> this case, we could just call into the clock driver directly.

I agree that drivers have no business calling clk_{get,set}_parent, this
is purely platform specific.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-11  0:54             ` Jeremy Kerr
@ 2011-01-16  7:26               ` Grant Likely
  -1 siblings, 0 replies; 86+ messages in thread
From: Grant Likely @ 2011-01-16  7:26 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: Russell King - ARM Linux, Sascha Hauer, Ben Herrenchmidt,
	linux-kernel, linux-arm-kernel, Uwe Kleine-König

On Mon, Jan 10, 2011 at 5:54 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
> Hi Russell,
>
>> Unless the locking problems can be resolved, the patches aren't ready.
>>
>> From what I've seen there's still quite a problem with what kind of
>> lock to use in the clock - mutex or spinlock.
>
> Yes, the clock driver may either use a spinlock or mutex.
>
> However, this exactly the same as the current clock code, my patches do not
> alter what we currently have.
>
> I do agree that we should define some specific semantics for the clock API
> with regards to sleeping, and I'll start a new thread about that. But we
> should definitely separate that issue from the problem of having multiple
> definitions for struct clk, which is what these patches address.

Given that each current struct clk implementation makes it's own
decisions about how to handle locking, would it not make sense to omit
locking entirely?  At least as a first step?  Let the clock ops
implement their own locking.  Make enable count management their
responsibility too.  That's all that the lock protects anyway.  The
clk_* apis can fall directly through to the ops hooks with no
manipulation or locking.  The way v3 of the patch worked.

Just having a common struct clk definition (without the locking) is
valuable on its own to get closer to supporting multiple platforms
with a single kernel on ARM.  It certainly shouldn't be worse that the
current state.  Locking consolidation can be implemented in follow-on
patches.

g.

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-16  7:26               ` Grant Likely
  0 siblings, 0 replies; 86+ messages in thread
From: Grant Likely @ 2011-01-16  7:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 10, 2011 at 5:54 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
> Hi Russell,
>
>> Unless the locking problems can be resolved, the patches aren't ready.
>>
>> From what I've seen there's still quite a problem with what kind of
>> lock to use in the clock - mutex or spinlock.
>
> Yes, the clock driver may either use a spinlock or mutex.
>
> However, this exactly the same as the current clock code, my patches do not
> alter what we currently have.
>
> I do agree that we should define some specific semantics for the clock API
> with regards to sleeping, and I'll start a new thread about that. But we
> should definitely separate that issue from the problem of having multiple
> definitions for struct clk, which is what these patches address.

Given that each current struct clk implementation makes it's own
decisions about how to handle locking, would it not make sense to omit
locking entirely?  At least as a first step?  Let the clock ops
implement their own locking.  Make enable count management their
responsibility too.  That's all that the lock protects anyway.  The
clk_* apis can fall directly through to the ops hooks with no
manipulation or locking.  The way v3 of the patch worked.

Just having a common struct clk definition (without the locking) is
valuable on its own to get closer to supporting multiple platforms
with a single kernel on ARM.  It certainly shouldn't be worse that the
current state.  Locking consolidation can be implemented in follow-on
patches.

g.

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-16  7:26               ` Grant Likely
@ 2011-01-16 20:41                 ` Ryan Mallon
  -1 siblings, 0 replies; 86+ messages in thread
From: Ryan Mallon @ 2011-01-16 20:41 UTC (permalink / raw)
  To: Grant Likely
  Cc: Jeremy Kerr, Russell King - ARM Linux, Sascha Hauer,
	Ben Herrenchmidt, linux-kernel, linux-arm-kernel,
	Uwe Kleine-König

On 01/16/2011 08:26 PM, Grant Likely wrote:
> On Mon, Jan 10, 2011 at 5:54 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
>> Hi Russell,
>>
>>> Unless the locking problems can be resolved, the patches aren't ready.
>>>
>>> From what I've seen there's still quite a problem with what kind of
>>> lock to use in the clock - mutex or spinlock.
>>
>> Yes, the clock driver may either use a spinlock or mutex.
>>
>> However, this exactly the same as the current clock code, my patches do not
>> alter what we currently have.
>>
>> I do agree that we should define some specific semantics for the clock API
>> with regards to sleeping, and I'll start a new thread about that. But we
>> should definitely separate that issue from the problem of having multiple
>> definitions for struct clk, which is what these patches address.
> 
> Given that each current struct clk implementation makes it's own
> decisions about how to handle locking, would it not make sense to omit
> locking entirely?  At least as a first step?  Let the clock ops
> implement their own locking.  Make enable count management their
> responsibility too.  That's all that the lock protects anyway.  The
> clk_* apis can fall directly through to the ops hooks with no
> manipulation or locking.  The way v3 of the patch worked.

This doesn't really work in a generic API because the call sites need to
know whether it safe to call clk_enable/disable, etc from a
non-sleepable context. This has essentially the same problems as using a
union with both a mutex and a spinlock.

That said, although we are aiming for a generic clock API, it's usage
typically isn't. Most of the users of the clock API are machine/platform
specific drivers and so they can make assumptions about the
implementation of the clock API calls. We currently do have a generic
set of clock calls which do not define rules about calling from atomic
context. We have a number of drivers, for several platforms, using the
clk_enable/disable calls. Some platforms are using sleeping clocks and
others are using atomic clocks, but because the _usage_ of the API is
largely platform specific it all hangs together.

This is a bit ugly in practice. It's hardly desirable to have an API
which looks generic, but in reality is platform/machine specific. I'm
guessing that a large benefit of having a unified API and well defined
rules about whether clock API calls may sleep or not allows the usage of
the clock API to become more generic.

I agree with Russell that the best short term approach is to create two
clock APIs, one for clocks which are atomic and the other for clocks
which need to sleep. If nothing else this at least allows the rules
about calling context to nailed down.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan@bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-16 20:41                 ` Ryan Mallon
  0 siblings, 0 replies; 86+ messages in thread
From: Ryan Mallon @ 2011-01-16 20:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 01/16/2011 08:26 PM, Grant Likely wrote:
> On Mon, Jan 10, 2011 at 5:54 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
>> Hi Russell,
>>
>>> Unless the locking problems can be resolved, the patches aren't ready.
>>>
>>> From what I've seen there's still quite a problem with what kind of
>>> lock to use in the clock - mutex or spinlock.
>>
>> Yes, the clock driver may either use a spinlock or mutex.
>>
>> However, this exactly the same as the current clock code, my patches do not
>> alter what we currently have.
>>
>> I do agree that we should define some specific semantics for the clock API
>> with regards to sleeping, and I'll start a new thread about that. But we
>> should definitely separate that issue from the problem of having multiple
>> definitions for struct clk, which is what these patches address.
> 
> Given that each current struct clk implementation makes it's own
> decisions about how to handle locking, would it not make sense to omit
> locking entirely?  At least as a first step?  Let the clock ops
> implement their own locking.  Make enable count management their
> responsibility too.  That's all that the lock protects anyway.  The
> clk_* apis can fall directly through to the ops hooks with no
> manipulation or locking.  The way v3 of the patch worked.

This doesn't really work in a generic API because the call sites need to
know whether it safe to call clk_enable/disable, etc from a
non-sleepable context. This has essentially the same problems as using a
union with both a mutex and a spinlock.

That said, although we are aiming for a generic clock API, it's usage
typically isn't. Most of the users of the clock API are machine/platform
specific drivers and so they can make assumptions about the
implementation of the clock API calls. We currently do have a generic
set of clock calls which do not define rules about calling from atomic
context. We have a number of drivers, for several platforms, using the
clk_enable/disable calls. Some platforms are using sleeping clocks and
others are using atomic clocks, but because the _usage_ of the API is
largely platform specific it all hangs together.

This is a bit ugly in practice. It's hardly desirable to have an API
which looks generic, but in reality is platform/machine specific. I'm
guessing that a large benefit of having a unified API and well defined
rules about whether clock API calls may sleep or not allows the usage of
the clock API to become more generic.

I agree with Russell that the best short term approach is to create two
clock APIs, one for clocks which are atomic and the other for clocks
which need to sleep. If nothing else this at least allows the rules
about calling context to nailed down.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan at bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-16 20:41                 ` Ryan Mallon
@ 2011-01-16 21:07                   ` Uwe Kleine-König
  -1 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2011-01-16 21:07 UTC (permalink / raw)
  To: Ryan Mallon
  Cc: Grant Likely, Jeremy Kerr, Russell King - ARM Linux,
	Sascha Hauer, Ben Herrenchmidt, linux-kernel, linux-arm-kernel

On Mon, Jan 17, 2011 at 09:41:46AM +1300, Ryan Mallon wrote:
> On 01/16/2011 08:26 PM, Grant Likely wrote:
> > On Mon, Jan 10, 2011 at 5:54 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
> >> Hi Russell,
> >>
> >>> Unless the locking problems can be resolved, the patches aren't ready.
> >>>
> >>> From what I've seen there's still quite a problem with what kind of
> >>> lock to use in the clock - mutex or spinlock.
> >>
> >> Yes, the clock driver may either use a spinlock or mutex.
> >>
> >> However, this exactly the same as the current clock code, my patches do not
> >> alter what we currently have.
> >>
> >> I do agree that we should define some specific semantics for the clock API
> >> with regards to sleeping, and I'll start a new thread about that. But we
> >> should definitely separate that issue from the problem of having multiple
> >> definitions for struct clk, which is what these patches address.
> > 
> > Given that each current struct clk implementation makes it's own
> > decisions about how to handle locking, would it not make sense to omit
> > locking entirely?  At least as a first step?  Let the clock ops
> > implement their own locking.  Make enable count management their
> > responsibility too.  That's all that the lock protects anyway.  The
> > clk_* apis can fall directly through to the ops hooks with no
> > manipulation or locking.  The way v3 of the patch worked.
> 
> This doesn't really work in a generic API because the call sites need to
> know whether it safe to call clk_enable/disable, etc from a
> non-sleepable context. This has essentially the same problems as using a
> union with both a mutex and a spinlock.
Note that this is the current status quo, too.  clk_enable on imx
sleeps, clk_enable on at91 doesn't.  I think we all agree we don't want
to change that during the unifying step.  So the common struct clk might
not solve all problems, but it's not worse than the state now.

> That said, although we are aiming for a generic clock API, it's usage
> typically isn't. Most of the users of the clock API are machine/platform
> specific drivers and so they can make assumptions about the
> implementation of the clock API calls. We currently do have a generic
> set of clock calls which do not define rules about calling from atomic
> context. We have a number of drivers, for several platforms, using the
> clk_enable/disable calls. Some platforms are using sleeping clocks and
> others are using atomic clocks, but because the _usage_ of the API is
> largely platform specific it all hangs together.
> 
> This is a bit ugly in practice. It's hardly desirable to have an API
> which looks generic, but in reality is platform/machine specific. I'm
> guessing that a large benefit of having a unified API and well defined
> rules about whether clock API calls may sleep or not allows the usage of
> the clock API to become more generic.
> 
> I agree with Russell that the best short term approach is to create two
> clock APIs, one for clocks which are atomic and the other for clocks
> which need to sleep. If nothing else this at least allows the rules
> about calling context to nailed down.
For me this sounds like code duplication if everything is identical only
spinlocks are substituted by mutexes.  What do you think about my
suggestion to use a Kconfig symbol that is selected by platforms (e.g.
COMMON_CLK_SLEEPING) and then use:

	#ifdef CONFIG_COMMON_CLK_SLEEPING
		... mutex stuff ...
	#else
		... spinlock stuff ...
	#endif

?

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-16 21:07                   ` Uwe Kleine-König
  0 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2011-01-16 21:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 17, 2011 at 09:41:46AM +1300, Ryan Mallon wrote:
> On 01/16/2011 08:26 PM, Grant Likely wrote:
> > On Mon, Jan 10, 2011 at 5:54 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
> >> Hi Russell,
> >>
> >>> Unless the locking problems can be resolved, the patches aren't ready.
> >>>
> >>> From what I've seen there's still quite a problem with what kind of
> >>> lock to use in the clock - mutex or spinlock.
> >>
> >> Yes, the clock driver may either use a spinlock or mutex.
> >>
> >> However, this exactly the same as the current clock code, my patches do not
> >> alter what we currently have.
> >>
> >> I do agree that we should define some specific semantics for the clock API
> >> with regards to sleeping, and I'll start a new thread about that. But we
> >> should definitely separate that issue from the problem of having multiple
> >> definitions for struct clk, which is what these patches address.
> > 
> > Given that each current struct clk implementation makes it's own
> > decisions about how to handle locking, would it not make sense to omit
> > locking entirely?  At least as a first step?  Let the clock ops
> > implement their own locking.  Make enable count management their
> > responsibility too.  That's all that the lock protects anyway.  The
> > clk_* apis can fall directly through to the ops hooks with no
> > manipulation or locking.  The way v3 of the patch worked.
> 
> This doesn't really work in a generic API because the call sites need to
> know whether it safe to call clk_enable/disable, etc from a
> non-sleepable context. This has essentially the same problems as using a
> union with both a mutex and a spinlock.
Note that this is the current status quo, too.  clk_enable on imx
sleeps, clk_enable on at91 doesn't.  I think we all agree we don't want
to change that during the unifying step.  So the common struct clk might
not solve all problems, but it's not worse than the state now.

> That said, although we are aiming for a generic clock API, it's usage
> typically isn't. Most of the users of the clock API are machine/platform
> specific drivers and so they can make assumptions about the
> implementation of the clock API calls. We currently do have a generic
> set of clock calls which do not define rules about calling from atomic
> context. We have a number of drivers, for several platforms, using the
> clk_enable/disable calls. Some platforms are using sleeping clocks and
> others are using atomic clocks, but because the _usage_ of the API is
> largely platform specific it all hangs together.
> 
> This is a bit ugly in practice. It's hardly desirable to have an API
> which looks generic, but in reality is platform/machine specific. I'm
> guessing that a large benefit of having a unified API and well defined
> rules about whether clock API calls may sleep or not allows the usage of
> the clock API to become more generic.
> 
> I agree with Russell that the best short term approach is to create two
> clock APIs, one for clocks which are atomic and the other for clocks
> which need to sleep. If nothing else this at least allows the rules
> about calling context to nailed down.
For me this sounds like code duplication if everything is identical only
spinlocks are substituted by mutexes.  What do you think about my
suggestion to use a Kconfig symbol that is selected by platforms (e.g.
COMMON_CLK_SLEEPING) and then use:

	#ifdef CONFIG_COMMON_CLK_SLEEPING
		... mutex stuff ...
	#else
		... spinlock stuff ...
	#endif

?

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-16 21:07                   ` Uwe Kleine-König
@ 2011-01-16 21:39                     ` Ryan Mallon
  -1 siblings, 0 replies; 86+ messages in thread
From: Ryan Mallon @ 2011-01-16 21:39 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Grant Likely, Jeremy Kerr, Russell King - ARM Linux,
	Sascha Hauer, Ben Herrenchmidt, linux-kernel, linux-arm-kernel

On 01/17/2011 10:07 AM, Uwe Kleine-König wrote:
> On Mon, Jan 17, 2011 at 09:41:46AM +1300, Ryan Mallon wrote:
>> On 01/16/2011 08:26 PM, Grant Likely wrote:
>>> On Mon, Jan 10, 2011 at 5:54 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
>>>> Hi Russell,
>>>>
>>>>> Unless the locking problems can be resolved, the patches aren't ready.
>>>>>
>>>>> From what I've seen there's still quite a problem with what kind of
>>>>> lock to use in the clock - mutex or spinlock.
>>>>
>>>> Yes, the clock driver may either use a spinlock or mutex.
>>>>
>>>> However, this exactly the same as the current clock code, my patches do not
>>>> alter what we currently have.
>>>>
>>>> I do agree that we should define some specific semantics for the clock API
>>>> with regards to sleeping, and I'll start a new thread about that. But we
>>>> should definitely separate that issue from the problem of having multiple
>>>> definitions for struct clk, which is what these patches address.
>>>
>>> Given that each current struct clk implementation makes it's own
>>> decisions about how to handle locking, would it not make sense to omit
>>> locking entirely?  At least as a first step?  Let the clock ops
>>> implement their own locking.  Make enable count management their
>>> responsibility too.  That's all that the lock protects anyway.  The
>>> clk_* apis can fall directly through to the ops hooks with no
>>> manipulation or locking.  The way v3 of the patch worked.
>>
>> This doesn't really work in a generic API because the call sites need to
>> know whether it safe to call clk_enable/disable, etc from a
>> non-sleepable context. This has essentially the same problems as using a
>> union with both a mutex and a spinlock.
> Note that this is the current status quo, too.  clk_enable on imx
> sleeps, clk_enable on at91 doesn't.  I think we all agree we don't want
> to change that during the unifying step.  So the common struct clk might
> not solve all problems, but it's not worse than the state now.

Yes, I pointed this out. I think we have ended up in this ugly situation
because the clock API calls never defined rules about calling context
and so some platforms have ended up needing to sleep in the calls, while
drivers for other platforms assume that the clock API calls can be
safely called from atomic context.

My point, and I think Russell's point, is that if you are going to have
a truly generic, unified API we don't want this sort of mix and match.
The clock API functions should have clearly defined rules about what
context they can be called from and each platform/machine implementation
of the API should obey those rules.

Partly this is about code clarity. At the moment, to determine if a
clk_enable call might sleep I need to go and look at the implementation
for the platform I am on. There are drivers, such as the amba-pl010
serial driver, which can be used on multiple platforms. To verify that
the clock API call sites are correct you need to check each platform
that the driver runs on. By having an explicit separation of the clock
implementations which are atomic and those which may need to sleep these
problems disappear.

For the current patch series, the documentation for clk_enable would
need include this.

  "This function may or may not be safe to call from atomic context
   depending on the platform you are on."

I don't think we have too many other generic APIs in the kernel which
have this kind of loose documentation.

>> That said, although we are aiming for a generic clock API, it's usage
>> typically isn't. Most of the users of the clock API are machine/platform
>> specific drivers and so they can make assumptions about the
>> implementation of the clock API calls. We currently do have a generic
>> set of clock calls which do not define rules about calling from atomic
>> context. We have a number of drivers, for several platforms, using the
>> clk_enable/disable calls. Some platforms are using sleeping clocks and
>> others are using atomic clocks, but because the _usage_ of the API is
>> largely platform specific it all hangs together.
>>
>> This is a bit ugly in practice. It's hardly desirable to have an API
>> which looks generic, but in reality is platform/machine specific. I'm
>> guessing that a large benefit of having a unified API and well defined
>> rules about whether clock API calls may sleep or not allows the usage of
>> the clock API to become more generic.
>>
>> I agree with Russell that the best short term approach is to create two
>> clock APIs, one for clocks which are atomic and the other for clocks
>> which need to sleep. If nothing else this at least allows the rules
>> about calling context to nailed down.
> For me this sounds like code duplication if everything is identical only
> spinlocks are substituted by mutexes.  What do you think about my
> suggestion to use a Kconfig symbol that is selected by platforms (e.g.
> COMMON_CLK_SLEEPING) and then use:
> 
> 	#ifdef CONFIG_COMMON_CLK_SLEEPING
> 		... mutex stuff ...
> 	#else
> 		... spinlock stuff ...
> 	#endif

You still have the problem that cannot make any assumptions about
calling context for calls to the clock API. The point is that the
semantics about calling context for a generic clock API are currently
too loose. Part of consolidating the clock implementations should be to
fix that. Russell's suggestion to reduce to two implementations (from
the 30+ we have now) will have a net reduction in code, but will also
clarify which platforms/drivers are using sleeping clocks.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan@bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-16 21:39                     ` Ryan Mallon
  0 siblings, 0 replies; 86+ messages in thread
From: Ryan Mallon @ 2011-01-16 21:39 UTC (permalink / raw)
  To: linux-arm-kernel

On 01/17/2011 10:07 AM, Uwe Kleine-K?nig wrote:
> On Mon, Jan 17, 2011 at 09:41:46AM +1300, Ryan Mallon wrote:
>> On 01/16/2011 08:26 PM, Grant Likely wrote:
>>> On Mon, Jan 10, 2011 at 5:54 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
>>>> Hi Russell,
>>>>
>>>>> Unless the locking problems can be resolved, the patches aren't ready.
>>>>>
>>>>> From what I've seen there's still quite a problem with what kind of
>>>>> lock to use in the clock - mutex or spinlock.
>>>>
>>>> Yes, the clock driver may either use a spinlock or mutex.
>>>>
>>>> However, this exactly the same as the current clock code, my patches do not
>>>> alter what we currently have.
>>>>
>>>> I do agree that we should define some specific semantics for the clock API
>>>> with regards to sleeping, and I'll start a new thread about that. But we
>>>> should definitely separate that issue from the problem of having multiple
>>>> definitions for struct clk, which is what these patches address.
>>>
>>> Given that each current struct clk implementation makes it's own
>>> decisions about how to handle locking, would it not make sense to omit
>>> locking entirely?  At least as a first step?  Let the clock ops
>>> implement their own locking.  Make enable count management their
>>> responsibility too.  That's all that the lock protects anyway.  The
>>> clk_* apis can fall directly through to the ops hooks with no
>>> manipulation or locking.  The way v3 of the patch worked.
>>
>> This doesn't really work in a generic API because the call sites need to
>> know whether it safe to call clk_enable/disable, etc from a
>> non-sleepable context. This has essentially the same problems as using a
>> union with both a mutex and a spinlock.
> Note that this is the current status quo, too.  clk_enable on imx
> sleeps, clk_enable on at91 doesn't.  I think we all agree we don't want
> to change that during the unifying step.  So the common struct clk might
> not solve all problems, but it's not worse than the state now.

Yes, I pointed this out. I think we have ended up in this ugly situation
because the clock API calls never defined rules about calling context
and so some platforms have ended up needing to sleep in the calls, while
drivers for other platforms assume that the clock API calls can be
safely called from atomic context.

My point, and I think Russell's point, is that if you are going to have
a truly generic, unified API we don't want this sort of mix and match.
The clock API functions should have clearly defined rules about what
context they can be called from and each platform/machine implementation
of the API should obey those rules.

Partly this is about code clarity. At the moment, to determine if a
clk_enable call might sleep I need to go and look at the implementation
for the platform I am on. There are drivers, such as the amba-pl010
serial driver, which can be used on multiple platforms. To verify that
the clock API call sites are correct you need to check each platform
that the driver runs on. By having an explicit separation of the clock
implementations which are atomic and those which may need to sleep these
problems disappear.

For the current patch series, the documentation for clk_enable would
need include this.

  "This function may or may not be safe to call from atomic context
   depending on the platform you are on."

I don't think we have too many other generic APIs in the kernel which
have this kind of loose documentation.

>> That said, although we are aiming for a generic clock API, it's usage
>> typically isn't. Most of the users of the clock API are machine/platform
>> specific drivers and so they can make assumptions about the
>> implementation of the clock API calls. We currently do have a generic
>> set of clock calls which do not define rules about calling from atomic
>> context. We have a number of drivers, for several platforms, using the
>> clk_enable/disable calls. Some platforms are using sleeping clocks and
>> others are using atomic clocks, but because the _usage_ of the API is
>> largely platform specific it all hangs together.
>>
>> This is a bit ugly in practice. It's hardly desirable to have an API
>> which looks generic, but in reality is platform/machine specific. I'm
>> guessing that a large benefit of having a unified API and well defined
>> rules about whether clock API calls may sleep or not allows the usage of
>> the clock API to become more generic.
>>
>> I agree with Russell that the best short term approach is to create two
>> clock APIs, one for clocks which are atomic and the other for clocks
>> which need to sleep. If nothing else this at least allows the rules
>> about calling context to nailed down.
> For me this sounds like code duplication if everything is identical only
> spinlocks are substituted by mutexes.  What do you think about my
> suggestion to use a Kconfig symbol that is selected by platforms (e.g.
> COMMON_CLK_SLEEPING) and then use:
> 
> 	#ifdef CONFIG_COMMON_CLK_SLEEPING
> 		... mutex stuff ...
> 	#else
> 		... spinlock stuff ...
> 	#endif

You still have the problem that cannot make any assumptions about
calling context for calls to the clock API. The point is that the
semantics about calling context for a generic clock API are currently
too loose. Part of consolidating the clock implementations should be to
fix that. Russell's suggestion to reduce to two implementations (from
the 30+ we have now) will have a net reduction in code, but will also
clarify which platforms/drivers are using sleeping clocks.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan at bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-11 11:22         ` Sascha Hauer
@ 2011-01-18  8:44           ` Paul Mundt
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Mundt @ 2011-01-18  8:44 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Jeremy Kerr, linux-kernel, linux-arm-kernel, Ben Herrenchmidt,
	Uwe Kleine-K?nig

On Tue, Jan 11, 2011 at 12:22:40PM +0100, Sascha Hauer wrote:
> On Tue, Jan 11, 2011 at 06:27:11PM +0800, Jeremy Kerr wrote:
> > Hi Sascha,
> >  
> > > The i.MX clk implementation disables the old parent if clk is enabled
> > > and enables the new parent if clk is enabled (modulo bugs). Shouldn't
> > > we do this here aswell?
> > 
> > Sounds reasonable, yes.
> > 
> > > I thought about returning -EBUSY if clk_set_parent is called for an
> > > enabled clk, but this way we could never reparent the cpu clock which I
> > > think is done in the Freescale BSP for power saving.
> > 
> > I think that the possibility for changing the parent really depends on the 
> > implementation; in some cases we may want to disallow it, in others it might 
> > be fine.
> > 
> > Related: do we really need globally-accessible clk_{get,set}_parent in the clk 
> > API? For cases where we need to set the parent, we probably need details about 
> > the platform clock configuration (eg, which clocks are possible parents). In 
> > this case, we could just call into the clock driver directly.
> 
> I agree that drivers have no business calling clk_{get,set}_parent, this
> is purely platform specific.
> 
Do you guys even bother to grep the kernel for users of the API before
coming up with arbitrary policy?

There are plenty of cases where clocks are allocated dynamically by
driver code that in turn can be set up as a parent for other dynamically
allocated clocks. This has not a damn thing to do with platform code and
everything to do with the clock circuitry of the device or IP block in
question.

If you actually want this API unification thing to not be completely
stillborn, I recommend focusing on how people are actually using the API
today (especially the parts that are used by the majority of users, not
the one you happened to base your implementation off of), and then trying
to push your interpretation or roadmap for the API at a later stage. This
way the former has a chance of getting upstream without the latter
completely derailing it.

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-18  8:44           ` Paul Mundt
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Mundt @ 2011-01-18  8:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 11, 2011 at 12:22:40PM +0100, Sascha Hauer wrote:
> On Tue, Jan 11, 2011 at 06:27:11PM +0800, Jeremy Kerr wrote:
> > Hi Sascha,
> >  
> > > The i.MX clk implementation disables the old parent if clk is enabled
> > > and enables the new parent if clk is enabled (modulo bugs). Shouldn't
> > > we do this here aswell?
> > 
> > Sounds reasonable, yes.
> > 
> > > I thought about returning -EBUSY if clk_set_parent is called for an
> > > enabled clk, but this way we could never reparent the cpu clock which I
> > > think is done in the Freescale BSP for power saving.
> > 
> > I think that the possibility for changing the parent really depends on the 
> > implementation; in some cases we may want to disallow it, in others it might 
> > be fine.
> > 
> > Related: do we really need globally-accessible clk_{get,set}_parent in the clk 
> > API? For cases where we need to set the parent, we probably need details about 
> > the platform clock configuration (eg, which clocks are possible parents). In 
> > this case, we could just call into the clock driver directly.
> 
> I agree that drivers have no business calling clk_{get,set}_parent, this
> is purely platform specific.
> 
Do you guys even bother to grep the kernel for users of the API before
coming up with arbitrary policy?

There are plenty of cases where clocks are allocated dynamically by
driver code that in turn can be set up as a parent for other dynamically
allocated clocks. This has not a damn thing to do with platform code and
everything to do with the clock circuitry of the device or IP block in
question.

If you actually want this API unification thing to not be completely
stillborn, I recommend focusing on how people are actually using the API
today (especially the parts that are used by the majority of users, not
the one you happened to base your implementation off of), and then trying
to push your interpretation or roadmap for the API at a later stage. This
way the former has a chance of getting upstream without the latter
completely derailing it.

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-18  8:44           ` Paul Mundt
@ 2011-01-18  9:21             ` Sascha Hauer
  -1 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-18  9:21 UTC (permalink / raw)
  To: Paul Mundt
  Cc: Jeremy Kerr, linux-kernel, linux-arm-kernel, Ben Herrenchmidt,
	Uwe Kleine-K?nig

On Tue, Jan 18, 2011 at 05:44:45PM +0900, Paul Mundt wrote:
> On Tue, Jan 11, 2011 at 12:22:40PM +0100, Sascha Hauer wrote:
> > On Tue, Jan 11, 2011 at 06:27:11PM +0800, Jeremy Kerr wrote:
> > > Hi Sascha,
> > >  
> > > > The i.MX clk implementation disables the old parent if clk is enabled
> > > > and enables the new parent if clk is enabled (modulo bugs). Shouldn't
> > > > we do this here aswell?
> > > 
> > > Sounds reasonable, yes.
> > > 
> > > > I thought about returning -EBUSY if clk_set_parent is called for an
> > > > enabled clk, but this way we could never reparent the cpu clock which I
> > > > think is done in the Freescale BSP for power saving.
> > > 
> > > I think that the possibility for changing the parent really depends on the 
> > > implementation; in some cases we may want to disallow it, in others it might 
> > > be fine.
> > > 
> > > Related: do we really need globally-accessible clk_{get,set}_parent in the clk 
> > > API? For cases where we need to set the parent, we probably need details about 
> > > the platform clock configuration (eg, which clocks are possible parents). In 
> > > this case, we could just call into the clock driver directly.
> > 
> > I agree that drivers have no business calling clk_{get,set}_parent, this
> > is purely platform specific.
> > 
> Do you guys even bother to grep the kernel for users of the API before
> coming up with arbitrary policy?

Actually I did bother to grep the kernel and I came up with these
results:

drivers/video/omap2/dss/dss.c:219:      dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/omap2/dss/dss.c:312:      prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/omap2/dss/dss.c:325:              prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/omap2/dss/dss.c:344:              prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/omap2/dss/dss.c:359:              return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/sh_mobile_hdmi.c:716:     else if (clk_get_parent(hdmi->hdmi_clk))
drivers/video/sh_mobile_hdmi.c:717:             *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk));
drivers/video/sh_mobile_hdmi.c:1089:    if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) {
drivers/video/sh_mobile_hdmi.c:1090:            ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate);
drivers/usb/host/ehci-omap.c:405:                       ret = clk_set_parent(omap->utmi_p1_fck,
drivers/usb/host/ehci-omap.c:435:                       ret = clk_set_parent(omap->utmi_p2_fck,

In case of the omap2 dss driver the parent rate seems to be used for
calculating valid clock frequencies based on the knowledge that between
the parent clock and the device clock is a divider with some fixed values.
It's arguable whether this is a valid use of the clock API.
In the sh mobile hdmi driver both the device clock and the parent clock
seem to be adjustable and the driver tries to get the best possible rate
by adjusting both clocks. I think this could better be abstracted in the
clock framework.
The omap ehci driver is the only one I found which uses clk_set_parent,
but it uses detailed platform knowledge to do so. Is it really necessary
to put this into a driver?

> 
> There are plenty of cases where clocks are allocated dynamically by
> driver code that in turn can be set up as a parent for other dynamically
> allocated clocks. This has not a damn thing to do with platform code and
> everything to do with the clock circuitry of the device or IP block in
> question.
> 
> If you actually want this API unification thing to not be completely
> stillborn, I recommend focusing on how people are actually using the API
> today (especially the parts that are used by the majority of users, not
> the one you happened to base your implementation off of), and then trying
> to push your interpretation or roadmap for the API at a later stage. This
> way the former has a chance of getting upstream without the latter
> completely derailing it.

The majority of users do not use clk_{get,set}_parent at all. And it's
really questionable whether drivers should know anything about the
layout of the clock tree. I'm pretty sure that these are the code pieces
where there will be a if_soc_rev(x) around it once the next incarnation
of a SoC comes out.

Saascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-18  9:21             ` Sascha Hauer
  0 siblings, 0 replies; 86+ messages in thread
From: Sascha Hauer @ 2011-01-18  9:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 18, 2011 at 05:44:45PM +0900, Paul Mundt wrote:
> On Tue, Jan 11, 2011 at 12:22:40PM +0100, Sascha Hauer wrote:
> > On Tue, Jan 11, 2011 at 06:27:11PM +0800, Jeremy Kerr wrote:
> > > Hi Sascha,
> > >  
> > > > The i.MX clk implementation disables the old parent if clk is enabled
> > > > and enables the new parent if clk is enabled (modulo bugs). Shouldn't
> > > > we do this here aswell?
> > > 
> > > Sounds reasonable, yes.
> > > 
> > > > I thought about returning -EBUSY if clk_set_parent is called for an
> > > > enabled clk, but this way we could never reparent the cpu clock which I
> > > > think is done in the Freescale BSP for power saving.
> > > 
> > > I think that the possibility for changing the parent really depends on the 
> > > implementation; in some cases we may want to disallow it, in others it might 
> > > be fine.
> > > 
> > > Related: do we really need globally-accessible clk_{get,set}_parent in the clk 
> > > API? For cases where we need to set the parent, we probably need details about 
> > > the platform clock configuration (eg, which clocks are possible parents). In 
> > > this case, we could just call into the clock driver directly.
> > 
> > I agree that drivers have no business calling clk_{get,set}_parent, this
> > is purely platform specific.
> > 
> Do you guys even bother to grep the kernel for users of the API before
> coming up with arbitrary policy?

Actually I did bother to grep the kernel and I came up with these
results:

drivers/video/omap2/dss/dss.c:219:      dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/omap2/dss/dss.c:312:      prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/omap2/dss/dss.c:325:              prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/omap2/dss/dss.c:344:              prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/omap2/dss/dss.c:359:              return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
drivers/video/sh_mobile_hdmi.c:716:     else if (clk_get_parent(hdmi->hdmi_clk))
drivers/video/sh_mobile_hdmi.c:717:             *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk));
drivers/video/sh_mobile_hdmi.c:1089:    if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) {
drivers/video/sh_mobile_hdmi.c:1090:            ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate);
drivers/usb/host/ehci-omap.c:405:                       ret = clk_set_parent(omap->utmi_p1_fck,
drivers/usb/host/ehci-omap.c:435:                       ret = clk_set_parent(omap->utmi_p2_fck,

In case of the omap2 dss driver the parent rate seems to be used for
calculating valid clock frequencies based on the knowledge that between
the parent clock and the device clock is a divider with some fixed values.
It's arguable whether this is a valid use of the clock API.
In the sh mobile hdmi driver both the device clock and the parent clock
seem to be adjustable and the driver tries to get the best possible rate
by adjusting both clocks. I think this could better be abstracted in the
clock framework.
The omap ehci driver is the only one I found which uses clk_set_parent,
but it uses detailed platform knowledge to do so. Is it really necessary
to put this into a driver?

> 
> There are plenty of cases where clocks are allocated dynamically by
> driver code that in turn can be set up as a parent for other dynamically
> allocated clocks. This has not a damn thing to do with platform code and
> everything to do with the clock circuitry of the device or IP block in
> question.
> 
> If you actually want this API unification thing to not be completely
> stillborn, I recommend focusing on how people are actually using the API
> today (especially the parts that are used by the majority of users, not
> the one you happened to base your implementation off of), and then trying
> to push your interpretation or roadmap for the API at a later stage. This
> way the former has a chance of getting upstream without the latter
> completely derailing it.

The majority of users do not use clk_{get,set}_parent at all. And it's
really questionable whether drivers should know anything about the
layout of the clock tree. I'm pretty sure that these are the code pieces
where there will be a if_soc_rev(x) around it once the next incarnation
of a SoC comes out.

Saascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-18  9:21             ` Sascha Hauer
@ 2011-01-18  9:23               ` Paul Mundt
  -1 siblings, 0 replies; 86+ messages in thread
From: Paul Mundt @ 2011-01-18  9:23 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Jeremy Kerr, linux-kernel, linux-arm-kernel, Ben Herrenchmidt,
	Uwe Kleine-K?nig

On Tue, Jan 18, 2011 at 10:21:28AM +0100, Sascha Hauer wrote:
> On Tue, Jan 18, 2011 at 05:44:45PM +0900, Paul Mundt wrote:
> > Do you guys even bother to grep the kernel for users of the API before
> > coming up with arbitrary policy?
> 
> Actually I did bother to grep the kernel and I came up with these
> results:
> 
> drivers/video/omap2/dss/dss.c:219:      dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/omap2/dss/dss.c:312:      prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/omap2/dss/dss.c:325:              prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/omap2/dss/dss.c:344:              prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/omap2/dss/dss.c:359:              return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/sh_mobile_hdmi.c:716:     else if (clk_get_parent(hdmi->hdmi_clk))
> drivers/video/sh_mobile_hdmi.c:717:             *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk));
> drivers/video/sh_mobile_hdmi.c:1089:    if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) {
> drivers/video/sh_mobile_hdmi.c:1090:            ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate);
> drivers/usb/host/ehci-omap.c:405:                       ret = clk_set_parent(omap->utmi_p1_fck,
> drivers/usb/host/ehci-omap.c:435:                       ret = clk_set_parent(omap->utmi_p2_fck,
> 
Then I recommend you grep harder. There are more drivers than the ones
that simply live in drivers/.

> > There are plenty of cases where clocks are allocated dynamically by
> > driver code that in turn can be set up as a parent for other dynamically
> > allocated clocks. This has not a damn thing to do with platform code and
> > everything to do with the clock circuitry of the device or IP block in
> > question.
> 
> The majority of users do not use clk_{get,set}_parent at all. And it's
> really questionable whether drivers should know anything about the
> layout of the clock tree. I'm pretty sure that these are the code pieces
> where there will be a if_soc_rev(x) around it once the next incarnation
> of a SoC comes out.
> 
It's not questionable in the least, you're simply dealing with cases
where you personally haven't had a need to do so and are attempting to
project that as a policy. I'm getting pretty tired of this.

We have many IP blocks that can use external clocks or drive their own
clock circuitry, in which case the internal clocks are parented by a
parent clock that is likewise also dynamically created. Your lack of
imagination is really not my concern, and again, this has nothing to do
with the SoC.

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-18  9:23               ` Paul Mundt
  0 siblings, 0 replies; 86+ messages in thread
From: Paul Mundt @ 2011-01-18  9:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 18, 2011 at 10:21:28AM +0100, Sascha Hauer wrote:
> On Tue, Jan 18, 2011 at 05:44:45PM +0900, Paul Mundt wrote:
> > Do you guys even bother to grep the kernel for users of the API before
> > coming up with arbitrary policy?
> 
> Actually I did bother to grep the kernel and I came up with these
> results:
> 
> drivers/video/omap2/dss/dss.c:219:      dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/omap2/dss/dss.c:312:      prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/omap2/dss/dss.c:325:              prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/omap2/dss/dss.c:344:              prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/omap2/dss/dss.c:359:              return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
> drivers/video/sh_mobile_hdmi.c:716:     else if (clk_get_parent(hdmi->hdmi_clk))
> drivers/video/sh_mobile_hdmi.c:717:             *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk));
> drivers/video/sh_mobile_hdmi.c:1089:    if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) {
> drivers/video/sh_mobile_hdmi.c:1090:            ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate);
> drivers/usb/host/ehci-omap.c:405:                       ret = clk_set_parent(omap->utmi_p1_fck,
> drivers/usb/host/ehci-omap.c:435:                       ret = clk_set_parent(omap->utmi_p2_fck,
> 
Then I recommend you grep harder. There are more drivers than the ones
that simply live in drivers/.

> > There are plenty of cases where clocks are allocated dynamically by
> > driver code that in turn can be set up as a parent for other dynamically
> > allocated clocks. This has not a damn thing to do with platform code and
> > everything to do with the clock circuitry of the device or IP block in
> > question.
> 
> The majority of users do not use clk_{get,set}_parent at all. And it's
> really questionable whether drivers should know anything about the
> layout of the clock tree. I'm pretty sure that these are the code pieces
> where there will be a if_soc_rev(x) around it once the next incarnation
> of a SoC comes out.
> 
It's not questionable in the least, you're simply dealing with cases
where you personally haven't had a need to do so and are attempting to
project that as a policy. I'm getting pretty tired of this.

We have many IP blocks that can use external clocks or drive their own
clock circuitry, in which case the internal clocks are parented by a
parent clock that is likewise also dynamically created. Your lack of
imagination is really not my concern, and again, this has nothing to do
with the SoC.

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-01-05  3:51   ` Jeremy Kerr
@ 2011-01-18 12:21     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2011-01-18 12:21 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: linux-kernel, linux-arm-kernel, Ben Herrenchmidt, Uwe Kleine-König

On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:
> ---
>  arch/Kconfig        |    3 
>  include/linux/clk.h |  164 +++++++++++++++++++++++++++++++++++++++++---
>  kernel/Makefile     |    1 
>  kernel/clk.c        |  102 +++++++++++++++++++++++++++
>  4 files changed, 261 insertions(+), 9 deletions(-)

As we already have drivers/clk/, does it really make sense to spread this
far and wide around the kernel tree by putting it in kernel/ ?

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

* [PATCH 1/2] Add a common struct clk
@ 2011-01-18 12:21     ` Russell King - ARM Linux
  0 siblings, 0 replies; 86+ messages in thread
From: Russell King - ARM Linux @ 2011-01-18 12:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:
> ---
>  arch/Kconfig        |    3 
>  include/linux/clk.h |  164 +++++++++++++++++++++++++++++++++++++++++---
>  kernel/Makefile     |    1 
>  kernel/clk.c        |  102 +++++++++++++++++++++++++++
>  4 files changed, 261 insertions(+), 9 deletions(-)

As we already have drivers/clk/, does it really make sense to spread this
far and wide around the kernel tree by putting it in kernel/ ?

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-03-03  6:40       ` Jeremy Kerr
  (?)
@ 2011-04-14 12:49         ` Tony Lindgren
  -1 siblings, 0 replies; 86+ messages in thread
From: Tony Lindgren @ 2011-04-14 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

* Jeremy Kerr <jeremy.kerr@canonical.com> [110303 08:39]:
> 
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
> 
> struct clk {
> 	const struct clk_ops	*ops;
> 	unsigned int		enable_count;
> 	unsigned int		prepare_count;
> 	spinlock_t		enable_lock;
> 	struct mutex		prepare_lock;
> };
> 
> And a set of clock operations (defined per type of clock):
> 
> struct clk_ops {
> 	int             (*enable)(struct clk *);
> 	void            (*disable)(struct clk *);
> 	unsigned long   (*get_rate)(struct clk *);
> 	[...]
> };
> 
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
> 
> struct clk_foo {
> 	struct clk	clk;
> 	void __iomem	*some_register;
> };
> 
> struct clk_ops clk_foo_ops = {
> 	.get_rate = clk_foo_get_rate,
> };

Anybody looked into passing the clock register and type
from device tree?

To me it looks like the above would allow doing that
pretty easily while avoiding duplicating all the
data from devicetree into struct clk_foo.

Tony

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

* Re: [PATCH 1/2] Add a common struct clk
@ 2011-04-14 12:49         ` Tony Lindgren
  0 siblings, 0 replies; 86+ messages in thread
From: Tony Lindgren @ 2011-04-14 12:49 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: linux-kernel, linux-arm-kernel, Nicolas Pitre, Lorenzo Pieralisi,
	Vincent Guittot, linux-sh, Ben Herrenschmidt, Sascha Hauer,
	Paul Mundt, Dima Zavin, Saravana Kannan, Ben Dooks,
	Uwe Kleine-König, Russell King, Paul Walmsley

* Jeremy Kerr <jeremy.kerr@canonical.com> [110303 08:39]:
> 
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
> 
> struct clk {
> 	const struct clk_ops	*ops;
> 	unsigned int		enable_count;
> 	unsigned int		prepare_count;
> 	spinlock_t		enable_lock;
> 	struct mutex		prepare_lock;
> };
> 
> And a set of clock operations (defined per type of clock):
> 
> struct clk_ops {
> 	int             (*enable)(struct clk *);
> 	void            (*disable)(struct clk *);
> 	unsigned long   (*get_rate)(struct clk *);
> 	[...]
> };
> 
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
> 
> struct clk_foo {
> 	struct clk	clk;
> 	void __iomem	*some_register;
> };
> 
> struct clk_ops clk_foo_ops = {
> 	.get_rate = clk_foo_get_rate,
> };

Anybody looked into passing the clock register and type
from device tree?

To me it looks like the above would allow doing that
pretty easily while avoiding duplicating all the
data from devicetree into struct clk_foo.

Tony

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

* [PATCH 1/2] Add a common struct clk
@ 2011-04-14 12:49         ` Tony Lindgren
  0 siblings, 0 replies; 86+ messages in thread
From: Tony Lindgren @ 2011-04-14 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

* Jeremy Kerr <jeremy.kerr@canonical.com> [110303 08:39]:
> 
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
> 
> struct clk {
> 	const struct clk_ops	*ops;
> 	unsigned int		enable_count;
> 	unsigned int		prepare_count;
> 	spinlock_t		enable_lock;
> 	struct mutex		prepare_lock;
> };
> 
> And a set of clock operations (defined per type of clock):
> 
> struct clk_ops {
> 	int             (*enable)(struct clk *);
> 	void            (*disable)(struct clk *);
> 	unsigned long   (*get_rate)(struct clk *);
> 	[...]
> };
> 
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
> 
> struct clk_foo {
> 	struct clk	clk;
> 	void __iomem	*some_register;
> };
> 
> struct clk_ops clk_foo_ops = {
> 	.get_rate = clk_foo_get_rate,
> };

Anybody looked into passing the clock register and type
from device tree?

To me it looks like the above would allow doing that
pretty easily while avoiding duplicating all the
data from devicetree into struct clk_foo.

Tony

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

* [PATCH 1/2] Add a common struct clk
  2011-03-03  6:40   ` [PATCH 0/2] Common struct clk implementation, v14 Jeremy Kerr
  2011-03-03  6:40       ` Jeremy Kerr
@ 2011-03-03  6:40       ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-03-03  6:40 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	unsigned int		prepare_count;
	spinlock_t		enable_lock;
	struct mutex		prepare_lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 drivers/clk/Kconfig  |    3 
 drivers/clk/Makefile |    1 
 drivers/clk/clk.c    |  132 ++++++++++++++++++++++++++++++++++
 drivers/clk/clkdev.c |    7 +
 include/linux/clk.h  |  164 ++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 298 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
 config CLKDEV_LOOKUP
 	bool
 	select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+	bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
 
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..0bc9c6f
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count = 0 && clk->ops->prepare)
+		ret = clk->ops->prepare(clk);
+
+	if (!ret)
+		clk->prepare_count++;
+	mutex_unlock(&clk->prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+	mutex_lock(&clk->prepare_lock);
+
+	WARN_ON(clk->prepare_count = 0);
+
+	if (--clk->prepare_count = 0 && clk->ops->unprepare) {
+		WARN_ON(clk->enable_count != 0);
+		clk->ops->unprepare(clk);
+	}
+
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	WARN_ON(clk->prepare_count = 0);
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+	if (clk->enable_count = 0 && clk->ops->enable)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+
+	WARN_ON(clk->enable_count = 0);
+
+	if (!--clk->enable_count = 0 && clk->ops->disable)
+		clk->ops->disable(clk);
+
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	might_sleep();
+
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+
+void __clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0fc0a79..a7999d2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -23,6 +23,13 @@
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
 
+/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported
+ * through other headers; we don't want them used anywhere but here. */
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+extern int __clk_get(struct clk *clk);
+extern void __clk_put(struct clk *clk);
+#endif
+
 /*
  * Find the correct struct clk for the device and connection ID.
  * We do slightly fuzzy matching here:
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..7b406bd 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,168 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @enable_lock:	lock for atomic enable
+ * @prepare_count:	count of clk_prepare() calls active on this clock
+ * @prepare_lock:	lock for sleepable prepare
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_lock and @prepare_lock members are used to serialise accesses
+ * to the ops->enable and ops->prepare functions (and the corresponding
+ * ops->disable and ops->unprepare functions).
  */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	unsigned int		prepare_count;
+	spinlock_t		enable_lock;
+	struct mutex		prepare_lock;
+};
 
+/* static initialiser for clocks. */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_lock	= __SPIN_LOCK_UNLOCKED(name.enable_lock),	\
+	.prepare_lock	= __MUTEX_INITIALIZER(name.prepare_lock),	\
+}
+
+/**
+ * struct clk_ops -  Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare:	Prepare the clock for enabling. This must not return until
+ *		the clock is fully prepared, and it's safe to call clk_enable.
+ *		This callback is intended to allow clock implementations to
+ *		do any initialisation that may sleep. Called with
+ *		clk->prepare_lock held.
+ *
+ * @unprepare:	Release the clock from its prepared state. This will typically
+ *		undo any work done in the @prepare callback. Called with
+ *		clk->prepare_lock held.
+ *
+ * @enable:	Enable the clock atomically. This must not return until the
+ *		clock is generating a valid clock signal, usable by consumer
+ *		devices. Called with clk->enable_lock held. This function
+ *		must not sleep.
+ *
+ * @disable:	Disable the clock atomically. Called with clk->enable_lock held.
+ *		This function must not sleep.
+ *
+ * @get:	Called by the core clock code when a device driver acquires a
+ *		clock via clk_get(). Optional.
+ *
+ * @put:	Called by the core clock code when a devices driver releases a
+ *		clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts.  If a clock requires sleeping code to be turned on, this
+ * should be done in clk_prepare. Switching that will not sleep should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare *must* have been
+ * called before clk_enable.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see drivers/clk/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+	int		(*prepare)(struct clk *);
+	void		(*unprepare)(struct clk *);
+	int		(*enable)(struct clk *);
+	void		(*disable)(struct clk *);
+	int		(*get)(struct clk *);
+	void		(*put)(struct clk *);
+	unsigned long	(*get_rate)(struct clk *);
+	long		(*round_rate)(struct clk *, unsigned long);
+	int		(*set_rate)(struct clk *, unsigned long);
+	int		(*set_parent)(struct clk *, struct clk *);
+	struct clk *	(*get_parent)(struct clk *);
+};
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any possibly sleeping initialisation on @clk, allowing the clock to be
+ * later enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possibly sleeping) cleanup on clk. This function may sleep.
+ */
+void clk_unprepare(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = clk->prepare_count = 0;
+	spin_lock_init(&clk->enable_lock);
+	mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+static inline int clk_prepare(struct clk *clk) { return 0; }
+static inline void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -67,6 +218,7 @@ void clk_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.
+ *		  Returns zero if the clock rate is unknown.
  * @clk: clock source
  */
 unsigned long clk_get_rate(struct clk *clk);
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source

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

* [PATCH 1/2] Add a common struct clk
@ 2011-03-03  6:40       ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-03-03  6:40 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: Nicolas Pitre, Dima Zavin, Lorenzo Pieralisi, Vincent Guittot,
	linux-sh, Ben Herrenschmidt, Uwe Kleine-König, Sascha Hauer,
	Paul Mundt, Saravana Kannan, Ben Dooks, Jeremy Kerr,
	Russell King

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	unsigned int		prepare_count;
	spinlock_t		enable_lock;
	struct mutex		prepare_lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 drivers/clk/Kconfig  |    3 
 drivers/clk/Makefile |    1 
 drivers/clk/clk.c    |  132 ++++++++++++++++++++++++++++++++++
 drivers/clk/clkdev.c |    7 +
 include/linux/clk.h  |  164 ++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 298 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
 config CLKDEV_LOOKUP
 	bool
 	select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+	bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
 
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..0bc9c6f
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count == 0 && clk->ops->prepare)
+		ret = clk->ops->prepare(clk);
+
+	if (!ret)
+		clk->prepare_count++;
+	mutex_unlock(&clk->prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+	mutex_lock(&clk->prepare_lock);
+
+	WARN_ON(clk->prepare_count == 0);
+
+	if (--clk->prepare_count == 0 && clk->ops->unprepare) {
+		WARN_ON(clk->enable_count != 0);
+		clk->ops->unprepare(clk);
+	}
+
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	WARN_ON(clk->prepare_count == 0);
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+	if (clk->enable_count == 0 && clk->ops->enable)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+
+	WARN_ON(clk->enable_count == 0);
+
+	if (!--clk->enable_count == 0 && clk->ops->disable)
+		clk->ops->disable(clk);
+
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	might_sleep();
+
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+
+void __clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0fc0a79..a7999d2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -23,6 +23,13 @@
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
 
+/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported
+ * through other headers; we don't want them used anywhere but here. */
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+extern int __clk_get(struct clk *clk);
+extern void __clk_put(struct clk *clk);
+#endif
+
 /*
  * Find the correct struct clk for the device and connection ID.
  * We do slightly fuzzy matching here:
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..7b406bd 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,168 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @enable_lock:	lock for atomic enable
+ * @prepare_count:	count of clk_prepare() calls active on this clock
+ * @prepare_lock:	lock for sleepable prepare
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_lock and @prepare_lock members are used to serialise accesses
+ * to the ops->enable and ops->prepare functions (and the corresponding
+ * ops->disable and ops->unprepare functions).
  */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	unsigned int		prepare_count;
+	spinlock_t		enable_lock;
+	struct mutex		prepare_lock;
+};
 
+/* static initialiser for clocks. */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_lock	= __SPIN_LOCK_UNLOCKED(name.enable_lock),	\
+	.prepare_lock	= __MUTEX_INITIALIZER(name.prepare_lock),	\
+}
+
+/**
+ * struct clk_ops -  Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare:	Prepare the clock for enabling. This must not return until
+ *		the clock is fully prepared, and it's safe to call clk_enable.
+ *		This callback is intended to allow clock implementations to
+ *		do any initialisation that may sleep. Called with
+ *		clk->prepare_lock held.
+ *
+ * @unprepare:	Release the clock from its prepared state. This will typically
+ *		undo any work done in the @prepare callback. Called with
+ *		clk->prepare_lock held.
+ *
+ * @enable:	Enable the clock atomically. This must not return until the
+ *		clock is generating a valid clock signal, usable by consumer
+ *		devices. Called with clk->enable_lock held. This function
+ *		must not sleep.
+ *
+ * @disable:	Disable the clock atomically. Called with clk->enable_lock held.
+ *		This function must not sleep.
+ *
+ * @get:	Called by the core clock code when a device driver acquires a
+ *		clock via clk_get(). Optional.
+ *
+ * @put:	Called by the core clock code when a devices driver releases a
+ *		clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts.  If a clock requires sleeping code to be turned on, this
+ * should be done in clk_prepare. Switching that will not sleep should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare *must* have been
+ * called before clk_enable.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see drivers/clk/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+	int		(*prepare)(struct clk *);
+	void		(*unprepare)(struct clk *);
+	int		(*enable)(struct clk *);
+	void		(*disable)(struct clk *);
+	int		(*get)(struct clk *);
+	void		(*put)(struct clk *);
+	unsigned long	(*get_rate)(struct clk *);
+	long		(*round_rate)(struct clk *, unsigned long);
+	int		(*set_rate)(struct clk *, unsigned long);
+	int		(*set_parent)(struct clk *, struct clk *);
+	struct clk *	(*get_parent)(struct clk *);
+};
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any possibly sleeping initialisation on @clk, allowing the clock to be
+ * later enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possibly sleeping) cleanup on clk. This function may sleep.
+ */
+void clk_unprepare(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = clk->prepare_count = 0;
+	spin_lock_init(&clk->enable_lock);
+	mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+static inline int clk_prepare(struct clk *clk) { return 0; }
+static inline void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -67,6 +218,7 @@ void clk_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.
+ *		  Returns zero if the clock rate is unknown.
  * @clk: clock source
  */
 unsigned long clk_get_rate(struct clk *clk);
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source

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

* [PATCH 1/2] Add a common struct clk
@ 2011-03-03  6:40       ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-03-03  6:40 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	unsigned int		prepare_count;
	spinlock_t		enable_lock;
	struct mutex		prepare_lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 drivers/clk/Kconfig  |    3 
 drivers/clk/Makefile |    1 
 drivers/clk/clk.c    |  132 ++++++++++++++++++++++++++++++++++
 drivers/clk/clkdev.c |    7 +
 include/linux/clk.h  |  164 ++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 298 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
 config CLKDEV_LOOKUP
 	bool
 	select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+	bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
 
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..0bc9c6f
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count == 0 && clk->ops->prepare)
+		ret = clk->ops->prepare(clk);
+
+	if (!ret)
+		clk->prepare_count++;
+	mutex_unlock(&clk->prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+	mutex_lock(&clk->prepare_lock);
+
+	WARN_ON(clk->prepare_count == 0);
+
+	if (--clk->prepare_count == 0 && clk->ops->unprepare) {
+		WARN_ON(clk->enable_count != 0);
+		clk->ops->unprepare(clk);
+	}
+
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	WARN_ON(clk->prepare_count == 0);
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+	if (clk->enable_count == 0 && clk->ops->enable)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+
+	WARN_ON(clk->enable_count == 0);
+
+	if (!--clk->enable_count == 0 && clk->ops->disable)
+		clk->ops->disable(clk);
+
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	might_sleep();
+
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+
+void __clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0fc0a79..a7999d2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -23,6 +23,13 @@
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
 
+/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported
+ * through other headers; we don't want them used anywhere but here. */
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+extern int __clk_get(struct clk *clk);
+extern void __clk_put(struct clk *clk);
+#endif
+
 /*
  * Find the correct struct clk for the device and connection ID.
  * We do slightly fuzzy matching here:
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..7b406bd 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,168 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @enable_lock:	lock for atomic enable
+ * @prepare_count:	count of clk_prepare() calls active on this clock
+ * @prepare_lock:	lock for sleepable prepare
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_lock and @prepare_lock members are used to serialise accesses
+ * to the ops->enable and ops->prepare functions (and the corresponding
+ * ops->disable and ops->unprepare functions).
  */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	unsigned int		prepare_count;
+	spinlock_t		enable_lock;
+	struct mutex		prepare_lock;
+};
 
+/* static initialiser for clocks. */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_lock	= __SPIN_LOCK_UNLOCKED(name.enable_lock),	\
+	.prepare_lock	= __MUTEX_INITIALIZER(name.prepare_lock),	\
+}
+
+/**
+ * struct clk_ops -  Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare:	Prepare the clock for enabling. This must not return until
+ *		the clock is fully prepared, and it's safe to call clk_enable.
+ *		This callback is intended to allow clock implementations to
+ *		do any initialisation that may sleep. Called with
+ *		clk->prepare_lock held.
+ *
+ * @unprepare:	Release the clock from its prepared state. This will typically
+ *		undo any work done in the @prepare callback. Called with
+ *		clk->prepare_lock held.
+ *
+ * @enable:	Enable the clock atomically. This must not return until the
+ *		clock is generating a valid clock signal, usable by consumer
+ *		devices. Called with clk->enable_lock held. This function
+ *		must not sleep.
+ *
+ * @disable:	Disable the clock atomically. Called with clk->enable_lock held.
+ *		This function must not sleep.
+ *
+ * @get:	Called by the core clock code when a device driver acquires a
+ *		clock via clk_get(). Optional.
+ *
+ * @put:	Called by the core clock code when a devices driver releases a
+ *		clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts.  If a clock requires sleeping code to be turned on, this
+ * should be done in clk_prepare. Switching that will not sleep should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare *must* have been
+ * called before clk_enable.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see drivers/clk/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+	int		(*prepare)(struct clk *);
+	void		(*unprepare)(struct clk *);
+	int		(*enable)(struct clk *);
+	void		(*disable)(struct clk *);
+	int		(*get)(struct clk *);
+	void		(*put)(struct clk *);
+	unsigned long	(*get_rate)(struct clk *);
+	long		(*round_rate)(struct clk *, unsigned long);
+	int		(*set_rate)(struct clk *, unsigned long);
+	int		(*set_parent)(struct clk *, struct clk *);
+	struct clk *	(*get_parent)(struct clk *);
+};
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any possibly sleeping initialisation on @clk, allowing the clock to be
+ * later enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possibly sleeping) cleanup on clk. This function may sleep.
+ */
+void clk_unprepare(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = clk->prepare_count = 0;
+	spin_lock_init(&clk->enable_lock);
+	mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+static inline int clk_prepare(struct clk *clk) { return 0; }
+static inline void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -67,6 +218,7 @@ void clk_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.
+ *		  Returns zero if the clock rate is unknown.
  * @clk: clock source
  */
 unsigned long clk_get_rate(struct clk *clk);
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-02-22 20:17     ` Uwe Kleine-König
  (?)
@ 2011-02-23  2:49       ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-02-23  2:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe,

> > +static inline void clk_common_init(struct clk *clk) { }
> > +
> > +/*
> > + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> > + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> > + * functions are no-ops
> > + */
> > +int clk_prepare(struct clk *clk) { return 0; }
> > +void clk_unprepare(struct clk *clk) { }
> 
> these should be static inline.  Otherwise these functions end up in many
> files and so provoke a build failure.

Ugh, brown paper bag time. Thanks for that, I'll update this patch.

Cheers,


Jeremy

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

* Re: [PATCH 1/2] Add a common struct clk
@ 2011-02-23  2:49       ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-02-23  2:49 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-kernel, linux-arm-kernel, Nicolas Pitre, Lorenzo Pieralisi,
	Vincent Guittot, linux-sh, Ben Herrenchmidt, Sascha Hauer,
	Paul Mundt, Dima Zavin, Saravana Kannan, Ben Dooks, Russell King

Hi Uwe,

> > +static inline void clk_common_init(struct clk *clk) { }
> > +
> > +/*
> > + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> > + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> > + * functions are no-ops
> > + */
> > +int clk_prepare(struct clk *clk) { return 0; }
> > +void clk_unprepare(struct clk *clk) { }
> 
> these should be static inline.  Otherwise these functions end up in many
> files and so provoke a build failure.

Ugh, brown paper bag time. Thanks for that, I'll update this patch.

Cheers,


Jeremy

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

* [PATCH 1/2] Add a common struct clk
@ 2011-02-23  2:49       ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-02-23  2:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe,

> > +static inline void clk_common_init(struct clk *clk) { }
> > +
> > +/*
> > + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> > + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> > + * functions are no-ops
> > + */
> > +int clk_prepare(struct clk *clk) { return 0; }
> > +void clk_unprepare(struct clk *clk) { }
> 
> these should be static inline.  Otherwise these functions end up in many
> files and so provoke a build failure.

Ugh, brown paper bag time. Thanks for that, I'll update this patch.

Cheers,


Jeremy

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

* Re: [PATCH 1/2] Add a common struct clk
  2011-02-21  2:50   ` Jeremy Kerr
  (?)
@ 2011-02-22 20:17     ` Uwe Kleine-König
  -1 siblings, 0 replies; 86+ messages in thread
From:  @ 2011-02-22 20:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jeremy,

On Mon, Feb 21, 2011 at 10:50:58AM +0800, Jeremy Kerr wrote:
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..604be74 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -11,18 +12,168 @@
> ...
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> ...
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>  
>  /*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
>   */
>  struct clk;
>  
> +static inline void clk_common_init(struct clk *clk) { }
> +
> +/*
> + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> + * functions are no-ops
> + */
> +int clk_prepare(struct clk *clk) { return 0; }
> +void clk_unprepare(struct clk *clk) { }
these should be static inline.  Otherwise these functions end up in many
files and so provoke a build failure.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 1/2] Add a common struct clk
@ 2011-02-22 20:17     ` Uwe Kleine-König
  0 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2011-02-22 20:17 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: linux-kernel, linux-arm-kernel, Nicolas Pitre, Lorenzo Pieralisi,
	Vincent Guittot, linux-sh, Ben Herrenchmidt, Sascha Hauer,
	Paul Mundt, Dima Zavin, Saravana Kannan, Ben Dooks, Russell King

Hi Jeremy,

On Mon, Feb 21, 2011 at 10:50:58AM +0800, Jeremy Kerr wrote:
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..604be74 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -11,18 +12,168 @@
> ...
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> ...
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>  
>  /*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
>   */
>  struct clk;
>  
> +static inline void clk_common_init(struct clk *clk) { }
> +
> +/*
> + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> + * functions are no-ops
> + */
> +int clk_prepare(struct clk *clk) { return 0; }
> +void clk_unprepare(struct clk *clk) { }
these should be static inline.  Otherwise these functions end up in many
files and so provoke a build failure.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/2] Add a common struct clk
@ 2011-02-22 20:17     ` Uwe Kleine-König
  0 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2011-02-22 20:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jeremy,

On Mon, Feb 21, 2011 at 10:50:58AM +0800, Jeremy Kerr wrote:
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..604be74 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -11,18 +12,168 @@
> ...
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> ...
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>  
>  /*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
>   */
>  struct clk;
>  
> +static inline void clk_common_init(struct clk *clk) { }
> +
> +/*
> + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> + * functions are no-ops
> + */
> +int clk_prepare(struct clk *clk) { return 0; }
> +void clk_unprepare(struct clk *clk) { }
these should be static inline.  Otherwise these functions end up in many
files and so provoke a build failure.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/2] Add a common struct clk
  2011-02-21  2:50 [PATCH 0/2] Common struct clk implementation, v13 Jeremy Kerr
  2011-02-21  2:50   ` Jeremy Kerr
@ 2011-02-21  2:50   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-02-21  2:50 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	unsigned int		prepare_count;
	spinlock_t		enable_lock;
	struct mutex		prepare_lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 drivers/clk/Kconfig  |    3 
 drivers/clk/Makefile |    1 
 drivers/clk/clk.c    |  132 ++++++++++++++++++++++++++++++++++
 drivers/clk/clkdev.c |    7 +
 include/linux/clk.h  |  164 ++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 298 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
 config CLKDEV_LOOKUP
 	bool
 	select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+	bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
 
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..0bc9c6f
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count = 0 && clk->ops->prepare)
+		ret = clk->ops->prepare(clk);
+
+	if (!ret)
+		clk->prepare_count++;
+	mutex_unlock(&clk->prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+	mutex_lock(&clk->prepare_lock);
+
+	WARN_ON(clk->prepare_count = 0);
+
+	if (--clk->prepare_count = 0 && clk->ops->unprepare) {
+		WARN_ON(clk->enable_count != 0);
+		clk->ops->unprepare(clk);
+	}
+
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	WARN_ON(clk->prepare_count = 0);
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+	if (clk->enable_count = 0 && clk->ops->enable)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+
+	WARN_ON(clk->enable_count = 0);
+
+	if (!--clk->enable_count = 0 && clk->ops->disable)
+		clk->ops->disable(clk);
+
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	might_sleep();
+
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+
+void __clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0fc0a79..a7999d2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -23,6 +23,13 @@
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
 
+/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported
+ * through other headers; we don't want them used anywhere but here. */
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+extern int __clk_get(struct clk *clk);
+extern void __clk_put(struct clk *clk);
+#endif
+
 /*
  * Find the correct struct clk for the device and connection ID.
  * We do slightly fuzzy matching here:
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..604be74 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,168 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @enable_lock:	lock for atomic enable
+ * @prepare_count:	count of clk_prepare() calls active on this clock
+ * @prepare_lock:	lock for sleepable prepare
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_lock and @prepare_lock members are used to serialise accesses
+ * to the ops->enable and ops->prepare functions (and the corresponding
+ * ops->disable and ops->unprepare functions).
  */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	unsigned int		prepare_count;
+	spinlock_t		enable_lock;
+	struct mutex		prepare_lock;
+};
 
+/* static initialiser for clocks. */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_lock	= __SPIN_LOCK_UNLOCKED(name.enable_lock),	\
+	.prepare_lock	= __MUTEX_INITIALIZER(name.prepare_lock),	\
+}
+
+/**
+ * struct clk_ops -  Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare:	Prepare the clock for enabling. This must not return until
+ *		the clock is fully prepared, and it's safe to call clk_enable.
+ *		This callback is intended to allow clock implementations to
+ *		do any initialisation that may sleep. Called with
+ *		clk->prepare_lock held.
+ *
+ * @unprepare:	Release the clock from its prepared state. This will typically
+ *		undo any work done in the @prepare callback. Called with
+ *		clk->prepare_lock held.
+ *
+ * @enable:	Enable the clock atomically. This must not return until the
+ *		clock is generating a valid clock signal, usable by consumer
+ *		devices. Called with clk->enable_lock held. This function
+ *		must not sleep.
+ *
+ * @disable:	Disable the clock atomically. Called with clk->enable_lock held.
+ *		This function must not sleep.
+ *
+ * @get:	Called by the core clock code when a device driver acquires a
+ *		clock via clk_get(). Optional.
+ *
+ * @put:	Called by the core clock code when a devices driver releases a
+ *		clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts.  If a clock requires sleeping code to be turned on, this
+ * should be done in clk_prepare. Switching that will not sleep should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare *must* have been
+ * called before clk_enable.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see drivers/clk/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+	int		(*prepare)(struct clk *);
+	void		(*unprepare)(struct clk *);
+	int		(*enable)(struct clk *);
+	void		(*disable)(struct clk *);
+	int		(*get)(struct clk *);
+	void		(*put)(struct clk *);
+	unsigned long	(*get_rate)(struct clk *);
+	long		(*round_rate)(struct clk *, unsigned long);
+	int		(*set_rate)(struct clk *, unsigned long);
+	int		(*set_parent)(struct clk *, struct clk *);
+	struct clk *	(*get_parent)(struct clk *);
+};
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any possibly sleeping initialisation on @clk, allowing the clock to be
+ * later enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possibly sleeping) cleanup on clk. This function may sleep.
+ */
+void clk_unprepare(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = clk->prepare_count = 0;
+	spin_lock_init(&clk->enable_lock);
+	mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+int clk_prepare(struct clk *clk) { return 0; }
+void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -67,6 +218,7 @@ void clk_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.
+ *		  Returns zero if the clock rate is unknown.
  * @clk: clock source
  */
 unsigned long clk_get_rate(struct clk *clk);
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source

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

* [PATCH 1/2] Add a common struct clk
@ 2011-02-21  2:50   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-02-21  2:50 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: Nicolas Pitre, Dima Zavin, Lorenzo Pieralisi, Vincent Guittot,
	linux-sh, Ben Herrenchmidt, Uwe Kleine-König, Sascha Hauer,
	Paul Mundt, Saravana Kannan, Ben Dooks, Jeremy Kerr,
	Russell King

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	unsigned int		prepare_count;
	spinlock_t		enable_lock;
	struct mutex		prepare_lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 drivers/clk/Kconfig  |    3 
 drivers/clk/Makefile |    1 
 drivers/clk/clk.c    |  132 ++++++++++++++++++++++++++++++++++
 drivers/clk/clkdev.c |    7 +
 include/linux/clk.h  |  164 ++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 298 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
 config CLKDEV_LOOKUP
 	bool
 	select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+	bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
 
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..0bc9c6f
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count == 0 && clk->ops->prepare)
+		ret = clk->ops->prepare(clk);
+
+	if (!ret)
+		clk->prepare_count++;
+	mutex_unlock(&clk->prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+	mutex_lock(&clk->prepare_lock);
+
+	WARN_ON(clk->prepare_count == 0);
+
+	if (--clk->prepare_count == 0 && clk->ops->unprepare) {
+		WARN_ON(clk->enable_count != 0);
+		clk->ops->unprepare(clk);
+	}
+
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	WARN_ON(clk->prepare_count == 0);
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+	if (clk->enable_count == 0 && clk->ops->enable)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+
+	WARN_ON(clk->enable_count == 0);
+
+	if (!--clk->enable_count == 0 && clk->ops->disable)
+		clk->ops->disable(clk);
+
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	might_sleep();
+
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+
+void __clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0fc0a79..a7999d2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -23,6 +23,13 @@
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
 
+/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported
+ * through other headers; we don't want them used anywhere but here. */
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+extern int __clk_get(struct clk *clk);
+extern void __clk_put(struct clk *clk);
+#endif
+
 /*
  * Find the correct struct clk for the device and connection ID.
  * We do slightly fuzzy matching here:
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..604be74 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,168 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @enable_lock:	lock for atomic enable
+ * @prepare_count:	count of clk_prepare() calls active on this clock
+ * @prepare_lock:	lock for sleepable prepare
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_lock and @prepare_lock members are used to serialise accesses
+ * to the ops->enable and ops->prepare functions (and the corresponding
+ * ops->disable and ops->unprepare functions).
  */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	unsigned int		prepare_count;
+	spinlock_t		enable_lock;
+	struct mutex		prepare_lock;
+};
 
+/* static initialiser for clocks. */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_lock	= __SPIN_LOCK_UNLOCKED(name.enable_lock),	\
+	.prepare_lock	= __MUTEX_INITIALIZER(name.prepare_lock),	\
+}
+
+/**
+ * struct clk_ops -  Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare:	Prepare the clock for enabling. This must not return until
+ *		the clock is fully prepared, and it's safe to call clk_enable.
+ *		This callback is intended to allow clock implementations to
+ *		do any initialisation that may sleep. Called with
+ *		clk->prepare_lock held.
+ *
+ * @unprepare:	Release the clock from its prepared state. This will typically
+ *		undo any work done in the @prepare callback. Called with
+ *		clk->prepare_lock held.
+ *
+ * @enable:	Enable the clock atomically. This must not return until the
+ *		clock is generating a valid clock signal, usable by consumer
+ *		devices. Called with clk->enable_lock held. This function
+ *		must not sleep.
+ *
+ * @disable:	Disable the clock atomically. Called with clk->enable_lock held.
+ *		This function must not sleep.
+ *
+ * @get:	Called by the core clock code when a device driver acquires a
+ *		clock via clk_get(). Optional.
+ *
+ * @put:	Called by the core clock code when a devices driver releases a
+ *		clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts.  If a clock requires sleeping code to be turned on, this
+ * should be done in clk_prepare. Switching that will not sleep should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare *must* have been
+ * called before clk_enable.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see drivers/clk/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+	int		(*prepare)(struct clk *);
+	void		(*unprepare)(struct clk *);
+	int		(*enable)(struct clk *);
+	void		(*disable)(struct clk *);
+	int		(*get)(struct clk *);
+	void		(*put)(struct clk *);
+	unsigned long	(*get_rate)(struct clk *);
+	long		(*round_rate)(struct clk *, unsigned long);
+	int		(*set_rate)(struct clk *, unsigned long);
+	int		(*set_parent)(struct clk *, struct clk *);
+	struct clk *	(*get_parent)(struct clk *);
+};
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any possibly sleeping initialisation on @clk, allowing the clock to be
+ * later enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possibly sleeping) cleanup on clk. This function may sleep.
+ */
+void clk_unprepare(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = clk->prepare_count = 0;
+	spin_lock_init(&clk->enable_lock);
+	mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+int clk_prepare(struct clk *clk) { return 0; }
+void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -67,6 +218,7 @@ void clk_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.
+ *		  Returns zero if the clock rate is unknown.
  * @clk: clock source
  */
 unsigned long clk_get_rate(struct clk *clk);
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source

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

* [PATCH 1/2] Add a common struct clk
@ 2011-02-21  2:50   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-02-21  2:50 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	unsigned int		prepare_count;
	spinlock_t		enable_lock;
	struct mutex		prepare_lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 drivers/clk/Kconfig  |    3 
 drivers/clk/Makefile |    1 
 drivers/clk/clk.c    |  132 ++++++++++++++++++++++++++++++++++
 drivers/clk/clkdev.c |    7 +
 include/linux/clk.h  |  164 ++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 298 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
 config CLKDEV_LOOKUP
 	bool
 	select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+	bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
 
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..0bc9c6f
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count == 0 && clk->ops->prepare)
+		ret = clk->ops->prepare(clk);
+
+	if (!ret)
+		clk->prepare_count++;
+	mutex_unlock(&clk->prepare_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+	mutex_lock(&clk->prepare_lock);
+
+	WARN_ON(clk->prepare_count == 0);
+
+	if (--clk->prepare_count == 0 && clk->ops->unprepare) {
+		WARN_ON(clk->enable_count != 0);
+		clk->ops->unprepare(clk);
+	}
+
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	WARN_ON(clk->prepare_count == 0);
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+	if (clk->enable_count == 0 && clk->ops->enable)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clk->enable_lock, flags);
+
+	WARN_ON(clk->enable_count == 0);
+
+	if (!--clk->enable_count == 0 && clk->ops->disable)
+		clk->ops->disable(clk);
+
+	spin_unlock_irqrestore(&clk->enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	might_sleep();
+
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+
+void __clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0fc0a79..a7999d2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -23,6 +23,13 @@
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
 
+/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported
+ * through other headers; we don't want them used anywhere but here. */
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+extern int __clk_get(struct clk *clk);
+extern void __clk_put(struct clk *clk);
+#endif
+
 /*
  * Find the correct struct clk for the device and connection ID.
  * We do slightly fuzzy matching here:
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..604be74 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,168 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @enable_lock:	lock for atomic enable
+ * @prepare_count:	count of clk_prepare() calls active on this clock
+ * @prepare_lock:	lock for sleepable prepare
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_lock and @prepare_lock members are used to serialise accesses
+ * to the ops->enable and ops->prepare functions (and the corresponding
+ * ops->disable and ops->unprepare functions).
  */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	unsigned int		prepare_count;
+	spinlock_t		enable_lock;
+	struct mutex		prepare_lock;
+};
 
+/* static initialiser for clocks. */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_lock	= __SPIN_LOCK_UNLOCKED(name.enable_lock),	\
+	.prepare_lock	= __MUTEX_INITIALIZER(name.prepare_lock),	\
+}
+
+/**
+ * struct clk_ops -  Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare:	Prepare the clock for enabling. This must not return until
+ *		the clock is fully prepared, and it's safe to call clk_enable.
+ *		This callback is intended to allow clock implementations to
+ *		do any initialisation that may sleep. Called with
+ *		clk->prepare_lock held.
+ *
+ * @unprepare:	Release the clock from its prepared state. This will typically
+ *		undo any work done in the @prepare callback. Called with
+ *		clk->prepare_lock held.
+ *
+ * @enable:	Enable the clock atomically. This must not return until the
+ *		clock is generating a valid clock signal, usable by consumer
+ *		devices. Called with clk->enable_lock held. This function
+ *		must not sleep.
+ *
+ * @disable:	Disable the clock atomically. Called with clk->enable_lock held.
+ *		This function must not sleep.
+ *
+ * @get:	Called by the core clock code when a device driver acquires a
+ *		clock via clk_get(). Optional.
+ *
+ * @put:	Called by the core clock code when a devices driver releases a
+ *		clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts.  If a clock requires sleeping code to be turned on, this
+ * should be done in clk_prepare. Switching that will not sleep should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare *must* have been
+ * called before clk_enable.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see drivers/clk/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+	int		(*prepare)(struct clk *);
+	void		(*unprepare)(struct clk *);
+	int		(*enable)(struct clk *);
+	void		(*disable)(struct clk *);
+	int		(*get)(struct clk *);
+	void		(*put)(struct clk *);
+	unsigned long	(*get_rate)(struct clk *);
+	long		(*round_rate)(struct clk *, unsigned long);
+	int		(*set_rate)(struct clk *, unsigned long);
+	int		(*set_parent)(struct clk *, struct clk *);
+	struct clk *	(*get_parent)(struct clk *);
+};
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any possibly sleeping initialisation on @clk, allowing the clock to be
+ * later enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possibly sleeping) cleanup on clk. This function may sleep.
+ */
+void clk_unprepare(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = clk->prepare_count = 0;
+	spin_lock_init(&clk->enable_lock);
+	mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+int clk_prepare(struct clk *clk) { return 0; }
+void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -67,6 +218,7 @@ void clk_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.
+ *		  Returns zero if the clock rate is unknown.
  * @clk: clock source
  */
 unsigned long clk_get_rate(struct clk *clk);
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source

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

* [PATCH 1/2] Add a common struct clk
  2011-01-05  3:18 [PATCH 0/2] Common struct clk implementation, v10 Jeremy Kerr
@ 2011-01-05  3:18 ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2011-01-05  3:18 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	int			flags;
	union {
		struct mutex	mutex;
		spinlock_t	spinlock;
	} lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
Acked-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>

---
 arch/Kconfig        |    3 
 include/linux/clk.h |  164 +++++++++++++++++++++++++++++++++++++++++---
 kernel/Makefile     |    1 
 kernel/clk.c        |  102 +++++++++++++++++++++++++++
 4 files changed, 261 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8bf0fa6..212bd3c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -165,6 +165,9 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 config HAVE_PERF_EVENTS_NMI
 	bool
 	help
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..95c49b1 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,169 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+#define CLK_ATOMIC	0x1
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @flags:		platform-independent flags
+ * @lock:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @lock member provides either a spinlock or a mutex to protect (at least)
+ * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
+ * set, then the core clock code will use a spinlock, otherwise a mutex. This
+ * lock will be acquired during clk_enable and clk_disable, so for atomic
+ * clocks, these ops callbacks must not sleep.
+ *
+ * The choice of atomic or non-atomic clock depends on how the clock is enabled.
+ * Typically, you'll want to use a non-atomic clock. For clocks that need to be
+ * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
+ * clocks with parents will typically cascade enable/disable operations to
+ * their parent, so the parent of an atomic clock *must* be atomic too.
+ */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	int			flags;
+	union {
+		struct mutex	mutex;
+		spinlock_t	spinlock;
+	} lock;
+};
+
+/* static initialiser for non-atomic clocks */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= 0,						\
+	.lock.mutex	= __MUTEX_INITIALIZER(name.lock.mutex),		\
+}
+
+/* static initialiser for atomic clocks */
+#define INIT_CLK_ATOMIC(name, o) {					\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= CLK_ATOMIC,					\
+	.lock.spinlock	= __SPIN_LOCK_UNLOCKED(name.lock.spinlock),	\
+}
+
+/**
+ * struct clk_ops -  Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @enable:	Enable the clock. This must not return until the clock is
+ *		generating a valid clock signal, usable by consumer devices.
+ *		Called with clk->lock held.
+ *
+ * @disable:	Disable the clock. Called with clk->lock held.
+ *
+ * @get:	Called by the core clock code when a device driver acquires a
+ *		clock via clk_get(). Optional.
+ *
+ * @put:	Called by the core clock code when a devices driver releases a
+ *		clock via clk_put(). Optional.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see kernel/clk.c for implementation details. All are optional.
  */
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
 
+static inline void __clk_lock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock(&clk->lock.spinlock);
+	else
+		mutex_lock(&clk->lock.mutex);
+}
+
+static inline void __clk_unlock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_unlock(&clk->lock.spinlock);
+	else
+		mutex_unlock(&clk->lock.mutex);
+}
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = 0;
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock_init(&clk->lock.spinlock);
+	else
+		mutex_init(&clk->lock.mutex);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 0b5ff08..01383a0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..8de8fe3
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	__clk_lock(clk);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	__clk_unlock(clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	__clk_lock(clk);
+
+	WARN_ON(!clk->enable_count);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	__clk_unlock(clk);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* [PATCH 1/2] Add a common struct clk
  2010-12-10  1:58     ` Jeremy Kerr
  (?)
@ 2010-12-10  9:21     ` Uwe Kleine-König
  -1 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2010-12-10  9:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Dec 10, 2010 at 09:58:31AM +0800, Jeremy Kerr wrote:
> Hi Uwe
> 
> > > +/**
> > > + * clk_ops: Callback operations for clocks; these are to be provided by
> > > the + * clock implementation, and will be called by drivers through the
> > > clk_* API. + *
> > > + * @enable:	Enable the clock. This must not return until the clock is
> > > + *		generating a valid clock signal, usable by consumer devices.
> > > + *		Called with clk->lock held.
> > > + *
> > > + * @disable:	Disable the clock. Called with clk->lock held.
> > > + *
> > > + * @get	/ @put:	Called by the core clock code to notify the driver 
> about
> > 
> > I wonder if this is valid kerneldoc.  The tab before / looks (IMHO)
> > ugly.
> 
> Not valid kernel doc, so I'll fix that up. The tab was unintentional.
> 
> > Maybe specify "driver" a bit more to distinguish from "drivers"
> > above.  "clk_ops driver"?
> 
> This is actually for refcounting for uses by device drivers (ie, not the clock 
> provider), I've updated the comment:
> 
> /**
>  * struct clk_ops -  Callback operations for clocks; these are to be provided
>  * by the clock implementation, and will be called by drivers through the
>  * clk_* API.
>  *
>  * @enable:	Enable the clock. This must not return until the clock is
>  *		generating a valid clock signal, usable by consumer devices.
>  *		Called with clk->lock held.
>  *
>  * @disable:	Disable the clock. Called with clk->lock held.
>  *
>  * @get:	     Called by the core clock code to increment the clock's
>  *		     refount as clk is passed to device drivers. Optional.
s/refount/refcount/ (once more below)
>  *
>  * @put:	     Called by the core clock code to decrement the clocks's
>  *		     refounts as clk is released from device drivers. Optional.
again inconsistent tabbing.

IMHO the wording above is better.  This makes me unsure if the callback
has to fiddle with the refcount.

>  *
>  * For other callbacks, see the corresponding clk_* functions. Parameters and
>  * return values are passed directly from/to these API functions, or
>  * -ENOSYS is returned if the callback is NULL, see kernel/clk.c for
This is not true for clk_get_rate.  This returns 0 if the callback isn't
set.

>  * implementation details. All are optional.
>  */
> 
> > > +/**
> > > + * __clk_get - update clock-specific refcounter
> > > + *
> > > + * @clk: The clock to refcount
> > 
> > "The clock to update the refcount for"?
> 
> I'm using refcount as a verb here; if this isn't clear I can come up with 
> something else. Your solution splits the 'clock' and the 'for' which may be 
> difficult to parse too. Let me know if you have any other suggestions :)
hmm, don't know.  Keeping it as is is OK for me, too, if you don't
consider my suggestion to be better.
 
> > I wonder if it's worth to handle parents here, e.g.
> > 
> > 	if (!clk->enable_count) {
> > 		struct clk *parent = clk_get_parent(clk);
> > 		if (parent) {
> > 			ret = clk_enable(parent);
> > 			if (ret)
> > 				return ret;
> > 		}
> > 
> > 		ret = clk->ops->enable(clk);
> > 		if (likely(!ret))
> > 			clk->enable_count++;
> > 		else if (parent)
> > 			clk_disable(parent);
> > 	}
> > 
> > as they are quite common.
> 
> I'm not convinced we should do the parent handling in the core clock code. 
> It's fairly easy to do the parent enable/disable in platform code, which 
> should have explicit knowledge about whether or not the clock has a parent, 
> and the semantics of how the parent/child clocks interact.
> 
> However, happy to discuss this further if needs be.
As already said in #armlinux, in the meantime I agree.

> > > +void clk_disable(struct clk *clk)
> > > +{
> > > +	if (!clk->ops->disable)
> > > +		return;
> > 
> > 	WARN_ON(!clk->enable_count) ?
> 
> Yep, good idea. I'll do this check with the lock acquired.
fine.

> Thanks for the comments, I've updated my tree accordingly (along with some 
> other kerneldoc fixups). I'll wait to see if there is any other feedback and 
> re-post next week.
fine, too.

Thanks for your efforts
Uwe

PS: I don't know who looks at your git tree, but you might want to
update the arch branches to base on your current work.

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 1/2] Add a common struct clk
  2010-12-08 10:21   ` Uwe Kleine-König
@ 2010-12-10  1:58     ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-12-10  1:58 UTC (permalink / raw)
  To: Uwe Kleine-König; +Cc: linux-arm-kernel, linux-kernel

Hi Uwe

> > +/**
> > + * clk_ops: Callback operations for clocks; these are to be provided by
> > the + * clock implementation, and will be called by drivers through the
> > clk_* API. + *
> > + * @enable:	Enable the clock. This must not return until the clock is
> > + *		generating a valid clock signal, usable by consumer devices.
> > + *		Called with clk->lock held.
> > + *
> > + * @disable:	Disable the clock. Called with clk->lock held.
> > + *
> > + * @get	/ @put:	Called by the core clock code to notify the driver 
about
> 
> I wonder if this is valid kerneldoc.  The tab before / looks (IMHO)
> ugly.

Not valid kernel doc, so I'll fix that up. The tab was unintentional.

> Maybe specify "driver" a bit more to distinguish from "drivers"
> above.  "clk_ops driver"?

This is actually for refcounting for uses by device drivers (ie, not the clock 
provider), I've updated the comment:

/**
 * struct clk_ops -  Callback operations for clocks; these are to be provided
 * by the clock implementation, and will be called by drivers through the
 * clk_* API.
 *
 * @enable:	Enable the clock. This must not return until the clock is
 *		generating a valid clock signal, usable by consumer devices.
 *		Called with clk->lock held.
 *
 * @disable:	Disable the clock. Called with clk->lock held.
 *
 * @get:	     Called by the core clock code to increment the clock's
 *		     refount as clk is passed to device drivers. Optional.
 *
 * @put:	     Called by the core clock code to decrement the clocks's
 *		     refounts as clk is released from device drivers. Optional.
 *
 * For other callbacks, see the corresponding clk_* functions. Parameters and
 * return values are passed directly from/to these API functions, or
 * -ENOSYS is returned if the callback is NULL, see kernel/clk.c for
 * implementation details. All are optional.
 */

> > +/**
> > + * __clk_get - update clock-specific refcounter
> > + *
> > + * @clk: The clock to refcount
> 
> "The clock to update the refcount for"?

I'm using refcount as a verb here; if this isn't clear I can come up with 
something else. Your solution splits the 'clock' and the 'for' which may be 
difficult to parse too. Let me know if you have any other suggestions :)

> I wonder if it's worth to handle parents here, e.g.
> 
> 	if (!clk->enable_count) {
> 		struct clk *parent = clk_get_parent(clk);
> 		if (parent) {
> 			ret = clk_enable(parent);
> 			if (ret)
> 				return ret;
> 		}
> 
> 		ret = clk->ops->enable(clk);
> 		if (likely(!ret))
> 			clk->enable_count++;
> 		else if (parent)
> 			clk_disable(parent);
> 	}
> 
> as they are quite common.

I'm not convinced we should do the parent handling in the core clock code. 
It's fairly easy to do the parent enable/disable in platform code, which 
should have explicit knowledge about whether or not the clock has a parent, 
and the semantics of how the parent/child clocks interact.

However, happy to discuss this further if needs be.

> > +void clk_disable(struct clk *clk)
> > +{
> > +	if (!clk->ops->disable)
> > +		return;
> 
> 	WARN_ON(!clk->enable_count) ?

Yep, good idea. I'll do this check with the lock acquired.

Thanks for the comments, I've updated my tree accordingly (along with some 
other kerneldoc fixups). I'll wait to see if there is any other feedback and 
re-post next week.

Cheers,


Jeremy

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

* [PATCH 1/2] Add a common struct clk
@ 2010-12-10  1:58     ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-12-10  1:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe

> > +/**
> > + * clk_ops: Callback operations for clocks; these are to be provided by
> > the + * clock implementation, and will be called by drivers through the
> > clk_* API. + *
> > + * @enable:	Enable the clock. This must not return until the clock is
> > + *		generating a valid clock signal, usable by consumer devices.
> > + *		Called with clk->lock held.
> > + *
> > + * @disable:	Disable the clock. Called with clk->lock held.
> > + *
> > + * @get	/ @put:	Called by the core clock code to notify the driver 
about
> 
> I wonder if this is valid kerneldoc.  The tab before / looks (IMHO)
> ugly.

Not valid kernel doc, so I'll fix that up. The tab was unintentional.

> Maybe specify "driver" a bit more to distinguish from "drivers"
> above.  "clk_ops driver"?

This is actually for refcounting for uses by device drivers (ie, not the clock 
provider), I've updated the comment:

/**
 * struct clk_ops -  Callback operations for clocks; these are to be provided
 * by the clock implementation, and will be called by drivers through the
 * clk_* API.
 *
 * @enable:	Enable the clock. This must not return until the clock is
 *		generating a valid clock signal, usable by consumer devices.
 *		Called with clk->lock held.
 *
 * @disable:	Disable the clock. Called with clk->lock held.
 *
 * @get:	     Called by the core clock code to increment the clock's
 *		     refount as clk is passed to device drivers. Optional.
 *
 * @put:	     Called by the core clock code to decrement the clocks's
 *		     refounts as clk is released from device drivers. Optional.
 *
 * For other callbacks, see the corresponding clk_* functions. Parameters and
 * return values are passed directly from/to these API functions, or
 * -ENOSYS is returned if the callback is NULL, see kernel/clk.c for
 * implementation details. All are optional.
 */

> > +/**
> > + * __clk_get - update clock-specific refcounter
> > + *
> > + * @clk: The clock to refcount
> 
> "The clock to update the refcount for"?

I'm using refcount as a verb here; if this isn't clear I can come up with 
something else. Your solution splits the 'clock' and the 'for' which may be 
difficult to parse too. Let me know if you have any other suggestions :)

> I wonder if it's worth to handle parents here, e.g.
> 
> 	if (!clk->enable_count) {
> 		struct clk *parent = clk_get_parent(clk);
> 		if (parent) {
> 			ret = clk_enable(parent);
> 			if (ret)
> 				return ret;
> 		}
> 
> 		ret = clk->ops->enable(clk);
> 		if (likely(!ret))
> 			clk->enable_count++;
> 		else if (parent)
> 			clk_disable(parent);
> 	}
> 
> as they are quite common.

I'm not convinced we should do the parent handling in the core clock code. 
It's fairly easy to do the parent enable/disable in platform code, which 
should have explicit knowledge about whether or not the clock has a parent, 
and the semantics of how the parent/child clocks interact.

However, happy to discuss this further if needs be.

> > +void clk_disable(struct clk *clk)
> > +{
> > +	if (!clk->ops->disable)
> > +		return;
> 
> 	WARN_ON(!clk->enable_count) ?

Yep, good idea. I'll do this check with the lock acquired.

Thanks for the comments, I've updated my tree accordingly (along with some 
other kerneldoc fixups). I'll wait to see if there is any other feedback and 
re-post next week.

Cheers,


Jeremy

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

* Re: [PATCH 1/2] Add a common struct clk
  2010-12-08  2:05 ` Jeremy Kerr
@ 2010-12-08 10:21   ` Uwe Kleine-König
  -1 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2010-12-08 10:21 UTC (permalink / raw)
  To: Jeremy Kerr; +Cc: linux-arm-kernel, linux-kernel

Hi Jeremy,

On Wed, Dec 08, 2010 at 10:05:32AM +0800, Jeremy Kerr wrote:
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
> 
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
> 
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
> 
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
> 
> struct clk {
> 	const struct clk_ops	*ops;
> 	unsigned int		enable_count;
> 	int			flags;
> 	union {
> 		struct mutex	mutex;
> 		spinlock_t	spinlock;
> 	} lock;
> };
> 
> And a set of clock operations (defined per type of clock):
> 
> struct clk_ops {
> 	int             (*enable)(struct clk *);
> 	void            (*disable)(struct clk *);
> 	unsigned long   (*get_rate)(struct clk *);
> 	[...]
> };
> 
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
> 
> struct clk_foo {
> 	struct clk	clk;
> 	void __iomem	*some_register;
> };
> 
> struct clk_ops clk_foo_ops = {
> 	.get_rate = clk_foo_get_rate,
> };
> 
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <benh@kernel.crashing.org>.
> 
> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
> Acked-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>
> 
> ---
>  arch/Kconfig        |    3 
>  include/linux/clk.h |  158 +++++++++++++++++++++++++++++++++++++++++---
>  kernel/Makefile     |    1 
>  kernel/clk.c        |  100 +++++++++++++++++++++++++++
>  4 files changed, 253 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/Kconfig b/arch/Kconfig
> index 8bf0fa6..212bd3c 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -165,6 +165,9 @@ config HAVE_MIXED_BREAKPOINTS_REGS
>  config HAVE_USER_RETURN_NOTIFIER
>  	bool
>  
> +config USE_COMMON_STRUCT_CLK
> +	bool
> +
>  config HAVE_PERF_EVENTS_NMI
>  	bool
>  	help
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..e09e40e 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -3,6 +3,7 @@
>   *
>   *  Copyright (C) 2004 ARM Limited.
>   *  Written by Deep Blue Solutions Limited.
> + *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License version 2 as
> @@ -11,18 +12,163 @@
>  #ifndef __LINUX_CLK_H
>  #define __LINUX_CLK_H
>  
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/spinlock.h>
> +
>  struct device;
>  
> -/*
> - * The base API.
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> +
> +#define CLK_ATOMIC	0x1
> +
> +/* If we're using the common struct clk, we define the base clk object here */
> +
> +/**
> + * struct clk - hardware independent clock structure
> + * @clk_ops:		implementation-specific ops for this clock
> + * @enable_count:	count of clk_enable() calls active on this clock
> + * @flags:		platform-independent flags
> + * @lock:		lock for enable/disable or other HW-specific ops
> + *
> + * The base clock object, used by drivers for hardware-independent manipulation
> + * of clock lines. This will be 'subclassed' by device-specific implementations,
> + * which add device-specific data to struct clk. For example:
> + *
> + *  struct clk_foo {
> + *      struct clk;
> + *      [device specific fields]
> + *  };
> + *
> + * The clock driver code will manage the device-specific data, and pass
> + * clk_foo.clk to the common clock code. The clock driver will be called
> + * through the @ops callbacks.
> + *
> + * The @lock member provides either a spinlock or a mutex to protect (at least)
> + * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
> + * set, then the core clock code will use a spinlock, otherwise a mutex. This
> + * lock will be acquired during clk_enable and clk_disable, so for atomic
> + * clocks, these ops callbacks must not sleep.
> + *
> + * The choice of atomic or non-atomic clock depends on how the clock is enabled.
> + * Typically, you'll want to use a non-atomic clock. For clocks that need to be
> + * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
> + * clocks with parents will typically cascade enable/disable operations to
> + * their parent, so the parent of an atomic clock *must* be atomic too.
> + */
> +struct clk {
> +	const struct clk_ops	*ops;
> +	unsigned int		enable_count;
> +	int			flags;
> +	union {
> +		struct mutex	mutex;
> +		spinlock_t	spinlock;
> +	} lock;
> +};
> +
> +/* static initialiser for non-atomic clocks */
> +#define INIT_CLK(name, o) {						\
> +	.ops		= &o,						\
> +	.enable_count	= 0,						\
> +	.flags		= 0,						\
> +	.lock.mutex	= __MUTEX_INITIALIZER(name.lock.mutex),		\
> +}
> +
> +/* static initialiser for atomic clocks */
> +#define INIT_CLK_ATOMIC(name, o) {					\
> +	.ops		= &o,						\
> +	.enable_count	= 0,						\
> +	.flags		= CLK_ATOMIC,					\
> +	.lock.spinlock	= __SPIN_LOCK_UNLOCKED(name.lock.spinlock),	\
> +}
> +
> +/**
> + * clk_ops: Callback operations for clocks; these are to be provided by the
> + * clock implementation, and will be called by drivers through the clk_* API.
> + *
> + * @enable:	Enable the clock. This must not return until the clock is
> + *		generating a valid clock signal, usable by consumer devices.
> + *		Called with clk->lock held.
> + *
> + * @disable:	Disable the clock. Called with clk->lock held.
> + *
> + * @get	/ @put:	Called by the core clock code to notify the driver about
I wonder if this is valid kerneldoc.  The tab before / looks (IMHO)
ugly.  Maybe specify "driver" a bit more to distinguish from "drivers"
above.  "clk_ops driver"?

> + *		refounts as clk is passed to drivers. Optional.
> + *
> + * For other callbacks, see the corresponding clk_* functions. Parameters and
> + * return values are passed directly from/to these API functions directly, or
duplicated "directly"
> + * -ENOSYS is returned if the callback is NULL, see kernel/clk.c for
> + * implementation details. All are optional.
>   */
> +struct clk_ops {
> +       int		(*enable)(struct clk *);
> +       void		(*disable)(struct clk *);
> +       int		(*get)(struct clk *);
> +       void		(*put)(struct clk *);
> +       unsigned long	(*get_rate)(struct clk *);
> +       long		(*round_rate)(struct clk *, unsigned long);
> +       int		(*set_rate)(struct clk *, unsigned long);
> +       int		(*set_parent)(struct clk *, struct clk *);
> +       struct clk *	(*get_parent)(struct clk *);
> +};
>  
> +static inline void __clk_lock(struct clk *clk)
> +{
> +	if (clk->flags & CLK_ATOMIC)
> +		spin_lock(&clk->lock.spinlock);
> +	else
> +		mutex_lock(&clk->lock.mutex);
> +}
> +
> +static inline void __clk_unlock(struct clk *clk)
> +{
> +	if (clk->flags & CLK_ATOMIC)
> +		spin_unlock(&clk->lock.spinlock);
> +	else
> +		mutex_unlock(&clk->lock.mutex);
> +}
> +
> +/**
> + * __clk_get - update clock-specific refcounter
> + *
> + * @clk: The clock to refcount
"The clock to update the refcount for"?

> + *
> + * Before a clock is returned from clk_get, this function should be called
> + * to update any clock-specific refcounting.
> + *
> + * Returns non-zero on success, zero on failure.
> + *
> + * Drivers should not need this function; it is only needed by the
> + * arch-specific clk_get() implementations.
> + */
> +int __clk_get(struct clk *clk);
> +
> +/**
> + * clk_common_init - initialise a clock for driver usage
> + *
> + * Used for runtime intialization of clocks; you don't need to call this
> + * if your clock has been (statically) initialized with INIT_CLK.
> + */
> +static inline void clk_common_init(struct clk *clk)
> +{
> +	clk->enable_count = 0;
> +	if (clk->flags & CLK_ATOMIC)
> +		spin_lock_init(&clk->lock.spinlock);
> +	else
> +		mutex_init(&clk->lock.mutex);
> +}
> +
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>  
>  /*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
>   */
>  struct clk;
>  
> +static inline void clk_common_init(struct clk *clk) { }
> +
> +#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
> +
>  /**
>   * clk_get - lookup and obtain a reference to a clock producer.
>   * @dev: device for clock "consumer"
> @@ -83,12 +229,6 @@ unsigned long clk_get_rate(struct clk *clk);
>   */
>  void clk_put(struct clk *clk);
>  
> -
> -/*
> - * The remaining APIs are optional for machine class support.
> - */
> -
> -
>  /**
>   * clk_round_rate - adjust a rate to the exact rate a clock can provide
>   * @clk: clock source
> diff --git a/kernel/Makefile b/kernel/Makefile
> index 0b5ff08..01383a0 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
>  obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
>  obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
>  obj-$(CONFIG_PADATA) += padata.o
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
>  
>  ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
>  # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
> diff --git a/kernel/clk.c b/kernel/clk.c
> new file mode 100644
> index 0000000..1545e69
> --- /dev/null
> +++ b/kernel/clk.c
> @@ -0,0 +1,100 @@
> +/*
> + * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +
> +int clk_enable(struct clk *clk)
> +{
> +	int ret = 0;
> +
> +	if (!clk->ops->enable)
> +		return 0;
> +
> +	__clk_lock(clk);
> +	if (!clk->enable_count)
> +		ret = clk->ops->enable(clk);
I wonder if it's worth to handle parents here, e.g.

	if (!clk->enable_count) {
		struct clk *parent = clk_get_parent(clk);
		if (parent) {
			ret = clk_enable(parent);
			if (ret)
				return ret;
		}

		ret = clk->ops->enable(clk);
		if (likely(!ret))
			clk->enable_count++;
		else if (parent)
			clk_disable(parent);
	}

as they are quite common.

And I wonder further if it makes the code a bit more efficient to use:

	if (!clk->enable_count++) {
		... enable clock (and maybe parent)
		if (unlikely(ret))
			clk->enable_count--
		...


> +
> +	if (!ret)
> +		clk->enable_count++;
> +	__clk_unlock(clk);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_enable);
> +
> +void clk_disable(struct clk *clk)
> +{
> +	if (!clk->ops->disable)
> +		return;

	WARN_ON(!clk->enable_count) ?
> +
> +	__clk_lock(clk);
> +
> +	if (!--clk->enable_count)
> +		clk->ops->disable(clk);
> +
> +	__clk_unlock(clk);
> +}
> +EXPORT_SYMBOL_GPL(clk_disable);
> +
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> +	if (clk->ops->get_rate)
> +		return clk->ops->get_rate(clk);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_get_rate);
> +
> +int __clk_get(struct clk *clk)
> +{
> +	if (clk->ops->get)
> +		return clk->ops->get(clk);
> +	return 1;
> +}
> +EXPORT_SYMBOL_GPL(__clk_get);
> +
> +void clk_put(struct clk *clk)
> +{
> +	if (clk->ops->put)
> +		clk->ops->put(clk);
> +}
> +EXPORT_SYMBOL_GPL(clk_put);
> +
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> +	if (clk->ops->round_rate)
> +		return clk->ops->round_rate(clk, rate);
> +	return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_round_rate);
> +
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> +	if (clk->ops->set_rate)
> +		return clk->ops->set_rate(clk, rate);
> +	return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_rate);
> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> +	if (clk->ops->set_parent)
> +		return clk->ops->set_parent(clk, parent);
> +	return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);
> +
> +struct clk *clk_get_parent(struct clk *clk)
> +{
> +	if (clk->ops->get_parent)
> +		return clk->ops->get_parent(clk);
> +	return ERR_PTR(-ENOSYS);
> +}
> +EXPORT_SYMBOL_GPL(clk_get_parent);
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/2] Add a common struct clk
@ 2010-12-08 10:21   ` Uwe Kleine-König
  0 siblings, 0 replies; 86+ messages in thread
From: Uwe Kleine-König @ 2010-12-08 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jeremy,

On Wed, Dec 08, 2010 at 10:05:32AM +0800, Jeremy Kerr wrote:
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
> 
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
> 
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
> 
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
> 
> struct clk {
> 	const struct clk_ops	*ops;
> 	unsigned int		enable_count;
> 	int			flags;
> 	union {
> 		struct mutex	mutex;
> 		spinlock_t	spinlock;
> 	} lock;
> };
> 
> And a set of clock operations (defined per type of clock):
> 
> struct clk_ops {
> 	int             (*enable)(struct clk *);
> 	void            (*disable)(struct clk *);
> 	unsigned long   (*get_rate)(struct clk *);
> 	[...]
> };
> 
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
> 
> struct clk_foo {
> 	struct clk	clk;
> 	void __iomem	*some_register;
> };
> 
> struct clk_ops clk_foo_ops = {
> 	.get_rate = clk_foo_get_rate,
> };
> 
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <benh@kernel.crashing.org>.
> 
> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
> Acked-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>
> 
> ---
>  arch/Kconfig        |    3 
>  include/linux/clk.h |  158 +++++++++++++++++++++++++++++++++++++++++---
>  kernel/Makefile     |    1 
>  kernel/clk.c        |  100 +++++++++++++++++++++++++++
>  4 files changed, 253 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/Kconfig b/arch/Kconfig
> index 8bf0fa6..212bd3c 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -165,6 +165,9 @@ config HAVE_MIXED_BREAKPOINTS_REGS
>  config HAVE_USER_RETURN_NOTIFIER
>  	bool
>  
> +config USE_COMMON_STRUCT_CLK
> +	bool
> +
>  config HAVE_PERF_EVENTS_NMI
>  	bool
>  	help
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..e09e40e 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -3,6 +3,7 @@
>   *
>   *  Copyright (C) 2004 ARM Limited.
>   *  Written by Deep Blue Solutions Limited.
> + *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License version 2 as
> @@ -11,18 +12,163 @@
>  #ifndef __LINUX_CLK_H
>  #define __LINUX_CLK_H
>  
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/spinlock.h>
> +
>  struct device;
>  
> -/*
> - * The base API.
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> +
> +#define CLK_ATOMIC	0x1
> +
> +/* If we're using the common struct clk, we define the base clk object here */
> +
> +/**
> + * struct clk - hardware independent clock structure
> + * @clk_ops:		implementation-specific ops for this clock
> + * @enable_count:	count of clk_enable() calls active on this clock
> + * @flags:		platform-independent flags
> + * @lock:		lock for enable/disable or other HW-specific ops
> + *
> + * The base clock object, used by drivers for hardware-independent manipulation
> + * of clock lines. This will be 'subclassed' by device-specific implementations,
> + * which add device-specific data to struct clk. For example:
> + *
> + *  struct clk_foo {
> + *      struct clk;
> + *      [device specific fields]
> + *  };
> + *
> + * The clock driver code will manage the device-specific data, and pass
> + * clk_foo.clk to the common clock code. The clock driver will be called
> + * through the @ops callbacks.
> + *
> + * The @lock member provides either a spinlock or a mutex to protect (at least)
> + * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
> + * set, then the core clock code will use a spinlock, otherwise a mutex. This
> + * lock will be acquired during clk_enable and clk_disable, so for atomic
> + * clocks, these ops callbacks must not sleep.
> + *
> + * The choice of atomic or non-atomic clock depends on how the clock is enabled.
> + * Typically, you'll want to use a non-atomic clock. For clocks that need to be
> + * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
> + * clocks with parents will typically cascade enable/disable operations to
> + * their parent, so the parent of an atomic clock *must* be atomic too.
> + */
> +struct clk {
> +	const struct clk_ops	*ops;
> +	unsigned int		enable_count;
> +	int			flags;
> +	union {
> +		struct mutex	mutex;
> +		spinlock_t	spinlock;
> +	} lock;
> +};
> +
> +/* static initialiser for non-atomic clocks */
> +#define INIT_CLK(name, o) {						\
> +	.ops		= &o,						\
> +	.enable_count	= 0,						\
> +	.flags		= 0,						\
> +	.lock.mutex	= __MUTEX_INITIALIZER(name.lock.mutex),		\
> +}
> +
> +/* static initialiser for atomic clocks */
> +#define INIT_CLK_ATOMIC(name, o) {					\
> +	.ops		= &o,						\
> +	.enable_count	= 0,						\
> +	.flags		= CLK_ATOMIC,					\
> +	.lock.spinlock	= __SPIN_LOCK_UNLOCKED(name.lock.spinlock),	\
> +}
> +
> +/**
> + * clk_ops: Callback operations for clocks; these are to be provided by the
> + * clock implementation, and will be called by drivers through the clk_* API.
> + *
> + * @enable:	Enable the clock. This must not return until the clock is
> + *		generating a valid clock signal, usable by consumer devices.
> + *		Called with clk->lock held.
> + *
> + * @disable:	Disable the clock. Called with clk->lock held.
> + *
> + * @get	/ @put:	Called by the core clock code to notify the driver about
I wonder if this is valid kerneldoc.  The tab before / looks (IMHO)
ugly.  Maybe specify "driver" a bit more to distinguish from "drivers"
above.  "clk_ops driver"?

> + *		refounts as clk is passed to drivers. Optional.
> + *
> + * For other callbacks, see the corresponding clk_* functions. Parameters and
> + * return values are passed directly from/to these API functions directly, or
duplicated "directly"
> + * -ENOSYS is returned if the callback is NULL, see kernel/clk.c for
> + * implementation details. All are optional.
>   */
> +struct clk_ops {
> +       int		(*enable)(struct clk *);
> +       void		(*disable)(struct clk *);
> +       int		(*get)(struct clk *);
> +       void		(*put)(struct clk *);
> +       unsigned long	(*get_rate)(struct clk *);
> +       long		(*round_rate)(struct clk *, unsigned long);
> +       int		(*set_rate)(struct clk *, unsigned long);
> +       int		(*set_parent)(struct clk *, struct clk *);
> +       struct clk *	(*get_parent)(struct clk *);
> +};
>  
> +static inline void __clk_lock(struct clk *clk)
> +{
> +	if (clk->flags & CLK_ATOMIC)
> +		spin_lock(&clk->lock.spinlock);
> +	else
> +		mutex_lock(&clk->lock.mutex);
> +}
> +
> +static inline void __clk_unlock(struct clk *clk)
> +{
> +	if (clk->flags & CLK_ATOMIC)
> +		spin_unlock(&clk->lock.spinlock);
> +	else
> +		mutex_unlock(&clk->lock.mutex);
> +}
> +
> +/**
> + * __clk_get - update clock-specific refcounter
> + *
> + * @clk: The clock to refcount
"The clock to update the refcount for"?

> + *
> + * Before a clock is returned from clk_get, this function should be called
> + * to update any clock-specific refcounting.
> + *
> + * Returns non-zero on success, zero on failure.
> + *
> + * Drivers should not need this function; it is only needed by the
> + * arch-specific clk_get() implementations.
> + */
> +int __clk_get(struct clk *clk);
> +
> +/**
> + * clk_common_init - initialise a clock for driver usage
> + *
> + * Used for runtime intialization of clocks; you don't need to call this
> + * if your clock has been (statically) initialized with INIT_CLK.
> + */
> +static inline void clk_common_init(struct clk *clk)
> +{
> +	clk->enable_count = 0;
> +	if (clk->flags & CLK_ATOMIC)
> +		spin_lock_init(&clk->lock.spinlock);
> +	else
> +		mutex_init(&clk->lock.mutex);
> +}
> +
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>  
>  /*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
>   */
>  struct clk;
>  
> +static inline void clk_common_init(struct clk *clk) { }
> +
> +#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
> +
>  /**
>   * clk_get - lookup and obtain a reference to a clock producer.
>   * @dev: device for clock "consumer"
> @@ -83,12 +229,6 @@ unsigned long clk_get_rate(struct clk *clk);
>   */
>  void clk_put(struct clk *clk);
>  
> -
> -/*
> - * The remaining APIs are optional for machine class support.
> - */
> -
> -
>  /**
>   * clk_round_rate - adjust a rate to the exact rate a clock can provide
>   * @clk: clock source
> diff --git a/kernel/Makefile b/kernel/Makefile
> index 0b5ff08..01383a0 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
>  obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
>  obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
>  obj-$(CONFIG_PADATA) += padata.o
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
>  
>  ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
>  # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
> diff --git a/kernel/clk.c b/kernel/clk.c
> new file mode 100644
> index 0000000..1545e69
> --- /dev/null
> +++ b/kernel/clk.c
> @@ -0,0 +1,100 @@
> +/*
> + * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +
> +int clk_enable(struct clk *clk)
> +{
> +	int ret = 0;
> +
> +	if (!clk->ops->enable)
> +		return 0;
> +
> +	__clk_lock(clk);
> +	if (!clk->enable_count)
> +		ret = clk->ops->enable(clk);
I wonder if it's worth to handle parents here, e.g.

	if (!clk->enable_count) {
		struct clk *parent = clk_get_parent(clk);
		if (parent) {
			ret = clk_enable(parent);
			if (ret)
				return ret;
		}

		ret = clk->ops->enable(clk);
		if (likely(!ret))
			clk->enable_count++;
		else if (parent)
			clk_disable(parent);
	}

as they are quite common.

And I wonder further if it makes the code a bit more efficient to use:

	if (!clk->enable_count++) {
		... enable clock (and maybe parent)
		if (unlikely(ret))
			clk->enable_count--
		...


> +
> +	if (!ret)
> +		clk->enable_count++;
> +	__clk_unlock(clk);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_enable);
> +
> +void clk_disable(struct clk *clk)
> +{
> +	if (!clk->ops->disable)
> +		return;

	WARN_ON(!clk->enable_count) ?
> +
> +	__clk_lock(clk);
> +
> +	if (!--clk->enable_count)
> +		clk->ops->disable(clk);
> +
> +	__clk_unlock(clk);
> +}
> +EXPORT_SYMBOL_GPL(clk_disable);
> +
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> +	if (clk->ops->get_rate)
> +		return clk->ops->get_rate(clk);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_get_rate);
> +
> +int __clk_get(struct clk *clk)
> +{
> +	if (clk->ops->get)
> +		return clk->ops->get(clk);
> +	return 1;
> +}
> +EXPORT_SYMBOL_GPL(__clk_get);
> +
> +void clk_put(struct clk *clk)
> +{
> +	if (clk->ops->put)
> +		clk->ops->put(clk);
> +}
> +EXPORT_SYMBOL_GPL(clk_put);
> +
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> +	if (clk->ops->round_rate)
> +		return clk->ops->round_rate(clk, rate);
> +	return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_round_rate);
> +
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> +	if (clk->ops->set_rate)
> +		return clk->ops->set_rate(clk, rate);
> +	return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_rate);
> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> +	if (clk->ops->set_parent)
> +		return clk->ops->set_parent(clk, parent);
> +	return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);
> +
> +struct clk *clk_get_parent(struct clk *clk)
> +{
> +	if (clk->ops->get_parent)
> +		return clk->ops->get_parent(clk);
> +	return ERR_PTR(-ENOSYS);
> +}
> +EXPORT_SYMBOL_GPL(clk_get_parent);
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/2] Add a common struct clk
  2010-12-08  2:08 [PATCH 0/2] Common struct clk implementation, v8 Jeremy Kerr
@ 2010-12-08  2:08   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-12-08  2:08 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	int			flags;
	union {
		struct mutex	mutex;
		spinlock_t	spinlock;
	} lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
Acked-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>

---
 arch/Kconfig        |    3 
 include/linux/clk.h |  158 +++++++++++++++++++++++++++++++++++++++++---
 kernel/Makefile     |    1 
 kernel/clk.c        |  100 +++++++++++++++++++++++++++
 4 files changed, 253 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8bf0fa6..212bd3c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -165,6 +165,9 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 config HAVE_PERF_EVENTS_NMI
 	bool
 	help
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..e09e40e 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,163 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+#define CLK_ATOMIC	0x1
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @clk_ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @flags:		platform-independent flags
+ * @lock:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @lock member provides either a spinlock or a mutex to protect (at least)
+ * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
+ * set, then the core clock code will use a spinlock, otherwise a mutex. This
+ * lock will be acquired during clk_enable and clk_disable, so for atomic
+ * clocks, these ops callbacks must not sleep.
+ *
+ * The choice of atomic or non-atomic clock depends on how the clock is enabled.
+ * Typically, you'll want to use a non-atomic clock. For clocks that need to be
+ * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
+ * clocks with parents will typically cascade enable/disable operations to
+ * their parent, so the parent of an atomic clock *must* be atomic too.
+ */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	int			flags;
+	union {
+		struct mutex	mutex;
+		spinlock_t	spinlock;
+	} lock;
+};
+
+/* static initialiser for non-atomic clocks */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= 0,						\
+	.lock.mutex	= __MUTEX_INITIALIZER(name.lock.mutex),		\
+}
+
+/* static initialiser for atomic clocks */
+#define INIT_CLK_ATOMIC(name, o) {					\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= CLK_ATOMIC,					\
+	.lock.spinlock	= __SPIN_LOCK_UNLOCKED(name.lock.spinlock),	\
+}
+
+/**
+ * clk_ops: Callback operations for clocks; these are to be provided by the
+ * clock implementation, and will be called by drivers through the clk_* API.
+ *
+ * @enable:	Enable the clock. This must not return until the clock is
+ *		generating a valid clock signal, usable by consumer devices.
+ *		Called with clk->lock held.
+ *
+ * @disable:	Disable the clock. Called with clk->lock held.
+ *
+ * @get	/ @put:	Called by the core clock code to notify the driver about
+ *		refounts as clk is passed to drivers. Optional.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions directly, or
+ * -ENOSYS is returned if the callback is NULL, see kernel/clk.c for
+ * implementation details. All are optional.
  */
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
 
+static inline void __clk_lock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock(&clk->lock.spinlock);
+	else
+		mutex_lock(&clk->lock.mutex);
+}
+
+static inline void __clk_unlock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_unlock(&clk->lock.spinlock);
+	else
+		mutex_unlock(&clk->lock.mutex);
+}
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = 0;
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock_init(&clk->lock.spinlock);
+	else
+		mutex_init(&clk->lock.mutex);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +229,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 0b5ff08..01383a0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..1545e69
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	__clk_lock(clk);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	__clk_unlock(clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	__clk_lock(clk);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	__clk_unlock(clk);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* [PATCH 1/2] Add a common struct clk
@ 2010-12-08  2:08   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-12-08  2:08 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	int			flags;
	union {
		struct mutex	mutex;
		spinlock_t	spinlock;
	} lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
Acked-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>

---
 arch/Kconfig        |    3 
 include/linux/clk.h |  158 +++++++++++++++++++++++++++++++++++++++++---
 kernel/Makefile     |    1 
 kernel/clk.c        |  100 +++++++++++++++++++++++++++
 4 files changed, 253 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8bf0fa6..212bd3c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -165,6 +165,9 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 config HAVE_PERF_EVENTS_NMI
 	bool
 	help
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..e09e40e 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,163 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+#define CLK_ATOMIC	0x1
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @clk_ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @flags:		platform-independent flags
+ * @lock:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @lock member provides either a spinlock or a mutex to protect (at least)
+ * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
+ * set, then the core clock code will use a spinlock, otherwise a mutex. This
+ * lock will be acquired during clk_enable and clk_disable, so for atomic
+ * clocks, these ops callbacks must not sleep.
+ *
+ * The choice of atomic or non-atomic clock depends on how the clock is enabled.
+ * Typically, you'll want to use a non-atomic clock. For clocks that need to be
+ * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
+ * clocks with parents will typically cascade enable/disable operations to
+ * their parent, so the parent of an atomic clock *must* be atomic too.
+ */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	int			flags;
+	union {
+		struct mutex	mutex;
+		spinlock_t	spinlock;
+	} lock;
+};
+
+/* static initialiser for non-atomic clocks */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= 0,						\
+	.lock.mutex	= __MUTEX_INITIALIZER(name.lock.mutex),		\
+}
+
+/* static initialiser for atomic clocks */
+#define INIT_CLK_ATOMIC(name, o) {					\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= CLK_ATOMIC,					\
+	.lock.spinlock	= __SPIN_LOCK_UNLOCKED(name.lock.spinlock),	\
+}
+
+/**
+ * clk_ops: Callback operations for clocks; these are to be provided by the
+ * clock implementation, and will be called by drivers through the clk_* API.
+ *
+ * @enable:	Enable the clock. This must not return until the clock is
+ *		generating a valid clock signal, usable by consumer devices.
+ *		Called with clk->lock held.
+ *
+ * @disable:	Disable the clock. Called with clk->lock held.
+ *
+ * @get	/ @put:	Called by the core clock code to notify the driver about
+ *		refounts as clk is passed to drivers. Optional.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions directly, or
+ * -ENOSYS is returned if the callback is NULL, see kernel/clk.c for
+ * implementation details. All are optional.
  */
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
 
+static inline void __clk_lock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock(&clk->lock.spinlock);
+	else
+		mutex_lock(&clk->lock.mutex);
+}
+
+static inline void __clk_unlock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_unlock(&clk->lock.spinlock);
+	else
+		mutex_unlock(&clk->lock.mutex);
+}
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = 0;
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock_init(&clk->lock.spinlock);
+	else
+		mutex_init(&clk->lock.mutex);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +229,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 0b5ff08..01383a0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..1545e69
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	__clk_lock(clk);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	__clk_unlock(clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	__clk_lock(clk);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	__clk_unlock(clk);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* [PATCH 1/2] Add a common struct clk
@ 2010-12-08  2:05 ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-12-08  2:05 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	int			flags;
	union {
		struct mutex	mutex;
		spinlock_t	spinlock;
	} lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
Acked-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>

---
 arch/Kconfig        |    3 
 include/linux/clk.h |  158 +++++++++++++++++++++++++++++++++++++++++---
 kernel/Makefile     |    1 
 kernel/clk.c        |  100 +++++++++++++++++++++++++++
 4 files changed, 253 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8bf0fa6..212bd3c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -165,6 +165,9 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 config HAVE_PERF_EVENTS_NMI
 	bool
 	help
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..e09e40e 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,163 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+#define CLK_ATOMIC	0x1
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @clk_ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @flags:		platform-independent flags
+ * @lock:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @lock member provides either a spinlock or a mutex to protect (at least)
+ * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
+ * set, then the core clock code will use a spinlock, otherwise a mutex. This
+ * lock will be acquired during clk_enable and clk_disable, so for atomic
+ * clocks, these ops callbacks must not sleep.
+ *
+ * The choice of atomic or non-atomic clock depends on how the clock is enabled.
+ * Typically, you'll want to use a non-atomic clock. For clocks that need to be
+ * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
+ * clocks with parents will typically cascade enable/disable operations to
+ * their parent, so the parent of an atomic clock *must* be atomic too.
+ */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	int			flags;
+	union {
+		struct mutex	mutex;
+		spinlock_t	spinlock;
+	} lock;
+};
+
+/* static initialiser for non-atomic clocks */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= 0,						\
+	.lock.mutex	= __MUTEX_INITIALIZER(name.lock.mutex),		\
+}
+
+/* static initialiser for atomic clocks */
+#define INIT_CLK_ATOMIC(name, o) {					\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= CLK_ATOMIC,					\
+	.lock.spinlock	= __SPIN_LOCK_UNLOCKED(name.lock.spinlock),	\
+}
+
+/**
+ * clk_ops: Callback operations for clocks; these are to be provided by the
+ * clock implementation, and will be called by drivers through the clk_* API.
+ *
+ * @enable:	Enable the clock. This must not return until the clock is
+ *		generating a valid clock signal, usable by consumer devices.
+ *		Called with clk->lock held.
+ *
+ * @disable:	Disable the clock. Called with clk->lock held.
+ *
+ * @get	/ @put:	Called by the core clock code to notify the driver about
+ *		refounts as clk is passed to drivers. Optional.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions directly, or
+ * -ENOSYS is returned if the callback is NULL, see kernel/clk.c for
+ * implementation details. All are optional.
  */
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
 
+static inline void __clk_lock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock(&clk->lock.spinlock);
+	else
+		mutex_lock(&clk->lock.mutex);
+}
+
+static inline void __clk_unlock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_unlock(&clk->lock.spinlock);
+	else
+		mutex_unlock(&clk->lock.mutex);
+}
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = 0;
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock_init(&clk->lock.spinlock);
+	else
+		mutex_init(&clk->lock.mutex);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +229,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 0b5ff08..01383a0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..1545e69
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	__clk_lock(clk);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	__clk_unlock(clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	__clk_lock(clk);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	__clk_unlock(clk);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* [PATCH 1/2] Add a common struct clk
@ 2010-12-08  2:05 ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-12-08  2:05 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	int			flags;
	union {
		struct mutex	mutex;
		spinlock_t	spinlock;
	} lock;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
	int             (*enable)(struct clk *);
	void            (*disable)(struct clk *);
	unsigned long   (*get_rate)(struct clk *);
	[...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
Acked-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>

---
 arch/Kconfig        |    3 
 include/linux/clk.h |  158 +++++++++++++++++++++++++++++++++++++++++---
 kernel/Makefile     |    1 
 kernel/clk.c        |  100 +++++++++++++++++++++++++++
 4 files changed, 253 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 8bf0fa6..212bd3c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -165,6 +165,9 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 config HAVE_PERF_EVENTS_NMI
 	bool
 	help
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..e09e40e 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,163 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+#define CLK_ATOMIC	0x1
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @clk_ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @flags:		platform-independent flags
+ * @lock:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @lock member provides either a spinlock or a mutex to protect (at least)
+ * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
+ * set, then the core clock code will use a spinlock, otherwise a mutex. This
+ * lock will be acquired during clk_enable and clk_disable, so for atomic
+ * clocks, these ops callbacks must not sleep.
+ *
+ * The choice of atomic or non-atomic clock depends on how the clock is enabled.
+ * Typically, you'll want to use a non-atomic clock. For clocks that need to be
+ * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
+ * clocks with parents will typically cascade enable/disable operations to
+ * their parent, so the parent of an atomic clock *must* be atomic too.
+ */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	int			flags;
+	union {
+		struct mutex	mutex;
+		spinlock_t	spinlock;
+	} lock;
+};
+
+/* static initialiser for non-atomic clocks */
+#define INIT_CLK(name, o) {						\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= 0,						\
+	.lock.mutex	= __MUTEX_INITIALIZER(name.lock.mutex),		\
+}
+
+/* static initialiser for atomic clocks */
+#define INIT_CLK_ATOMIC(name, o) {					\
+	.ops		= &o,						\
+	.enable_count	= 0,						\
+	.flags		= CLK_ATOMIC,					\
+	.lock.spinlock	= __SPIN_LOCK_UNLOCKED(name.lock.spinlock),	\
+}
+
+/**
+ * clk_ops: Callback operations for clocks; these are to be provided by the
+ * clock implementation, and will be called by drivers through the clk_* API.
+ *
+ * @enable:	Enable the clock. This must not return until the clock is
+ *		generating a valid clock signal, usable by consumer devices.
+ *		Called with clk->lock held.
+ *
+ * @disable:	Disable the clock. Called with clk->lock held.
+ *
+ * @get	/ @put:	Called by the core clock code to notify the driver about
+ *		refounts as clk is passed to drivers. Optional.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions directly, or
+ * -ENOSYS is returned if the callback is NULL, see kernel/clk.c for
+ * implementation details. All are optional.
  */
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
 
+static inline void __clk_lock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock(&clk->lock.spinlock);
+	else
+		mutex_lock(&clk->lock.mutex);
+}
+
+static inline void __clk_unlock(struct clk *clk)
+{
+	if (clk->flags & CLK_ATOMIC)
+		spin_unlock(&clk->lock.spinlock);
+	else
+		mutex_unlock(&clk->lock.mutex);
+}
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	clk->enable_count = 0;
+	if (clk->flags & CLK_ATOMIC)
+		spin_lock_init(&clk->lock.spinlock);
+	else
+		mutex_init(&clk->lock.mutex);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +229,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 0b5ff08..01383a0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..1545e69
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	__clk_lock(clk);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	__clk_unlock(clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	__clk_lock(clk);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	__clk_unlock(clk);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* [PATCH 1/2] Add a common struct clk
  2010-07-12  2:37 [PATCH 0/2] Common struct clk implementation, v6 Jeremy Kerr
@ 2010-07-12  2:37   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-07-12  2:37 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: linux-kernel, Ben Herrenchmidt

We currently have 21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	struct mutex		mutex;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
       int             (*enable)(struct clk *);
       void            (*disable)(struct clk *);
       unsigned long   (*get_rate)(struct clk *);
       [...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 arch/Kconfig        |    3 +
 include/linux/clk.h |   90 +++++++++++++++++++++++++++++++++++----
 kernel/Makefile     |    1 
 kernel/clk.c        |  101 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 186 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index acda512..2458b5e 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -151,4 +151,7 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 source "kernel/gcov/Kconfig"
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..a95cc82 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,95 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @clk_ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @mutex:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_count and @mutex members are initialised when a clock is
+ * registered with the arch-specific clock management code; the clock driver
+ * code does not need to handle these.
  */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	struct mutex		mutex;
+};
+
+#define INIT_CLK(o) { .ops = &o, }
+
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
 
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * Used by arch code on registration with the clock infrastructure.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	mutex_init(&clk->mutex);
+	clk->enable_count = 0;
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +161,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 057472f..1ae15aa 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..cdea25f
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	mutex_lock(&clk->mutex);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	mutex_unlock(&clk->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	mutex_lock(&clk->mutex);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	mutex_unlock(&clk->mutex);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* [PATCH 1/2] Add a common struct clk
@ 2010-07-12  2:37   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-07-12  2:37 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have 21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	struct mutex		mutex;
};

And a set of clock operations (defined per type of clock):

struct clk_ops {
       int             (*enable)(struct clk *);
       void            (*disable)(struct clk *);
       unsigned long   (*get_rate)(struct clk *);
       [...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_ops clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 arch/Kconfig        |    3 +
 include/linux/clk.h |   90 +++++++++++++++++++++++++++++++++++----
 kernel/Makefile     |    1 
 kernel/clk.c        |  101 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 186 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index acda512..2458b5e 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -151,4 +151,7 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 source "kernel/gcov/Kconfig"
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..a95cc82 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,95 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @clk_ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @mutex:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_count and @mutex members are initialised when a clock is
+ * registered with the arch-specific clock management code; the clock driver
+ * code does not need to handle these.
  */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	struct mutex		mutex;
+};
+
+#define INIT_CLK(o) { .ops = &o, }
+
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
 
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * Used by arch code on registration with the clock infrastructure.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+	mutex_init(&clk->mutex);
+	clk->enable_count = 0;
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+static inline void clk_common_init(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +161,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 057472f..1ae15aa 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..cdea25f
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	mutex_lock(&clk->mutex);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	mutex_unlock(&clk->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	mutex_lock(&clk->mutex);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	mutex_unlock(&clk->mutex);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* Re: [PATCH 1/2] Add a common struct clk
  2010-07-05  2:33     ` MyungJoo Ham
@ 2010-07-12  2:19       ` Jeremy Kerr
  -1 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-07-12  2:19 UTC (permalink / raw)
  To: MyungJoo Ham; +Cc: linux-kernel, Ben Herrenchmidt, linux-arm-kernel

Hi MyungJoo,

> > +int clk_enable(struct clk *clk)
> > +{
> > +       int ret = 0;
> > +
> > +       if (!clk->ops->enable)
> > +               return 0;
> 
> Wouldn't it be better (safer?) to check "clk" and "clk->ops" before
> accessing clk->ops->enable?
> For example,
> 
>         if (IS_ERR_OR_NULL(clk))
>                 return -EINVAL;
> 
>         if (!clk->ops || !clk->ops->enable)
>                 return 0;
> 
> Or, do you think it'd be better not to check and save some time?
> 
> Anyway, if we intend to check the input, the patch for the patch
> including kernel/clk.c would be...

I think that we should leave it as-is; although it may be 'safer', it
may mean more subtle bugs can arise because we've been handed an invalid
clock pointer.

I'd rather the code oops on first usage so that the developer realises
that something is broken, rather than fail with an error code.

BTW - nice work on the samsung implementation, I will check it out soon.

Cheers,


Jeremy


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

* [PATCH 1/2] Add a common struct clk
@ 2010-07-12  2:19       ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-07-12  2:19 UTC (permalink / raw)
  To: linux-arm-kernel

Hi MyungJoo,

> > +int clk_enable(struct clk *clk)
> > +{
> > +       int ret = 0;
> > +
> > +       if (!clk->ops->enable)
> > +               return 0;
> 
> Wouldn't it be better (safer?) to check "clk" and "clk->ops" before
> accessing clk->ops->enable?
> For example,
> 
>         if (IS_ERR_OR_NULL(clk))
>                 return -EINVAL;
> 
>         if (!clk->ops || !clk->ops->enable)
>                 return 0;
> 
> Or, do you think it'd be better not to check and save some time?
> 
> Anyway, if we intend to check the input, the patch for the patch
> including kernel/clk.c would be...

I think that we should leave it as-is; although it may be 'safer', it
may mean more subtle bugs can arise because we've been handed an invalid
clock pointer.

I'd rather the code oops on first usage so that the developer realises
that something is broken, rather than fail with an error code.

BTW - nice work on the samsung implementation, I will check it out soon.

Cheers,


Jeremy

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

* Re: [PATCH 1/2] Add a common struct clk
  2010-06-21  5:35   ` Jeremy Kerr
@ 2010-07-05  2:33     ` MyungJoo Ham
  -1 siblings, 0 replies; 86+ messages in thread
From: MyungJoo Ham @ 2010-07-05  2:33 UTC (permalink / raw)
  To: Jeremy Kerr; +Cc: linux-kernel, Ben Herrenchmidt, linux-arm-kernel

Hello Jeremy,

On Mon, Jun 21, 2010 at 2:35 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
> We currently have 21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
>
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
>
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
>
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
>
> struct clk {
>        const struct clk_ops    *ops;
>        unsigned int            enable_count;
>        struct mutex            mutex;
> };
>
> And a set of clock operations (defined per type of clock):
>
> struct clk_operations {
>       int             (*enable)(struct clk *);
>       void            (*disable)(struct clk *);
>       unsigned long   (*get_rate)(struct clk *);
>       [...]
> };
>
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
>
> struct clk_foo {
>        struct clk      clk;
>        void __iomem    *some_register;
> };
>
> struct clk_operations clk_foo_ops = {
>        .get_rate = clk_foo_get_rate,
> };
>
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <benh@kernel.crashing.org>.
>
> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
>
> ---
>  arch/Kconfig        |    3 +
>  include/linux/clk.h |   77 +++++++++++++++++++++++++++++----
>  kernel/Makefile     |    1
>  kernel/clk.c        |  101 ++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 173 insertions(+), 9 deletions(-)
>
> diff --git a/arch/Kconfig b/arch/Kconfig
> index acda512..2458b5e 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -151,4 +151,7 @@ config HAVE_MIXED_BREAKPOINTS_REGS
>  config HAVE_USER_RETURN_NOTIFIER
>        bool
>
> +config USE_COMMON_STRUCT_CLK
> +       bool
> +
>  source "kernel/gcov/Kconfig"
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..5c1098b 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -3,6 +3,7 @@
>  *
>  *  Copyright (C) 2004 ARM Limited.
>  *  Written by Deep Blue Solutions Limited.
> + *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
>  *
>  * This program is free software; you can redistribute it and/or modify
>  * it under the terms of the GNU General Public License version 2 as
> @@ -11,18 +12,82 @@
>  #ifndef __LINUX_CLK_H
>  #define __LINUX_CLK_H
>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +
>  struct device;
>
> -/*
> - * The base API.
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> +
> +/* If we're using the common struct clk, we define the base clk object here */
> +
> +/**
> + * struct clk - hardware independent clock structure
> + * @clk_ops:           implementation-specific ops for this clock
> + * @enable_count:      count of clk_enable() calls active on this clock
> + * @mutex:             lock for enable/disable or other HW-specific ops
> + *
> + * The base clock object, used by drivers for hardware-independent manipulation
> + * of clock lines. This will be 'subclassed' by device-specific implementations,
> + * which add device-specific data to struct clk. For example:
> + *
> + *  struct clk_foo {
> + *      struct clk;
> + *      [device specific fields]
> + *  };
> + *
> + * The clock driver code will manage the device-specific data, and pass
> + * clk_foo.clk to the common clock code. The clock driver will be called
> + * through the @ops callbacks.
> + *
> + * The @enable_count and @mutex members are initialised when a clock is
> + * registered with the arch-specific clock management code; the clock driver
> + * code does not need to handle these.
> + */
> +struct clk {
> +       const struct clk_ops    *ops;
> +       unsigned int            enable_count;
> +       struct mutex            mutex;
> +};
> +
> +#define INIT_CLK(o) { .ops = &o, }
> +
> +struct clk_ops {
> +       int             (*enable)(struct clk *);
> +       void            (*disable)(struct clk *);
> +       int             (*get)(struct clk *);
> +       void            (*put)(struct clk *);
> +       unsigned long   (*get_rate)(struct clk *);
> +       long            (*round_rate)(struct clk *, unsigned long);
> +       int             (*set_rate)(struct clk *, unsigned long);
> +       int             (*set_parent)(struct clk *, struct clk *);
> +       struct clk *    (*get_parent)(struct clk *);
> +};
> +
> +/**
> + * __clk_get - update clock-specific refcounter
> + *
> + * @clk: The clock to refcount
> + *
> + * Before a clock is returned from clk_get, this function should be called
> + * to update any clock-specific refcounting.
> + *
> + * Returns non-zero on success, zero on failure.
> + *
> + * Drivers should not need this function; it is only needed by the
> + * arch-specific clk_get() implementations.
>  */
> +int __clk_get(struct clk *clk);
>
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>
>  /*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
>  */
>  struct clk;
>
> +#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
> +
>  /**
>  * clk_get - lookup and obtain a reference to a clock producer.
>  * @dev: device for clock "consumer"
> @@ -83,12 +148,6 @@ unsigned long clk_get_rate(struct clk *clk);
>  */
>  void clk_put(struct clk *clk);
>
> -
> -/*
> - * The remaining APIs are optional for machine class support.
> - */
> -
> -
>  /**
>  * clk_round_rate - adjust a rate to the exact rate a clock can provide
>  * @clk: clock source
> diff --git a/kernel/Makefile b/kernel/Makefile
> index 057472f..1ae15aa 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -105,6 +105,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
>  obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
>  obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
>  obj-$(CONFIG_PADATA) += padata.o
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
>
>  ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
>  # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
> diff --git a/kernel/clk.c b/kernel/clk.c
> new file mode 100644
> index 0000000..cdea25f
> --- /dev/null
> +++ b/kernel/clk.c
> @@ -0,0 +1,101 @@
> +/*
> + * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/mutex.h>
> +#include <linux/module.h>
> +
> +int clk_enable(struct clk *clk)
> +{
> +       int ret = 0;
> +
> +       if (!clk->ops->enable)
> +               return 0;

Wouldn't it be better (safer?) to check "clk" and "clk->ops" before
accessing clk->ops->enable?
For example,

        if (IS_ERR_OR_NULL(clk))
                return -EINVAL;

        if (!clk->ops || !clk->ops->enable)
                return 0;

Or, do you think it'd be better not to check and save some time?

Anyway, if we intend to check the input, the patch for the patch
including kernel/clk.c would be...

----------------------------------------------------
diff --git a/kernel/clk.c b/kernel/clk.c
index 32f25ef..c35f0ac 100644
--- a/kernel/clk.c
+++ b/kernel/clk.c
@@ -16,7 +16,10 @@ int clk_enable(struct clk *clk)
 {
        int ret = 0;

-       if (!clk->ops->enable)
+       if (IS_ERR_OR_NULL(clk))
+               return -EINVAL;
+
+       if (!clk->ops || !clk->ops->enable)
                return 0;

        mutex_lock(&clk->mutex);
@@ -33,7 +36,12 @@ EXPORT_SYMBOL_GPL(clk_enable);

 void clk_disable(struct clk *clk)
 {
-       if (!clk->ops->disable)
+       if (IS_ERR_OR_NULL(clk)) {
+               printk(KERN_ERR "clk_disable(NULL) is called.\n");
+               return;
+       }
+
+       if (!clk->ops || !clk->ops->disable)
                return;

        mutex_lock(&clk->mutex);
@@ -47,7 +55,9 @@ EXPORT_SYMBOL_GPL(clk_disable);

 unsigned long clk_get_rate(struct clk *clk)
 {
-       if (clk->ops->get_rate)
+       if (IS_ERR_OR_NULL(clk))
+               return -EINVAL;
+       if (clk->ops && clk->ops->get_rate)
                return clk->ops->get_rate(clk);
        return 0;
 }
@@ -55,7 +65,9 @@ EXPORT_SYMBOL_GPL(clk_get_rate);

 int __clk_get(struct clk *clk)
 {
-       if (clk->ops->get)
+       if (IS_ERR_OR_NULL(clk))
+               return -EINVAL;
+       if (clk->ops && clk->ops->get)
                return clk->ops->get(clk);
        return 1;
 }
@@ -63,14 +75,19 @@ EXPORT_SYMBOL_GPL(__clk_get);

 void clk_put(struct clk *clk)
 {
-       if (clk->ops->put)
+       if (IS_ERR_OR_NULL(clk)) {
+               printk(KERN_ERR "clk_disable(NULL) is called.\n");
+               return;
+       }
+
+       if (clk->ops && clk->ops->put)
                clk->ops->put(clk);
 }
 EXPORT_SYMBOL_GPL(clk_put);

 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       if (clk->ops->round_rate)
+       if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->round_rate)
                return clk->ops->round_rate(clk, rate);
        return -ENOSYS;
 }
@@ -78,7 +95,7 @@ EXPORT_SYMBOL_GPL(clk_round_rate);

 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
-       if (clk->ops->set_rate)
+       if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->set_rate)
                return clk->ops->set_rate(clk, rate);
        return -ENOSYS;
 }
@@ -86,7 +103,7 @@ EXPORT_SYMBOL_GPL(clk_set_rate);

 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
-       if (clk->ops->set_parent)
+       if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->set_parent)
                return clk->ops->set_parent(clk, parent);
        return -ENOSYS;
 }
@@ -94,7 +111,7 @@ EXPORT_SYMBOL_GPL(clk_set_parent);

 struct clk *clk_get_parent(struct clk *clk)
 {
-       if (clk->ops->get_parent)
+       if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->get_parent)
                return clk->ops->get_parent(clk);
        return ERR_PTR(-ENOSYS);
 }



> +
> +       mutex_lock(&clk->mutex);
> +       if (!clk->enable_count)
> +               ret = clk->ops->enable(clk);
> +
> +       if (!ret)
> +               clk->enable_count++;
> +       mutex_unlock(&clk->mutex);
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_enable);
> +
> +void clk_disable(struct clk *clk)
> +{
> +       if (!clk->ops->disable)
> +               return;
> +
> +       mutex_lock(&clk->mutex);
> +
> +       if (!--clk->enable_count)
> +               clk->ops->disable(clk);
> +
> +       mutex_unlock(&clk->mutex);
> +}
> +EXPORT_SYMBOL_GPL(clk_disable);
> +
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> +       if (clk->ops->get_rate)
> +               return clk->ops->get_rate(clk);
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_get_rate);
> +
> +int __clk_get(struct clk *clk)
> +{
> +       if (clk->ops->get)
> +               return clk->ops->get(clk);
> +       return 1;
> +}
> +EXPORT_SYMBOL_GPL(__clk_get);
> +
> +void clk_put(struct clk *clk)
> +{
> +       if (clk->ops->put)
> +               clk->ops->put(clk);
> +}
> +EXPORT_SYMBOL_GPL(clk_put);
> +
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> +       if (clk->ops->round_rate)
> +               return clk->ops->round_rate(clk, rate);
> +       return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_round_rate);
> +
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> +       if (clk->ops->set_rate)
> +               return clk->ops->set_rate(clk, rate);
> +       return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_rate);
> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> +       if (clk->ops->set_parent)
> +               return clk->ops->set_parent(clk, parent);
> +       return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);
> +
> +struct clk *clk_get_parent(struct clk *clk)
> +{
> +       if (clk->ops->get_parent)
> +               return clk->ops->get_parent(clk);
> +       return ERR_PTR(-ENOSYS);
> +}
> +EXPORT_SYMBOL_GPL(clk_get_parent);
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>



-- 
MyungJoo Ham (함명주), Ph.D.
Mobile Software Platform Lab,
Digital Media and Communications (DMC) Business
Samsung Electronics
cell: 82-10-6714-2858

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

* [PATCH 1/2] Add a common struct clk
@ 2010-07-05  2:33     ` MyungJoo Ham
  0 siblings, 0 replies; 86+ messages in thread
From: MyungJoo Ham @ 2010-07-05  2:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Jeremy,

On Mon, Jun 21, 2010 at 2:35 PM, Jeremy Kerr <jeremy.kerr@canonical.com> wrote:
> We currently have 21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
>
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
>
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
>
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
>
> struct clk {
> ? ? ? ?const struct clk_ops ? ?*ops;
> ? ? ? ?unsigned int ? ? ? ? ? ?enable_count;
> ? ? ? ?struct mutex ? ? ? ? ? ?mutex;
> };
>
> And a set of clock operations (defined per type of clock):
>
> struct clk_operations {
> ? ? ? int ? ? ? ? ? ? (*enable)(struct clk *);
> ? ? ? void ? ? ? ? ? ?(*disable)(struct clk *);
> ? ? ? unsigned long ? (*get_rate)(struct clk *);
> ? ? ? [...]
> };
>
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
>
> struct clk_foo {
> ? ? ? ?struct clk ? ? ?clk;
> ? ? ? ?void __iomem ? ?*some_register;
> };
>
> struct clk_operations clk_foo_ops = {
> ? ? ? ?.get_rate = clk_foo_get_rate,
> };
>
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <benh@kernel.crashing.org>.
>
> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
>
> ---
> ?arch/Kconfig ? ? ? ?| ? ?3 +
> ?include/linux/clk.h | ? 77 +++++++++++++++++++++++++++++----
> ?kernel/Makefile ? ? | ? ?1
> ?kernel/clk.c ? ? ? ?| ?101 ++++++++++++++++++++++++++++++++++++++++++++
> ?4 files changed, 173 insertions(+), 9 deletions(-)
>
> diff --git a/arch/Kconfig b/arch/Kconfig
> index acda512..2458b5e 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -151,4 +151,7 @@ config HAVE_MIXED_BREAKPOINTS_REGS
> ?config HAVE_USER_RETURN_NOTIFIER
> ? ? ? ?bool
>
> +config USE_COMMON_STRUCT_CLK
> + ? ? ? bool
> +
> ?source "kernel/gcov/Kconfig"
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..5c1098b 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -3,6 +3,7 @@
> ?*
> ?* ?Copyright (C) 2004 ARM Limited.
> ?* ?Written by Deep Blue Solutions Limited.
> + * ?Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
> ?*
> ?* This program is free software; you can redistribute it and/or modify
> ?* it under the terms of the GNU General Public License version 2 as
> @@ -11,18 +12,82 @@
> ?#ifndef __LINUX_CLK_H
> ?#define __LINUX_CLK_H
>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +
> ?struct device;
>
> -/*
> - * The base API.
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> +
> +/* If we're using the common struct clk, we define the base clk object here */
> +
> +/**
> + * struct clk - hardware independent clock structure
> + * @clk_ops: ? ? ? ? ? implementation-specific ops for this clock
> + * @enable_count: ? ? ?count of clk_enable() calls active on this clock
> + * @mutex: ? ? ? ? ? ? lock for enable/disable or other HW-specific ops
> + *
> + * The base clock object, used by drivers for hardware-independent manipulation
> + * of clock lines. This will be 'subclassed' by device-specific implementations,
> + * which add device-specific data to struct clk. For example:
> + *
> + * ?struct clk_foo {
> + * ? ? ?struct clk;
> + * ? ? ?[device specific fields]
> + * ?};
> + *
> + * The clock driver code will manage the device-specific data, and pass
> + * clk_foo.clk to the common clock code. The clock driver will be called
> + * through the @ops callbacks.
> + *
> + * The @enable_count and @mutex members are initialised when a clock is
> + * registered with the arch-specific clock management code; the clock driver
> + * code does not need to handle these.
> + */
> +struct clk {
> + ? ? ? const struct clk_ops ? ?*ops;
> + ? ? ? unsigned int ? ? ? ? ? ?enable_count;
> + ? ? ? struct mutex ? ? ? ? ? ?mutex;
> +};
> +
> +#define INIT_CLK(o) { .ops = &o, }
> +
> +struct clk_ops {
> + ? ? ? int ? ? ? ? ? ? (*enable)(struct clk *);
> + ? ? ? void ? ? ? ? ? ?(*disable)(struct clk *);
> + ? ? ? int ? ? ? ? ? ? (*get)(struct clk *);
> + ? ? ? void ? ? ? ? ? ?(*put)(struct clk *);
> + ? ? ? unsigned long ? (*get_rate)(struct clk *);
> + ? ? ? long ? ? ? ? ? ?(*round_rate)(struct clk *, unsigned long);
> + ? ? ? int ? ? ? ? ? ? (*set_rate)(struct clk *, unsigned long);
> + ? ? ? int ? ? ? ? ? ? (*set_parent)(struct clk *, struct clk *);
> + ? ? ? struct clk * ? ?(*get_parent)(struct clk *);
> +};
> +
> +/**
> + * __clk_get - update clock-specific refcounter
> + *
> + * @clk: The clock to refcount
> + *
> + * Before a clock is returned from clk_get, this function should be called
> + * to update any clock-specific refcounting.
> + *
> + * Returns non-zero on success, zero on failure.
> + *
> + * Drivers should not need this function; it is only needed by the
> + * arch-specific clk_get() implementations.
> ?*/
> +int __clk_get(struct clk *clk);
>
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>
> ?/*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
> ?*/
> ?struct clk;
>
> +#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
> +
> ?/**
> ?* clk_get - lookup and obtain a reference to a clock producer.
> ?* @dev: device for clock "consumer"
> @@ -83,12 +148,6 @@ unsigned long clk_get_rate(struct clk *clk);
> ?*/
> ?void clk_put(struct clk *clk);
>
> -
> -/*
> - * The remaining APIs are optional for machine class support.
> - */
> -
> -
> ?/**
> ?* clk_round_rate - adjust a rate to the exact rate a clock can provide
> ?* @clk: clock source
> diff --git a/kernel/Makefile b/kernel/Makefile
> index 057472f..1ae15aa 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -105,6 +105,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
> ?obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
> ?obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
> ?obj-$(CONFIG_PADATA) += padata.o
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
>
> ?ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
> ?# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
> diff --git a/kernel/clk.c b/kernel/clk.c
> new file mode 100644
> index 0000000..cdea25f
> --- /dev/null
> +++ b/kernel/clk.c
> @@ -0,0 +1,101 @@
> +/*
> + * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/mutex.h>
> +#include <linux/module.h>
> +
> +int clk_enable(struct clk *clk)
> +{
> + ? ? ? int ret = 0;
> +
> + ? ? ? if (!clk->ops->enable)
> + ? ? ? ? ? ? ? return 0;

Wouldn't it be better (safer?) to check "clk" and "clk->ops" before
accessing clk->ops->enable?
For example,

        if (IS_ERR_OR_NULL(clk))
                return -EINVAL;

        if (!clk->ops || !clk->ops->enable)
                return 0;

Or, do you think it'd be better not to check and save some time?

Anyway, if we intend to check the input, the patch for the patch
including kernel/clk.c would be...

----------------------------------------------------
diff --git a/kernel/clk.c b/kernel/clk.c
index 32f25ef..c35f0ac 100644
--- a/kernel/clk.c
+++ b/kernel/clk.c
@@ -16,7 +16,10 @@ int clk_enable(struct clk *clk)
 {
        int ret = 0;

-       if (!clk->ops->enable)
+       if (IS_ERR_OR_NULL(clk))
+               return -EINVAL;
+
+       if (!clk->ops || !clk->ops->enable)
                return 0;

        mutex_lock(&clk->mutex);
@@ -33,7 +36,12 @@ EXPORT_SYMBOL_GPL(clk_enable);

 void clk_disable(struct clk *clk)
 {
-       if (!clk->ops->disable)
+       if (IS_ERR_OR_NULL(clk)) {
+               printk(KERN_ERR "clk_disable(NULL) is called.\n");
+               return;
+       }
+
+       if (!clk->ops || !clk->ops->disable)
                return;

        mutex_lock(&clk->mutex);
@@ -47,7 +55,9 @@ EXPORT_SYMBOL_GPL(clk_disable);

 unsigned long clk_get_rate(struct clk *clk)
 {
-       if (clk->ops->get_rate)
+       if (IS_ERR_OR_NULL(clk))
+               return -EINVAL;
+       if (clk->ops && clk->ops->get_rate)
                return clk->ops->get_rate(clk);
        return 0;
 }
@@ -55,7 +65,9 @@ EXPORT_SYMBOL_GPL(clk_get_rate);

 int __clk_get(struct clk *clk)
 {
-       if (clk->ops->get)
+       if (IS_ERR_OR_NULL(clk))
+               return -EINVAL;
+       if (clk->ops && clk->ops->get)
                return clk->ops->get(clk);
        return 1;
 }
@@ -63,14 +75,19 @@ EXPORT_SYMBOL_GPL(__clk_get);

 void clk_put(struct clk *clk)
 {
-       if (clk->ops->put)
+       if (IS_ERR_OR_NULL(clk)) {
+               printk(KERN_ERR "clk_disable(NULL) is called.\n");
+               return;
+       }
+
+       if (clk->ops && clk->ops->put)
                clk->ops->put(clk);
 }
 EXPORT_SYMBOL_GPL(clk_put);

 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       if (clk->ops->round_rate)
+       if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->round_rate)
                return clk->ops->round_rate(clk, rate);
        return -ENOSYS;
 }
@@ -78,7 +95,7 @@ EXPORT_SYMBOL_GPL(clk_round_rate);

 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
-       if (clk->ops->set_rate)
+       if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->set_rate)
                return clk->ops->set_rate(clk, rate);
        return -ENOSYS;
 }
@@ -86,7 +103,7 @@ EXPORT_SYMBOL_GPL(clk_set_rate);

 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
-       if (clk->ops->set_parent)
+       if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->set_parent)
                return clk->ops->set_parent(clk, parent);
        return -ENOSYS;
 }
@@ -94,7 +111,7 @@ EXPORT_SYMBOL_GPL(clk_set_parent);

 struct clk *clk_get_parent(struct clk *clk)
 {
-       if (clk->ops->get_parent)
+       if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->get_parent)
                return clk->ops->get_parent(clk);
        return ERR_PTR(-ENOSYS);
 }



> +
> + ? ? ? mutex_lock(&clk->mutex);
> + ? ? ? if (!clk->enable_count)
> + ? ? ? ? ? ? ? ret = clk->ops->enable(clk);
> +
> + ? ? ? if (!ret)
> + ? ? ? ? ? ? ? clk->enable_count++;
> + ? ? ? mutex_unlock(&clk->mutex);
> +
> + ? ? ? return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_enable);
> +
> +void clk_disable(struct clk *clk)
> +{
> + ? ? ? if (!clk->ops->disable)
> + ? ? ? ? ? ? ? return;
> +
> + ? ? ? mutex_lock(&clk->mutex);
> +
> + ? ? ? if (!--clk->enable_count)
> + ? ? ? ? ? ? ? clk->ops->disable(clk);
> +
> + ? ? ? mutex_unlock(&clk->mutex);
> +}
> +EXPORT_SYMBOL_GPL(clk_disable);
> +
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> + ? ? ? if (clk->ops->get_rate)
> + ? ? ? ? ? ? ? return clk->ops->get_rate(clk);
> + ? ? ? return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_get_rate);
> +
> +int __clk_get(struct clk *clk)
> +{
> + ? ? ? if (clk->ops->get)
> + ? ? ? ? ? ? ? return clk->ops->get(clk);
> + ? ? ? return 1;
> +}
> +EXPORT_SYMBOL_GPL(__clk_get);
> +
> +void clk_put(struct clk *clk)
> +{
> + ? ? ? if (clk->ops->put)
> + ? ? ? ? ? ? ? clk->ops->put(clk);
> +}
> +EXPORT_SYMBOL_GPL(clk_put);
> +
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> + ? ? ? if (clk->ops->round_rate)
> + ? ? ? ? ? ? ? return clk->ops->round_rate(clk, rate);
> + ? ? ? return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_round_rate);
> +
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> + ? ? ? if (clk->ops->set_rate)
> + ? ? ? ? ? ? ? return clk->ops->set_rate(clk, rate);
> + ? ? ? return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_rate);
> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> + ? ? ? if (clk->ops->set_parent)
> + ? ? ? ? ? ? ? return clk->ops->set_parent(clk, parent);
> + ? ? ? return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);
> +
> +struct clk *clk_get_parent(struct clk *clk)
> +{
> + ? ? ? if (clk->ops->get_parent)
> + ? ? ? ? ? ? ? return clk->ops->get_parent(clk);
> + ? ? ? return ERR_PTR(-ENOSYS);
> +}
> +EXPORT_SYMBOL_GPL(clk_get_parent);
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>



-- 
MyungJoo Ham (???), Ph.D.
Mobile Software Platform Lab,
Digital Media and Communications (DMC) Business
Samsung Electronics
cell: 82-10-6714-2858

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

* Re: [PATCH 1/2] Add a common struct clk
  2010-06-21  5:35   ` Jeremy Kerr
@ 2010-06-22  4:43     ` Baruch Siach
  -1 siblings, 0 replies; 86+ messages in thread
From: Baruch Siach @ 2010-06-22  4:43 UTC (permalink / raw)
  To: Jeremy Kerr; +Cc: linux-kernel, Ben Herrenchmidt, linux-arm-kernel

Hi Jeremy,

On Mon, Jun 21, 2010 at 01:35:13PM +0800, Jeremy Kerr wrote:
> We currently have 21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
> 
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
> 
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
> 
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
> 
> struct clk {
> 	const struct clk_ops	*ops;
> 	unsigned int		enable_count;
> 	struct mutex		mutex;
> };
> 
> And a set of clock operations (defined per type of clock):
> 
> struct clk_operations {

That's clk_ops above, and in the code.

>        int             (*enable)(struct clk *);
>        void            (*disable)(struct clk *);
>        unsigned long   (*get_rate)(struct clk *);
>        [...]
> };
> 
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
> 
> struct clk_foo {
> 	struct clk	clk;
> 	void __iomem	*some_register;
> };
> 
> struct clk_operations clk_foo_ops = {

Ditto.

> 	.get_rate = clk_foo_get_rate,
> };
> 
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <benh@kernel.crashing.org>.
> 
> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

baruch

-- 
                                                     ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch@tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il -

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

* [PATCH 1/2] Add a common struct clk
@ 2010-06-22  4:43     ` Baruch Siach
  0 siblings, 0 replies; 86+ messages in thread
From: Baruch Siach @ 2010-06-22  4:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jeremy,

On Mon, Jun 21, 2010 at 01:35:13PM +0800, Jeremy Kerr wrote:
> We currently have 21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
> 
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
> 
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
> 
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
> 
> struct clk {
> 	const struct clk_ops	*ops;
> 	unsigned int		enable_count;
> 	struct mutex		mutex;
> };
> 
> And a set of clock operations (defined per type of clock):
> 
> struct clk_operations {

That's clk_ops above, and in the code.

>        int             (*enable)(struct clk *);
>        void            (*disable)(struct clk *);
>        unsigned long   (*get_rate)(struct clk *);
>        [...]
> };
> 
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
> 
> struct clk_foo {
> 	struct clk	clk;
> 	void __iomem	*some_register;
> };
> 
> struct clk_operations clk_foo_ops = {

Ditto.

> 	.get_rate = clk_foo_get_rate,
> };
> 
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <benh@kernel.crashing.org>.
> 
> Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

baruch

-- 
                                                     ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch at tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il -

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

* [PATCH 1/2] Add a common struct clk
  2010-06-21  5:35 [PATCH 0/2] Common struct clk implementation, v5 Jeremy Kerr
@ 2010-06-21  5:35   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-06-21  5:35 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-arm-kernel, Ben Herrenchmidt

We currently have 21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	struct mutex		mutex;
};

And a set of clock operations (defined per type of clock):

struct clk_operations {
       int             (*enable)(struct clk *);
       void            (*disable)(struct clk *);
       unsigned long   (*get_rate)(struct clk *);
       [...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_operations clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 arch/Kconfig        |    3 +
 include/linux/clk.h |   77 +++++++++++++++++++++++++++++----
 kernel/Makefile     |    1 
 kernel/clk.c        |  101 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 173 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index acda512..2458b5e 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -151,4 +151,7 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 source "kernel/gcov/Kconfig"
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..5c1098b 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,82 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @clk_ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @mutex:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_count and @mutex members are initialised when a clock is
+ * registered with the arch-specific clock management code; the clock driver
+ * code does not need to handle these.
+ */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	struct mutex		mutex;
+};
+
+#define INIT_CLK(o) { .ops = &o, }
+
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure. 
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
  */
+int __clk_get(struct clk *clk);
 
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +148,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 057472f..1ae15aa 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..cdea25f
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	mutex_lock(&clk->mutex);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	mutex_unlock(&clk->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	mutex_lock(&clk->mutex);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	mutex_unlock(&clk->mutex);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

* [PATCH 1/2] Add a common struct clk
@ 2010-06-21  5:35   ` Jeremy Kerr
  0 siblings, 0 replies; 86+ messages in thread
From: Jeremy Kerr @ 2010-06-21  5:35 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have 21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.

This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.

This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.

Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:

struct clk {
	const struct clk_ops	*ops;
	unsigned int		enable_count;
	struct mutex		mutex;
};

And a set of clock operations (defined per type of clock):

struct clk_operations {
       int             (*enable)(struct clk *);
       void            (*disable)(struct clk *);
       unsigned long   (*get_rate)(struct clk *);
       [...]
};

To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:

struct clk_foo {
	struct clk	clk;
	void __iomem	*some_register;
};

struct clk_operations clk_foo_ops = {
	.get_rate = clk_foo_get_rate,
};

The common clock definitions are based on a development patch from Ben
Herrenschmidt <benh@kernel.crashing.org>.

Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>

---
 arch/Kconfig        |    3 +
 include/linux/clk.h |   77 +++++++++++++++++++++++++++++----
 kernel/Makefile     |    1 
 kernel/clk.c        |  101 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 173 insertions(+), 9 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index acda512..2458b5e 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -151,4 +151,7 @@ config HAVE_MIXED_BREAKPOINTS_REGS
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
+config USE_COMMON_STRUCT_CLK
+	bool
+
 source "kernel/gcov/Kconfig"
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..5c1098b 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (c) 2010 Jeremy Kerr <jeremy.kerr@canonical.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,82 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+#include <linux/mutex.h>
+
 struct device;
 
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @clk_ops:		implementation-specific ops for this clock
+ * @enable_count:	count of clk_enable() calls active on this clock
+ * @mutex:		lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ *  struct clk_foo {
+ *      struct clk;
+ *      [device specific fields]
+ *  };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_count and @mutex members are initialised when a clock is
+ * registered with the arch-specific clock management code; the clock driver
+ * code does not need to handle these.
+ */
+struct clk {
+	const struct clk_ops	*ops;
+	unsigned int		enable_count;
+	struct mutex		mutex;
+};
+
+#define INIT_CLK(o) { .ops = &o, }
+
+struct clk_ops {
+       int		(*enable)(struct clk *);
+       void		(*disable)(struct clk *);
+       int		(*get)(struct clk *);
+       void		(*put)(struct clk *);
+       unsigned long	(*get_rate)(struct clk *);
+       long		(*round_rate)(struct clk *, unsigned long);
+       int		(*set_rate)(struct clk *, unsigned long);
+       int		(*set_parent)(struct clk *, struct clk *);
+       struct clk *	(*get_parent)(struct clk *);
+};
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure. 
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
  */
+int __clk_get(struct clk *clk);
 
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
 
 /*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
  */
 struct clk;
 
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -83,12 +148,6 @@ unsigned long clk_get_rate(struct clk *clk);
  */
 void clk_put(struct clk *clk);
 
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
 /**
  * clk_round_rate - adjust a rate to the exact rate a clock can provide
  * @clk: clock source
diff --git a/kernel/Makefile b/kernel/Makefile
index 057472f..1ae15aa 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/clk.c b/kernel/clk.c
new file mode 100644
index 0000000..cdea25f
--- /dev/null
+++ b/kernel/clk.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk->ops->enable)
+		return 0;
+
+	mutex_lock(&clk->mutex);
+	if (!clk->enable_count)
+		ret = clk->ops->enable(clk);
+
+	if (!ret)
+		clk->enable_count++;
+	mutex_unlock(&clk->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (!clk->ops->disable)
+		return;
+
+	mutex_lock(&clk->mutex);
+
+	if (!--clk->enable_count)
+		clk->ops->disable(clk);
+
+	mutex_unlock(&clk->mutex);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+	if (clk->ops->get)
+		return clk->ops->get(clk);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk->ops->put)
+		clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->round_rate)
+		return clk->ops->round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->ops->set_rate)
+		return clk->ops->set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk->ops->set_parent)
+		return clk->ops->set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk->ops->get_parent)
+		return clk->ops->get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);

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

end of thread, other threads:[~2011-04-14 12:49 UTC | newest]

Thread overview: 86+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-05  3:51 [PATCH 0/2] Common struct clk implementation, v10 Jeremy Kerr
2011-01-05  3:51 ` Jeremy Kerr
2011-01-05  3:51 ` [PATCH 2/2] clk: Generic support for fixed-rate clocks Jeremy Kerr
2011-01-05  3:51   ` Jeremy Kerr
2011-01-05  3:51 ` [PATCH 1/2] Add a common struct clk Jeremy Kerr
2011-01-05  3:51   ` Jeremy Kerr
2011-01-06 16:07   ` Richard Cochran
2011-01-06 16:07     ` Richard Cochran
2011-01-06 20:11     ` Uwe Kleine-König
2011-01-06 20:11       ` Uwe Kleine-König
2011-01-07  0:10       ` Jeremy Kerr
2011-01-07  0:10         ` Jeremy Kerr
2011-01-07  0:32         ` Russell King - ARM Linux
2011-01-07  0:32           ` Russell King - ARM Linux
2011-01-07  9:40           ` Uwe Kleine-König
2011-01-07  9:40             ` Uwe Kleine-König
2011-01-08 13:15   ` Sascha Hauer
2011-01-08 13:15     ` Sascha Hauer
2011-01-10  2:43     ` Jeremy Kerr
2011-01-10  2:43       ` Jeremy Kerr
2011-01-10 10:41       ` Sascha Hauer
2011-01-10 10:41         ` Sascha Hauer
2011-01-10 11:00         ` Russell King - ARM Linux
2011-01-10 11:00           ` Russell King - ARM Linux
2011-01-11  0:54           ` Jeremy Kerr
2011-01-11  0:54             ` Jeremy Kerr
2011-01-16  7:26             ` Grant Likely
2011-01-16  7:26               ` Grant Likely
2011-01-16 20:41               ` Ryan Mallon
2011-01-16 20:41                 ` Ryan Mallon
2011-01-16 21:07                 ` Uwe Kleine-König
2011-01-16 21:07                   ` Uwe Kleine-König
2011-01-16 21:39                   ` Ryan Mallon
2011-01-16 21:39                     ` Ryan Mallon
2011-01-11 10:16   ` Sascha Hauer
2011-01-11 10:16     ` Sascha Hauer
2011-01-11 10:27     ` Jeremy Kerr
2011-01-11 10:27       ` Jeremy Kerr
2011-01-11 11:22       ` Sascha Hauer
2011-01-11 11:22         ` Sascha Hauer
2011-01-18  8:44         ` Paul Mundt
2011-01-18  8:44           ` Paul Mundt
2011-01-18  9:21           ` Sascha Hauer
2011-01-18  9:21             ` Sascha Hauer
2011-01-18  9:23             ` Paul Mundt
2011-01-18  9:23               ` Paul Mundt
2011-01-18 12:21   ` Russell King - ARM Linux
2011-01-18 12:21     ` Russell King - ARM Linux
2011-01-05  3:55 ` [PATCH 0/2] Common struct clk implementation, v10 Jeremy Kerr
2011-01-07  1:33 ` Ben Dooks
2011-01-07  9:49   ` Uwe Kleine-König
  -- strict thread matches above, loose matches on Subject: below --
2011-02-21  2:50 [PATCH 0/2] Common struct clk implementation, v13 Jeremy Kerr
2011-02-21  2:50 ` [PATCH 1/2] Add a common struct clk Jeremy Kerr
2011-02-21  2:50   ` Jeremy Kerr
2011-02-21  2:50   ` Jeremy Kerr
2011-02-22 20:17   ` 
2011-02-22 20:17     ` Uwe Kleine-König
2011-02-22 20:17     ` Uwe Kleine-König
2011-02-23  2:49     ` Jeremy Kerr
2011-02-23  2:49       ` Jeremy Kerr
2011-02-23  2:49       ` Jeremy Kerr
2011-03-03  6:40   ` [PATCH 0/2] Common struct clk implementation, v14 Jeremy Kerr
2011-03-03  6:40     ` [PATCH 1/2] Add a common struct clk Jeremy Kerr
2011-03-03  6:40       ` Jeremy Kerr
2011-03-03  6:40       ` Jeremy Kerr
2011-04-14 12:49       ` Tony Lindgren
2011-04-14 12:49         ` Tony Lindgren
2011-04-14 12:49         ` Tony Lindgren
2011-01-05  3:18 [PATCH 0/2] Common struct clk implementation, v10 Jeremy Kerr
2011-01-05  3:18 ` [PATCH 1/2] Add a common struct clk Jeremy Kerr
2010-12-08  2:08 [PATCH 0/2] Common struct clk implementation, v8 Jeremy Kerr
2010-12-08  2:08 ` [PATCH 1/2] Add a common struct clk Jeremy Kerr
2010-12-08  2:08   ` Jeremy Kerr
2010-12-08  2:05 Jeremy Kerr
2010-12-08  2:05 ` Jeremy Kerr
2010-12-08 10:21 ` Uwe Kleine-König
2010-12-08 10:21   ` Uwe Kleine-König
2010-12-10  1:58   ` Jeremy Kerr
2010-12-10  1:58     ` Jeremy Kerr
2010-12-10  9:21     ` Uwe Kleine-König
2010-07-12  2:37 [PATCH 0/2] Common struct clk implementation, v6 Jeremy Kerr
2010-07-12  2:37 ` [PATCH 1/2] Add a common struct clk Jeremy Kerr
2010-07-12  2:37   ` Jeremy Kerr
2010-06-21  5:35 [PATCH 0/2] Common struct clk implementation, v5 Jeremy Kerr
2010-06-21  5:35 ` [PATCH 1/2] Add a common struct clk Jeremy Kerr
2010-06-21  5:35   ` Jeremy Kerr
2010-06-22  4:43   ` Baruch Siach
2010-06-22  4:43     ` Baruch Siach
2010-07-05  2:33   ` MyungJoo Ham
2010-07-05  2:33     ` MyungJoo Ham
2010-07-12  2:19     ` Jeremy Kerr
2010-07-12  2:19       ` Jeremy Kerr

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.