c49a3def3d7e5a617ddec58a9ab6bdcc93fa1ee3
[lincan.git] / lincan / src / kv_pcican.c
1 /* kv_pcican.c - support for KVASER PCIcan-S/D/Q cards
2  * Linux CAN-bus device driver.
3  * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
4  * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
5  * email:pisa@cmp.felk.cvut.cz
6  * This software is released under the GPL-License.
7  * Version lincan-0.2  9 Jul 2003
8  */ 
9
10 #include "../include/can.h"
11 #include "../include/can_sysdep.h"
12 #include "../include/main.h"
13 #include "../include/sja1000p.h"
14
15 #ifdef CAN_ENABLE_PCI_SUPPORT
16
17 #define KV_PCICAN_PCICAN_VENDOR  0x10e8
18 #define KV_PCICAN_PCICAN_ID 0x8406
19
20 /*AMCC 5920*/
21
22 #define S5920_OMB    0x0C
23 #define S5920_IMB    0x1C
24 #define S5920_MBEF   0x34
25 #define S5920_INTCSR 0x38
26 #define S5920_RCR    0x3C
27 #define S5920_PTCR   0x60
28
29 #define INTCSR_ADDON_INTENABLE_M        0x2000
30 #define INTCSR_INTERRUPT_ASSERTED_M     0x800000
31
32 #define KV_PCICAN_BYTES_PER_CIRCUIT 0x20
33
34 // Standard value: Pushpull  (OCTP1|OCTN1|OCTP0|OCTN0|OCM1)
35 #define KV_PCICAN_OCR_DEFAULT_STD 0xDA
36 // For Galathea piggyback.
37 #define KV_PCICAN_OCR_DEFAULT_GAL 0xDB
38
39 /*
40
41 You need to know the following: 
42 " RX1 is connected to ground. 
43 " TX1 is not connected. 
44 " CLKO is not connected. 
45 " Setting the OCR register to 0xDA is a good idea. 
46   This means  normal output mode , push-pull and the correct polarity. 
47 " In the CDR register, you should set CBP to 1. 
48   You will probably also want to set the clock divider value to 0 (meaning divide-by-2),
49   the Pelican bit, and the clock-off bit (you have no need for CLKOUT anyway.)
50
51 */
52
53
54
55 void kv_pcican_disconnect_irq(struct candevice_t *candev)
56 {
57         unsigned long tmp;
58         /* Disable interrupts from card */
59         tmp = inl(candev->dev_base_addr + S5920_INTCSR);
60         tmp &= ~INTCSR_ADDON_INTENABLE_M;
61         outl(tmp, candev->dev_base_addr + S5920_INTCSR);
62 }
63
64 void kv_pcican_connect_irq(struct candevice_t *candev)
65 {
66         unsigned long tmp;
67         /* Enable interrupts from card */
68         tmp = inl(candev->dev_base_addr + S5920_INTCSR);
69         tmp |= INTCSR_ADDON_INTENABLE_M;
70         outl(tmp, candev->dev_base_addr + S5920_INTCSR);
71 }
72
73
74 int kv_pcican_request_io(struct candevice_t *candev)
75 {
76     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
77         if(pci_request_region(candev->sysdevptr.pcidev, 0, "kv_pcican_s5920") != 0){
78                 CANMSG("Request of kv_pcican_s5920 range failed\n");
79                 return -ENODEV;
80         }else if(pci_request_region(candev->sysdevptr.pcidev, 1, "kv_pcican_io") != 0){
81                 CANMSG("Request of kv_pcican_io range failed\n");
82                 goto error_io;
83         }else if(pci_request_region(candev->sysdevptr.pcidev, 2, "kv_pcican_xilinx") != 0){
84                 CANMSG("Request of kv_pcican_xilinx range failed\n");
85                 goto error_xilinx;
86         }
87     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
88         if(pci_request_regions(candev->sysdevptr.pcidev, "kv_pcican") != 0){
89                 CANMSG("Request of kv_pcican_s5920 regions failed\n");
90                 return -ENODEV;
91         }
92     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
93
94         kv_pcican_disconnect_irq(candev);
95
96         return 0;
97
98     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
99     error_xilinx:
100         pci_release_region(candev->sysdevptr.pcidev, 1);
101     error_io:
102         pci_release_region(candev->sysdevptr.pcidev, 0);
103     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
104         
105         return -ENODEV;
106 }
107
108 int kv_pcican_release_io(struct candevice_t *candev)
109 {
110         kv_pcican_disconnect_irq(candev);
111
112     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
113         pci_release_region(candev->sysdevptr.pcidev, 2);
114         pci_release_region(candev->sysdevptr.pcidev, 1);
115         pci_release_region(candev->sysdevptr.pcidev, 0);
116     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
117         pci_release_regions(candev->sysdevptr.pcidev);
118     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
119
120         return 0;
121 }
122
123
124 void kv_pcican_write_register(unsigned char data, unsigned long address)
125 {
126         outb(data,address); 
127 }
128
129 unsigned kv_pcican_read_register(unsigned long address)
130 {
131         return inb(address);
132 }
133
134 int kv_pcican_reset(struct candevice_t *candev)
135 {
136         int i=0,chip_nr;
137         struct chip_t *chip;
138         unsigned cdr;
139
140         DEBUGMSG("Resetting kv_pcican hardware ...\n");
141
142         /* Assert PTADR# - we're in passive mode so the other bits are not important */
143         outl(0x80808080L, candev->dev_base_addr + S5920_PTCR);
144
145         kv_pcican_disconnect_irq(candev);
146
147         for(chip_nr=0;chip_nr<candev->nr_all_chips;chip_nr++){
148                 if(!candev->chip[chip_nr]) continue;
149                 chip=candev->chip[chip_nr];
150
151                 kv_pcican_write_register(MOD_RM, chip->chip_base_addr+SJAMOD);
152                 udelay(1000);
153
154                 cdr=kv_pcican_read_register(chip->chip_base_addr+SJACDR);
155                 kv_pcican_write_register(cdr|CDR_PELICAN, chip->chip_base_addr+SJACDR);
156
157                 kv_pcican_write_register(0, chip->chip_base_addr+SJAIER);
158
159                 i=20;
160                 kv_pcican_write_register(0, chip->chip_base_addr+SJAMOD);
161                 while (kv_pcican_read_register(chip->chip_base_addr+SJAMOD)&MOD_RM){
162                         if(!i--) return -ENODEV;
163                         udelay(1000);
164                         kv_pcican_write_register(0, chip->chip_base_addr+SJAMOD);
165                 }
166
167                 cdr=kv_pcican_read_register(chip->chip_base_addr+SJACDR);
168                 kv_pcican_write_register(cdr|CDR_PELICAN, chip->chip_base_addr+SJACDR);
169
170                 kv_pcican_write_register(0, chip->chip_base_addr+SJAIER);
171                 
172                 kv_pcican_read_register(chip->chip_base_addr+SJAIR);
173         }
174         
175
176         kv_pcican_connect_irq(candev);
177
178         return 0;
179 }       
180
181 int kv_pcican_init_hw_data(struct candevice_t *candev)
182 {
183         struct pci_dev *pcidev = NULL;
184         int i;
185
186         pcidev = pci_find_device(KV_PCICAN_PCICAN_VENDOR, KV_PCICAN_PCICAN_ID, pcidev);
187         if(pcidev == NULL) return -ENODEV;
188         
189         if (pci_enable_device (pcidev)){
190                 printk(KERN_CRIT "Setup of PCICAN failed\n");
191                 return -EIO;
192         }
193         candev->sysdevptr.pcidev=pcidev;
194         
195         for(i=0;i<3;i++){
196                 if(!(pci_resource_flags(pcidev,0)&IORESOURCE_IO)){
197                         printk(KERN_CRIT "PCICAN region %d is not IO\n",i);
198                         return -EIO;
199                 }
200         }
201         candev->dev_base_addr=pci_resource_start(pcidev,0); /*S5920*/
202         candev->io_addr=pci_resource_start(pcidev,1); /*IO window for SJA1000 chips*/
203         candev->res_addr=pci_resource_start(pcidev,2); /*XILINX board wide address*/
204         
205         /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/
206
207         if (!strcmp(candev->hwname,"pcican-s")) {
208                 candev->nr_82527_chips=0;
209                 candev->nr_sja1000_chips=1;
210                 candev->nr_all_chips=1;
211         }
212         if (!strcmp(candev->hwname,"pcican-d")) {
213                 candev->nr_82527_chips=0;
214                 candev->nr_sja1000_chips=2;
215                 candev->nr_all_chips=2;
216         }
217         if (!strcmp(candev->hwname,"pcican-q")) {
218                 candev->nr_82527_chips=0;
219                 candev->nr_sja1000_chips=4;
220                 candev->nr_all_chips=4;
221         }
222
223         return 0;
224 }
225
226 int kv_pcican_init_chip_data(struct candevice_t *candev, int chipnr)
227 {
228
229         if(candev->sysdevptr.pcidev==NULL)
230                 return -ENODEV;
231         
232         candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq;
233
234         candev->chip[chipnr]->chip_type="sja1000p";
235         candev->chip[chipnr]->chip_base_addr=
236                         candev->io_addr+chipnr*KV_PCICAN_BYTES_PER_CIRCUIT;
237         candev->chip[chipnr]->flags = 0;
238         candev->chip[chipnr]->int_cpu_reg = 0;
239         candev->chip[chipnr]->int_clk_reg = 0;
240         candev->chip[chipnr]->int_bus_reg = 0;
241         candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF;
242         candev->chip[chipnr]->sja_ocr_reg = KV_PCICAN_OCR_DEFAULT_STD;
243         candev->chip[chipnr]->clock = 16000000;
244         candev->chip[chipnr]->flags |= CHIP_IRQ_PCI;
245
246         return 0;
247 }       
248
249 int kv_pcican_init_obj_data(struct chip_t *chip, int objnr)
250 {
251         chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
252         return 0;
253 }
254
255 int kv_pcican_program_irq(struct candevice_t *candev)
256 {
257
258         return 0;
259 }
260
261 int kv_pcican_register(struct hwspecops_t *hwspecops)
262 {
263         hwspecops->request_io = kv_pcican_request_io;
264         hwspecops->release_io = kv_pcican_release_io;
265         hwspecops->reset = kv_pcican_reset;
266         hwspecops->init_hw_data = kv_pcican_init_hw_data;
267         hwspecops->init_chip_data = kv_pcican_init_chip_data;
268         hwspecops->init_obj_data = kv_pcican_init_obj_data;
269         hwspecops->write_register = kv_pcican_write_register;
270         hwspecops->read_register = kv_pcican_read_register;
271         hwspecops->program_irq = kv_pcican_program_irq;
272         return 0;
273 }
274
275
276 #endif /*CAN_ENABLE_PCI_SUPPORT*/