aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/can/c_can/Kconfig7
-rw-r--r--drivers/net/can/c_can/Makefile1
-rw-r--r--drivers/net/can/c_can/c_can_pci.c236
3 files changed, 244 insertions, 0 deletions
diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
index 25d371cf98dd..3b83bafcd947 100644
--- a/drivers/net/can/c_can/Kconfig
+++ b/drivers/net/can/c_can/Kconfig
@@ -13,4 +13,11 @@ config CAN_C_CAN_PLATFORM
13 boards from ST Microelectronics (http://www.st.com) like the 13 boards from ST Microelectronics (http://www.st.com) like the
14 SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com) 14 SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
15 boards like am335x, dm814x, dm813x and dm811x. 15 boards like am335x, dm814x, dm813x and dm811x.
16
17config CAN_C_CAN_PCI
18 tristate "Generic PCI Bus based C_CAN/D_CAN driver"
19 depends on PCI
20 ---help---
21 This driver adds support for the C_CAN/D_CAN chips connected
22 to the PCI bus.
16endif 23endif
diff --git a/drivers/net/can/c_can/Makefile b/drivers/net/can/c_can/Makefile
index 9273f6d5c4b7..ad1cc842170a 100644
--- a/drivers/net/can/c_can/Makefile
+++ b/drivers/net/can/c_can/Makefile
@@ -4,5 +4,6 @@
4 4
5obj-$(CONFIG_CAN_C_CAN) += c_can.o 5obj-$(CONFIG_CAN_C_CAN) += c_can.o
6obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o 6obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
7obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o
7 8
8ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG 9ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/c_can/c_can_pci.c b/drivers/net/can/c_can/c_can_pci.c
new file mode 100644
index 000000000000..914aecfa09a9
--- /dev/null
+++ b/drivers/net/can/c_can/c_can_pci.c
@@ -0,0 +1,236 @@
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/clk.h>
17#include <linux/pci.h>
18
19#include <linux/can/dev.h>
20
21#include "c_can.h"
22
23enum c_can_pci_reg_align {
24 C_CAN_REG_ALIGN_16,
25 C_CAN_REG_ALIGN_32,
26};
27
28struct c_can_pci_data {
29 /* Specify if is C_CAN or D_CAN */
30 enum c_can_dev_id type;
31 /* Set the register alignment in the memory */
32 enum c_can_pci_reg_align reg_align;
33 /* Set the frequency if clk is not usable */
34 unsigned int freq;
35};
36
37/*
38 * 16-bit c_can registers can be arranged differently in the memory
39 * architecture of different implementations. For example: 16-bit
40 * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
41 * Handle the same by providing a common read/write interface.
42 */
43static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv,
44 enum reg index)
45{
46 return readw(priv->base + priv->regs[index]);
47}
48
49static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv,
50 enum reg index, u16 val)
51{
52 writew(val, priv->base + priv->regs[index]);
53}
54
55static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv,
56 enum reg index)
57{
58 return readw(priv->base + 2 * priv->regs[index]);
59}
60
61static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
62 enum reg index, u16 val)
63{
64 writew(val, priv->base + 2 * priv->regs[index]);
65}
66
67static int __devinit c_can_pci_probe(struct pci_dev *pdev,
68 const struct pci_device_id *ent)
69{
70 struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;
71 struct c_can_priv *priv;
72 struct net_device *dev;
73 void __iomem *addr;
74 struct clk *clk;
75 int ret;
76
77 ret = pci_enable_device(pdev);
78 if (ret) {
79 dev_err(&pdev->dev, "pci_enable_device FAILED\n");
80 goto out;
81 }
82
83 ret = pci_request_regions(pdev, KBUILD_MODNAME);
84 if (ret) {
85 dev_err(&pdev->dev, "pci_request_regions FAILED\n");
86 goto out_disable_device;
87 }
88
89 pci_set_master(pdev);
90 pci_enable_msi(pdev);
91
92 addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
93 if (!addr) {
94 dev_err(&pdev->dev,
95 "device has no PCI memory resources, "
96 "failing adapter\n");
97 ret = -ENOMEM;
98 goto out_release_regions;
99 }
100
101 /* allocate the c_can device */
102 dev = alloc_c_can_dev();
103 if (!dev) {
104 ret = -ENOMEM;
105 goto out_iounmap;
106 }
107
108 priv = netdev_priv(dev);
109 pci_set_drvdata(pdev, dev);
110 SET_NETDEV_DEV(dev, &pdev->dev);
111
112 dev->irq = pdev->irq;
113 priv->base = addr;
114
115 if (!c_can_pci_data->freq) {
116 /* get the appropriate clk */
117 clk = clk_get(&pdev->dev, NULL);
118 if (IS_ERR(clk)) {
119 dev_err(&pdev->dev, "no clock defined\n");
120 ret = -ENODEV;
121 goto out_free_c_can;
122 }
123 priv->can.clock.freq = clk_get_rate(clk);
124 priv->priv = clk;
125 } else {
126 priv->can.clock.freq = c_can_pci_data->freq;
127 priv->priv = NULL;
128 }
129
130 /* Configure CAN type */
131 switch (c_can_pci_data->type) {
132 case C_CAN_DEVTYPE:
133 priv->regs = reg_map_c_can;
134 break;
135 case D_CAN_DEVTYPE:
136 priv->regs = reg_map_d_can;
137 priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
138 break;
139 default:
140 ret = -EINVAL;
141 goto out_free_clock;
142 }
143
144 /* Configure access to registers */
145 switch (c_can_pci_data->reg_align) {
146 case C_CAN_REG_ALIGN_32:
147 priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
148 priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
149 break;
150 case C_CAN_REG_ALIGN_16:
151 priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
152 priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
153 break;
154 default:
155 ret = -EINVAL;
156 goto out_free_clock;
157 }
158
159 ret = register_c_can_dev(dev);
160 if (ret) {
161 dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
162 KBUILD_MODNAME, ret);
163 goto out_free_clock;
164 }
165
166 dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
167 KBUILD_MODNAME, priv->regs, dev->irq);
168
169 return 0;
170
171out_free_clock:
172 if (priv->priv)
173 clk_put(priv->priv);
174out_free_c_can:
175 pci_set_drvdata(pdev, NULL);
176 free_c_can_dev(dev);
177out_iounmap:
178 pci_iounmap(pdev, addr);
179out_release_regions:
180 pci_disable_msi(pdev);
181 pci_clear_master(pdev);
182 pci_release_regions(pdev);
183out_disable_device:
184 pci_disable_device(pdev);
185out:
186 return ret;
187}
188
189static void __devexit c_can_pci_remove(struct pci_dev *pdev)
190{
191 struct net_device *dev = pci_get_drvdata(pdev);
192 struct c_can_priv *priv = netdev_priv(dev);
193
194 unregister_c_can_dev(dev);
195
196 if (priv->priv)
197 clk_put(priv->priv);
198
199 pci_set_drvdata(pdev, NULL);
200 free_c_can_dev(dev);
201
202 pci_iounmap(pdev, priv->base);
203 pci_disable_msi(pdev);
204 pci_clear_master(pdev);
205 pci_release_regions(pdev);
206 pci_disable_device(pdev);
207}
208
209static struct c_can_pci_data c_can_sta2x11= {
210 .type = C_CAN_DEVTYPE,
211 .reg_align = C_CAN_REG_ALIGN_32,
212 .freq = 52000000, /* 52 Mhz */
213};
214
215#define C_CAN_ID(_vend, _dev, _driverdata) { \
216 PCI_DEVICE(_vend, _dev), \
217 .driver_data = (unsigned long)&_driverdata, \
218}
219static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
220 C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
221 c_can_sta2x11),
222 {},
223};
224static struct pci_driver c_can_pci_driver = {
225 .name = KBUILD_MODNAME,
226 .id_table = c_can_pci_tbl,
227 .probe = c_can_pci_probe,
228 .remove = __devexit_p(c_can_pci_remove),
229};
230
231module_pci_driver(c_can_pci_driver);
232
233MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
234MODULE_LICENSE("GPL v2");
235MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
236MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);