c_can_platform.c revision 006cd138fc8813220cb4b6450bd9b44f3401bb89
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 */
47static 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
53static 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
59static 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
65static 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
71static 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
87static 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
93static 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
208exit_free_device:
209	platform_set_drvdata(pdev, NULL);
210	free_c_can_dev(dev);
211exit_iounmap:
212	iounmap(addr);
213exit_release_mem:
214	release_mem_region(mem->start, resource_size(mem));
215exit_free_clk:
216	clk_put(clk);
217exit:
218	dev_err(&pdev->dev, "probe failed\n");
219
220	return ret;
221}
222
223static 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
244static 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
271static 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
302static 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
315module_platform_driver(c_can_plat_driver);
316
317MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
318MODULE_LICENSE("GPL v2");
319MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");
320