aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnilKumar Ch <anilkumar@ti.com>2012-08-02 09:13:10 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2012-09-21 17:58:47 -0400
commit2469627d175c1d6d7812a1395dd3ef053a0e65b3 (patch)
tree8ee10f2f87ddccc8fa6160e9d73bfd93b33b57ac
parentf27b1db95d047d05e8d4dd22813b1078267892f2 (diff)
can: c_can: Add device tree support to Bosch C_CAN/D_CAN controller
Add device tree support to C_CAN/D_CAN controller and usage details are added to device tree documentation. Driver was tested on AM335x EVM. Signed-off-by: AnilKumar Ch <anilkumar@ti.com> For the of binding doc: Reviewed-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--Documentation/devicetree/bindings/net/can/c_can.txt49
-rw-r--r--drivers/net/can/c_can/c_can_platform.c55
2 files changed, 87 insertions, 17 deletions
diff --git a/Documentation/devicetree/bindings/net/can/c_can.txt b/Documentation/devicetree/bindings/net/can/c_can.txt
new file mode 100644
index 00000000000..8f1ae81228e
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/c_can.txt
@@ -0,0 +1,49 @@
1Bosch C_CAN/D_CAN controller Device Tree Bindings
2-------------------------------------------------
3
4Required properties:
5- compatible : Should be "bosch,c_can" for C_CAN controllers and
6 "bosch,d_can" for D_CAN controllers.
7- reg : physical base address and size of the C_CAN/D_CAN
8 registers map
9- interrupts : property with a value describing the interrupt
10 number
11
12Optional properties:
13- ti,hwmods : Must be "d_can<n>" or "c_can<n>", n being the
14 instance number
15
16Note: "ti,hwmods" field is used to fetch the base address and irq
17resources from TI, omap hwmod data base during device registration.
18Future plan is to migrate hwmod data base contents into device tree
19blob so that, all the required data will be used from device tree dts
20file.
21
22Example:
23
24Step1: SoC common .dtsi file
25
26 dcan1: d_can@481d0000 {
27 compatible = "bosch,d_can";
28 reg = <0x481d0000 0x2000>;
29 interrupts = <55>;
30 interrupt-parent = <&intc>;
31 status = "disabled";
32 };
33
34(or)
35
36 dcan1: d_can@481d0000 {
37 compatible = "bosch,d_can";
38 ti,hwmods = "d_can1";
39 reg = <0x481d0000 0x2000>;
40 interrupts = <55>;
41 interrupt-parent = <&intc>;
42 status = "disabled";
43 };
44
45Step 2: board specific .dts file
46
47 &dcan1 {
48 status = "okay";
49 };
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index 5c46d1cc5cf..d0a66cf298b 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -30,6 +30,8 @@
30#include <linux/io.h> 30#include <linux/io.h>
31#include <linux/platform_device.h> 31#include <linux/platform_device.h>
32#include <linux/clk.h> 32#include <linux/clk.h>
33#include <linux/of.h>
34#include <linux/of_device.h>
33 35
34#include <linux/can/dev.h> 36#include <linux/can/dev.h>
35 37
@@ -65,17 +67,52 @@ static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
65 writew(val, priv->base + 2 * priv->regs[index]); 67 writew(val, priv->base + 2 * priv->regs[index]);
66} 68}
67 69
70static struct platform_device_id c_can_id_table[] = {
71 [BOSCH_C_CAN_PLATFORM] = {
72 .name = KBUILD_MODNAME,
73 .driver_data = BOSCH_C_CAN,
74 },
75 [BOSCH_C_CAN] = {
76 .name = "c_can",
77 .driver_data = BOSCH_C_CAN,
78 },
79 [BOSCH_D_CAN] = {
80 .name = "d_can",
81 .driver_data = BOSCH_D_CAN,
82 }, {
83 }
84};
85
86static const struct of_device_id c_can_of_table[] = {
87 { .compatible = "bosch,c_can", .data = &c_can_id_table[BOSCH_C_CAN] },
88 { .compatible = "bosch,d_can", .data = &c_can_id_table[BOSCH_D_CAN] },
89 { /* sentinel */ },
90};
91
68static int __devinit c_can_plat_probe(struct platform_device *pdev) 92static int __devinit c_can_plat_probe(struct platform_device *pdev)
69{ 93{
70 int ret; 94 int ret;
71 void __iomem *addr; 95 void __iomem *addr;
72 struct net_device *dev; 96 struct net_device *dev;
73 struct c_can_priv *priv; 97 struct c_can_priv *priv;
98 const struct of_device_id *match;
74 const struct platform_device_id *id; 99 const struct platform_device_id *id;
75 struct resource *mem; 100 struct resource *mem;
76 int irq; 101 int irq;
77 struct clk *clk; 102 struct clk *clk;
78 103
104 if (pdev->dev.of_node) {
105 match = of_match_device(c_can_of_table, &pdev->dev);
106 if (!match) {
107 dev_err(&pdev->dev, "Failed to find matching dt id\n");
108 ret = -EINVAL;
109 goto exit;
110 }
111 id = match->data;
112 } else {
113 id = platform_get_device_id(pdev);
114 }
115
79 /* get the appropriate clk */ 116 /* get the appropriate clk */
80 clk = clk_get(&pdev->dev, NULL); 117 clk = clk_get(&pdev->dev, NULL);
81 if (IS_ERR(clk)) { 118 if (IS_ERR(clk)) {
@@ -114,7 +151,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
114 } 151 }
115 152
116 priv = netdev_priv(dev); 153 priv = netdev_priv(dev);
117 id = platform_get_device_id(pdev);
118 switch (id->driver_data) { 154 switch (id->driver_data) {
119 case BOSCH_C_CAN: 155 case BOSCH_C_CAN:
120 priv->regs = reg_map_c_can; 156 priv->regs = reg_map_c_can;
@@ -195,26 +231,11 @@ static int __devexit c_can_plat_remove(struct platform_device *pdev)
195 return 0; 231 return 0;
196} 232}
197 233
198static const struct platform_device_id c_can_id_table[] = {
199 [BOSCH_C_CAN_PLATFORM] = {
200 .name = KBUILD_MODNAME,
201 .driver_data = BOSCH_C_CAN,
202 },
203 [BOSCH_C_CAN] = {
204 .name = "c_can",
205 .driver_data = BOSCH_C_CAN,
206 },
207 [BOSCH_D_CAN] = {
208 .name = "d_can",
209 .driver_data = BOSCH_D_CAN,
210 }, {
211 }
212};
213
214static struct platform_driver c_can_plat_driver = { 234static struct platform_driver c_can_plat_driver = {
215 .driver = { 235 .driver = {
216 .name = KBUILD_MODNAME, 236 .name = KBUILD_MODNAME,
217 .owner = THIS_MODULE, 237 .owner = THIS_MODULE,
238 .of_match_table = of_match_ptr(c_can_of_table),
218 }, 239 },
219 .probe = c_can_plat_probe, 240 .probe = c_can_plat_probe,
220 .remove = __devexit_p(c_can_plat_remove), 241 .remove = __devexit_p(c_can_plat_remove),