[PATCH 1/3] powerpc/85xx: Add clock driver for PWM
From: Chunhe Lan <hidden>
Date: 2012-01-10 10:25:27
Plugs into the generic powerpc clock driver in
arch/powerpc/kernel/clock.c
The following subset of clk_interface is implemented:
clk_get: get clock via name
clk_put: stubbed
clk_enable: enable clock
clk_disable: disable clock
clk_get_rate: get clock rate in Hz
clk_set_rate: NULL
clk_round_rate: NULL
clk_set_parent: NULL
clk_get_parent: NULL
Signed-off-by: Chunhe Lan <redacted>
---
arch/powerpc/include/asm/clock.h | 33 +++++++
arch/powerpc/platforms/85xx/Makefile | 1 +
arch/powerpc/platforms/85xx/pwm-clock.c | 161 +++++++++++++++++++++++++++++++
3 files changed, 195 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/include/asm/clock.h
create mode 100644 arch/powerpc/platforms/85xx/pwm-clock.c
diff --git a/arch/powerpc/include/asm/clock.h b/arch/powerpc/include/asm/clock.h
new file mode 100644
index 0000000..98447eb
--- /dev/null
+++ b/arch/powerpc/include/asm/clock.h@@ -0,0 +1,33 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * Author: Chunhe Lan <Chunhe.Lan@freescale.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +struct clk { + struct list_head node; + const char *name; /* unique clock name */ + const char *function; /* function of the clock */ + struct device *dev; /* device associated with function */ + unsigned int id:2; /* clock identification */ + unsigned long rate_hz; + struct clk *parent; + void (*mode)(struct clk *clk, int status); + u16 users; +}; + +extern int clk_register(struct clk *clk);
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index bc5acb9..ba0d0a9 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile@@ -18,6 +18,7 @@ obj-$(CONFIG_P3041_DS) += p3041_ds.o corenet_ds.o obj-$(CONFIG_P3060_QDS) += p3060_qds.o corenet_ds.o obj-$(CONFIG_P4080_DS) += p4080_ds.o corenet_ds.o obj-$(CONFIG_P5020_DS) += p5020_ds.o corenet_ds.o +obj-$(CONFIG_FSL_PWM) += pwm-clock.o obj-$(CONFIG_STX_GP3) += stx_gp3.o obj-$(CONFIG_TQM85xx) += tqm85xx.o obj-$(CONFIG_SBC8560) += sbc8560.o
diff --git a/arch/powerpc/platforms/85xx/pwm-clock.c b/arch/powerpc/platforms/85xx/pwm-clock.c
new file mode 100644
index 0000000..bba9872
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/pwm-clock.c@@ -0,0 +1,161 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * Implements the clk api defined in include/linux/clk.h + * + * Author: Chunhe Lan <Chunhe.Lan@freescale.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/of_platform.h> +#include <asm/clk_interface.h> +#include <asm/clock.h> + +static LIST_HEAD(clocks); +static DEFINE_SPINLOCK(clk_lock); + +static struct clk pwm_clk = { + .name = "pwm-clk", + .rate_hz = 0, + .users = 1, /* always on */ + .id = 0, +}; + +static struct clk *all_clocks[] __initdata = { + &pwm_clk, +}; + +/* clocks cannot be de-registered no refcounting necessary */ +static struct clk *fsl_clk_get(struct device *dev, const char *id) +{ + struct clk *clk; + + list_for_each_entry(clk, &clocks, node) { + if (strcmp(id, clk->name) == 0) + return clk; + } + + return ERR_PTR(-ENOENT); +} + +static void fsl_clk_put(struct clk *clk) +{ +} + +static void __clk_enable(struct clk *clk) +{ + if (clk->parent) + __clk_enable(clk->parent); + if (clk->users++ == 0 && clk->mode) + clk->mode(clk, 1); +} + +static int fsl_clk_enable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(&clk_lock, flags); + __clk_enable(clk); + spin_unlock_irqrestore(&clk_lock, flags); + + return 0; +} + +static void __clk_disable(struct clk *clk) +{ + BUG_ON(clk->users == 0); + + if (--clk->users == 0 && clk->mode) + clk->mode(clk, 0); + if (clk->parent) + __clk_disable(clk->parent); +} + +static void fsl_clk_disable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(&clk_lock, flags); + __clk_disable(clk); + spin_unlock_irqrestore(&clk_lock, flags); +} + +static unsigned long fsl_clk_get_rate(struct clk *clk) +{ + unsigned long flags; + unsigned long rate; + + spin_lock_irqsave(&clk_lock, flags); + for (;;) { + rate = clk->rate_hz; + if (rate || !clk->parent) + break; + clk = clk->parent; + } + spin_unlock_irqrestore(&clk_lock, flags); + + return rate; +} + +static struct clk_interface fsl_clk_functions = { + .clk_get = fsl_clk_get, + .clk_put = fsl_clk_put, + .clk_enable = fsl_clk_enable, + .clk_disable = fsl_clk_disable, + .clk_get_rate = fsl_clk_get_rate, +}; + +/* Register a new clock */ +int clk_register(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(&clk_lock, flags); + list_add(&clk->node, &clocks); + spin_unlock_irqrestore(&clk_lock, flags); + + return 0; +} +EXPORT_SYMBOL(clk_register); + +static int fsl_register_clocks(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(all_clocks); i++) + clk_register(all_clocks[i]); + + return 0; +} + +static int __init fsl_clk_init(void) +{ + fsl_register_clocks(); + clk_functions = fsl_clk_functions; + + return 0; +} + +arch_initcall(fsl_clk_init);
--
1.5.6.5