]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/adlink7841.c
18266b8716cea5ca23f7e7b5148abd47f9b73eca
[lincan.git] / lincan / src / adlink7841.c
1 /**************************************************************************/
2 /* File: adlink7841.c - support for ADLINK 7841 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 #define ADLINK7841_PCI_VENDOR_ID        0x144A  /* ADLINK vednor id */
43 #define ADLINK7841_PCI_PRODUCT_ID       0x7841  /* PCI 7841 device ID */
44
45 /* PCI to local bus bridge PLX9050 */
46
47 #define PLX9050_INTCSR  0x4c    /* interrupt control register */
48
49 #define ADLINK7841_BYTES_PER_CIRCUIT 0x80
50
51 // Standard value: Pushpull  (OCTP1|OCTN1|OCPOL1|OCTP0|OCTN0|OCM1)
52 #define ADLINK7841_OCR_DEFAULT_STD 0xFA
53
54 /*
55
56 You need to know the following: 
57 " RX1 is connected to ground. 
58 " TX1 is not connected. 
59 " CLKO is not connected. 
60 " Setting the OCR register to 0xFA is a good idea. 
61   This means  normal output mode , push-pull and the correct polarity. 
62 " In the CDR register, you should set CBP to 1. 
63   You will probably also want to set the clock divider value to 0 (meaning divide-by-2),
64   the Pelican bit, and the clock-off bit (you have no need for CLKOUT anyway.)
65
66 */
67
68
69
70 void adlink7841_disconnect_irq(struct candevice_t *candev)
71 {
72 }
73
74 void adlink7841_connect_irq(struct candevice_t *candev)
75 {
76 }
77
78
79 int adlink7841_request_io(struct candevice_t *candev)
80 {
81     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
82         if(pci_request_region(candev->sysdevptr.pcidev, 1, "adlink7841_plx9050") != 0){
83                 CANMSG("Request of adlink7841_plx9050 range failed\n");
84                 return -ENODEV;
85         }else if(pci_request_region(candev->sysdevptr.pcidev, 2, "adlink7841_io") != 0){
86                 CANMSG("Request of adlink7841_io range failed\n");
87                 goto error_io;
88         }
89     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
90         if(pci_request_regions(candev->sysdevptr.pcidev, "adlink7841") != 0){
91                 CANMSG("Request of adlink7841_plx9050 regions failed\n");
92                 return -ENODEV;
93         }
94     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
95
96         adlink7841_disconnect_irq(candev);
97
98         return 0;
99
100     #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))
101     error_io:
102         pci_release_region(candev->sysdevptr.pcidev, 1);
103     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
104         
105         return -ENODEV;
106 }
107
108 int adlink7841_release_io(struct candevice_t *candev)
109 {
110         adlink7841_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     #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
116         pci_release_regions(candev->sysdevptr.pcidev);
117     #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/
118
119         return 0;
120 }
121
122
123 void adlink7841_write_register(unsigned data, can_ioptr_t address)
124 {
125         can_outb(data,address); 
126 }
127
128 unsigned adlink7841_read_register(can_ioptr_t address)
129 {
130         return can_inb(address);
131 }
132
133 int adlink7841_reset(struct candevice_t *candev)
134 {
135         int i=0,chip_nr;
136         struct canchip_t *chip;
137         unsigned cdr;
138
139         DEBUGMSG("Resetting adlink7841 hardware ...\n");
140
141         adlink7841_disconnect_irq(candev);
142
143         for(chip_nr=0;chip_nr<candev->nr_all_chips;chip_nr++){
144                 if(!candev->chip[chip_nr]) continue;
145                 chip=candev->chip[chip_nr];
146
147                 adlink7841_write_register(sjaMOD_RM, chip->chip_base_addr+SJAMOD);
148                 udelay(1000);
149
150                 cdr=adlink7841_read_register(chip->chip_base_addr+SJACDR);
151                 adlink7841_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
152
153                 adlink7841_write_register(0, chip->chip_base_addr+SJAIER);
154
155                 i=20;
156                 adlink7841_write_register(0, chip->chip_base_addr+SJAMOD);
157                 while (adlink7841_read_register(chip->chip_base_addr+SJAMOD)&sjaMOD_RM){
158                         if(!i--) return -ENODEV;
159                         udelay(1000);
160                         adlink7841_write_register(0, chip->chip_base_addr+SJAMOD);
161                 }
162
163                 cdr=adlink7841_read_register(chip->chip_base_addr+SJACDR);
164                 adlink7841_write_register(cdr|sjaCDR_PELICAN, chip->chip_base_addr+SJACDR);
165
166                 adlink7841_write_register(0, chip->chip_base_addr+SJAIER);
167                 
168                 adlink7841_read_register(chip->chip_base_addr+SJAIR);
169         }
170         
171
172         adlink7841_connect_irq(candev);
173
174         return 0;
175 }       
176
177 int adlink7841_init_hw_data(struct candevice_t *candev)
178 {
179         struct pci_dev *pcidev = NULL;
180         int i;
181
182         do {
183                 pcidev = pci_find_device(ADLINK7841_PCI_VENDOR_ID, ADLINK7841_PCI_PRODUCT_ID, pcidev);
184                 if(pcidev == NULL) return -ENODEV;
185         } while(can_check_dev_taken(pcidev));
186         
187         if (pci_enable_device (pcidev)){
188                 printk(KERN_CRIT "Setup of ADLINK7841 failed\n");
189                 return -EIO;
190         }
191         candev->sysdevptr.pcidev=pcidev;
192         
193         for(i=1;i<3;i++){
194                 if(!(pci_resource_flags(pcidev,i)&IORESOURCE_IO)){
195                         printk(KERN_CRIT "ADLINK7841 region %d is not IO\n",i);
196                         return -EIO;
197                 }
198         }
199         candev->dev_base_addr=pci_resource_start(pcidev,1); /* PLX 9050 BASE*/
200         candev->io_addr=pci_resource_start(pcidev,2); /*IO window for SJA1000 chips*/
201         candev->res_addr=pci_resource_start(pcidev,1); /*reserved*/
202         
203         /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/
204
205         candev->nr_82527_chips=0;
206         candev->nr_sja1000_chips=2;
207         candev->nr_all_chips=2;
208
209         return 0;
210 }
211
212 int adlink7841_init_chip_data(struct candevice_t *candev, int chipnr)
213 {
214
215         if(candev->sysdevptr.pcidev==NULL)
216                 return -ENODEV;
217         
218         candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq;
219
220         sja1000p_fill_chipspecops(candev->chip[chipnr]);
221         candev->chip[chipnr]->chip_base_addr=
222                         can_ioport2ioptr(candev->io_addr+chipnr*ADLINK7841_BYTES_PER_CIRCUIT);
223         candev->chip[chipnr]->flags = 0;
224         candev->chip[chipnr]->int_cpu_reg = 0;
225         candev->chip[chipnr]->int_clk_reg = 0;
226         candev->chip[chipnr]->int_bus_reg = 0;
227         candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
228         candev->chip[chipnr]->sja_ocr_reg = ADLINK7841_OCR_DEFAULT_STD;
229         candev->chip[chipnr]->clock = 16000000;
230         candev->chip[chipnr]->flags |= CHIP_IRQ_PCI;
231
232         return 0;
233 }       
234
235 int adlink7841_init_obj_data(struct canchip_t *chip, int objnr)
236 {
237         chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
238         return 0;
239 }
240
241 int adlink7841_program_irq(struct candevice_t *candev)
242 {
243
244         return 0;
245 }
246
247 int adlink7841_register(struct hwspecops_t *hwspecops)
248 {
249         hwspecops->request_io = adlink7841_request_io;
250         hwspecops->release_io = adlink7841_release_io;
251         hwspecops->reset = adlink7841_reset;
252         hwspecops->init_hw_data = adlink7841_init_hw_data;
253         hwspecops->init_chip_data = adlink7841_init_chip_data;
254         hwspecops->init_obj_data = adlink7841_init_obj_data;
255         hwspecops->write_register = adlink7841_write_register;
256         hwspecops->read_register = adlink7841_read_register;
257         hwspecops->program_irq = adlink7841_program_irq;
258         return 0;
259 }
260
261
262 #endif /*CAN_ENABLE_PCI_SUPPORT*/