Added support for ESD PCI/PMC 266 cards. sf-ocera-lincan
authorppisa <ppisa>
Sun, 23 Nov 2008 23:38:36 +0000 (23:38 +0000)
committerppisa <ppisa>
Sun, 23 Nov 2008 23:38:36 +0000 (23:38 +0000)
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 <pisa@cmp.felk.cvut.cz>
lincan/README
lincan/src/Makefile.omk
lincan/src/boardlist.c
lincan/src/esdpci200.c
lincan/src/esdpci266.c [new file with mode: 0644]

index d05c780..0c89a19 100644 (file)
@@ -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
 
index 8d191f5..8a71a1f 100644 (file)
@@ -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
index 608595f..ab0bd09 100644 (file)
@@ -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},
index 1b62e7e..1d10d64 100644 (file)
@@ -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 (file)
index 0000000..a2f3183
--- /dev/null
@@ -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 */