Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
c_can_platform.c
Go to the documentation of this file.
1 /*
2  * Platform CAN bus driver for Bosch C_CAN controller
3  *
4  * Copyright (C) 2010 ST Microelectronics
5  * Bhupesh Sharma <[email protected]>
6  *
7  * Borrowed heavily from the C_CAN driver originally written by:
8  * Copyright (C) 2007
9  * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <[email protected]>
10  * - Simon Kallweit, intefo AG <[email protected]>
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[] = {
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) {
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;
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 
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 <[email protected]>");
318 MODULE_LICENSE("GPL v2");
319 MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");