2 * Platform CAN bus driver for Bosch D_CAN controller
4 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
6 * Borrowed from C_CAN driver
7 * Copyright (C) 2010 ST Microelectronics
8 * - Bhupesh Sharma <bhupesh.sharma@st.com>
10 * Borrowed heavily from the C_CAN driver originally written by:
12 * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
13 * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
15 * Bosch D_CAN controller is compliant to CAN protocol version 2.0 part A and B.
16 * Bosch D_CAN user manual can be obtained from:
17 * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/
18 * d_can_users_manual_111.pdf
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License as
22 * published by the Free Software Foundation version 2.
24 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
25 * kind, whether express or implied; without even the implied warranty
26 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
31 * Your platform definitions should specify module ram offsets and interrupt
32 * number to use as follows:
34 * static struct d_can_platform_data am33xx_evm_d_can_pdata = {
35 * .num_of_msg_objs = 64,
36 * .dma_support = false,
37 * .ram_init = d_can_hw_raminit,
40 * Please see include/linux/can/platform/d_can.h for description of
45 #include <linux/kernel.h>
46 #include <linux/module.h>
47 #include <linux/interrupt.h>
48 #include <linux/delay.h>
49 #include <linux/netdevice.h>
50 #include <linux/if_arp.h>
51 #include <linux/if_ether.h>
52 #include <linux/list.h>
54 #include <linux/platform_device.h>
55 #include <linux/can/platform/d_can.h>
56 #include <linux/clk.h>
57 #include <linux/pm_runtime.h>
58 #include <linux/slab.h>
59 #include <linux/can/dev.h>
63 static int __devinit d_can_plat_probe(struct platform_device *pdev)
67 struct net_device *ndev;
68 struct d_can_priv *priv;
70 struct d_can_platform_data *pdata;
73 pdata = pdev->dev.platform_data;
75 dev_err(&pdev->dev, "No platform data\n");
79 /* allocate the d_can device */
80 ndev = alloc_d_can_dev(pdata->num_of_msg_objs);
83 dev_err(&pdev->dev, "alloc_d_can_dev failed\n");
87 priv = netdev_priv(ndev);
88 fck = clk_get(&pdev->dev, "fck");
90 dev_err(&pdev->dev, "fck is not found\n");
95 /* get the platform data */
96 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
99 dev_err(&pdev->dev, "No mem resource\n");
103 if (!request_mem_region(mem->start, resource_size(mem),
105 dev_err(&pdev->dev, "resource unavailable\n");
110 addr = ioremap(mem->start, resource_size(mem));
112 dev_err(&pdev->dev, "ioremap failed\n");
114 goto exit_release_mem;
117 /* IRQ specific to Error and status & can be used for Message Object */
118 ndev->irq = platform_get_irq_byname(pdev, "d_can_ms");
120 dev_err(&pdev->dev, "No irq0 resource\n");
124 /* IRQ specific for Message Object */
125 priv->irq_obj = platform_get_irq_byname(pdev, "d_can_mo");
126 if (!priv->irq_obj) {
127 dev_err(&pdev->dev, "No irq1 resource\n");
131 pm_runtime_enable(&pdev->dev);
132 pm_runtime_get_sync(&pdev->dev);
135 priv->can.clock.freq = clk_get_rate(fck);
136 priv->ram_init = pdata->ram_init;
137 priv->opened = false;
139 platform_set_drvdata(pdev, ndev);
140 SET_NETDEV_DEV(ndev, &pdev->dev);
142 ret = register_d_can_dev(ndev);
144 dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
145 D_CAN_DRV_NAME, ret);
146 goto exit_free_device;
149 /* Initialize DCAN RAM */
150 d_can_reset_ram(priv, pdev->id, 1);
152 dev_info(&pdev->dev, "device registered (irq=%d, irq_obj=%d)\n",
153 ndev->irq, priv->irq_obj);
158 platform_set_drvdata(pdev, NULL);
159 pm_runtime_disable(&pdev->dev);
163 release_mem_region(mem->start, resource_size(mem));
167 free_d_can_dev(ndev);
169 dev_err(&pdev->dev, "probe failed\n");
174 static int __devexit d_can_plat_remove(struct platform_device *pdev)
176 struct net_device *ndev = platform_get_drvdata(pdev);
177 struct d_can_priv *priv = netdev_priv(ndev);
178 struct resource *mem;
179 void __iomem *base = priv->base;
181 /* De-initialize DCAN RAM */
182 d_can_reset_ram(priv, pdev->id, 0);
184 unregister_d_can_dev(ndev);
185 platform_set_drvdata(pdev, NULL);
187 free_d_can_dev(ndev);
190 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
191 release_mem_region(mem->start, resource_size(mem));
193 pm_runtime_put_sync(&pdev->dev);
194 pm_runtime_disable(&pdev->dev);
200 static int d_can_suspend(struct platform_device *pdev, pm_message_t state)
203 struct net_device *ndev = platform_get_drvdata(pdev);
204 struct d_can_priv *priv = netdev_priv(ndev);
206 if (netif_running(ndev)) {
207 netif_stop_queue(ndev);
208 netif_device_detach(ndev);
211 ret = d_can_power_down(priv);
213 dev_err(&pdev->dev, "Not entered power down mode\n");
217 priv->can.state = CAN_STATE_SLEEPING;
219 /* De-initialize DCAN RAM */
220 d_can_reset_ram(priv, pdev->id, 0);
222 /* Disable the module */
223 pm_runtime_put_sync(&pdev->dev);
228 static int d_can_resume(struct platform_device *pdev)
232 struct net_device *ndev = platform_get_drvdata(pdev);
233 struct d_can_priv *priv = netdev_priv(ndev);
235 /* Enable the module */
236 pm_runtime_get_sync(&pdev->dev);
238 /* Initialize DCAN RAM */
239 d_can_reset_ram(priv, pdev->id, 1);
241 ret = d_can_power_up(priv);
243 dev_err(&pdev->dev, "Not came out from power down mode\n");
247 priv->can.state = CAN_STATE_ERROR_ACTIVE;
249 if (netif_running(ndev)) {
250 netif_device_attach(ndev);
251 netif_start_queue(ndev);
257 #define d_can_suspend NULL
258 #define d_can_resume NULL
261 static struct platform_driver d_can_plat_driver = {
263 .name = D_CAN_DRV_NAME,
264 .owner = THIS_MODULE,
266 .probe = d_can_plat_probe,
267 .remove = __devexit_p(d_can_plat_remove),
268 .suspend = d_can_suspend,
269 .resume = d_can_resume,
272 static int __init d_can_plat_init(void)
274 printk(KERN_INFO D_CAN_DRV_DESC "\n");
275 return platform_driver_register(&d_can_plat_driver);
277 module_init(d_can_plat_init);
279 static void __exit d_can_plat_exit(void)
281 printk(KERN_INFO D_CAN_DRV_DESC " unloaded\n");
282 platform_driver_unregister(&d_can_plat_driver);
284 module_exit(d_can_plat_exit);
286 MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
287 MODULE_LICENSE("GPL v2");
288 MODULE_VERSION(D_CAN_VERSION);
289 MODULE_DESCRIPTION(D_CAN_DRV_DESC);