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 | |
25 | enum c_can_pci_reg_align { |
26 | C_CAN_REG_ALIGN_16, |
27 | C_CAN_REG_ALIGN_32, |
28 | C_CAN_REG_32, |
29 | }; |
30 | |
31 | struct 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 | */ |
51 | static u16 c_can_pci_read_reg_aligned_to_16bit(const struct c_can_priv *priv, |
52 | enum reg index) |
53 | { |
54 | return readw(addr: priv->base + priv->regs[index]); |
55 | } |
56 | |
57 | static 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, addr: priv->base + priv->regs[index]); |
61 | } |
62 | |
63 | static u16 c_can_pci_read_reg_aligned_to_32bit(const struct c_can_priv *priv, |
64 | enum reg index) |
65 | { |
66 | return readw(addr: priv->base + 2 * priv->regs[index]); |
67 | } |
68 | |
69 | static 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, addr: priv->base + 2 * priv->regs[index]); |
73 | } |
74 | |
75 | static 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 | |
81 | static 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 | |
87 | static 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 | |
97 | static 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 | |
104 | static 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 | |
115 | static 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(dev: 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(dev: pdev); |
137 | if (!ret) { |
138 | dev_info(&pdev->dev, "MSI enabled\n" ); |
139 | pci_set_master(dev: pdev); |
140 | } |
141 | |
142 | addr = pci_iomap(dev: pdev, bar: 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(msg_obj_num: 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, data: 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 | |
224 | out_free_c_can: |
225 | free_c_can_dev(dev); |
226 | out_iounmap: |
227 | pci_iounmap(dev: pdev, addr); |
228 | out_release_regions: |
229 | pci_disable_msi(dev: pdev); |
230 | pci_release_regions(pdev); |
231 | out_disable_device: |
232 | pci_disable_device(dev: pdev); |
233 | out: |
234 | return ret; |
235 | } |
236 | |
237 | static 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(dev: pdev, addr); |
248 | pci_disable_msi(dev: pdev); |
249 | pci_release_regions(pdev); |
250 | pci_disable_device(dev: pdev); |
251 | } |
252 | |
253 | static 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 | |
261 | static 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 | |
275 | static 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 | |
283 | static 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 | |
290 | module_pci_driver(c_can_pci_driver); |
291 | |
292 | MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>" ); |
293 | MODULE_LICENSE("GPL v2" ); |
294 | MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller" ); |
295 | MODULE_DEVICE_TABLE(pci, c_can_pci_tbl); |
296 | |