]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/esdpci266.c
Eliminated busy loop in the USB can sources and thread priority increased.
[lincan.git] / lincan / src / esdpci266.c
1 /* esdpci266.c - support for ESD PCI/PMC 266 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.3  17 Jun 2004
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 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
18 #define ioread32        can_readl
19 #define iowrite32       can_writel
20 #define ioread8         can_readb
21 #define iowrite8        can_writeb
22 #define wmb()
23 #define rmb()
24 #endif
25
26 #define PLX_9056_VENDOR_ID   0x10B5
27 #define PLX_9056_DEVICE_ID   0x9056
28 #define ESDPCI266_PCI_VENDOR_ID    0x12FE
29 #define ESDPCI266_PCI_PRODUCT_ID   0x000E
30
31 /* PCI to local bus bridge PLX9050 */
32 #define ESDPCI266_BYTES_PER_CIRCUIT 0x100
33
34 void esdpci266_enable_irq(struct candevice_t *candev)
35 {
36         uint32_t intcsr;
37         can_ioptr_t addr = candev->aux_base_addr + 0x68;
38         intcsr = ioread32(addr);
39         intcsr |= 0x900;
40         iowrite32(intcsr, addr);
41 }
42
43 void esdpci266_disable_irq(struct candevice_t *candev)
44 {
45         uint32_t intcsr;
46         can_ioptr_t addr = candev->aux_base_addr + 0x68;
47         intcsr = ioread32(addr);
48         intcsr &= ~0x900;
49         iowrite32(intcsr, addr);
50 }
51
52 int esdpci266_request_io(struct candevice_t *candev)
53 {
54         unsigned long addr, size;
55         can_ioptr_t remap_addr;
56         struct pci_dev *dev = candev->sysdevptr.pcidev;
57
58         /* request memory region for SJA chips window */
59         if (pci_request_region(dev, 2, "ESD PCI/PMC 266 - MEM") != 0) {
60                 printk("lincan: request of memory range failed\n");
61                 return -ENODEV;
62         }
63
64         /* determine address and size of memory window #2 */
65         addr = pci_resource_start(dev, 2);
66         size = pci_resource_len(dev, 2);
67
68         /* remap to kernel address space */
69         remap_addr = ioremap(addr, size);
70
71         if (!remap_addr) {
72                 printk("lincan: Unable to access I/O memory at: 0x%lx\n", addr);
73                 pci_release_region(dev, 2);
74                 return -ENODEV;
75         }
76
77         /* remap base device address */
78         can_base_addr_fixup(candev, remap_addr);
79
80         /* request memory region for PLX registers */
81         if (pci_request_region(dev, 0, "ESD PCI/PMC 266 - PLX9056") != 0) {
82                 printk("lincan: request of memory range failed\n");
83                 iounmap(candev->dev_base_addr);
84                 pci_release_region(dev, 2);
85                 return -ENODEV;
86         }
87
88         /* determine address and size of memory window #2 */
89         addr = pci_resource_start(dev, 0);
90         size = pci_resource_len(dev, 0);
91
92         /* remap to kernel address space */
93         remap_addr = ioremap(addr, size);
94
95         if (!remap_addr) {
96                 printk("lincan: Unable to access I/O memory at: 0x%lx\n", addr);
97                 pci_release_region(dev, 0);
98                 iounmap(candev->dev_base_addr);
99                 pci_release_region(dev, 2);
100                 return -ENODEV;
101         }
102
103         /* save address of PLX regs */
104         candev->aux_base_addr = remap_addr;
105
106         /* enable irqs */
107         esdpci266_enable_irq(candev);
108
109         return 0;
110 }
111
112 int esdpci266_release_io(struct candevice_t *candev)
113 {
114         esdpci266_disable_irq(candev);
115         iounmap(candev->aux_base_addr);
116         pci_release_region(candev->sysdevptr.pcidev, 0);
117         iounmap(candev->dev_base_addr);
118         pci_release_region(candev->sysdevptr.pcidev, 2);
119         return 0;
120 }
121
122 void esdpci266_write_register(unsigned data, can_ioptr_t address)
123 {
124         iowrite8(data, address);
125         wmb();
126 }
127
128 unsigned esdpci266_read_register(can_ioptr_t address)
129 {
130         return ioread8(address);
131 }
132
133 int esdpci266_reset(struct candevice_t *candev)
134 {
135         int i = 0, chip_nr;
136         struct canchip_t *chip;
137         unsigned cdr;
138
139         printk("lincan: resetting ESD PCI/PMC 266 hardware ...\n");
140
141         for (chip_nr = 0; chip_nr < candev->nr_all_chips; chip_nr++) {
142                 if (!candev->chip[chip_nr])
143                         continue;
144
145                 printk("lincan: resetting SJA1000 chip nr. %d\n", chip_nr);
146
147                 chip = candev->chip[chip_nr];
148
149                 esdpci266_write_register(sjaMOD_RM,
150                                          chip->chip_base_addr + SJAMOD);
151                 udelay(1000);
152
153                 cdr = esdpci266_read_register(chip->chip_base_addr + SJACDR);
154                 esdpci266_write_register(cdr | sjaCDR_PELICAN,
155                                          chip->chip_base_addr + SJACDR);
156                 esdpci266_write_register(0, chip->chip_base_addr + SJAIER);
157
158                 i = 20;
159                 esdpci266_write_register(0, chip->chip_base_addr + SJAMOD);
160                 while (esdpci266_read_register(chip->chip_base_addr + SJAMOD) &
161                        sjaMOD_RM) {
162                         if (!i--)
163                                 return -ENODEV;
164                         udelay(1000);
165                         esdpci266_write_register(0,
166                                                  chip->chip_base_addr + SJAMOD);
167                 }
168
169                 cdr = esdpci266_read_register(chip->chip_base_addr + SJACDR);
170                 esdpci266_write_register(cdr | sjaCDR_PELICAN,
171                                          chip->chip_base_addr + SJACDR);
172                 esdpci266_write_register(0, chip->chip_base_addr + SJAIER);
173                 esdpci266_read_register(chip->chip_base_addr + SJAIR);
174         }
175
176         return 0;
177 }
178
179 int esdpci266_init_hw_data(struct candevice_t *candev)
180 {
181         struct pci_dev *pcidev = NULL;
182
183         printk("lincan: search for ESD PCI/PMC 266 board ...\n");
184
185         do {
186                 pcidev =
187                     pci_find_device(PLX_9056_VENDOR_ID, PLX_9056_DEVICE_ID,
188                                     pcidev);
189                 if (pcidev == NULL)
190                         return -ENODEV;
191                 if (pcidev->subsystem_vendor != ESDPCI266_PCI_VENDOR_ID
192                     || pcidev->subsystem_device != ESDPCI266_PCI_PRODUCT_ID) {
193                         printk
194                             ("PLX9056 found, subvendor/subdevice mismatch (%04d:%04d)\n",
195                              pcidev->subsystem_vendor,
196                              pcidev->subsystem_device);
197                         continue;
198                 }
199         } while (can_check_dev_taken(pcidev));
200
201         if (pci_enable_device(pcidev)) {
202                 printk("lincan: pci_enable_device() failed\n");
203                 return -EIO;
204         }
205
206         candev->sysdevptr.pcidev = pcidev;
207
208         candev->io_addr = pci_resource_start(pcidev, 2);
209         candev->dev_base_addr = 0;
210         candev->res_addr = 0;
211         candev->nr_82527_chips = 0;
212         candev->nr_sja1000_chips = 2;
213         candev->nr_all_chips = 2;
214
215         printk("lincan: ESD PCI/PMC 266 board found (%lx)\n", candev->io_addr);
216
217         return 0;
218 }
219
220 int esdpci266_init_chip_data(struct candevice_t *candev, int chipnr)
221 {
222         if (candev->sysdevptr.pcidev == NULL)
223                 return -ENODEV;
224
225         candev->chip[chipnr]->chip_irq = candev->sysdevptr.pcidev->irq;
226         sja1000p_fill_chipspecops(candev->chip[chipnr]);
227         candev->chip[chipnr]->chip_base_addr =
228             candev->dev_base_addr + chipnr * ESDPCI266_BYTES_PER_CIRCUIT;
229         candev->chip[chipnr]->clock = 16000000;
230         candev->chip[chipnr]->int_clk_reg = 0;
231         candev->chip[chipnr]->int_bus_reg = 0;
232         candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
233         candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH;
234         candev->chip[chipnr]->flags |= CHIP_IRQ_PCI;
235         return 0;
236 }
237
238 int esdpci266_init_obj_data(struct canchip_t *chip, int objnr)
239 {
240         chip->msgobj[objnr]->obj_base_addr = chip->chip_base_addr;
241         return 0;
242 }
243
244 int esdpci266_program_irq(struct candevice_t *candev)
245 {
246         return 0;
247 }
248
249 int esdpci266_register(struct hwspecops_t *hwspecops)
250 {
251         hwspecops->request_io = esdpci266_request_io;
252         hwspecops->release_io = esdpci266_release_io;
253         hwspecops->reset = esdpci266_reset;
254         hwspecops->init_hw_data = esdpci266_init_hw_data;
255         hwspecops->init_chip_data = esdpci266_init_chip_data;
256         hwspecops->init_obj_data = esdpci266_init_obj_data;
257         hwspecops->write_register = esdpci266_write_register;
258         hwspecops->read_register = esdpci266_read_register;
259         hwspecops->program_irq = esdpci266_program_irq;
260         return 0;
261 }
262
263 #endif /* CAN_ENABLE_PCI_SUPPORT */