Linux Audio

Check our new training course

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