]> Pileus Git - ~andy/linux/blob - drivers/net/can/c_can/c_can_platform.c
Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb...
[~andy/linux] / drivers / net / can / c_can / c_can_platform.c
1 /*
2  * Platform CAN bus driver for Bosch C_CAN controller
3  *
4  * Copyright (C) 2010 ST Microelectronics
5  * Bhupesh Sharma <bhupesh.sharma@st.com>
6  *
7  * Borrowed heavily from the C_CAN driver originally written by:
8  * Copyright (C) 2007
9  * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
10  * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
11  *
12  * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
13  * Bosch C_CAN user manual can be obtained from:
14  * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
15  * users_manual_c_can.pdf
16  *
17  * This file is licensed under the terms of the GNU General Public
18  * License version 2. This program is licensed "as is" without any
19  * warranty of any kind, whether express or implied.
20  */
21
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/interrupt.h>
25 #include <linux/delay.h>
26 #include <linux/netdevice.h>
27 #include <linux/if_arp.h>
28 #include <linux/if_ether.h>
29 #include <linux/list.h>
30 #include <linux/io.h>
31 #include <linux/platform_device.h>
32 #include <linux/clk.h>
33 #include <linux/of.h>
34 #include <linux/of_device.h>
35 #include <linux/pinctrl/consumer.h>
36
37 #include <linux/can/dev.h>
38
39 #include "c_can.h"
40
41 /*
42  * 16-bit c_can registers can be arranged differently in the memory
43  * architecture of different implementations. For example: 16-bit
44  * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
45  * Handle the same by providing a common read/write interface.
46  */
47 static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv,
48                                                 enum reg index)
49 {
50         return readw(priv->base + priv->regs[index]);
51 }
52
53 static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv,
54                                                 enum reg index, u16 val)
55 {
56         writew(val, priv->base + priv->regs[index]);
57 }
58
59 static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv,
60                                                 enum reg index)
61 {
62         return readw(priv->base + 2 * priv->regs[index]);
63 }
64
65 static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
66                                                 enum reg index, u16 val)
67 {
68         writew(val, priv->base + 2 * priv->regs[index]);
69 }
70
71 static struct platform_device_id c_can_id_table[] = {
72         [BOSCH_C_CAN_PLATFORM] = {
73                 .name = KBUILD_MODNAME,
74                 .driver_data = BOSCH_C_CAN,
75         },
76         [BOSCH_C_CAN] = {
77                 .name = "c_can",
78                 .driver_data = BOSCH_C_CAN,
79         },
80         [BOSCH_D_CAN] = {
81                 .name = "d_can",
82                 .driver_data = BOSCH_D_CAN,
83         }, {
84         }
85 };
86
87 static const struct of_device_id c_can_of_table[] = {
88         { .compatible = "bosch,c_can", .data = &c_can_id_table[BOSCH_C_CAN] },
89         { .compatible = "bosch,d_can", .data = &c_can_id_table[BOSCH_D_CAN] },
90         { /* sentinel */ },
91 };
92
93 static int __devinit c_can_plat_probe(struct platform_device *pdev)
94 {
95         int ret;
96         void __iomem *addr;
97         struct net_device *dev;
98         struct c_can_priv *priv;
99         const struct of_device_id *match;
100         const struct platform_device_id *id;
101         struct pinctrl *pinctrl;
102         struct resource *mem;
103         int irq;
104         struct clk *clk;
105
106         if (pdev->dev.of_node) {
107                 match = of_match_device(c_can_of_table, &pdev->dev);
108                 if (!match) {
109                         dev_err(&pdev->dev, "Failed to find matching dt id\n");
110                         ret = -EINVAL;
111                         goto exit;
112                 }
113                 id = match->data;
114         } else {
115                 id = platform_get_device_id(pdev);
116         }
117
118         pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
119         if (IS_ERR(pinctrl))
120                 dev_warn(&pdev->dev,
121                         "failed to configure pins from driver\n");
122
123         /* get the appropriate clk */
124         clk = clk_get(&pdev->dev, NULL);
125         if (IS_ERR(clk)) {
126                 dev_err(&pdev->dev, "no clock defined\n");
127                 ret = -ENODEV;
128                 goto exit;
129         }
130
131         /* get the platform data */
132         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
133         irq = platform_get_irq(pdev, 0);
134         if (!mem || irq <= 0) {
135                 ret = -ENODEV;
136                 goto exit_free_clk;
137         }
138
139         if (!request_mem_region(mem->start, resource_size(mem),
140                                 KBUILD_MODNAME)) {
141                 dev_err(&pdev->dev, "resource unavailable\n");
142                 ret = -ENODEV;
143                 goto exit_free_clk;
144         }
145
146         addr = ioremap(mem->start, resource_size(mem));
147         if (!addr) {
148                 dev_err(&pdev->dev, "failed to map can port\n");
149                 ret = -ENOMEM;
150                 goto exit_release_mem;
151         }
152
153         /* allocate the c_can device */
154         dev = alloc_c_can_dev();
155         if (!dev) {
156                 ret = -ENOMEM;
157                 goto exit_iounmap;
158         }
159
160         priv = netdev_priv(dev);
161         switch (id->driver_data) {
162         case BOSCH_C_CAN:
163                 priv->regs = reg_map_c_can;
164                 switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
165                 case IORESOURCE_MEM_32BIT:
166                         priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
167                         priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
168                         break;
169                 case IORESOURCE_MEM_16BIT:
170                 default:
171                         priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
172                         priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
173                         break;
174                 }
175                 break;
176         case BOSCH_D_CAN:
177                 priv->regs = reg_map_d_can;
178                 priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
179                 priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
180                 priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
181                 break;
182         default:
183                 ret = -EINVAL;
184                 goto exit_free_device;
185         }
186
187         dev->irq = irq;
188         priv->base = addr;
189         priv->device = &pdev->dev;
190         priv->can.clock.freq = clk_get_rate(clk);
191         priv->priv = clk;
192         priv->type = id->driver_data;
193
194         platform_set_drvdata(pdev, dev);
195         SET_NETDEV_DEV(dev, &pdev->dev);
196
197         ret = register_c_can_dev(dev);
198         if (ret) {
199                 dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
200                         KBUILD_MODNAME, ret);
201                 goto exit_free_device;
202         }
203
204         dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
205                  KBUILD_MODNAME, priv->base, dev->irq);
206         return 0;
207
208 exit_free_device:
209         platform_set_drvdata(pdev, NULL);
210         free_c_can_dev(dev);
211 exit_iounmap:
212         iounmap(addr);
213 exit_release_mem:
214         release_mem_region(mem->start, resource_size(mem));
215 exit_free_clk:
216         clk_put(clk);
217 exit:
218         dev_err(&pdev->dev, "probe failed\n");
219
220         return ret;
221 }
222
223 static int __devexit c_can_plat_remove(struct platform_device *pdev)
224 {
225         struct net_device *dev = platform_get_drvdata(pdev);
226         struct c_can_priv *priv = netdev_priv(dev);
227         struct resource *mem;
228
229         unregister_c_can_dev(dev);
230         platform_set_drvdata(pdev, NULL);
231
232         free_c_can_dev(dev);
233         iounmap(priv->base);
234
235         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
236         release_mem_region(mem->start, resource_size(mem));
237
238         clk_put(priv->priv);
239
240         return 0;
241 }
242
243 #ifdef CONFIG_PM
244 static int c_can_suspend(struct platform_device *pdev, pm_message_t state)
245 {
246         int ret;
247         struct net_device *ndev = platform_get_drvdata(pdev);
248         struct c_can_priv *priv = netdev_priv(ndev);
249
250         if (priv->type != BOSCH_D_CAN) {
251                 dev_warn(&pdev->dev, "Not supported\n");
252                 return 0;
253         }
254
255         if (netif_running(ndev)) {
256                 netif_stop_queue(ndev);
257                 netif_device_detach(ndev);
258         }
259
260         ret = c_can_power_down(ndev);
261         if (ret) {
262                 netdev_err(ndev, "failed to enter power down mode\n");
263                 return ret;
264         }
265
266         priv->can.state = CAN_STATE_SLEEPING;
267
268         return 0;
269 }
270
271 static int c_can_resume(struct platform_device *pdev)
272 {
273         int ret;
274         struct net_device *ndev = platform_get_drvdata(pdev);
275         struct c_can_priv *priv = netdev_priv(ndev);
276
277         if (priv->type != BOSCH_D_CAN) {
278                 dev_warn(&pdev->dev, "Not supported\n");
279                 return 0;
280         }
281
282         ret = c_can_power_up(ndev);
283         if (ret) {
284                 netdev_err(ndev, "Still in power down mode\n");
285                 return ret;
286         }
287
288         priv->can.state = CAN_STATE_ERROR_ACTIVE;
289
290         if (netif_running(ndev)) {
291                 netif_device_attach(ndev);
292                 netif_start_queue(ndev);
293         }
294
295         return 0;
296 }
297 #else
298 #define c_can_suspend NULL
299 #define c_can_resume NULL
300 #endif
301
302 static struct platform_driver c_can_plat_driver = {
303         .driver = {
304                 .name = KBUILD_MODNAME,
305                 .owner = THIS_MODULE,
306                 .of_match_table = of_match_ptr(c_can_of_table),
307         },
308         .probe = c_can_plat_probe,
309         .remove = __devexit_p(c_can_plat_remove),
310         .suspend = c_can_suspend,
311         .resume = c_can_resume,
312         .id_table = c_can_id_table,
313 };
314
315 module_platform_driver(c_can_plat_driver);
316
317 MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
318 MODULE_LICENSE("GPL v2");
319 MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");