]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/esdpci200.c
Includded support for ESD Electronics CAN/PCI-200 card contributed by Manuel Bessler
[lincan.git] / lincan / src / esdpci200.c
1 /* esdpci200.c - support for ESD Electronics' CAN/PCI-200 cards
2  * Linux CAN-bus device driver.
3  * The card support was added by Manuel Bessler <m.bessler@gmx.net>
4  * Based on adlink7841.c and nsi_canpci.c
5  * This software is released under the GPL-License.
6  * Version lincan-0.3.3
7  */ 
8
9 #include "../include/can.h"
10 #include "../include/can_sysdep.h"
11 #include "../include/main.h"
12 #include "../include/sja1000p.h"
13
14 #ifdef CAN_ENABLE_PCI_SUPPORT
15
16 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
17         #define ioread32        readl
18         #define iowrite32       writel
19         #define ioread8         readb
20         #define iowrite8        writeb
21         #define wmb()
22         #define rmb()
23 #else
24 #endif
25
26 #define ESDPCI200_PCI_VENDOR_ID 0x10B5
27 #define ESDPCI200_PCI_PRODUCT_ID        0x9050
28
29 /* PCI to local bus bridge PLX9052 */
30
31 #define PLX9052_INTCSR  0x4c    /* interrupt control register */
32 #define PLX9052_CNTRL   0x50    /* control register, for software reset */
33
34 /* The ESD PCI/200 uses (per default) just LINTi1 (Local Interrupt 1)
35  * on the PLX. This means that both CAN channels' (SJA1000's) /INT pins 
36  * are OR'ed to the LINTi1 pin (actually ANDed in the 74HC08 since both
37  * the SJA1000's /INT pins and the LINTi1 pin are active low).
38  *
39  * The board does have an option to route the 2nd channel to LINTi2,
40  * apparently just one or two resistors need to be added.
41  *
42  * LINTi2 is floating per default, so don't set its interrupt enable flag 
43  * 'PLX9052_INTCSR_LI2EN', it'll just interrupt all the time.
44  */
45 #define PLX9052_INTCSR_LI1EN 0x00000001 /* Local Interrupt 1 enable */
46 #define PLX9052_INTCSR_LI1S  0x00000004 /* Local Interrupt 1 status */
47 #define PLX9052_INTCSR_LI2EN 0x00000008 /* Local Interrupt 2 enable */
48 #define PLX9052_INTCSR_LI2S  0x00000020 /* Local Interrupt 2 status */
49 #define PLX9052_INTCSR_PIEN  0x00000040 /* PCI Interrupt enable */
50
51 #define PLX9052_CNTRL_SWRESET 0x40000000 /* PCI Adapter Software Reset to Local Bus */
52
53 #define IO_RANGE 0x100
54 #define RESET_ADDR 0x00
55
56 // Standard value: Pushpull  (OCTP1|OCTN1|OCPOL1|OCTP0|OCTN0|OCM1)
57 #define ESDPCI200_OCR_DEFAULT_STD 0xFA
58 /* Setting the OCR register to 0xFA is a good idea. 
59    This means  normal output mode , push-pull and the correct polarity. */
60
61
62 void esdpci200_pci_soft_reset(struct candevice_t *candev)
63 {
64         unsigned long reg_reset;
65         reg_reset = inl( candev->dev_base_addr+PLX9052_CNTRL);
66         reg_reset &= ~(PLX9052_CNTRL_SWRESET);
67         rmb();
68         /* PCI Adapter Software Reset plus reset local bus */
69         outl( (reg_reset | PLX9052_CNTRL_SWRESET ), candev->dev_base_addr+PLX9052_CNTRL);
70         wmb();
71         udelay(2500);
72         outl(reg_reset, candev->dev_base_addr+PLX9052_CNTRL);
73         wmb();
74         udelay(2500);
75 }
76
77 void esdpci200_disconnect_irq(struct candevice_t *candev)
78 {
79     /* writing 0x0 into the PLX's INTCSR register disables interrupts */
80         /* 0x0 is also the value in the register after a power-on reset */
81         outl(0x0, candev->dev_base_addr + PLX9052_INTCSR);
82         DEBUGMSG("disabled interrupts on the PLX\n");
83 }
84
85 void esdpci200_connect_irq(struct candevice_t *candev)
86 {
87         /* enable interrupts for the SJA1000's, enable PCI interrupts */
88         outl(   PLX9052_INTCSR_LI1EN | PLX9052_INTCSR_PIEN,
89                 candev->dev_base_addr+PLX9052_INTCSR);
90         DEBUGMSG("enabled interrupts on the PLX\n"); 
91 }
92
93 int esdpci200_irq_handler(int irq, struct canchip_t *chip)
94 {
95         int retcode;
96         unsigned long it_reg;
97         struct candevice_t *candev;
98         candev = chip->hostdevice;
99         retcode = CANCHIP_IRQ_NONE;
100         //DEBUGMSG("Starting to handle an IRQ\n");
101         it_reg = inl(candev->dev_base_addr+PLX9052_INTCSR);
102         rmb();
103         if((it_reg & (PLX9052_INTCSR_LI1S | PLX9052_INTCSR_LI1EN) ) 
104                 == (PLX9052_INTCSR_LI1S | PLX9052_INTCSR_LI1EN) ) 
105         {       /*interrupt enabled and active */
106                 int chipnum;
107                 for(chipnum=0; chipnum < candev->nr_sja1000_chips; chipnum++)
108                 {
109                         if(sja1000p_irq_handler(irq, candev->chip[chipnum]) == CANCHIP_IRQ_NONE)
110                         { /* since both chips use the same IRQ and the same LINTi on the PLX,
111                              we need manually do 'interrupt sharing' on the boardlevel
112                              by checking all chips one-by-one */
113                                 continue;
114                         }
115                         else
116                         {
117                                 retcode=CANCHIP_IRQ_HANDLED;
118                         }
119                 }
120                 if( retcode != CANCHIP_IRQ_HANDLED )
121                 {/* None of the chips felt they were responsible for this IRQ... 
122                     so it appears we have problems with the IRQ */
123                         it_reg &= ~(PLX9052_INTCSR_LI1EN);
124                         //Either we have a problem with IRQ malfunctions, or our IRQ is shared with some other device.
125                         //
126                         //not actually disabled, unless outl() below is uncommented
127                         //outl(it_reg,(void*)(candev->dev_base_addr+PLX9052_INTCSR));
128                         //CANMSG("CAN Interrupt disabled due to malfunction\n");
129                 }
130         }
131         return retcode;
132 }
133
134 int esdpci200_request_io(struct candevice_t *candev)
135 {
136         return 0;
137 }
138
139 int esdpci200_release_io(struct candevice_t *candev)
140 {
141         esdpci200_disconnect_irq(candev);
142         esdpci200_pci_soft_reset(candev);
143
144         iounmap((void*)candev->io_addr);
145     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
146         pci_release_region(candev->sysdevptr.pcidev, 2);
147         pci_release_region(candev->sysdevptr.pcidev, 1);
148         pci_release_region(candev->sysdevptr.pcidev, 0);
149     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
150         pci_release_regions(candev->sysdevptr.pcidev);
151     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
152
153         return 0;
154 }
155
156 void esdpci200_write_register(unsigned data, unsigned long address)
157 {
158         //writeb(data,address); 
159         iowrite8((u8)data,(void*)address);
160         wmb();
161 }
162
163 unsigned esdpci200_read_register(unsigned long address)
164 {
165         //return readb(address);
166         return ioread8((void*)address);
167 }
168
169 int esdpci200_reset(struct candevice_t *candev)
170 {
171         int i=0,chip_nr;
172         struct canchip_t *chip;
173         unsigned cdr;
174         DEBUGMSG("Resetting esdpci200 hardware ...\n");
175
176         esdpci200_disconnect_irq(candev);
177         esdpci200_pci_soft_reset(candev);
178
179         for(chip_nr=0;chip_nr<candev->nr_all_chips;chip_nr++){
180                 if(!candev->chip[chip_nr]) continue;
181                 chip=candev->chip[chip_nr];
182
183                 esdpci200_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD);
184                 udelay(1000);
185
186                 cdr=esdpci200_read_register(chip->chip_base_addr+SJACDR);
187                 esdpci200_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
188
189                 esdpci200_write_register(0, chip->chip_base_addr+SJAIER);
190
191                 i=20;
192                 esdpci200_write_register(0, chip->chip_base_addr+SJAMOD);
193                 while (esdpci200_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM){
194                         if(!i--) return -ENODEV;
195                         udelay(1000);
196                         esdpci200_write_register(0, chip->chip_base_addr+SJAMOD);
197                 }
198
199                 cdr=esdpci200_read_register(chip->chip_base_addr+SJACDR);
200                 esdpci200_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
201
202                 esdpci200_write_register(0, chip->chip_base_addr+SJAIER);
203                 
204                 esdpci200_read_register(chip->chip_base_addr+SJAIR);
205         }
206         
207
208         esdpci200_connect_irq(candev);
209
210         return 0;
211 }       
212
213 int esdpci200_init_hw_data(struct candevice_t *candev)
214 {
215         struct pci_dev *pcidev = NULL;
216         unsigned long bar2_addr;
217
218         do {
219                 pcidev = pci_find_device(ESDPCI200_PCI_VENDOR_ID, ESDPCI200_PCI_PRODUCT_ID, pcidev);
220                 if(pcidev == NULL) return -ENODEV;
221         } while(can_check_dev_taken(pcidev));
222         
223         if (pci_enable_device (pcidev)){
224                 printk(KERN_CRIT "Setup of ESDPCI200 failed\n");
225                 return -EIO;
226         }
227         candev->sysdevptr.pcidev=pcidev;
228
229         can_spin_lock_init(&candev->device_lock);
230
231         if(!(pci_resource_flags(pcidev, 0)&IORESOURCE_MEM))
232         {
233            printk(KERN_CRIT "PCI200 region %d is not MEM\n",0);
234            return -EIO;
235         }
236         if(!(pci_resource_flags(pcidev, 1)&IORESOURCE_IO))
237         {
238            printk(KERN_CRIT "PCI200 region %d is not IO\n",1);
239            return -EIO;
240         }
241
242         if(!(pci_resource_flags(pcidev,2)&IORESOURCE_MEM))
243         {
244            printk(KERN_CRIT "PCI200 region %d is not MEM\n",2);
245            return -EIO;
246         }
247         
248
249         #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
250         if(pci_request_region(candev->sysdevptr.pcidev, 0, "esdpci200_plx9050") != 0){
251                 CANMSG("Request of esdpci200_plx9050 range failed\n");
252                 return -ENODEV;
253         }else if(pci_request_region(candev->sysdevptr.pcidev, 1, "esdpci200_io") != 0){
254                 CANMSG("Request of esdpci200_io range failed\n");
255                 pci_release_region(candev->sysdevptr.pcidev, 0);
256                 return -ENODEV;
257         }else if(pci_request_region(candev->sysdevptr.pcidev, 2, "esdpci200_sja") != 0){
258                 CANMSG("Request of esdpci200_sja range failed\n");
259                 pci_release_region(candev->sysdevptr.pcidev, 1);
260                 pci_release_region(candev->sysdevptr.pcidev, 0);
261                 return -ENODEV;
262         }
263         #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
264         if(pci_request_regions(candev->sysdevptr.pcidev, "esdpci200") != 0){
265                 CANMSG("Request of esdpci200_plx9050 regions failed\n");
266                 return -ENODEV;
267         }
268         #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
269
270
271         candev->res_addr=RESET_ADDR; /* reset address not used currently. Not used by other Lincan parts either */
272         candev->dev_base_addr=pci_resource_start(pcidev,1); /* ioports, PLX local configuration registers */
273         bar2_addr = pci_resource_start(pcidev,2);
274         if( ! (candev->io_addr=(long)ioremap(bar2_addr, 
275                 pci_resource_len(pcidev,2)))) /*MEM window for SJA1000 chips*/
276         {
277                 CANMSG("Unable to access I/O memory at: 0x%lx\n", bar2_addr);
278                 goto ioremap_error;
279         }
280         /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/
281
282         candev->nr_82527_chips=0;
283         candev->nr_sja1000_chips=2;
284         candev->nr_all_chips=2;
285
286         return 0;
287
288     ioremap_error:
289         #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
290         pci_release_region(candev->sysdevptr.pcidev, 2);
291         pci_release_region(candev->sysdevptr.pcidev, 1);
292         pci_release_region(candev->sysdevptr.pcidev, 0);
293         #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
294         pci_release_regions(candev->sysdevptr.pcidev);
295         #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
296         return -ENODEV;
297 }
298
299 int esdpci200_init_chip_data(struct candevice_t *candev, int chipnr)
300 {
301
302         if(candev->sysdevptr.pcidev==NULL)
303                 return -ENODEV; 
304
305         CANMSG("initializing esdpci200 chip operations\n");
306
307
308         sja1000p_fill_chipspecops(candev->chip[chipnr]);
309 //      candev->chip[chipnr]->chip_base_addr= candev->io_addr + chipnr*IO_RANGE;
310         //candev->chip[chipnr]->chip_base_addr= (long)ioremap( candev->io_addr, IO_RANGE ) + chipnr * IO_RANGE;
311         candev->chip[chipnr]->chip_base_addr=candev->io_addr + chipnr * IO_RANGE;
312
313         candev->chip[chipnr]->chipspecops->irq_handler=esdpci200_irq_handler;
314
315         candev->chip[chipnr]->flags = 0;
316         candev->chip[chipnr]->int_cpu_reg = 0; /* i82527 specific */
317         candev->chip[chipnr]->int_clk_reg = 0; /* i82527 specific */
318         candev->chip[chipnr]->int_bus_reg = 0; /* i82527 specific */
319         candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF; /* hardware specific options for the Clock Divider register */
320         candev->chip[chipnr]->sja_ocr_reg = ESDPCI200_OCR_DEFAULT_STD; /* hardware specific options for the Output Control register */
321         candev->chip[chipnr]->clock = 16000000;
322         candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq;
323         candev->chip[chipnr]->flags |= CHIP_IRQ_PCI;
324         if( chipnr > 0 ) /* only one IRQ used for both channels.
325                             CHIP_IRQ_CUSTOM req'd for RTAI, since 
326                             registering two handlers for the same IRQ 
327                             returns an error */
328                 candev->chip[chipnr]->flags |= CHIP_IRQ_CUSTOM;
329
330         return 0;
331 }       
332
333 int esdpci200_init_obj_data(struct canchip_t *chip, int objnr)
334 {
335         chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
336         return 0;
337 }
338
339 int esdpci200_program_irq(struct candevice_t *candev)
340 {
341
342         return 0;
343 }
344
345 int esdpci200_register(struct hwspecops_t *hwspecops)
346 {
347         hwspecops->request_io = esdpci200_request_io;
348         hwspecops->release_io = esdpci200_release_io;
349         hwspecops->reset = esdpci200_reset;
350         hwspecops->init_hw_data = esdpci200_init_hw_data;
351         hwspecops->init_chip_data = esdpci200_init_chip_data;
352         hwspecops->init_obj_data = esdpci200_init_obj_data;
353         hwspecops->write_register = esdpci200_write_register;
354         hwspecops->read_register = esdpci200_read_register;
355         hwspecops->program_irq = esdpci200_program_irq;
356         return 0;
357 }
358
359
360 #endif /*CAN_ENABLE_PCI_SUPPORT*/