]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/pcisja1000mm.c
Actual driver code for directly mapped SJA1000 into PCI mem region 0.
[lincan.git] / lincan / src / pcisja1000mm.c
1 /**************************************************************************/
2 /* File: pcisja1000mm.c - SJA1000 directly mapped into PCI mem region 0   */
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 #define DIRECT_PCISJA100_VENDOR        0x1b36
43 #define DIRECT_PCISJA100_ID            0xbeef
44
45 #define PCISJA1000MM_OCR_DEFAULT_STD   0xDA
46
47 #define PCISJA1000MM_BYTES_PER_CIRCUIT 0x80
48
49 void pcisja1000mm_disconnect_irq(struct candevice_t *candev)
50 {
51 }
52
53 void pcisja1000mm_connect_irq(struct candevice_t *candev)
54 {
55 }
56
57 int pcisja1000mm_request_io(struct candevice_t *candev)
58 {
59         unsigned long io_addr;
60         int i;
61
62     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
63         if(pci_request_region(candev->sysdevptr.pcidev, 0, "pcisja1000mm") != 0){
64                 CANMSG("Request of pcisja1000mm range failed\n");
65                 return -ENODEV;
66         }
67     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
68         if(pci_request_regions(candev->sysdevptr.pcidev, "pcisja1000mm") != 0){
69                 CANMSG("Request of pcisja1000mm regions failed\n");
70                 return -ENODEV;
71         }
72     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
73
74         io_addr=pci_resource_start(candev->sysdevptr.pcidev,0);;
75         if (!(candev->dev_base_addr = ioremap(io_addr,
76               pci_resource_len(candev->sysdevptr.pcidev,0)))) {
77                 CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr);
78                 goto error_ioremap_io;
79         }
80
81         candev->io_addr=io_addr;
82
83         /*
84          * this is redundant with chip initialization, but remap address
85          * can change when resources are temporarily released
86          */
87         for(i=0;i<candev->nr_all_chips;i++) {
88                 struct canchip_t *chip=candev->chip[i];
89                 if(!chip) continue;
90                 chip->chip_base_addr = candev->dev_base_addr +
91                         i * PCISJA1000MM_BYTES_PER_CIRCUIT;
92                 if(!chip->msgobj[0]) continue;
93                 chip->msgobj[0]->obj_base_addr=chip->chip_base_addr;
94         }
95
96         pcisja1000mm_disconnect_irq(candev);
97
98         return 0;
99
100 error_ioremap_io:
101     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
102         pci_release_region(candev->sysdevptr.pcidev, 0);
103     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
104         pci_release_regions(candev->sysdevptr.pcidev);
105     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
106         return -ENODEV;
107 }
108
109 int pcisja1000mm_release_io(struct candevice_t *candev)
110 {
111         pcisja1000mm_disconnect_irq(candev);
112
113         iounmap(candev->dev_base_addr);
114
115     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
116         pci_release_region(candev->sysdevptr.pcidev, 0);
117     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
118         pci_release_regions(candev->sysdevptr.pcidev);
119     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
120
121         return 0;
122 }
123
124
125 void pcisja1000mm_write_register(unsigned data, can_ioptr_t address)
126 {
127         can_writeb(data,address);
128 }
129
130 unsigned pcisja1000mm_read_register(can_ioptr_t address)
131 {
132         return can_readb(address);
133 }
134
135 int pcisja1000mm_reset(struct candevice_t *candev)
136 {
137         int i=0,chip_nr;
138         struct canchip_t *chip;
139         unsigned cdr;
140
141         DEBUGMSG("Resetting pcisja1000mm hardware ...\n");
142
143         pcisja1000mm_disconnect_irq(candev);
144
145         for(chip_nr=0;chip_nr<candev->nr_all_chips;chip_nr++){
146                 if(!candev->chip[chip_nr]) continue;
147                 chip=candev->chip[chip_nr];
148
149                 pcisja1000mm_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD);
150                 udelay(1000);
151
152                 cdr=pcisja1000mm_read_register(chip->chip_base_addr+SJACDR);
153                 pcisja1000mm_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
154
155                 pcisja1000mm_write_register(0, chip->chip_base_addr+SJAIER);
156
157                 i=20;
158                 pcisja1000mm_write_register(0, chip->chip_base_addr+SJAMOD);
159                 while (pcisja1000mm_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM){
160                         if(!i--) return -ENODEV;
161                         udelay(1000);
162                         pcisja1000mm_write_register(0, chip->chip_base_addr+SJAMOD);
163                 }
164
165                 cdr=pcisja1000mm_read_register(chip->chip_base_addr+SJACDR);
166                 pcisja1000mm_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
167
168                 pcisja1000mm_write_register(0, chip->chip_base_addr+SJAIER);
169
170                 pcisja1000mm_read_register(chip->chip_base_addr+SJAIR);
171         }
172
173
174         pcisja1000mm_connect_irq(candev);
175
176         return 0;
177 }
178
179 int pcisja1000mm_init_hw_data(struct candevice_t *candev)
180 {
181         struct pci_dev *pcidev;
182         int i;
183
184         pcidev = can_pci_get_next_untaken_device(DIRECT_PCISJA100_VENDOR, DIRECT_PCISJA100_ID);
185         if(pcidev == NULL)
186                 return -ENODEV;
187
188         if (pci_enable_device (pcidev)){
189                 printk(KERN_CRIT "Setup of PCISJA1000MM failed\n");
190                 can_pci_dev_put(pcidev);
191                 return -EIO;
192         }
193         candev->sysdevptr.pcidev=pcidev;
194
195         for(i=0;i<1;i++){
196
197                 if(!(pci_resource_flags(pcidev,0)&IORESOURCE_MEM)){
198                         printk(KERN_ERR "PCISJA1000MM region %d is not memory\n",i);
199                         goto error_ret;
200                 }
201         }
202         candev->io_addr=pci_resource_start(pcidev,0); /*IO window for SJA1000 chips*/
203         candev->dev_base_addr=can_ulong2ioptr(candev->io_addr);
204         candev->res_addr=0;
205
206         /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/
207
208         candev->nr_82527_chips=0;
209         candev->nr_sja1000_chips=1;
210         candev->nr_all_chips=1;
211
212         return 0;
213
214 error_ret:
215
216         printk(KERN_CRIT "Setup of PCISJA1000MM failed\n");
217         pci_disable_device (pcidev);
218         can_pci_dev_put(pcidev);
219         return -EIO;
220 }
221
222 void pcisja1000mm_done_hw_data(struct candevice_t *candev)
223 {
224         struct pci_dev *pcidev = candev->sysdevptr.pcidev;
225         can_pci_dev_put(pcidev);
226 }
227
228 int pcisja1000mm_init_chip_data(struct candevice_t *candev, int chipnr)
229 {
230
231         if(candev->sysdevptr.pcidev==NULL)
232                 return -ENODEV;
233
234         candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq;
235
236         sja1000p_fill_chipspecops(candev->chip[chipnr]);
237         candev->chip[chipnr]->chip_base_addr=
238                         can_ioport2ioptr(candev->io_addr+chipnr*PCISJA1000MM_BYTES_PER_CIRCUIT);
239
240         candev->chip[chipnr]->flags = 0;
241         candev->chip[chipnr]->int_cpu_reg = 0;
242         candev->chip[chipnr]->int_clk_reg = 0;
243         candev->chip[chipnr]->int_bus_reg = 0;
244         candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
245         candev->chip[chipnr]->sja_ocr_reg = PCISJA1000MM_OCR_DEFAULT_STD;
246         candev->chip[chipnr]->clock = 16000000;
247         candev->chip[chipnr]->flags |= CHIP_IRQ_PCI;
248
249         return 0;
250 }
251
252 int pcisja1000mm_init_obj_data(struct canchip_t *chip, int objnr)
253 {
254         chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
255         return 0;
256 }
257
258 int pcisja1000mm_program_irq(struct candevice_t *candev)
259 {
260
261         return 0;
262 }
263
264 int pcisja1000mm_register(struct hwspecops_t *hwspecops)
265 {
266         hwspecops->request_io = pcisja1000mm_request_io;
267         hwspecops->release_io = pcisja1000mm_release_io;
268         hwspecops->reset = pcisja1000mm_reset;
269         hwspecops->init_hw_data = pcisja1000mm_init_hw_data;
270         hwspecops->done_hw_data = pcisja1000mm_done_hw_data;
271         hwspecops->init_chip_data = pcisja1000mm_init_chip_data;
272         hwspecops->init_obj_data = pcisja1000mm_init_obj_data;
273         hwspecops->write_register = pcisja1000mm_write_register;
274         hwspecops->read_register = pcisja1000mm_read_register;
275         hwspecops->program_irq = pcisja1000mm_program_irq;
276         return 0;
277 }
278
279
280 #endif /*CAN_ENABLE_PCI_SUPPORT*/