diff mbox

[v2,02/14] clocksource: sp804: add device tree support

Message ID 1363108124-17484-3-git-send-email-haojian.zhuang@linaro.org
State Superseded
Headers show

Commit Message

Haojian Zhuang March 12, 2013, 5:08 p.m. UTC
Parse clock & irq from device tree for sp804.

Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
 drivers/clocksource/timer-sp.c |  105 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

Comments

Arnd Bergmann March 12, 2013, 6:14 p.m. UTC | #1
On Tuesday 12 March 2013, Haojian Zhuang wrote:
> Parse clock & irq from device tree for sp804.
> 
> Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
> ---
>  drivers/clocksource/timer-sp.c |  105 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 105 insertions(+)
> 


The patch looks ok to me, but it need  a binding document in 
Documentation/devicetree/bindings/

	Arnd
Arnd Bergmann March 12, 2013, 6:51 p.m. UTC | #2
On Tuesday 12 March 2013, Haojian Zhuang wrote:
> +static void __init sp804_dt_init(void)
> +{
...
> +
> +       np = of_find_matching_node(from, sp804_timer_match);
...
> +}
> +CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_dt_init);

On second thought, I guess it would be nice if we could change the
calling conventions for CLOCKSOURCE_OF_DECLARE init functions to
always pass the device along.  It is a bit silly if we already have
the node in clocksource_of_init and then require the init function
to call of_find_matching_node(). That change would also make patch
3 in this series unnecessary.

	Arnd
Rob Herring March 12, 2013, 6:53 p.m. UTC | #3
On 03/12/2013 01:51 PM, Arnd Bergmann wrote:
> On Tuesday 12 March 2013, Haojian Zhuang wrote:
>> +static void __init sp804_dt_init(void)
>> +{
> ...
>> +
>> +       np = of_find_matching_node(from, sp804_timer_match);
> ...
>> +}
>> +CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_dt_init);
> 
> On second thought, I guess it would be nice if we could change the
> calling conventions for CLOCKSOURCE_OF_DECLARE init functions to
> always pass the device along.  It is a bit silly if we already have
> the node in clocksource_of_init and then require the init function
> to call of_find_matching_node(). That change would also make patch
> 3 in this series unnecessary.
> 

My pull request to you yesterday does this. And I also have similar
sp804 patches I'm working on...

Rob
diff mbox

Patch

diff --git a/drivers/clocksource/timer-sp.c b/drivers/clocksource/timer-sp.c
index a7f2510..f8c2c54 100644
--- a/drivers/clocksource/timer-sp.c
+++ b/drivers/clocksource/timer-sp.c
@@ -19,16 +19,23 @@ 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/clk.h>
+#include <linux/clkdev.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <clocksource/arm_timer.h>
+#include <clocksource/timer-sp.h>
 
 #include <asm/sched_clock.h>
 
+#define SP804_CLKSRC	"sp804 source"
+#define SP804_CLKEVT	"sp804 event"
+
 static long __init sp804_get_clock_rate(const char *name)
 {
 	struct clk *clk;
@@ -189,3 +196,101 @@  void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
 	setup_irq(irq, &sp804_timer_irq);
 	clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
 }
+
+static struct device_node *from = NULL;
+
+static struct of_device_id sp804_timer_match[] __initdata = {
+	{ .compatible = "arm,sp804", },
+	{}
+};
+
+static struct clk __init *sp804_dt_init_clk(struct device_node *np, int i,
+					    const char *name)
+{
+	struct clk_lookup *lookup = NULL;
+	struct clk *clk;
+
+	clk = of_clk_get(np, i);
+	if (IS_ERR(clk))
+		return clk;
+	lookup = clkdev_alloc(clk, name, "sp804");
+	if (!lookup) {
+		clk_put(clk);
+		return ERR_PTR(-EINVAL);
+	}
+	clkdev_add(lookup);
+	return clk;
+}
+
+static void __init sp804_dt_init(void)
+{
+	struct device_node *np = NULL;
+	struct clk *clksrc = NULL, *clkevt = NULL;
+	void __iomem *base;
+	int retsrc, retevt, i = 0, irq = 0;
+	u32 srcoffs = 0, evtoffs = 0;
+
+	np = of_find_matching_node(from, sp804_timer_match);
+	WARN_ON(!np);
+	if (!np) {
+		pr_err("Failed to find sp804 timer\n");
+		return;
+	}
+	from = np;
+	/* check whether timer node is available */
+	if (!of_device_is_available(np))
+		return;
+
+	base = of_iomap(np, 0);
+	WARN_ON(!base);
+	if (!base)
+		return;
+
+	retsrc = of_property_read_u32(np, "arm,sp804-clocksource", &srcoffs);
+	retevt = of_property_read_u32(np, "arm,sp804-clockevent", &evtoffs);
+	if (retsrc < 0 && retevt < 0)
+		goto err;
+
+	if (!retsrc) {
+		if (srcoffs) {
+			/* TIMER2 is clock source */
+			i = 1;
+			srcoffs = TIMER_2_BASE;
+		} else {
+			/* TIMER1 is clock source */
+			i = 0;
+			srcoffs = TIMER_1_BASE;
+		}
+		clksrc = sp804_dt_init_clk(np, i, SP804_CLKSRC);
+		if (IS_ERR(clksrc))
+			goto err;
+		sp804_clocksource_and_sched_clock_init(base + srcoffs,
+						       SP804_CLKSRC);
+	}
+	if (!retevt) {
+		if (evtoffs) {
+			/* TIMER2 is clock event */
+			i = 1;
+			evtoffs = TIMER_2_BASE;
+		} else {
+			/* TIMER1 is clock event */
+			i = 0;
+			evtoffs = TIMER_1_BASE;
+		}
+		irq = irq_of_parse_and_map(np, i);
+		if (irq < 0)
+			goto err_evt;
+		clkevt = sp804_dt_init_clk(np, i, SP804_CLKEVT);
+		if (IS_ERR(clkevt))
+			goto err_evt;
+		sp804_clockevents_init(base + evtoffs, irq, SP804_CLKEVT);
+	}
+
+	return;
+err_evt:
+	if (clksrc)
+		clk_put(clksrc);
+err:
+	iounmap(base);
+}
+CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_dt_init);