From: ppisa Date: Sun, 23 Nov 2008 23:38:36 +0000 (+0000) Subject: Added support for ESD PCI/PMC 266 cards. X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/7414f65d027e04893b7dce40d61feed2ca3a4319 Added support for ESD PCI/PMC 266 cards. Board support has to be enabled by CONFIG_OC_LINCAN_CARD_esdpci266=y in config.omk and hw=esdpci266. Code has been contributed by Unicontrols company. Signed-off-by: ppisa --- diff --git a/lincan/README b/lincan/README index d05c780..0c89a19 100644 --- a/lincan/README +++ b/lincan/README @@ -269,7 +269,8 @@ The hw argument can be one of: - ts7kv for Technologic Systems' TS-7KV Multi-function board with SJA1000 both these cards require CONFIG_OC_LINCAN_CARD_tscan1=y - pcan_pci for PEAK System PCAN-PCI single, double or quad SJA1000 based board -- esdpci200 for the CAN/PCI-200 card by ESD Electronics board +- esdpci200 for the CAN/PCI-200 card by ESD Electronics +- esdpci266 for the ESD PCI/PMC 266 card by ESD Electronics - template, for yet unsupported hardware (you need to edit src/template.c) - virtual, CAN channel for testing of software and driver without CAN hardware diff --git a/lincan/src/Makefile.omk b/lincan/src/Makefile.omk index 8d191f5..8a71a1f 100644 --- a/lincan/src/Makefile.omk +++ b/lincan/src/Makefile.omk @@ -2,7 +2,7 @@ lincan_cards_NAMES = pip pccan smartcan nsi cc_can104 ems_cpcpci \ pc_i03 pcm3680 aim104 m437 pcccan ssv bfadcan gensja1000io gensja1000mm eb8245 \ kv_pcican msmcan oscar adlink7841 pcan_pci esdpci200 unican virtual template -lincan_morecards_NAMES = hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 ts7kv nsi_canpci sh7760 +lincan_morecards_NAMES = esdpci266 hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 ts7kv nsi_canpci sh7760 default_CONFIG = CONFIG_OC_LINCAN=y CONFIG_OC_LINCANRTL=n CONFIG_OC_LINCANVME=n default_CONFIG += CONFIG_OC_LINCAN_PORTIO_ONLY=n CONFIG_OC_LINCAN_MEMIO_ONLY=n diff --git a/lincan/src/boardlist.c b/lincan/src/boardlist.c index 608595f..ab0bd09 100644 --- a/lincan/src/boardlist.c +++ b/lincan/src/boardlist.c @@ -49,6 +49,7 @@ extern int nsi_canpci_register(struct hwspecops_t *hwspecops); extern int usbcan_register(struct hwspecops_t *hwspecops); extern int pcan_pci_register(struct hwspecops_t *hwspecops); extern int esdpci200_register(struct hwspecops_t *hwspecops); +extern int esdpci266_register(struct hwspecops_t *hwspecops); extern int sh7760_register(struct hwspecops_t *hwspecops); const struct boardtype_t can_boardtypes[]={ @@ -147,6 +148,9 @@ const struct boardtype_t can_boardtypes[]={ #if defined(CONFIG_OC_LINCAN_CARD_esdpci200) {"esdpci200", esdpci200_register, 0}, #endif + #if defined(CONFIG_OC_LINCAN_CARD_esdpci266) + {"esdpci266", esdpci200_register, 0}, + #endif #if defined(CONFIG_OC_LINCAN_CARD_tscan1) {"tscan1", tscan1_register, 1}, {"tscan1mmio", tscan1mmio_register, 1}, diff --git a/lincan/src/esdpci200.c b/lincan/src/esdpci200.c index 1b62e7e..1d10d64 100644 --- a/lincan/src/esdpci200.c +++ b/lincan/src/esdpci200.c @@ -173,7 +173,7 @@ int esdpci200_request_io(struct candevice_t *candev) can_base_addr_fixup(candev, remap_addr); CANMSG("esdpci200_sja IO-memory: 0x%lx - 0x%lx (VMA 0x%lx)\n", (unsigned long) bar2_addr, - (unsigned long) bar2_addr + pci_resource_len(pcidev,2) - 1, + (unsigned long) (bar2_addr + pci_resource_len(pcidev,2) - 1), (long) remap_addr); return 0; @@ -208,13 +208,13 @@ int esdpci200_release_io(struct candevice_t *candev) void esdpci200_write_register(unsigned data, can_ioptr_t address) { - iowrite8((u8)data,(void*)address); + iowrite8((u8)data,address); wmb(); } unsigned esdpci200_read_register(can_ioptr_t address) { - return ioread8((void*)address); + return ioread8(address); } int esdpci200_reset(struct candevice_t *candev) diff --git a/lincan/src/esdpci266.c b/lincan/src/esdpci266.c new file mode 100644 index 0000000..a2f3183 --- /dev/null +++ b/lincan/src/esdpci266.c @@ -0,0 +1,263 @@ +/* esdpci266.c - support for ESD PCI/PMC 266 cards + * Linux CAN-bus device driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +#include "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/main.h" +#include "../include/sja1000p.h" + +#ifdef CAN_ENABLE_PCI_SUPPORT + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)) +#define ioread32 can_readl +#define iowrite32 can_writel +#define ioread8 can_readb +#define iowrite8 can_writeb +#define wmb() +#define rmb() +#endif + +#define PLX_9056_VENDOR_ID 0x10B5 +#define PLX_9056_DEVICE_ID 0x9056 +#define ESDPCI266_PCI_VENDOR_ID 0x12FE +#define ESDPCI266_PCI_PRODUCT_ID 0x000E + +/* PCI to local bus bridge PLX9050 */ +#define ESDPCI266_BYTES_PER_CIRCUIT 0x100 + +void esdpci266_enable_irq(struct candevice_t *candev) +{ + uint32_t intcsr; + can_ioptr_t addr = candev->aux_base_addr + 0x68; + intcsr = ioread32(addr); + intcsr |= 0x900; + iowrite32(intcsr, addr); +} + +void esdpci266_disable_irq(struct candevice_t *candev) +{ + uint32_t intcsr; + can_ioptr_t addr = candev->aux_base_addr + 0x68; + intcsr = ioread32(addr); + intcsr &= ~0x900; + iowrite32(intcsr, addr); +} + +int esdpci266_request_io(struct candevice_t *candev) +{ + unsigned long addr, size; + can_ioptr_t remap_addr; + struct pci_dev *dev = candev->sysdevptr.pcidev; + + /* request memory region for SJA chips window */ + if (pci_request_region(dev, 2, "ESD PCI/PMC 266 - MEM") != 0) { + printk("lincan: request of memory range failed\n"); + return -ENODEV; + } + + /* determine address and size of memory window #2 */ + addr = pci_resource_start(dev, 2); + size = pci_resource_len(dev, 2); + + /* remap to kernel address space */ + remap_addr = ioremap(addr, size); + + if (!remap_addr) { + printk("lincan: Unable to access I/O memory at: 0x%lx\n", addr); + pci_release_region(dev, 2); + return -ENODEV; + } + + /* remap base device address */ + can_base_addr_fixup(candev, remap_addr); + + /* request memory region for PLX registers */ + if (pci_request_region(dev, 0, "ESD PCI/PMC 266 - PLX9056") != 0) { + printk("lincan: request of memory range failed\n"); + iounmap(candev->dev_base_addr); + pci_release_region(dev, 2); + return -ENODEV; + } + + /* determine address and size of memory window #2 */ + addr = pci_resource_start(dev, 0); + size = pci_resource_len(dev, 0); + + /* remap to kernel address space */ + remap_addr = ioremap(addr, size); + + if (!remap_addr) { + printk("lincan: Unable to access I/O memory at: 0x%lx\n", addr); + pci_release_region(dev, 0); + iounmap(candev->dev_base_addr); + pci_release_region(dev, 2); + return -ENODEV; + } + + /* save address of PLX regs */ + candev->aux_base_addr = remap_addr; + + /* enable irqs */ + esdpci266_enable_irq(candev); + + return 0; +} + +int esdpci266_release_io(struct candevice_t *candev) +{ + esdpci266_disable_irq(candev); + iounmap(candev->aux_base_addr); + pci_release_region(candev->sysdevptr.pcidev, 0); + iounmap(candev->dev_base_addr); + pci_release_region(candev->sysdevptr.pcidev, 2); + return 0; +} + +void esdpci266_write_register(unsigned data, can_ioptr_t address) +{ + iowrite8(data, address); + wmb(); +} + +unsigned esdpci266_read_register(can_ioptr_t address) +{ + return ioread8(address); +} + +int esdpci266_reset(struct candevice_t *candev) +{ + int i = 0, chip_nr; + struct canchip_t *chip; + unsigned cdr; + + printk("lincan: resetting ESD PCI/PMC 266 hardware ...\n"); + + for (chip_nr = 0; chip_nr < candev->nr_all_chips; chip_nr++) { + if (!candev->chip[chip_nr]) + continue; + + printk("lincan: resetting SJA1000 chip nr. %d\n", chip_nr); + + chip = candev->chip[chip_nr]; + + esdpci266_write_register(sjaMOD_RM, + chip->chip_base_addr + SJAMOD); + udelay(1000); + + cdr = esdpci266_read_register(chip->chip_base_addr + SJACDR); + esdpci266_write_register(cdr | sjaCDR_PELICAN, + chip->chip_base_addr + SJACDR); + esdpci266_write_register(0, chip->chip_base_addr + SJAIER); + + i = 20; + esdpci266_write_register(0, chip->chip_base_addr + SJAMOD); + while (esdpci266_read_register(chip->chip_base_addr + SJAMOD) & + sjaMOD_RM) { + if (!i--) + return -ENODEV; + udelay(1000); + esdpci266_write_register(0, + chip->chip_base_addr + SJAMOD); + } + + cdr = esdpci266_read_register(chip->chip_base_addr + SJACDR); + esdpci266_write_register(cdr | sjaCDR_PELICAN, + chip->chip_base_addr + SJACDR); + esdpci266_write_register(0, chip->chip_base_addr + SJAIER); + esdpci266_read_register(chip->chip_base_addr + SJAIR); + } + + return 0; +} + +int esdpci266_init_hw_data(struct candevice_t *candev) +{ + struct pci_dev *pcidev = NULL; + + printk("lincan: search for ESD PCI/PMC 266 board ...\n"); + + do { + pcidev = + pci_find_device(PLX_9056_VENDOR_ID, PLX_9056_DEVICE_ID, + pcidev); + if (pcidev == NULL) + return -ENODEV; + if (pcidev->subsystem_vendor != ESDPCI266_PCI_VENDOR_ID + || pcidev->subsystem_device != ESDPCI266_PCI_PRODUCT_ID) { + printk + ("PLX9056 found, subvendor/subdevice mismatch (%04d:%04d)\n", + pcidev->subsystem_vendor, + pcidev->subsystem_device); + continue; + } + } while (can_check_dev_taken(pcidev)); + + if (pci_enable_device(pcidev)) { + printk("lincan: pci_enable_device() failed\n"); + return -EIO; + } + + candev->sysdevptr.pcidev = pcidev; + + candev->io_addr = pci_resource_start(pcidev, 2); + candev->dev_base_addr = 0; + candev->res_addr = 0; + candev->nr_82527_chips = 0; + candev->nr_sja1000_chips = 2; + candev->nr_all_chips = 2; + + printk("lincan: ESD PCI/PMC 266 board found (%lx)\n", candev->io_addr); + + return 0; +} + +int esdpci266_init_chip_data(struct candevice_t *candev, int chipnr) +{ + if (candev->sysdevptr.pcidev == NULL) + return -ENODEV; + + candev->chip[chipnr]->chip_irq = candev->sysdevptr.pcidev->irq; + sja1000p_fill_chipspecops(candev->chip[chipnr]); + candev->chip[chipnr]->chip_base_addr = + candev->dev_base_addr + chipnr * ESDPCI266_BYTES_PER_CIRCUIT; + candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->int_clk_reg = 0; + candev->chip[chipnr]->int_bus_reg = 0; + candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH; + candev->chip[chipnr]->flags |= CHIP_IRQ_PCI; + return 0; +} + +int esdpci266_init_obj_data(struct canchip_t *chip, int objnr) +{ + chip->msgobj[objnr]->obj_base_addr = chip->chip_base_addr; + return 0; +} + +int esdpci266_program_irq(struct candevice_t *candev) +{ + return 0; +} + +int esdpci266_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = esdpci266_request_io; + hwspecops->release_io = esdpci266_release_io; + hwspecops->reset = esdpci266_reset; + hwspecops->init_hw_data = esdpci266_init_hw_data; + hwspecops->init_chip_data = esdpci266_init_chip_data; + hwspecops->init_obj_data = esdpci266_init_obj_data; + hwspecops->write_register = esdpci266_write_register; + hwspecops->read_register = esdpci266_read_register; + hwspecops->program_irq = esdpci266_program_irq; + return 0; +} + +#endif /* CAN_ENABLE_PCI_SUPPORT */