c_can_pci.c revision abcd7f750a7e978a60c745e7c41dc468949365c2
1/*
2 * PCI bus driver for Bosch C_CAN/D_CAN controller
3 *
4 * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
5 *
6 * Borrowed from c_can_platform.c
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/netdevice.h>
16#include <linux/pci.h>
17
18#include <linux/can/dev.h>
19
20#include "c_can.h"
21
22#define PCI_DEVICE_ID_PCH_CAN	0x8818
23#define PCH_PCI_SOFT_RESET	0x01fc
24
25enum c_can_pci_reg_align {
26	C_CAN_REG_ALIGN_16,
27	C_CAN_REG_ALIGN_32,
28	C_CAN_REG_32,
29};
30
31struct c_can_pci_data {
32	/* Specify if is C_CAN or D_CAN */
33	enum c_can_dev_id type;
34	/* Set the register alignment in the memory */
35	enum c_can_pci_reg_align reg_align;
36	/* Set the frequency */
37	unsigned int freq;
38	/* PCI bar number */
39	int bar;
40	/* Callback for reset */
41	void (*init)(const struct c_can_priv *priv, bool enable);
42};
43
44/*
45 * 16-bit c_can registers can be arranged differently in the memory
46 * architecture of different implementations. For example: 16-bit
47 * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
48 * Handle the same by providing a common read/write interface.
49 */
50static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv,
51						enum reg index)
52{
53	return readw(priv->base + priv->regs[index]);
54}
55
56static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv,
57						enum reg index, u16 val)
58{
59	writew(val, priv->base + priv->regs[index]);
60}
61
62static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv,
63						enum reg index)
64{
65	return readw(priv->base + 2 * priv->regs[index]);
66}
67
68static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
69						enum reg index, u16 val)
70{
71	writew(val, priv->base + 2 * priv->regs[index]);
72}
73
74static u16 c_can_pci_read_reg_32bit(struct c_can_priv *priv,
75				    enum reg index)
76{
77	return (u16)ioread32(priv->base + 2 * priv->regs[index]);
78}
79
80static void c_can_pci_write_reg_32bit(struct c_can_priv *priv,
81				      enum reg index, u16 val)
82{
83	iowrite32((u32)val, priv->base + 2 * priv->regs[index]);
84}
85
86static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable)
87{
88	if (enable) {
89		u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET;
90
91		/* write to sw reset register */
92		iowrite32(1, addr);
93		iowrite32(0, addr);
94	}
95}
96
97static int c_can_pci_probe(struct pci_dev *pdev,
98			   const struct pci_device_id *ent)
99{
100	struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;
101	struct c_can_priv *priv;
102	struct net_device *dev;
103	void __iomem *addr;
104	int ret;
105
106	ret = pci_enable_device(pdev);
107	if (ret) {
108		dev_err(&pdev->dev, "pci_enable_device FAILED\n");
109		goto out;
110	}
111
112	ret = pci_request_regions(pdev, KBUILD_MODNAME);
113	if (ret) {
114		dev_err(&pdev->dev, "pci_request_regions FAILED\n");
115		goto out_disable_device;
116	}
117
118	pci_set_master(pdev);
119	pci_enable_msi(pdev);
120
121	addr = pci_iomap(pdev, c_can_pci_data->bar,
122			 pci_resource_len(pdev, c_can_pci_data->bar));
123	if (!addr) {
124		dev_err(&pdev->dev,
125			"device has no PCI memory resources, "
126			"failing adapter\n");
127		ret = -ENOMEM;
128		goto out_release_regions;
129	}
130
131	/* allocate the c_can device */
132	dev = alloc_c_can_dev();
133	if (!dev) {
134		ret = -ENOMEM;
135		goto out_iounmap;
136	}
137
138	priv = netdev_priv(dev);
139	pci_set_drvdata(pdev, dev);
140	SET_NETDEV_DEV(dev, &pdev->dev);
141
142	dev->irq = pdev->irq;
143	priv->base = addr;
144
145	if (!c_can_pci_data->freq) {
146		dev_err(&pdev->dev, "no clock frequency defined\n");
147		ret = -ENODEV;
148		goto out_free_c_can;
149	} else {
150		priv->can.clock.freq = c_can_pci_data->freq;
151	}
152
153	/* Configure CAN type */
154	switch (c_can_pci_data->type) {
155	case BOSCH_C_CAN:
156		priv->regs = reg_map_c_can;
157		break;
158	case BOSCH_D_CAN:
159		priv->regs = reg_map_d_can;
160		priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
161		break;
162	default:
163		ret = -EINVAL;
164		goto out_free_c_can;
165	}
166
167	/* Configure access to registers */
168	switch (c_can_pci_data->reg_align) {
169	case C_CAN_REG_ALIGN_32:
170		priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
171		priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
172		break;
173	case C_CAN_REG_ALIGN_16:
174		priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
175		priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
176		break;
177	case C_CAN_REG_32:
178		priv->read_reg = c_can_pci_read_reg_32bit;
179		priv->write_reg = c_can_pci_write_reg_32bit;
180		break;
181	default:
182		ret = -EINVAL;
183		goto out_free_c_can;
184	}
185
186	priv->raminit = c_can_pci_data->init;
187
188	ret = register_c_can_dev(dev);
189	if (ret) {
190		dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
191			KBUILD_MODNAME, ret);
192		goto out_free_c_can;
193	}
194
195	dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
196		 KBUILD_MODNAME, priv->regs, dev->irq);
197
198	return 0;
199
200out_free_c_can:
201	free_c_can_dev(dev);
202out_iounmap:
203	pci_iounmap(pdev, addr);
204out_release_regions:
205	pci_disable_msi(pdev);
206	pci_clear_master(pdev);
207	pci_release_regions(pdev);
208out_disable_device:
209	pci_disable_device(pdev);
210out:
211	return ret;
212}
213
214static void c_can_pci_remove(struct pci_dev *pdev)
215{
216	struct net_device *dev = pci_get_drvdata(pdev);
217	struct c_can_priv *priv = netdev_priv(dev);
218
219	unregister_c_can_dev(dev);
220
221	free_c_can_dev(dev);
222
223	pci_iounmap(pdev, priv->base);
224	pci_disable_msi(pdev);
225	pci_clear_master(pdev);
226	pci_release_regions(pdev);
227	pci_disable_device(pdev);
228}
229
230static struct c_can_pci_data c_can_sta2x11= {
231	.type = BOSCH_C_CAN,
232	.reg_align = C_CAN_REG_ALIGN_32,
233	.freq = 52000000, /* 52 Mhz */
234	.bar = 0,
235};
236
237static struct c_can_pci_data c_can_pch = {
238	.type = BOSCH_C_CAN,
239	.reg_align = C_CAN_REG_32,
240	.freq = 50000000, /* 50 MHz */
241	.init = c_can_pci_reset_pch,
242	.bar = 1,
243};
244
245#define C_CAN_ID(_vend, _dev, _driverdata) {		\
246	PCI_DEVICE(_vend, _dev),			\
247	.driver_data = (unsigned long)&_driverdata,	\
248}
249static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
250	C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
251		 c_can_sta2x11),
252	C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN,
253		 c_can_pch),
254	{},
255};
256static struct pci_driver c_can_pci_driver = {
257	.name = KBUILD_MODNAME,
258	.id_table = c_can_pci_tbl,
259	.probe = c_can_pci_probe,
260	.remove = c_can_pci_remove,
261};
262
263module_pci_driver(c_can_pci_driver);
264
265MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
266MODULE_LICENSE("GPL v2");
267MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
268MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);
269