c_can_pci.c revision e07e83ae600ea51b857e02132220eb7b7e52e928
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(const 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(const 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(const 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(const 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(const 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(const 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	ret = pci_enable_msi(pdev);
119	if (!ret) {
120		dev_info(&pdev->dev, "MSI enabled\n");
121		pci_set_master(pdev);
122	}
123
124	addr = pci_iomap(pdev, c_can_pci_data->bar,
125			 pci_resource_len(pdev, c_can_pci_data->bar));
126	if (!addr) {
127		dev_err(&pdev->dev,
128			"device has no PCI memory resources, "
129			"failing adapter\n");
130		ret = -ENOMEM;
131		goto out_release_regions;
132	}
133
134	/* allocate the c_can device */
135	dev = alloc_c_can_dev();
136	if (!dev) {
137		ret = -ENOMEM;
138		goto out_iounmap;
139	}
140
141	priv = netdev_priv(dev);
142	pci_set_drvdata(pdev, dev);
143	SET_NETDEV_DEV(dev, &pdev->dev);
144
145	dev->irq = pdev->irq;
146	priv->base = addr;
147
148	if (!c_can_pci_data->freq) {
149		dev_err(&pdev->dev, "no clock frequency defined\n");
150		ret = -ENODEV;
151		goto out_free_c_can;
152	} else {
153		priv->can.clock.freq = c_can_pci_data->freq;
154	}
155
156	/* Configure CAN type */
157	switch (c_can_pci_data->type) {
158	case BOSCH_C_CAN:
159		priv->regs = reg_map_c_can;
160		break;
161	case BOSCH_D_CAN:
162		priv->regs = reg_map_d_can;
163		priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
164		break;
165	default:
166		ret = -EINVAL;
167		goto out_free_c_can;
168	}
169
170	priv->type = c_can_pci_data->type;
171
172	/* Configure access to registers */
173	switch (c_can_pci_data->reg_align) {
174	case C_CAN_REG_ALIGN_32:
175		priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
176		priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
177		break;
178	case C_CAN_REG_ALIGN_16:
179		priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
180		priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
181		break;
182	case C_CAN_REG_32:
183		priv->read_reg = c_can_pci_read_reg_32bit;
184		priv->write_reg = c_can_pci_write_reg_32bit;
185		break;
186	default:
187		ret = -EINVAL;
188		goto out_free_c_can;
189	}
190
191	priv->raminit = c_can_pci_data->init;
192
193	ret = register_c_can_dev(dev);
194	if (ret) {
195		dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
196			KBUILD_MODNAME, ret);
197		goto out_free_c_can;
198	}
199
200	dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
201		 KBUILD_MODNAME, priv->regs, dev->irq);
202
203	return 0;
204
205out_free_c_can:
206	free_c_can_dev(dev);
207out_iounmap:
208	pci_iounmap(pdev, addr);
209out_release_regions:
210	pci_disable_msi(pdev);
211	pci_clear_master(pdev);
212	pci_release_regions(pdev);
213out_disable_device:
214	pci_disable_device(pdev);
215out:
216	return ret;
217}
218
219static void c_can_pci_remove(struct pci_dev *pdev)
220{
221	struct net_device *dev = pci_get_drvdata(pdev);
222	struct c_can_priv *priv = netdev_priv(dev);
223
224	unregister_c_can_dev(dev);
225
226	free_c_can_dev(dev);
227
228	pci_iounmap(pdev, priv->base);
229	pci_disable_msi(pdev);
230	pci_clear_master(pdev);
231	pci_release_regions(pdev);
232	pci_disable_device(pdev);
233}
234
235static struct c_can_pci_data c_can_sta2x11= {
236	.type = BOSCH_C_CAN,
237	.reg_align = C_CAN_REG_ALIGN_32,
238	.freq = 52000000, /* 52 Mhz */
239	.bar = 0,
240};
241
242static struct c_can_pci_data c_can_pch = {
243	.type = BOSCH_C_CAN,
244	.reg_align = C_CAN_REG_32,
245	.freq = 50000000, /* 50 MHz */
246	.init = c_can_pci_reset_pch,
247	.bar = 1,
248};
249
250#define C_CAN_ID(_vend, _dev, _driverdata) {		\
251	PCI_DEVICE(_vend, _dev),			\
252	.driver_data = (unsigned long)&_driverdata,	\
253}
254static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
255	C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
256		 c_can_sta2x11),
257	C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN,
258		 c_can_pch),
259	{},
260};
261static struct pci_driver c_can_pci_driver = {
262	.name = KBUILD_MODNAME,
263	.id_table = c_can_pci_tbl,
264	.probe = c_can_pci_probe,
265	.remove = c_can_pci_remove,
266};
267
268module_pci_driver(c_can_pci_driver);
269
270MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
271MODULE_LICENSE("GPL v2");
272MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
273MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);
274