Commit 3a61a5da authored by Nicolas Ferre's avatar Nicolas Ferre

ARM: at91/tc: add device tree support to atmel_tclib

Device tree support added to atmel_tclib: the generic Timer Counter
library. This is used by the clocksource/clockevent driver tcb_clksrc.

The current DT enabled platforms are also modified to use it:
- .dtsi files are modified to add Timer Counter Block entries
- alias are created to allow identification of each block
- clkdev lookup tables are added for clocks identification.
Signed-off-by: default avatarNicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: default avatarJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent 29831297
...@@ -6,3 +6,27 @@ PIT Timer required properties: ...@@ -6,3 +6,27 @@ PIT Timer required properties:
- reg: Should contain registers location and length - reg: Should contain registers location and length
- interrupts: Should contain interrupt for the PIT which is the IRQ line - interrupts: Should contain interrupt for the PIT which is the IRQ line
shared across all System Controller members. shared across all System Controller members.
TC/TCLIB Timer required properties:
- compatible: Should be "atmel,<chip>-pit".
<chip> can be "at91rm9200" or "at91sam9x5"
- reg: Should contain registers location and length
- interrupts: Should contain all interrupts for the TC block
Note that you can specify several interrupt cells if the TC
block has one interrupt per channel.
Examples:
One interrupt per TC block:
tcb0: timer@fff7c000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfff7c000 0x100>;
interrupts = <18 4>;
};
One interrupt per TC channel in a TC block:
tcb1: timer@fffdc000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfffdc000 0x100>;
interrupts = <26 4 27 4 28 4>;
};
...@@ -26,6 +26,8 @@ aliases { ...@@ -26,6 +26,8 @@ aliases {
gpio0 = &pioA; gpio0 = &pioA;
gpio1 = &pioB; gpio1 = &pioB;
gpio2 = &pioC; gpio2 = &pioC;
tcb0 = &tcb0;
tcb1 = &tcb1;
}; };
cpus { cpus {
cpu@0 { cpu@0 {
...@@ -63,6 +65,18 @@ pit: timer@fffffd30 { ...@@ -63,6 +65,18 @@ pit: timer@fffffd30 {
interrupts = <1 4>; interrupts = <1 4>;
}; };
tcb0: timer@fffa0000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfffa0000 0x100>;
interrupts = <17 4 18 4 19 4>;
};
tcb1: timer@fffdc000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfffdc000 0x100>;
interrupts = <26 4 27 4 28 4>;
};
pioA: gpio@fffff400 { pioA: gpio@fffff400 {
compatible = "atmel,at91rm9200-gpio"; compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff400 0x100>; reg = <0xfffff400 0x100>;
......
...@@ -27,6 +27,8 @@ aliases { ...@@ -27,6 +27,8 @@ aliases {
gpio2 = &pioC; gpio2 = &pioC;
gpio3 = &pioD; gpio3 = &pioD;
gpio4 = &pioE; gpio4 = &pioE;
tcb0 = &tcb0;
tcb1 = &tcb1;
}; };
cpus { cpus {
cpu@0 { cpu@0 {
...@@ -64,6 +66,19 @@ pit: timer@fffffd30 { ...@@ -64,6 +66,19 @@ pit: timer@fffffd30 {
interrupts = <1 4>; interrupts = <1 4>;
}; };
tcb0: timer@fff7c000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfff7c000 0x100>;
interrupts = <18 4>;
};
tcb1: timer@fffd4000 {
compatible = "atmel,at91rm9200-tcb";
reg = <0xfffd4000 0x100>;
interrupts = <18 4>;
};
dma: dma-controller@ffffec00 { dma: dma-controller@ffffec00 {
compatible = "atmel,at91sam9g45-dma"; compatible = "atmel,at91sam9g45-dma";
reg = <0xffffec00 0x200>; reg = <0xffffec00 0x200>;
......
...@@ -209,6 +209,13 @@ static struct clk_lookup periph_clocks_lookups[] = { ...@@ -209,6 +209,13 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk), CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk), CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk), CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
/* more tc lookup table for DT entries */
CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
CLKDEV_CON_DEV_ID("t0_clk", "fffdc000.timer", &tc3_clk),
CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
/* fake hclk clock */ /* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk), CLKDEV_CON_ID("pioA", &pioA_clk),
......
...@@ -699,8 +699,25 @@ static struct platform_device at91sam9260_tcb1_device = { ...@@ -699,8 +699,25 @@ static struct platform_device at91sam9260_tcb1_device = {
.num_resources = ARRAY_SIZE(tcb1_resources), .num_resources = ARRAY_SIZE(tcb1_resources),
}; };
#if defined(CONFIG_OF)
static struct of_device_id tcb_ids[] = {
{ .compatible = "atmel,at91rm9200-tcb" },
{ /*sentinel*/ }
};
#endif
static void __init at91_add_device_tc(void) static void __init at91_add_device_tc(void)
{ {
#if defined(CONFIG_OF)
struct device_node *np;
np = of_find_matching_node(NULL, tcb_ids);
if (np) {
of_node_put(np);
return;
}
#endif
platform_device_register(&at91sam9260_tcb0_device); platform_device_register(&at91sam9260_tcb0_device);
platform_device_register(&at91sam9260_tcb1_device); platform_device_register(&at91sam9260_tcb1_device);
} }
......
...@@ -229,6 +229,9 @@ static struct clk_lookup periph_clocks_lookups[] = { ...@@ -229,6 +229,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk), CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk), CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
CLKDEV_CON_DEV_ID("usart", "fff98000.serial", &usart3_clk), CLKDEV_CON_DEV_ID("usart", "fff98000.serial", &usart3_clk),
/* more tc lookup table for DT entries */
CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb0_clk),
CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
/* fake hclk clock */ /* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk), CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
CLKDEV_CON_ID("pioA", &pioA_clk), CLKDEV_CON_ID("pioA", &pioA_clk),
......
...@@ -1090,8 +1090,25 @@ static struct platform_device at91sam9g45_tcb1_device = { ...@@ -1090,8 +1090,25 @@ static struct platform_device at91sam9g45_tcb1_device = {
.num_resources = ARRAY_SIZE(tcb1_resources), .num_resources = ARRAY_SIZE(tcb1_resources),
}; };
#if defined(CONFIG_OF)
static struct of_device_id tcb_ids[] = {
{ .compatible = "atmel,at91rm9200-tcb" },
{ /*sentinel*/ }
};
#endif
static void __init at91_add_device_tc(void) static void __init at91_add_device_tc(void)
{ {
#if defined(CONFIG_OF)
struct device_node *np;
np = of_find_matching_node(NULL, tcb_ids);
if (np) {
of_node_put(np);
return;
}
#endif
platform_device_register(&at91sam9g45_tcb0_device); platform_device_register(&at91sam9g45_tcb0_device);
platform_device_register(&at91sam9g45_tcb1_device); platform_device_register(&at91sam9g45_tcb1_device);
} }
......
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/of.h>
/* /*
* This is a thin library to solve the problem of how to portably allocate * This is a thin library to solve the problem of how to portably allocate
...@@ -48,7 +50,13 @@ struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name) ...@@ -48,7 +50,13 @@ struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
spin_lock(&tc_list_lock); spin_lock(&tc_list_lock);
list_for_each_entry(tc, &tc_list, node) { list_for_each_entry(tc, &tc_list, node) {
if (tc->pdev->id == block) { if (tc->pdev->dev.of_node) {
if (of_alias_get_id(tc->pdev->dev.of_node, "tcb")
== block) {
pdev = tc->pdev;
break;
}
} else if (tc->pdev->id == block) {
pdev = tc->pdev; pdev = tc->pdev;
break; break;
} }
...@@ -105,6 +113,18 @@ void atmel_tc_free(struct atmel_tc *tc) ...@@ -105,6 +113,18 @@ void atmel_tc_free(struct atmel_tc *tc)
} }
EXPORT_SYMBOL_GPL(atmel_tc_free); EXPORT_SYMBOL_GPL(atmel_tc_free);
#if defined(CONFIG_OF)
static const struct of_device_id atmel_tcb_dt_ids[] = {
{
.compatible = "atmel,at91rm9200-tcb",
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, atmel_tcb_dt_ids);
#endif
static int __init tc_probe(struct platform_device *pdev) static int __init tc_probe(struct platform_device *pdev)
{ {
struct atmel_tc *tc; struct atmel_tc *tc;
...@@ -154,7 +174,10 @@ static int __init tc_probe(struct platform_device *pdev) ...@@ -154,7 +174,10 @@ static int __init tc_probe(struct platform_device *pdev)
} }
static struct platform_driver tc_driver = { static struct platform_driver tc_driver = {
.driver.name = "atmel_tcb", .driver = {
.name = "atmel_tcb",
.of_match_table = of_match_ptr(atmel_tcb_dt_ids),
},
}; };
static int __init tc_init(void) static int __init tc_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment