]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/pcan_pci.c
e40db7c4515034e0ea6912bd4b69bafa7bf7f025
[lincan.git] / lincan / src / pcan_pci.c
1 /**************************************************************************/
2 /* File: pcan_pci.c - support for PEAK System PCAN-PCI cards              */
3 /*                                                                        */
4 /* LinCAN - (Not only) Linux CAN bus driver                               */
5 /* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz>   */
6 /* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz>             */
7 /* Funded by OCERA and FRESCOR IST projects                               */
8 /* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl>      */
9 /*                                                                        */
10 /* LinCAN is free software; you can redistribute it and/or modify it      */
11 /* under terms of the GNU General Public License as published by the      */
12 /* Free Software Foundation; either version 2, or (at your option) any    */
13 /* later version.  LinCAN is distributed in the hope that it will be      */
14 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
15 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
16 /* General Public License for more details. You should have received a    */
17 /* copy of the GNU General Public License along with LinCAN; see file     */
18 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
19 /* Cambridge, MA 02139, USA.                                              */
20 /*                                                                        */
21 /* To allow use of LinCAN in the compact embedded systems firmware        */
22 /* and RT-executives (RTEMS for example), main authors agree with next    */
23 /* special exception:                                                     */
24 /*                                                                        */
25 /* Including LinCAN header files in a file, instantiating LinCAN generics */
26 /* or templates, or linking other files with LinCAN objects to produce    */
27 /* an application image/executable, does not by itself cause the          */
28 /* resulting application image/executable to be covered by                */
29 /* the GNU General Public License.                                        */
30 /* This exception does not however invalidate any other reasons           */
31 /* why the executable file might be covered by the GNU Public License.    */
32 /* Publication of enhanced or derived LinCAN files is required although.  */
33 /**************************************************************************/
34
35 #include "../include/can.h"
36 #include "../include/can_sysdep.h"
37 #include "../include/main.h"
38 #include "../include/sja1000p.h"
39
40 #ifdef CAN_ENABLE_PCI_SUPPORT
41
42 /* This card is based on Infineon's PSB 4600 PITA bridge */
43
44 #define PITA_ICR         0x00        /* interrupt control register */
45 #define PITA_ICR_STAT    0x00        /*   - status/IRQ pending bits */
46 #define PITA_ICR_IEN     0x02        /*   - IRQ enable bits */
47 #define PITA_GPIOICR     0x18        /* general purpose IO interface control register */
48 #define PITA_MISC        0x1C        /* misc register */
49
50 #define PCAN_PCI_CONFIG_PORT_SIZE 0x1000  /* size of the config io-memory */
51 #define PCAN_PCI_PORT_SIZE        0x0400  /* size of a channel io-memory */
52
53 #define PCAN_PCI_VENDOR_ID      0x001C  /* PCAN-PCI and clones vednor id */
54 #define PCAN_PCI_PRODUCT_ID     0x0001  /* PCAN-PCI and clones device ID */
55
56 /* Standard value: Pushpull  (OCTP1|OCTN1|OCPOL1|OCTP0|OCTN0|OCM1) */
57 #define PCAN_PCI_OCR_DEFAULT_STD 0xFA
58
59 #define PCAN_PCI_BYTES_PER_CIRCUIT 0x400
60 #define PCAN_PCI_BYTES_PER_REG     4
61
62 /* Conversion of the chip index to IRQ register mask */
63 static unsigned int pcan_pci_idx2mask[4]={
64         0x0002,
65         0x0001,
66         0x0040,
67         0x0080
68 };
69
70 void pcan_pci_disconnect_irq(struct candevice_t *candev)
71 {
72         u16 w;
73
74         /* disable interrupts sources */
75         w = can_readw(candev->aux_base_addr + PITA_ICR_IEN);
76         can_writew(w & ~0xC3, candev->aux_base_addr + PITA_ICR_IEN);
77 }
78
79 void pcan_pci_connect_irq(struct candevice_t *candev)
80 {
81         u16 w;
82         int i;
83
84         /* clear previous accumulated status */
85         can_writew(0xC3, candev->aux_base_addr + PITA_ICR_STAT);
86
87         /* enable interrupts sources */
88         w = can_readw(candev->aux_base_addr + PITA_ICR_IEN);
89         for(i = 0; i < candev->nr_all_chips; i++)
90                 w |= pcan_pci_idx2mask[i];
91         can_writew(w, candev->aux_base_addr + PITA_ICR_IEN);
92 }
93
94
95 int pcan_pci_request_io(struct candevice_t *candev)
96 {
97         unsigned long ctrl_addr;
98         unsigned long io_addr;
99         int i;
100
101     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
102         if(pci_request_region(candev->sysdevptr.pcidev, 0, "pcan_pci_ctrl") != 0){
103                 CANMSG("Request of pcan_pci_ctrl range failed\n");
104                 return -ENODEV;
105         }else if(pci_request_region(candev->sysdevptr.pcidev, 1, "pcan_pci_io") != 0){
106                 CANMSG("Request of pcan_pci_io range failed\n");
107                 goto error_io;
108         }
109     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
110         if(pci_request_regions(candev->sysdevptr.pcidev, "pcan_pci") != 0){
111                 CANMSG("Request of pcan_pci_bridge regions failed\n");
112                 return -ENODEV;
113         }
114     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
115
116         ctrl_addr=pci_resource_start(candev->sysdevptr.pcidev,0);
117         if (!(candev->aux_base_addr = ioremap(ctrl_addr,
118               pci_resource_len(candev->sysdevptr.pcidev,0)))) {
119                 CANMSG("Unable to access I/O memory at: 0x%lx\n", ctrl_addr);
120                 goto error_ioremap_ctrl;
121         }
122
123         io_addr=pci_resource_start(candev->sysdevptr.pcidev,1);;
124         if (!(candev->dev_base_addr = ioremap(io_addr,
125               pci_resource_len(candev->sysdevptr.pcidev,1)))) {
126                 CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr);
127                 goto error_ioremap_io;
128         }
129
130         candev->io_addr=io_addr;
131         candev->res_addr=ctrl_addr;
132
133         /*
134          * this is redundant with chip initialization, but remap address
135          * can change when resources are temporarily released
136          */
137         for(i=0;i<candev->nr_all_chips;i++) {
138                 struct canchip_t *chip=candev->chip[i];
139                 if(!chip) continue;
140                 chip->chip_base_addr = candev->dev_base_addr +
141                         i * PCAN_PCI_BYTES_PER_CIRCUIT;
142                 if(!chip->msgobj[0]) continue;
143                 chip->msgobj[0]->obj_base_addr=chip->chip_base_addr;
144         }
145
146         pcan_pci_disconnect_irq(candev);
147
148         /* Configure PITA */
149         can_writew(0x0005, candev->aux_base_addr + PITA_GPIOICR + 2);   /* set GPIO control register */
150
151         can_writeb(0x00, candev->aux_base_addr + PITA_GPIOICR);         /* enable all channels */
152
153         can_writeb(0x05, candev->aux_base_addr + PITA_MISC + 3);        /* toggle reset */
154         mdelay(5);
155         writeb(0x04, candev->aux_base_addr + PITA_MISC + 3);            /* leave parport mux mode */
156         wmb();
157
158         return 0;
159
160     error_ioremap_io:
161         iounmap(candev->aux_base_addr);
162     error_ioremap_ctrl:
163     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
164         pci_release_region(candev->sysdevptr.pcidev, 1);
165     error_io:
166         pci_release_region(candev->sysdevptr.pcidev, 0);
167     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
168         pci_release_regions(candev->sysdevptr.pcidev);
169     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
170
171         return -ENODEV;
172 }
173
174 int pcan_pci_release_io(struct candevice_t *candev)
175 {
176         pcan_pci_disconnect_irq(candev);
177
178         iounmap(candev->dev_base_addr);
179         iounmap(candev->aux_base_addr);
180     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
181         pci_release_region(candev->sysdevptr.pcidev, 1);
182         pci_release_region(candev->sysdevptr.pcidev, 0);
183     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
184         pci_release_regions(candev->sysdevptr.pcidev);
185     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
186
187         return 0;
188 }
189
190 void pcan_pci_write_register(unsigned data, can_ioptr_t address)
191 {
192         address += ((can_ioptr2ulong(address)&(PCAN_PCI_BYTES_PER_CIRCUIT-1))
193                                              *(PCAN_PCI_BYTES_PER_REG-1));
194         can_writeb(data,address);
195 }
196
197 unsigned pcan_pci_read_register(can_ioptr_t address)
198 {
199         address += ((can_ioptr2ulong(address)&(PCAN_PCI_BYTES_PER_CIRCUIT-1))
200                                              *(PCAN_PCI_BYTES_PER_REG-1));
201         return can_readb(address);
202 }
203
204 int pcan_pci_irq_handler(int irq, struct canchip_t *chip)
205 {
206         struct candevice_t *candev=chip->hostdevice;
207         int ret;
208         unsigned int icr_stat;
209         unsigned int chip_mask = pcan_pci_idx2mask[chip->chip_idx];
210
211         icr_stat = can_readw(candev->aux_base_addr + PITA_ICR_STAT);
212
213         if(!(icr_stat & chip_mask)) return CANCHIP_IRQ_NONE;
214
215         ret = sja1000p_irq_handler(irq, chip);
216
217         can_writew(chip_mask, candev->aux_base_addr + PITA_ICR_STAT);
218
219         return ret;
220 }
221
222 int pcan_pci_reset(struct candevice_t *candev)
223 {
224         int i=0,chip_nr;
225         struct canchip_t *chip;
226         unsigned cdr;
227
228         DEBUGMSG("Resetting pcan_pci hardware ...\n");
229
230         pcan_pci_disconnect_irq(candev);
231
232         for(chip_nr=0;chip_nr<candev->nr_all_chips;chip_nr++){
233                 if(!candev->chip[chip_nr]) continue;
234                 chip=candev->chip[chip_nr];
235
236                 pcan_pci_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD);
237                 udelay(1000);
238
239                 cdr=pcan_pci_read_register(chip->chip_base_addr+SJACDR);
240                 pcan_pci_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
241
242                 pcan_pci_write_register(0, chip->chip_base_addr+SJAIER);
243
244                 i=20;
245                 pcan_pci_write_register(0, chip->chip_base_addr+SJAMOD);
246                 while (pcan_pci_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM){
247                         if(!i--) return -ENODEV;
248                         udelay(1000);
249                         pcan_pci_write_register(0, chip->chip_base_addr+SJAMOD);
250                 }
251
252                 cdr=pcan_pci_read_register(chip->chip_base_addr+SJACDR);
253                 pcan_pci_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
254
255                 pcan_pci_write_register(0, chip->chip_base_addr+SJAIER);
256
257                 pcan_pci_read_register(chip->chip_base_addr+SJAIR);
258         }
259
260
261         pcan_pci_connect_irq(candev);
262
263         return 0;
264 }
265
266 int pcan_pci_init_hw_data(struct candevice_t *candev)
267 {
268         struct pci_dev *pcidev = NULL;
269         int i;
270         int nr_chips;
271         u16 subsysid;
272
273         i = 0;
274         do {
275                 pcidev = pci_find_device(PCAN_PCI_VENDOR_ID, PCAN_PCI_PRODUCT_ID, pcidev);
276                 if(pcidev == NULL) {
277                         printk(KERN_ERR "No unused PCAN_PCI #%d card found\n", i);
278                         return -ENODEV;
279                 }
280                 i++;
281         } while(can_check_dev_taken(pcidev));
282
283         if (pci_enable_device (pcidev)){
284                 printk(KERN_ERR "Enable PCAN_PCI failed\n");
285                 return -EIO;
286         }
287         candev->sysdevptr.pcidev=pcidev;
288
289         if(pci_read_config_word(pcidev, 0x2E, &subsysid))
290                 goto error_ret;
291
292         if(pci_write_config_word(pcidev, 0x04, 2))
293                 goto error_ret;
294
295         if(pci_write_config_word(pcidev, 0x44, 0))
296                 goto error_ret;
297
298         wmb();
299
300         for(i=0;i<2;i++){
301                 if(!(pci_resource_flags(pcidev,0)&IORESOURCE_MEM)){
302                         printk(KERN_ERR "PCAN_PCI region %d is not memory\n",i);
303                         goto error_ret;
304                 }
305         }
306
307         candev->res_addr=pci_resource_start(pcidev,0);  /* Control registers */
308         candev->io_addr=pci_resource_start(pcidev,1);   /* SJA1000 chips are mapped here */
309         candev->dev_base_addr=pci_resource_start(pcidev,1);
310
311         /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/
312
313         if(subsysid >= 12)
314                 nr_chips = 4;
315         else if(subsysid >= 10)
316                 nr_chips = 3;
317         else if(subsysid >= 4)
318                 nr_chips = 2;
319         else
320                 nr_chips = 1;
321
322         candev->nr_82527_chips=0;
323         candev->nr_sja1000_chips=nr_chips;
324         candev->nr_all_chips=nr_chips;
325
326         printk(KERN_INFO "Found PCAN_PCI device with %d chip(s)\n", nr_chips);
327
328         return 0;
329
330 error_ret:
331
332         printk(KERN_CRIT "Setup of PCAN_PCI failed\n");
333         pci_disable_device (pcidev);
334         return -EIO;
335 }
336
337 int pcan_pci_init_chip_data(struct candevice_t *candev, int chipnr)
338 {
339
340         if(candev->sysdevptr.pcidev==NULL)
341                 return -ENODEV;
342
343         sja1000p_fill_chipspecops(candev->chip[chipnr]);
344
345         /* special version of the IRQ handler is required for PCAN_PCI board */
346         candev->chip[chipnr]->chipspecops->irq_handler=pcan_pci_irq_handler;
347
348         candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq;
349
350         candev->chip[chipnr]->chip_base_addr=
351                         can_ioport2ioptr(candev->io_addr+chipnr*PCAN_PCI_BYTES_PER_CIRCUIT);
352         candev->chip[chipnr]->flags = 0;
353         candev->chip[chipnr]->int_cpu_reg = 0;
354         candev->chip[chipnr]->int_clk_reg = 0;
355         candev->chip[chipnr]->int_bus_reg = 0;
356         candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
357         candev->chip[chipnr]->sja_ocr_reg = PCAN_PCI_OCR_DEFAULT_STD;
358         candev->chip[chipnr]->clock = 16000000;
359         candev->chip[chipnr]->flags |= CHIP_IRQ_PCI;
360
361         return 0;
362 }
363
364 int pcan_pci_init_obj_data(struct canchip_t *chip, int objnr)
365 {
366         chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
367         return 0;
368 }
369
370 int pcan_pci_program_irq(struct candevice_t *candev)
371 {
372
373         return 0;
374 }
375
376 int pcan_pci_register(struct hwspecops_t *hwspecops)
377 {
378         hwspecops->request_io = pcan_pci_request_io;
379         hwspecops->release_io = pcan_pci_release_io;
380         hwspecops->reset = pcan_pci_reset;
381         hwspecops->init_hw_data = pcan_pci_init_hw_data;
382         hwspecops->init_chip_data = pcan_pci_init_chip_data;
383         hwspecops->init_obj_data = pcan_pci_init_obj_data;
384         hwspecops->write_register = pcan_pci_write_register;
385         hwspecops->read_register = pcan_pci_read_register;
386         hwspecops->program_irq = pcan_pci_program_irq;
387         return 0;
388 }
389
390
391 #endif /*CAN_ENABLE_PCI_SUPPORT*/