Commit 2469627d175c1d6d7812a1395dd3ef053a0e65b3
Committed by
Marc Kleine-Budde
1 parent
f27b1db95d
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 2 changed files with 87 additions and 17 deletions Side-by-side Diff
Documentation/devicetree/bindings/net/can/c_can.txt
1 | +Bosch C_CAN/D_CAN controller Device Tree Bindings | |
2 | +------------------------------------------------- | |
3 | + | |
4 | +Required 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 | + | |
12 | +Optional properties: | |
13 | +- ti,hwmods : Must be "d_can<n>" or "c_can<n>", n being the | |
14 | + instance number | |
15 | + | |
16 | +Note: "ti,hwmods" field is used to fetch the base address and irq | |
17 | +resources from TI, omap hwmod data base during device registration. | |
18 | +Future plan is to migrate hwmod data base contents into device tree | |
19 | +blob so that, all the required data will be used from device tree dts | |
20 | +file. | |
21 | + | |
22 | +Example: | |
23 | + | |
24 | +Step1: 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 | + | |
45 | +Step 2: board specific .dts file | |
46 | + | |
47 | + &dcan1 { | |
48 | + status = "okay"; | |
49 | + }; |
drivers/net/can/c_can/c_can_platform.c
... | ... | @@ -30,6 +30,8 @@ |
30 | 30 | #include <linux/io.h> |
31 | 31 | #include <linux/platform_device.h> |
32 | 32 | #include <linux/clk.h> |
33 | +#include <linux/of.h> | |
34 | +#include <linux/of_device.h> | |
33 | 35 | |
34 | 36 | #include <linux/can/dev.h> |
35 | 37 | |
36 | 38 | |
37 | 39 | |
... | ... | @@ -65,17 +67,52 @@ |
65 | 67 | writew(val, priv->base + 2 * priv->regs[index]); |
66 | 68 | } |
67 | 69 | |
70 | +static 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 | + | |
86 | +static 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 | + | |
68 | 92 | static int __devinit c_can_plat_probe(struct platform_device *pdev) |
69 | 93 | { |
70 | 94 | int ret; |
71 | 95 | void __iomem *addr; |
72 | 96 | struct net_device *dev; |
73 | 97 | struct c_can_priv *priv; |
98 | + const struct of_device_id *match; | |
74 | 99 | const struct platform_device_id *id; |
75 | 100 | struct resource *mem; |
76 | 101 | int irq; |
77 | 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 | 116 | /* get the appropriate clk */ |
80 | 117 | clk = clk_get(&pdev->dev, NULL); |
81 | 118 | if (IS_ERR(clk)) { |
... | ... | @@ -114,7 +151,6 @@ |
114 | 151 | } |
115 | 152 | |
116 | 153 | priv = netdev_priv(dev); |
117 | - id = platform_get_device_id(pdev); | |
118 | 154 | switch (id->driver_data) { |
119 | 155 | case BOSCH_C_CAN: |
120 | 156 | priv->regs = reg_map_c_can; |
121 | 157 | |
... | ... | @@ -195,26 +231,11 @@ |
195 | 231 | return 0; |
196 | 232 | } |
197 | 233 | |
198 | -static 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 | - | |
214 | 234 | static struct platform_driver c_can_plat_driver = { |
215 | 235 | .driver = { |
216 | 236 | .name = KBUILD_MODNAME, |
217 | 237 | .owner = THIS_MODULE, |
238 | + .of_match_table = of_match_ptr(c_can_of_table), | |
218 | 239 | }, |
219 | 240 | .probe = c_can_plat_probe, |
220 | 241 | .remove = __devexit_p(c_can_plat_remove), |