1 /**************************************************************************/
2 /* File: esdpci266.c - support for ESD PCI/PMC 266 cards */
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> */
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. */
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: */
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 /**************************************************************************/
35 #include "../include/can.h"
36 #include "../include/can_sysdep.h"
37 #include "../include/main.h"
38 #include "../include/sja1000p.h"
40 #ifdef CAN_ENABLE_PCI_SUPPORT
42 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
43 #define ioread32 can_readl
44 #define iowrite32 can_writel
45 #define ioread8 can_readb
46 #define iowrite8 can_writeb
51 #define PLX_9056_VENDOR_ID 0x10B5
52 #define PLX_9056_DEVICE_ID 0x9056
53 #define ESDPCI266_PCI_VENDOR_ID 0x12FE
54 #define ESDPCI266_PCI_PRODUCT_ID 0x000E
56 /* PCI to local bus bridge PLX9050 */
57 #define ESDPCI266_BYTES_PER_CIRCUIT 0x100
59 void esdpci266_enable_irq(struct candevice_t *candev)
62 can_ioptr_t addr = candev->aux_base_addr + 0x68;
63 intcsr = ioread32(addr);
65 iowrite32(intcsr, addr);
68 void esdpci266_disable_irq(struct candevice_t *candev)
71 can_ioptr_t addr = candev->aux_base_addr + 0x68;
72 intcsr = ioread32(addr);
74 iowrite32(intcsr, addr);
77 int esdpci266_request_io(struct candevice_t *candev)
79 unsigned long addr, size;
80 can_ioptr_t remap_addr;
81 struct pci_dev *dev = candev->sysdevptr.pcidev;
83 /* request memory region for SJA chips window */
84 if (pci_request_region(dev, 2, "ESD PCI/PMC 266 - MEM") != 0) {
85 printk("lincan: request of memory range failed\n");
89 /* determine address and size of memory window #2 */
90 addr = pci_resource_start(dev, 2);
91 size = pci_resource_len(dev, 2);
93 /* remap to kernel address space */
94 remap_addr = ioremap(addr, size);
97 printk("lincan: Unable to access I/O memory at: 0x%lx\n", addr);
98 pci_release_region(dev, 2);
102 /* remap base device address */
103 can_base_addr_fixup(candev, remap_addr);
105 /* request memory region for PLX registers */
106 if (pci_request_region(dev, 0, "ESD PCI/PMC 266 - PLX9056") != 0) {
107 printk("lincan: request of memory range failed\n");
108 iounmap(candev->dev_base_addr);
109 pci_release_region(dev, 2);
113 /* determine address and size of memory window #2 */
114 addr = pci_resource_start(dev, 0);
115 size = pci_resource_len(dev, 0);
117 /* remap to kernel address space */
118 remap_addr = ioremap(addr, size);
121 printk("lincan: Unable to access I/O memory at: 0x%lx\n", addr);
122 pci_release_region(dev, 0);
123 iounmap(candev->dev_base_addr);
124 pci_release_region(dev, 2);
128 /* save address of PLX regs */
129 candev->aux_base_addr = remap_addr;
132 esdpci266_enable_irq(candev);
137 int esdpci266_release_io(struct candevice_t *candev)
139 esdpci266_disable_irq(candev);
140 iounmap(candev->aux_base_addr);
141 pci_release_region(candev->sysdevptr.pcidev, 0);
142 iounmap(candev->dev_base_addr);
143 pci_release_region(candev->sysdevptr.pcidev, 2);
147 void esdpci266_write_register(unsigned data, can_ioptr_t address)
149 iowrite8(data, address);
153 unsigned esdpci266_read_register(can_ioptr_t address)
155 return ioread8(address);
158 int esdpci266_reset(struct candevice_t *candev)
161 struct canchip_t *chip;
164 printk("lincan: resetting ESD PCI/PMC 266 hardware ...\n");
166 for (chip_nr = 0; chip_nr < candev->nr_all_chips; chip_nr++) {
167 if (!candev->chip[chip_nr])
170 printk("lincan: resetting SJA1000 chip nr. %d\n", chip_nr);
172 chip = candev->chip[chip_nr];
174 esdpci266_write_register(sjaMOD_RM,
175 chip->chip_base_addr + SJAMOD);
178 cdr = esdpci266_read_register(chip->chip_base_addr + SJACDR);
179 esdpci266_write_register(cdr | sjaCDR_PELICAN,
180 chip->chip_base_addr + SJACDR);
181 esdpci266_write_register(0, chip->chip_base_addr + SJAIER);
184 esdpci266_write_register(0, chip->chip_base_addr + SJAMOD);
185 while (esdpci266_read_register(chip->chip_base_addr + SJAMOD) &
190 esdpci266_write_register(0,
191 chip->chip_base_addr + SJAMOD);
194 cdr = esdpci266_read_register(chip->chip_base_addr + SJACDR);
195 esdpci266_write_register(cdr | sjaCDR_PELICAN,
196 chip->chip_base_addr + SJACDR);
197 esdpci266_write_register(0, chip->chip_base_addr + SJAIER);
198 esdpci266_read_register(chip->chip_base_addr + SJAIR);
204 int esdpci266_init_hw_data(struct candevice_t *candev)
206 struct pci_dev *pcidev;
208 printk("lincan: search for ESD PCI/PMC 266 board ...\n");
210 pcidev = can_pci_get_next_untaken_subsyst(PLX_9056_VENDOR_ID, PLX_9056_DEVICE_ID,
211 ESDPCI266_PCI_VENDOR_ID, ESDPCI266_PCI_PRODUCT_ID);
215 if (pci_enable_device(pcidev)) {
216 printk("lincan: pci_enable_device() failed\n");
217 can_pci_dev_put(pcidev);
221 candev->sysdevptr.pcidev = pcidev;
223 candev->io_addr = pci_resource_start(pcidev, 2);
224 candev->dev_base_addr = 0;
225 candev->res_addr = 0;
226 candev->nr_82527_chips = 0;
227 candev->nr_sja1000_chips = 2;
228 candev->nr_all_chips = 2;
230 printk("lincan: ESD PCI/PMC 266 board found (%lx)\n", candev->io_addr);
235 void esdpci266_done_hw_data(struct candevice_t *candev)
237 struct pci_dev *pcidev = candev->sysdevptr.pcidev;
238 can_pci_dev_put(pcidev);
241 int esdpci266_init_chip_data(struct candevice_t *candev, int chipnr)
243 if (candev->sysdevptr.pcidev == NULL)
246 candev->chip[chipnr]->chip_irq = candev->sysdevptr.pcidev->irq;
247 sja1000p_fill_chipspecops(candev->chip[chipnr]);
248 candev->chip[chipnr]->chip_base_addr =
249 candev->dev_base_addr + chipnr * ESDPCI266_BYTES_PER_CIRCUIT;
250 candev->chip[chipnr]->clock = 16000000;
251 candev->chip[chipnr]->int_clk_reg = 0;
252 candev->chip[chipnr]->int_bus_reg = 0;
253 candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
254 candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH;
255 candev->chip[chipnr]->flags |= CHIP_IRQ_PCI;
259 int esdpci266_init_obj_data(struct canchip_t *chip, int objnr)
261 chip->msgobj[objnr]->obj_base_addr = chip->chip_base_addr;
265 int esdpci266_program_irq(struct candevice_t *candev)
270 int esdpci266_register(struct hwspecops_t *hwspecops)
272 hwspecops->request_io = esdpci266_request_io;
273 hwspecops->release_io = esdpci266_release_io;
274 hwspecops->reset = esdpci266_reset;
275 hwspecops->init_hw_data = esdpci266_init_hw_data;
276 hwspecops->done_hw_data = esdpci266_done_hw_data;
277 hwspecops->init_chip_data = esdpci266_init_chip_data;
278 hwspecops->init_obj_data = esdpci266_init_obj_data;
279 hwspecops->write_register = esdpci266_write_register;
280 hwspecops->read_register = esdpci266_read_register;
281 hwspecops->program_irq = esdpci266_program_irq;
285 #endif /* CAN_ENABLE_PCI_SUPPORT */