Skip to contentSkip to conversation

clock (clk.h) framework for mpc52xx

PATCH Superseded Domen Puncer 5 participants 20 messages Jul 11, 2007 – Sep 20, 2007

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover clock (clk.h) framework for mpc52xx

Hi!

Clock managing in mpc52xx psc spi driver grew a bit, to do it "the right way" ;-)

1/3 - Generic powerpc clock interface, platforms that implement
it should fill clk_functions.
This is needed because powerpc supports multiple platforms in same kernel image.
2/3 - psc spi clocks (mclk) for mpc52xx
3/3 - Use the spi clocks in mpc52xx psc spi driver.

Thanks to David Brownell and Sylvain Munaut for feedback and help on patches.

Domen

#1 lore raw

PATCH 1/3 powerpc clk.h interface for platforms

clk interface for arch/powerpc, platforms should fill clk_functions.

---
 arch/powerpc/kernel/Makefile        |    3 -
 arch/powerpc/kernel/clock.c         |   82 ++++++++++++++++++++++++++++++++++++
 include/asm-powerpc/clk_interface.h |   20 ++++++++
 3 files changed, 104 insertions(+), 1 deletion(-)
arch/powerpc/kernel/clock.c new file +82 -0
Index: work-powerpc.git/arch/powerpc/kernel/clock.c
===================================================================
@@ -0,0 +1,82 @@
+/*
+ * Dummy clk implementations for powerpc.
+ * These need to be overridden in platform code.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <asm/clk_interface.h>
+
+struct clk_interface clk_functions;
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	if (clk_functions.clk_get)
+		return clk_functions.clk_get(dev, id);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk_functions.clk_put)
+		clk_functions.clk_put(clk);
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+	if (clk_functions.clk_enable)
+		return clk_functions.clk_enable(clk);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (clk_functions.clk_disable)
+		clk_functions.clk_disable(clk);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk_functions.clk_get_rate)
+		return clk_functions.clk_get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk_functions.clk_round_rate)
+		return clk_functions.clk_round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk_functions.clk_set_rate)
+		return clk_functions.clk_set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk_functions.clk_get_parent)
+		return clk_functions.clk_get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk_functions.clk_set_parent)
+		return clk_functions.clk_set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_parent);
include/asm-powerpc/clk_interface.h new file +20 -0
Index: work-powerpc.git/include/asm-powerpc/clk_interface.h
===================================================================
@@ -0,0 +1,20 @@
+#ifndef __ASM_POWERPC_CLK_INTERFACE_H
+#define __ASM_POWERPC_CLK_INTERFACE_H
+
+#include <linux/clk.h>
+
+struct clk_interface {
+	struct clk*	(*clk_get)	(struct device *dev, const char *id);
+	int		(*clk_enable)	(struct clk *clk);
+	void		(*clk_disable)	(struct clk *clk);
+	unsigned long	(*clk_get_rate)	(struct clk *clk);
+	void		(*clk_put)	(struct clk *clk);
+	long		(*clk_round_rate) (struct clk *clk, unsigned long rate);
+	int 		(*clk_set_rate)	(struct clk *clk, unsigned long rate);
+	int		(*clk_set_parent) (struct clk *clk, struct clk *parent);
+	struct clk*	(*clk_get_parent) (struct clk *clk);
+};
+
+extern struct clk_interface clk_functions;
+
+#endif /* __ASM_POWERPC_CLK_INTERFACE_H */
arch/powerpc/kernel/Makefile +2 -1
Index: work-powerpc.git/arch/powerpc/kernel/Makefile
===================================================================
@@ -12,7 +12,8 @@ endif
 
 obj-y				:= semaphore.o cputable.o ptrace.o syscalls.o \
 				   irq.o align.o signal_32.o pmc.o vdso.o \
-				   init_task.o process.o systbl.o idle.o
+				   init_task.o process.o systbl.o idle.o \
+				   clock.o
 obj-y				+= vdso32/
 obj-$(CONFIG_PPC64)		+= setup_64.o binfmt_elf32.o sys_ppc32.o \
 				   signal_64.o ptrace32.o \
#2 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

Quoted 2 lines · Domen Puncer

clk interface for arch/powerpc, platforms should fill clk_functions.

Umm, this is about the fifth almost identical implementation of the clk_ functions. Please, please put it into common code.

And talk to the mips folks which just got a similar comment from me.

#3 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

Quoted 8 lines · Christoph Hellwig
Quoted 2 lines · Domen Puncer

clk interface for arch/powerpc, platforms should fill clk_functions.

Umm, this is about the fifth almost identical implementation of the clk_ functions. Please, please put it into common code.

And talk to the mips folks which just got a similar comment from me.

You mean like a lib/clock.c core, rather than an opsvector?

ISTR that allowing custom platform-specific implementations was intended to be a feature. But it's also true that some folks see lack of shared implementation code as a drawback; so I've CC'd Russell King (who originated the interface for ARM platforms).

- Dave

#4 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

Quoted 6 lines · David Brownell
Quoted 4 lines

Umm, this is about the fifth almost identical implementation of the clk_ functions. Please, please put it into common code.

And talk to the mips folks which just got a similar comment from me.

You mean like a lib/clock.c core, rather than an opsvector?

I mean an ops vector and surrounding wrappers. Every architecture is reimplementing their own dispatch table which is rather annoying.

What would a lib/clock.c do?

#5 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

Quoted 10 lines · Christoph Hellwig
Quoted 6 lines · David Brownell
Quoted 4 lines

Umm, this is about the fifth almost identical implementation of the clk_ functions. Please, please put it into common code.

And talk to the mips folks which just got a similar comment from me.

You mean like a lib/clock.c core, rather than an opsvector?

I mean an ops vector and surrounding wrappers. Every architecture is reimplementing their own dispatch table which is rather annoying.

ARM doesn't. :)

But then, nobody expects one kernel to support more than one vendor's ARM chips; or usually, more than one generation of that vendor's chips. So any dispatch table is specific to a given platform, and tuned to its quirks. Not much to share between OMAP and AT91, for example, except in some cases maybe an arm926ejs block.

Quoted 1 line

What would a lib/clock.c do?

Some folk have suggested defining a core "struct clk {...}" with some of the basics -- refcount, parent, maybe enough to support the clk_get() lookup or even more -- so that the more obvious stuff doesn't need constant re-implementation, and so that new implementations become easier. Platforms would wrap that with whatever extensions they need.

I've not seen a solid proposal for such a thing, and it's not clear to me how that would play with with older code (e.g. any of the ARM implementations).

And I'm sure there are other suggestions ... I was mostly just wondering just what you were suggesting.

- Dave

#6 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

Quoted 12 lines · David Brownell
Quoted 10 lines · Christoph Hellwig
Quoted 6 lines · David Brownell
Quoted 4 lines

Umm, this is about the fifth almost identical implementation of the clk_ functions. Please, please put it into common code.

And talk to the mips folks which just got a similar comment from me.

You mean like a lib/clock.c core, rather than an opsvector?

I mean an ops vector and surrounding wrappers. Every architecture is reimplementing their own dispatch table which is rather annoying.

Quoted 8 lines

ARM doesn't. :)

But then, nobody expects one kernel to support more than one vendor's ARM chips; or usually, more than one generation of that vendor's chips. So any dispatch table is specific to a given platform, and tuned to its quirks. Not much to share between OMAP and AT91, for example, except in some cases maybe an arm926ejs block.

And also the information stored within a 'struct clk' is very platform dependent. In the most basic situation, 'struct clk' may not actually be a structure, but the clock rate. All functions with the exception of clk_get() and clk_get_rate() could well be no-ops, clk_get() just returns the 'struct clk' representing the rate and 'clk_get_rate' returns that as an integer.

More complex setups might want 'struct clk' to contain the address of a clock enable register, the bit position to enable that clock source, the clock rate, a refcount, and so on, all of which would be utterly useless for a platform which had fixed rate clocks.

Quoted 3 lines

I've not seen a solid proposal for such a thing, and it's not clear to me how that would play with with older code (e.g. any of the ARM implementations).

If people are implementing their own incompatible changes without reference to the API they're invalid implementations as far as I'm concerned. If they can't bothered to lift a finger to even _talk_ to me about their requirements they just don't have any say concerning any future developments IMO.

IOW, talk to me and I'll talk back. Ignore me and I'll ignore them.

Signature · 3 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:
#7 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

Quoted 2 lines · Russell King

IOW, talk to me and I'll talk back. Ignore me and I'll ignore them.

Exactly why I cc'd you ... if folk want any more sharable cross-platform code than just the clk.h interface, I expect you'll have useful comments.

- Dave

#8 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

In reply to Russell King
Quoted 29 lines · Russell King
Quoted 12 lines · David Brownell
Quoted 10 lines · Christoph Hellwig
Quoted 6 lines · David Brownell
Quoted 4 lines

Umm, this is about the fifth almost identical implementation of the clk_ functions. Please, please put it into common code.

And talk to the mips folks which just got a similar comment from me.

You mean like a lib/clock.c core, rather than an opsvector?

I mean an ops vector and surrounding wrappers. Every architecture is reimplementing their own dispatch table which is rather annoying.

Quoted 8 lines

ARM doesn't. :)

But then, nobody expects one kernel to support more than one vendor's ARM chips; or usually, more than one generation of that vendor's chips. So any dispatch table is specific to a given platform, and tuned to its quirks. Not much to share between OMAP and AT91, for example, except in some cases maybe an arm926ejs block.

And also the information stored within a 'struct clk' is very platform dependent. In the most basic situation, 'struct clk' may not actually be a structure, but the clock rate. All functions with the exception of clk_get() and clk_get_rate() could well be no-ops, clk_get() just returns the 'struct clk' representing the rate and 'clk_get_rate' returns that as an integer.

Quoted 4 lines

More complex setups might want 'struct clk' to contain the address of a clock enable register, the bit position to enable that clock source, the clock rate, a refcount, and so on, all of which would be utterly useless for a platform which had fixed rate clocks.

The patch that triggered this discussion is at the end. It doesn't make any assumption on struct clk, it's just a wrapper around functions from clk.h.
Point of this patch was to abstract exported functions, since arch/powerpc/ can support multiple platfroms in one binary.

Quoted 10 lines
Quoted 4 lines

I've not seen a solid proposal for such a thing, and it's not clear to me how that would play with with older code (e.g. any of the ARM implementations).

If people are implementing their own incompatible changes without reference to the API they're invalid implementations as far as I'm concerned. If they can't bothered to lift a finger to even _talk_ to me about their requirements they just don't have any say concerning any future developments IMO.

My changes were implemented according to clk.h API.
And honestly, I just wanted to rework clocks in some SPI driver and others made me do all the clk work. ;-)

Domen

Quoted 7 lines

IOW, talk to me and I'll talk back. Ignore me and I'll ignore them.

Signature · 3 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

clk interface for arch/powerpc, platforms should fill clk_functions.

---
 arch/powerpc/kernel/Makefile        |    3 -
 arch/powerpc/kernel/clock.c         |   82 ++++++++++++++++++++++++++++++++++++
 include/asm-powerpc/clk_interface.h |   20 ++++++++
 3 files changed, 104 insertions(+), 1 deletion(-)
arch/powerpc/kernel/clock.c new file +82 -0
Index: work-powerpc.git/arch/powerpc/kernel/clock.c
===================================================================
@@ -0,0 +1,82 @@
+/*
+ * Dummy clk implementations for powerpc.
+ * These need to be overridden in platform code.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <asm/clk_interface.h>
+
+struct clk_interface clk_functions;
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	if (clk_functions.clk_get)
+		return clk_functions.clk_get(dev, id);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk_functions.clk_put)
+		clk_functions.clk_put(clk);
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+	if (clk_functions.clk_enable)
+		return clk_functions.clk_enable(clk);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (clk_functions.clk_disable)
+		clk_functions.clk_disable(clk);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk_functions.clk_get_rate)
+		return clk_functions.clk_get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk_functions.clk_round_rate)
+		return clk_functions.clk_round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk_functions.clk_set_rate)
+		return clk_functions.clk_set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk_functions.clk_get_parent)
+		return clk_functions.clk_get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk_functions.clk_set_parent)
+		return clk_functions.clk_set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_parent);
include/asm-powerpc/clk_interface.h new file +20 -0
Index: work-powerpc.git/include/asm-powerpc/clk_interface.h
===================================================================
@@ -0,0 +1,20 @@
+#ifndef __ASM_POWERPC_CLK_INTERFACE_H
+#define __ASM_POWERPC_CLK_INTERFACE_H
+
+#include <linux/clk.h>
+
+struct clk_interface {
+	struct clk*	(*clk_get)	(struct device *dev, const char *id);
+	int		(*clk_enable)	(struct clk *clk);
+	void		(*clk_disable)	(struct clk *clk);
+	unsigned long	(*clk_get_rate)	(struct clk *clk);
+	void		(*clk_put)	(struct clk *clk);
+	long		(*clk_round_rate) (struct clk *clk, unsigned long rate);
+	int 		(*clk_set_rate)	(struct clk *clk, unsigned long rate);
+	int		(*clk_set_parent) (struct clk *clk, struct clk *parent);
+	struct clk*	(*clk_get_parent) (struct clk *clk);
+};
+
+extern struct clk_interface clk_functions;
+
+#endif /* __ASM_POWERPC_CLK_INTERFACE_H */
arch/powerpc/kernel/Makefile +2 -1
Index: work-powerpc.git/arch/powerpc/kernel/Makefile
===================================================================
@@ -12,7 +12,8 @@ endif
 
 obj-y				:= semaphore.o cputable.o ptrace.o syscalls.o \
 				   irq.o align.o signal_32.o pmc.o vdso.o \
-				   init_task.o process.o systbl.o idle.o
+				   init_task.o process.o systbl.o idle.o \
+				   clock.o
 obj-y				+= vdso32/
 obj-$(CONFIG_PPC64)		+= setup_64.o binfmt_elf32.o sys_ppc32.o \
 				   signal_64.o ptrace32.o \
#9 lore raw

Generic clk.h wrappers? [Was: Re: [PATCH 1/3] powerpc clk.h interface for platforms]

Quoted 35 lines · Domen Puncer
Quoted 29 lines · Russell King
Quoted 12 lines · David Brownell
Quoted 10 lines · Christoph Hellwig
Quoted 6 lines · David Brownell
Quoted 4 lines

Umm, this is about the fifth almost identical implementation of the clk_ functions. Please, please put it into common code.

And talk to the mips folks which just got a similar comment from me.

You mean like a lib/clock.c core, rather than an opsvector?

I mean an ops vector and surrounding wrappers. Every architecture is reimplementing their own dispatch table which is rather annoying.

Quoted 8 lines

ARM doesn't. :)

But then, nobody expects one kernel to support more than one vendor's ARM chips; or usually, more than one generation of that vendor's chips. So any dispatch table is specific to a given platform, and tuned to its quirks. Not much to share between OMAP and AT91, for example, except in some cases maybe an arm926ejs block.

And also the information stored within a 'struct clk' is very platform dependent. In the most basic situation, 'struct clk' may not actually be a structure, but the clock rate. All functions with the exception of clk_get() and clk_get_rate() could well be no-ops, clk_get() just returns the 'struct clk' representing the rate and 'clk_get_rate' returns that as an integer.

Quoted 4 lines

More complex setups might want 'struct clk' to contain the address of a clock enable register, the bit position to enable that clock source, the clock rate, a refcount, and so on, all of which would be utterly useless for a platform which had fixed rate clocks.

Quoted 5 lines

The patch that triggered this discussion is at the end. It doesn't make any assumption on struct clk, it's just a wrapper around functions from clk.h.
Point of this patch was to abstract exported functions, since arch/powerpc/ can support multiple platfroms in one binary.

So... the thread just ended without any consensus, ACK or whatever.

Choices I see:
- have EXPORT_SYMBOL for clk.h functions in ie. lib/clock.c and have every implemenation fill some global struct.
- leave this patch as it is, abstraction only for arch/powerpc/.
- or I can just forget about this, and leave it for the next sucker who will want nicer clock handling in some driver.

Domen

#10 lore raw

Re: Generic clk.h wrappers? [Was: Re: [PATCH 1/3] powerpc clk.h interface for platforms]

Quoted 5 lines · Domen Puncer
Quoted 4 lines

It doesn't make any assumption on struct clk, it's just a wrapper around functions from clk.h.
Point of this patch was to abstract exported functions, since arch/powerpc/ can support multiple platfroms in one binary.

Quoted 8 lines

So... the thread just ended without any consensus, ACK or whatever.

Choices I see:
- have EXPORT_SYMBOL for clk.h functions in ie. lib/clock.c and have every implemenation fill some global struct.
- leave this patch as it is, abstraction only for arch/powerpc/.
- or I can just forget about this, and leave it for the next sucker who will want nicer clock handling in some driver

It seems like arm really wants this optimized to the last cycle and no abstraction inbetween so we're probably stuck with the status
quo. I'm pretty sure this will get too messy sooner and later and
people will clean the mess up, but due to the political issues I don't think it's fair to put that burden on you just for submitting the powerpc implementation.

So, please leave the patch as-is.

#11 lore raw

Re: Generic clk.h wrappers? [Was: Re: [PATCH 1/3] powerpc clk.h interface for platforms]

Quoted 6 lines · Christoph Hellwig
Quoted 5 lines · Domen Puncer
Quoted 4 lines

It doesn't make any assumption on struct clk, it's just a wrapper around functions from clk.h.
Point of this patch was to abstract exported functions, since arch/powerpc/ can support multiple platfroms in one binary.

Quoted 6 lines
Quoted 6 lines

So... the thread just ended without any consensus, ACK or whatever.

Choices I see:
- have EXPORT_SYMBOL for clk.h functions in ie. lib/clock.c and have every implemenation fill some global struct.
- leave this patch as it is, abstraction only for arch/powerpc/.

That seems the best solution for now, I agree.

Quoted 12 lines
Quoted 2 lines

- or I can just forget about this, and leave it for the next sucker who will want nicer clock handling in some driver

It seems like arm really wants this optimized to the last cycle and no abstraction inbetween so we're probably stuck with the status
quo. I'm pretty sure this will get too messy sooner and later and
people will clean the mess up, but due to the political issues I don't think it's fair to put that burden on you just for submitting the powerpc implementation.

So, please leave the patch as-is.

#12 lore raw

Re: Generic clk.h wrappers? [Was: Re: [PATCH 1/3] powerpc clk.h interface for platforms]

Quoted 7 lines · David Brownell
Quoted 6 lines · Christoph Hellwig
Quoted 5 lines · Domen Puncer
Quoted 4 lines

It doesn't make any assumption on struct clk, it's just a wrapper around functions from clk.h.
Point of this patch was to abstract exported functions, since arch/powerpc/ can support multiple platfroms in one binary.

Quoted 8 lines
Quoted 6 lines
Quoted 6 lines

So... the thread just ended without any consensus, ACK or whatever.

Choices I see:
- have EXPORT_SYMBOL for clk.h functions in ie. lib/clock.c and have every implemenation fill some global struct.
- leave this patch as it is, abstraction only for arch/powerpc/.

That seems the best solution for now, I agree.

I've not been avoiding replying further to this thread in spite, it's just that I've not had any time what so ever to look at this further. It's very low priority for me at the moment, so it's getting zero time, and will continue to be in that state for at least the next month and a bit. Sorry.

Signature · 3 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:
#13 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

In reply to Domen Puncer

Hi!

Paul, what do you say about this?
Sylvain suggested it could also be integrated with define_machine interface.

If it's OK, it would be cool if it got merged in next release cycle.

Domen

Quoted 141 lines · Domen Puncer

clk interface for arch/powerpc, platforms should fill clk_functions.

---
 arch/powerpc/kernel/Makefile        |    3 -
 arch/powerpc/kernel/clock.c         |   82 ++++++++++++++++++++++++++++++++++++
 include/asm-powerpc/clk_interface.h |   20 ++++++++
 3 files changed, 104 insertions(+), 1 deletion(-)

Index: work-powerpc.git/arch/powerpc/kernel/clock.c
===================================================================

arch/powerpc/kernel/clock.c new file +82 -0
@@ -0,0 +1,82 @@
+/*
+ * Dummy clk implementations for powerpc.
+ * These need to be overridden in platform code.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <asm/clk_interface.h>
+
+struct clk_interface clk_functions;
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	if (clk_functions.clk_get)
+		return clk_functions.clk_get(dev, id);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk_functions.clk_put)
+		clk_functions.clk_put(clk);
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+	if (clk_functions.clk_enable)
+		return clk_functions.clk_enable(clk);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (clk_functions.clk_disable)
+		clk_functions.clk_disable(clk);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk_functions.clk_get_rate)
+		return clk_functions.clk_get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk_functions.clk_round_rate)
+		return clk_functions.clk_round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk_functions.clk_set_rate)
+		return clk_functions.clk_set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk_functions.clk_get_parent)
+		return clk_functions.clk_get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk_functions.clk_set_parent)
+		return clk_functions.clk_set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_parent);

Index: work-powerpc.git/include/asm-powerpc/clk_interface.h
===================================================================

include/asm-powerpc/clk_interface.h new file +20 -0
@@ -0,0 +1,20 @@
+#ifndef __ASM_POWERPC_CLK_INTERFACE_H
+#define __ASM_POWERPC_CLK_INTERFACE_H
+
+#include <linux/clk.h>
+
+struct clk_interface {
+	struct clk*	(*clk_get)	(struct device *dev, const char *id);
+	int		(*clk_enable)	(struct clk *clk);
+	void		(*clk_disable)	(struct clk *clk);
+	unsigned long	(*clk_get_rate)	(struct clk *clk);
+	void		(*clk_put)	(struct clk *clk);
+	long		(*clk_round_rate) (struct clk *clk, unsigned long rate);
+	int 		(*clk_set_rate)	(struct clk *clk, unsigned long rate);
+	int		(*clk_set_parent) (struct clk *clk, struct clk *parent);
+	struct clk*	(*clk_get_parent) (struct clk *clk);
+};
+
+extern struct clk_interface clk_functions;
+
+#endif /* __ASM_POWERPC_CLK_INTERFACE_H */

Index: work-powerpc.git/arch/powerpc/kernel/Makefile
===================================================================

arch/powerpc/kernel/Makefile +2 -1
@@ -12,7 +12,8 @@ endif
 
 obj-y				:= semaphore.o cputable.o ptrace.o syscalls.o \
 				   irq.o align.o signal_32.o pmc.o vdso.o \
-				   init_task.o process.o systbl.o idle.o
+				   init_task.o process.o systbl.o idle.o \
+				   clock.o
 obj-y				+= vdso32/
 obj-$(CONFIG_PPC64)		+= setup_64.o binfmt_elf32.o sys_ppc32.o \
 				   signal_64.o ptrace32.o \

_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev

#14 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

Quoted 3 lines · Domen Puncer

Paul, what do you say about this?
Sylvain suggested it could also be integrated with define_machine interface.

As it stands, your patch adds the clk_* functions on all platforms. What platforms would actually want to use them?

Paul.

#15 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

Quoted 8 lines · Paul Mackerras
Quoted 3 lines · Domen Puncer

Paul, what do you say about this?
Sylvain suggested it could also be integrated with define_machine interface.

As it stands, your patch adds the clk_* functions on all platforms. What platforms would actually want to use them?

52xx
Reason for adding it to all was that EXPORT_SYMBOL's would clash if one were to add clk support for another platform.

Domen

Quoted 2 lines

Paul.

#16 lore raw

Re: [PATCH 1/3] powerpc clk.h interface for platforms

Quoted 3 lines · Domen Puncer

52xx
Reason for adding it to all was that EXPORT_SYMBOL's would clash if one were to add clk support for another platform.

What I meant was, why aren't you using a config symbol so that we don't build it on platforms that don't need any "clk" support at all?

Paul.

#17 lore raw

PATCH v2 1/3 powerpc clk.h interface for platforms

clk interface for arch/powerpc, platforms should fill clk_functions.

---

Quoted 8 lines · Paul Mackerras
Quoted 3 lines · Domen Puncer

52xx
Reason for adding it to all was that EXPORT_SYMBOL's would clash if one were to add clk support for another platform.

What I meant was, why aren't you using a config symbol so that we don't build it on platforms that don't need any "clk" support at all?

Right, doh!

Quoted 2 lines

Paul.

 arch/powerpc/Kconfig                |    4 +
 arch/powerpc/kernel/Makefile        |    1 
 arch/powerpc/kernel/clock.c         |   82 ++++++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/52xx/Kconfig |    1 
 include/asm-powerpc/clk_interface.h |   20 ++++++++
 5 files changed, 108 insertions(+)
arch/powerpc/kernel/clock.c new file +82 -0
Index: linux.git/arch/powerpc/kernel/clock.c
===================================================================
@@ -0,0 +1,82 @@
+/*
+ * Dummy clk implementations for powerpc.
+ * These need to be overridden in platform code.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <asm/clk_interface.h>
+
+struct clk_interface clk_functions;
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	if (clk_functions.clk_get)
+		return clk_functions.clk_get(dev, id);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+	if (clk_functions.clk_put)
+		clk_functions.clk_put(clk);
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+	if (clk_functions.clk_enable)
+		return clk_functions.clk_enable(clk);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	if (clk_functions.clk_disable)
+		clk_functions.clk_disable(clk);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk_functions.clk_get_rate)
+		return clk_functions.clk_get_rate(clk);
+	return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk_functions.clk_round_rate)
+		return clk_functions.clk_round_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk_functions.clk_set_rate)
+		return clk_functions.clk_set_rate(clk, rate);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (clk_functions.clk_get_parent)
+		return clk_functions.clk_get_parent(clk);
+	return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	if (clk_functions.clk_set_parent)
+		return clk_functions.clk_set_parent(clk, parent);
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_parent);
include/asm-powerpc/clk_interface.h new file +20 -0
Index: linux.git/include/asm-powerpc/clk_interface.h
===================================================================
@@ -0,0 +1,20 @@
+#ifndef __ASM_POWERPC_CLK_INTERFACE_H
+#define __ASM_POWERPC_CLK_INTERFACE_H
+
+#include <linux/clk.h>
+
+struct clk_interface {
+	struct clk*	(*clk_get)	(struct device *dev, const char *id);
+	int		(*clk_enable)	(struct clk *clk);
+	void		(*clk_disable)	(struct clk *clk);
+	unsigned long	(*clk_get_rate)	(struct clk *clk);
+	void		(*clk_put)	(struct clk *clk);
+	long		(*clk_round_rate) (struct clk *clk, unsigned long rate);
+	int 		(*clk_set_rate)	(struct clk *clk, unsigned long rate);
+	int		(*clk_set_parent) (struct clk *clk, struct clk *parent);
+	struct clk*	(*clk_get_parent) (struct clk *clk);
+};
+
+extern struct clk_interface clk_functions;
+
+#endif /* __ASM_POWERPC_CLK_INTERFACE_H */
arch/powerpc/kernel/Makefile +1 -0
Index: linux.git/arch/powerpc/kernel/Makefile
===================================================================
@@ -24,6 +24,7 @@ obj-$(CONFIG_PPC64)		+= vdso64/
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
 obj-$(CONFIG_PPC_970_NAP)	+= idle_power4.o
 obj-$(CONFIG_PPC_OF)		+= of_device.o of_platform.o prom_parse.o
+obj-$(CONFIG_PPC_CLOCK)		+= clock.o
 procfs-$(CONFIG_PPC64)		:= proc_ppc64.o
 obj-$(CONFIG_PROC_FS)		+= $(procfs-y)
 rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI)	:= rtas_pci.o
arch/powerpc/Kconfig +4 -0
Index: linux.git/arch/powerpc/Kconfig
===================================================================
@@ -664,3 +664,7 @@ config KEYS_COMPAT
 	default y
 
 source "crypto/Kconfig"
+
+config PPC_CLOCK
+	bool
+	default n
arch/powerpc/platforms/52xx/Kconfig +1 -0
Index: linux.git/arch/powerpc/platforms/52xx/Kconfig
===================================================================
@@ -1,6 +1,7 @@
 config PPC_MPC52xx
 	bool
 	select FSL_SOC
+	select PPC_CLOCK
 	default n
 
 config PPC_MPC5200
#18 lore raw

PATCH 2/3 mpc52xx clk.h interface

In reply to Domen Puncer

clk.h interface for mpc52xx
Currently only psc_mclks are defined.

---
 arch/powerpc/platforms/52xx/Makefile         |    2 
 arch/powerpc/platforms/52xx/mpc52xx_clock.c  |  352 +++++++++++++++++++++++++++
 arch/powerpc/platforms/52xx/mpc52xx_common.c |    3 
 include/asm-powerpc/mpc52xx.h                |    2 
 4 files changed, 358 insertions(+), 1 deletion(-)
arch/powerpc/platforms/52xx/Makefile +1 -1
Index: work-powerpc.git/arch/powerpc/platforms/52xx/Makefile
===================================================================
@@ -2,7 +2,7 @@
 # Makefile for 52xx based boards
 #
 ifeq ($(CONFIG_PPC_MERGE),y)
-obj-y				+= mpc52xx_pic.o mpc52xx_common.o
+obj-y				+= mpc52xx_pic.o mpc52xx_common.o mpc52xx_clock.o
 obj-$(CONFIG_PCI)		+= mpc52xx_pci.o
 endif
 
arch/powerpc/platforms/52xx/mpc52xx_clock.c new file +352 -0

352 lines not on this page · raw message

arch/powerpc/platforms/52xx/mpc52xx_common.c +3 -0
Index: work-powerpc.git/arch/powerpc/platforms/52xx/mpc52xx_common.c
===================================================================
@@ -110,6 +110,9 @@ mpc52xx_setup_cpu(void)
 	    transaction and re-enable it afterwards ...) */
 	out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS);
 
+	/* setup clk system */
+	mpc52xx_clock_init();
+
 	/* Unmap zones */
 unmap_regs:
 	if (cdm) iounmap(cdm);
include/asm-powerpc/mpc52xx.h +2 -0
Index: work-powerpc.git/include/asm-powerpc/mpc52xx.h
===================================================================
@@ -274,5 +274,7 @@ extern char saved_sram[0x4000]; /* reuse
 #endif
 #endif /* CONFIG_PM */
 
+extern int __init mpc52xx_clock_init(void);
+
 #endif /* __ASM_POWERPC_MPC52xx_H__ */
 
#19 lore raw

PATCH 3/3 mpc52xx_psc_spi: use clk.h subsystem

In reply to Domen Puncer

Use clocks subsystem in spi driver.

---
 drivers/spi/mpc52xx_psc_spi.c |   64 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 57 insertions(+), 7 deletions(-)
drivers/spi/mpc52xx_psc_spi.c +57 -7
Index: work-powerpc.git/drivers/spi/mpc52xx_psc_spi.c
===================================================================
@@ -18,6 +18,7 @@
 
 #if defined(CONFIG_PPC_MERGE)
 #include <asm/of_platform.h>
+#include <linux/clk.h>
 #else
 #include <linux/platform_device.h>
 #endif
@@ -53,6 +54,8 @@ struct mpc52xx_psc_spi {
 	spinlock_t lock;
 
 	struct completion done;
+
+	struct clk *clk;
 };
 
 /* controller state */
@@ -85,6 +88,13 @@ static void mpc52xx_psc_spi_activate_cs(
 	u32 sicr;
 	u16 ccr;
 
+#ifdef CONFIG_PPC_MERGE
+	u8 bitclkdiv = 2;	/* minimum bitclkdiv */
+	int speed = cs->speed_hz ? cs->speed_hz : 1000000;
+	int mclk;
+	int system;
+#endif
+
 	sicr = in_be32(&psc->sicr);
 
 	/* Set clock phase and polarity */
@@ -106,13 +116,39 @@ static void mpc52xx_psc_spi_activate_cs(
 	/* Set clock frequency and bits per word
 	 * Because psc->ccr is defined as 16bit register instead of 32bit
 	 * just set the lower byte of BitClkDiv
+	 * Because BitClkDiv is 8-bit on mpc5200. Lets stay compatible.
 	 */
 	ccr = in_be16(&psc->ccr);
 	ccr &= 0xFF00;
+
+#ifdef CONFIG_PPC_MERGE
+	/*
+	 * pscclk = mclk/(bitclkdiv+1))		bitclkdiv is 8-bit, >= 2
+	 * mclk = fsys/(mclkdiv+1)		mclkdiv is 9-bit, >= 1
+	 * as mclkdiv has higher precision, we want is as big as possible
+	 * => we get < 0.002*clock error
+	 */
+
+	system = clk_get_rate(clk_get_parent(mps->clk));
+	mclk = speed * (bitclkdiv+1);
+	if (system/mclk > 512) { /* bigger than mclkdiv */
+		bitclkdiv = (system/512) / speed;
+		mclk = speed * (bitclkdiv+1);
+	}
+
+	if (clk_set_rate(mps->clk, mclk))
+		dev_err(&spi->dev, "couldn't set psc_mclk's rate\n");
+
+	dev_info(&spi->dev, "clock: wanted: %i, got: %li\n", speed,
+			clk_round_rate(mps->clk, mclk) / (bitclkdiv+1));
+
+	ccr |= bitclkdiv;
+#else
 	if (cs->speed_hz)
 		ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
 	else /* by default SPI Clk 1MHz */
 		ccr |= (MCLK / 1000000 - 1) & 0xFF;
+#endif
 	out_be16(&psc->ccr, ccr);
 	mps->bits_per_word = cs->bits_per_word;
 
@@ -321,20 +357,17 @@ static void mpc52xx_psc_spi_cleanup(stru
 
 static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
 {
+	struct mpc52xx_psc __iomem *psc = mps->psc;
+	int ret = 0;
+
+#if !defined(CONFIG_PPC_MERGE)
 	struct mpc52xx_cdm __iomem *cdm;
 	struct mpc52xx_gpio __iomem *gpio;
-	struct mpc52xx_psc __iomem *psc = mps->psc;
 	u32 ul;
 	u32 mclken_div;
-	int ret = 0;
 
-#if defined(CONFIG_PPC_MERGE)
-	cdm = mpc52xx_find_and_map("mpc5200-cdm");
-	gpio = mpc52xx_find_and_map("mpc5200-gpio");
-#else
 	cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
 	gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
-#endif
 	if (!cdm || !gpio) {
 		printk(KERN_ERR "Error mapping CDM/GPIO\n");
 		ret = -EFAULT;
@@ -390,6 +423,7 @@ static int mpc52xx_psc_spi_port_config(i
 		ret = -EINVAL;
 		goto unmap_regs;
 	}
+#endif
 
 	/* Reset the PSC into a known state */
 	out_8(&psc->command, MPC52xx_PSC_RST_RX);
@@ -413,11 +447,13 @@ static int mpc52xx_psc_spi_port_config(i
 
 	mps->bits_per_word = 8;
 
+#if !defined(CONFIG_PPC_MERGE)
 unmap_regs:
 	if (cdm)
 		iounmap(cdm);
 	if (gpio)
 		iounmap(gpio);
+#endif
 
 	return ret;
 }
@@ -502,11 +538,22 @@ static int __init mpc52xx_psc_spi_do_pro
 
 	ret = spi_register_master(master);
 	if (ret < 0)
+		goto destr_wq;
+
+#ifdef CONFIG_PPC_MERGE
+	mps->clk = clk_get(dev, "psc_mclk");
+	if (IS_ERR(mps->clk)) {
+		dev_err(dev, "couldn't get psc_mclk clock\n");
+		ret = -ENOENT;
 		goto unreg_master;
+	}
+#endif
 
 	return ret;
 
 unreg_master:
+	spi_unregister_master(master);
+destr_wq:
 	destroy_workqueue(mps->workqueue);
 free_irq:
 	free_irq(mps->irq, mps);
@@ -523,6 +570,9 @@ static int __exit mpc52xx_psc_spi_do_rem
 	struct spi_master *master = dev_get_drvdata(dev);
 	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
 
+#ifdef CONFIG_PPC_MERGE
+	clk_put(mps->clk);
+#endif
 	flush_workqueue(mps->workqueue);
 	destroy_workqueue(mps->workqueue);
 	spi_unregister_master(master);