]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/nsi_canpci.c
Actual driver code for directly mapped SJA1000 into PCI mem region 0.
[lincan.git] / lincan / src / nsi_canpci.c
index e3e607eb34fa29928c1a5f1a2e9c37636c9449ee..309ec850c692c4fea062dafa152ed97a6c1608f6 100644 (file)
@@ -1,13 +1,38 @@
-/* nsi.c
- * Linux CAN-bus device driver.
- * nsi_canpci.c - support for NSI CAN PCI card
- * The card support added by Eric Pennamen <pennamen@gmail.com>
- * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl
- * Ake Hedman, eurosource, akhe@eurosource.se ,
- * and 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
- */ 
+/**************************************************************************/
+/* File: nsi_canpci.c - NSI CAN PCI card (2xi82527)                       */
+/*                                                                        */
+/* LinCAN - (Not only) Linux CAN bus driver                               */
+/* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz>   */
+/* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz>             */
+/* Copyright (C) 2004 Eric Pennamen <pennamen@gmail.com>                  */
+/* Funded by OCERA and FRESCOR IST projects                               */
+/* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl>      */
+/* and Ake Hedman, eurosource <akhe@eurosource.se>                        */
+/*                                                                        */
+/* LinCAN is free software; you can redistribute it and/or modify it      */
+/* under terms of the GNU General Public License as published by the      */
+/* Free Software Foundation; either version 2, or (at your option) any    */
+/* later version.  LinCAN is distributed in the hope that it will be      */
+/* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
+/* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
+/* General Public License for more details. You should have received a    */
+/* copy of the GNU General Public License along with LinCAN; see file     */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
+/* Cambridge, MA 02139, USA.                                              */
+/*                                                                        */
+/* To allow use of LinCAN in the compact embedded systems firmware        */
+/* and RT-executives (RTEMS for example), main authors agree with next    */
+/* special exception:                                                     */
+/*                                                                        */
+/* Including LinCAN header files in a file, instantiating LinCAN generics */
+/* or templates, or linking other files with LinCAN objects to produce    */
+/* an application image/executable, does not by itself cause the          */
+/* resulting application image/executable to be covered by                */
+/* the GNU General Public License.                                        */
+/* This exception does not however invalidate any other reasons           */
+/* why the executable file might be covered by the GNU Public License.    */
+/* Publication of enhanced or derived LinCAN files is required although.  */
+/**************************************************************************/
 
 #include "../include/can.h"
 #include "../include/can_sysdep.h"
@@ -23,10 +48,10 @@ extern int mo15mask;
 #include <linux/module.h>
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
-       #define ioread32        readl
-       #define iowrite32       writel
-       #define ioread8         readb
-       #define iowrite8        writeb
+       #define ioread32        can_readl
+       #define iowrite32       can_writel
+       #define ioread8         can_readb
+       #define iowrite8        can_writeb
 #else
 #endif
 
@@ -72,7 +97,7 @@ void nsi_canpci_disconnect_irq(struct candevice_t *candev)
 
 int nsi_canpci_config_irqs(struct canchip_t *chip, short irqs)
 {
-       
+
        unsigned long it_mask,it_reg;
        struct candevice_t *candev;
        it_mask=0;
@@ -90,7 +115,7 @@ int nsi_canpci_config_irqs(struct canchip_t *chip, short irqs)
                        DEBUGMSG("starting interrupt on chip 1\n");
                        it_mask=8;
                }
-               candev=(struct candevice_t *)chip->chip_data;
+               candev=chip->hostdevice;
                it_reg = ioread32( (void*)(candev->io_addr+PLX_INTCSR));
                it_reg|=it_mask|0x40;
                iowrite32(it_reg,(void*)(candev->io_addr+PLX_INTCSR));
@@ -107,7 +132,7 @@ int nsi_canpci_config_irqs(struct canchip_t *chip, short irqs)
                        DEBUGMSG("stoping interrupt on chip 1\n");
                        it_mask=8;
                }
-               candev=(struct candevice_t *)chip->chip_data;
+               candev=chip->hostdevice;
                it_reg = ioread32( (void*)(candev->io_addr+PLX_INTCSR));
                it_reg&=~it_mask;
                iowrite32(it_reg,(void*)(candev->io_addr+PLX_INTCSR));
@@ -119,15 +144,15 @@ int nsi_canpci_i82527_chip_config(struct canchip_t *chip)
 {
        can_write_reg(chip,chip->int_cpu_reg,iCPU); // Configure cpu interface
        can_write_reg(chip,(iCTL_CCE|iCTL_INI),iCTL); // Enable configuration
-       i82527_seg_write_reg(chip,chip->int_clk_reg,iCLK); // Set clock out slew rates 
+       i82527_seg_write_reg(chip,chip->int_clk_reg,iCLK); // Set clock out slew rates
        i82527_seg_write_reg(chip,chip->int_bus_reg,iBUS); /* Bus configuration */
-       
+
        can_write_reg(chip,P2_2|P2_1,iP2C); // The pin P2_2,P2_1 of the 527 must be set as output
        can_write_reg(chip,P2_2|P2_1,iP2O); // and P2_2 must be set to 1
-       
+
        can_write_reg(chip,0x00,iSTAT); /* Clear error status register */
 
-       /* Check if we can at least read back some arbitrary data from the 
+       /* Check if we can at least read back some arbitrary data from the
         * card. If we can not, the card is not properly configured!
         */
        canobj_write_reg(chip,chip->msgobj[1],0x25,iMSGDAT1);
@@ -166,11 +191,11 @@ int nsi_canpci_i82527_chip_config(struct canchip_t *chip)
                CANMSG("Error clearing message objects\n");
                return -ENODEV;
        }
-       
+
        if (nsi_canpci_config_irqs(chip,iCTL_IE|iCTL_EIE)) { /* has been 0x0a */
                CANMSG("Error configuring interrupts\n");
                return -ENODEV;
-       }       
+       }
        return 0;
 }
 
@@ -190,12 +215,12 @@ int nsi_canpci_start_chip(struct canchip_t *chip)
                DEBUGMSG("starting chip 1\n");
                it_mask=8;
        }
-       candev=(struct candevice_t *)chip->chip_data;
+       candev=chip->hostdevice;
        it_reg = ioread32( (void*)(candev->io_addr+PLX_INTCSR));
        rmb();
        it_reg|=it_mask|0x40;
        iowrite32(it_reg,(void*)(candev->io_addr+PLX_INTCSR));
-       wmb();  
+       wmb();
        i82527_start_chip(chip);
        return 0;
 }
@@ -215,12 +240,12 @@ int nsi_canpci_stop_chip(struct canchip_t *chip)
                DEBUGMSG("stoping chip 1\n");
                it_mask=8;
        }
-       candev=(struct candevice_t *)chip->chip_data;
+       candev=chip->hostdevice;
        it_reg = ioread32( (void*)(candev->io_addr+PLX_INTCSR));
        rmb();
        it_reg&=~it_mask;
        iowrite32(it_reg,(void*)(candev->io_addr+PLX_INTCSR));
-       wmb();  
+       wmb();
        i82527_stop_chip(chip);
        return 0;
 }
@@ -230,7 +255,7 @@ int nsi_canpci_irq_handler(int irq, struct canchip_t *chip)
        int retcode;
        unsigned long it_reg;
        struct candevice_t *candev;
-       candev=(struct candevice_t *)chip->chip_data;
+       candev=chip->hostdevice;
        retcode = CANCHIP_IRQ_NONE;
        it_reg = ioread32( (void*)(candev->io_addr+PLX_INTCSR));
        rmb();
@@ -247,7 +272,7 @@ int nsi_canpci_irq_handler(int irq, struct canchip_t *chip)
                        {
                                retcode=CANCHIP_IRQ_HANDLED;
                        }
-               
+
                }
        }
        else
@@ -261,7 +286,7 @@ int nsi_canpci_irq_handler(int irq, struct canchip_t *chip)
                        }else
                        {
                                retcode=CANCHIP_IRQ_HANDLED;
-                       }       
+                       }
                }
        }
        return retcode;
@@ -276,11 +301,11 @@ int nsi_canpci_request_io(struct candevice_t *candev)
 {
   (void)candev;
   if(candev->dev_base_addr==0)
-       return -EIO;  
+       return -EIO;
   return 0;
 }
 
-/* The function template_release_io is used to free the previously reserved 
+/* The function template_release_io is used to free the previously reserved
  * io-memory. In case you reserved more memory, don't forget to free it here.
  */
 int nsi_canpci_release_io(struct candevice_t *candev)
@@ -288,7 +313,7 @@ int nsi_canpci_release_io(struct candevice_t *candev)
        unsigned long reg_reset;
        struct pci_dev *pcidev = candev->sysdevptr.pcidev;
        DEBUGMSG("Releasing board io\n");
-       
+
        nsi_canpci_disconnect_irq(candev);
        // First, set RESET signal to 0
        reg_reset = ioread32( (void*)(candev->io_addr+PLX_CNTRL));
@@ -308,8 +333,8 @@ int nsi_canpci_release_io(struct candevice_t *candev)
        kfree((void*)(candev->dev_base_addr));
        pci_release_region(pcidev,0);
        pci_release_region(pcidev,1);
-       pci_release_region(pcidev,2);                   
-       pci_release_region(pcidev,3);                   
+       pci_release_region(pcidev,2);
+       pci_release_region(pcidev,3);
        return 0;
 }
 
@@ -320,9 +345,9 @@ int nsi_canpci_release_io(struct candevice_t *candev)
 int nsi_canpci_reset(struct candevice_t *candev)
 {
        unsigned long reg_reset;
-       
+
        DEBUGMSG("Board reset !!!\n");
-       // Before reset disconnet interrupt to avoir freeze     
+       // Before reset disconnet interrupt to avoir freeze
        nsi_canpci_disconnect_irq(candev);
        // First, set RESET signal to 0
        reg_reset = ioread32( (void*)(candev->io_addr+PLX_CNTRL));
@@ -335,9 +360,9 @@ int nsi_canpci_reset(struct candevice_t *candev)
        wmb();
        udelay(2500); // Waiting for some additionnal time before writing in the 82527
        DEBUGMSG("Reset done !!!\n");
-       
+
        nsi_canpci_connect_irq(candev);
-       return 0;       
+       return 0;
 }
 
 /* The function template_init_hw_data is used to initialize the hardware
@@ -349,51 +374,33 @@ int nsi_canpci_reset(struct candevice_t *candev)
  * the hardware uses programmable interrupts.
  */
 
-int nsi_canpci_init_hw_data(struct candevice_t *candev) 
-     {
-  struct pci_dev *pcidev = NULL;
+int nsi_canpci_init_hw_data(struct candevice_t *candev)
+{
+       struct pci_dev *pcidev;
 
-  /* looking for NSI CANPCI ident on the pci bus*/
-  do
-  {
-    pcidev = pci_find_device(NSI_VENDOR_ID, NSI_CANPCI_DEVICE_ID, pcidev);
-  }
-  while(can_check_dev_taken(pcidev));
-  
-  if(pcidev == NULL) 
-  {
-       do
-       {
-       pcidev = pci_find_device(NSI_VENDOR_ID, NSI_CANPCI_DEVICE_ID+1, pcidev);
-       }
-       while(can_check_dev_taken(pcidev));
-       if(pcidev == NULL) 
-       {
+       /* looking for NSI CANPCI ident on the pci bus*/
+       pcidev = can_pci_get_next_untaken_device(NSI_VENDOR_ID, NSI_CANPCI_DEVICE_ID);
+       if(pcidev == NULL)
+               pcidev = can_pci_get_next_untaken_device(NSI_VENDOR_ID, NSI_CANPCI_DEVICE_ID+1);
+       if(pcidev == NULL) {
                CANMSG ("Error : NSI CAN PCI device not found\n");
                return -ENODEV;
        }
-       else
-       {
-               CANMSG ("NSI CANPCI OPTO device found\n");
-       }
-  }
-  else
-  {
-       CANMSG ("NSI CANPCI device found\n");  
-  }
-    
+
+       CANMSG ("NSI CANPCI device found\n");
+
   /* enable it */
   if (pci_enable_device (pcidev))
   {
     CANMSG ("Cannot enable PCI device\n");
-    return -EIO;
+    goto error_io;
   }
   CANMSG ("NSI CANPCI device started\n");
   candev->sysdevptr.pcidev = pcidev;
   candev->res_addr=0;
   candev->nr_82527_chips=2;
   candev->nr_sja1000_chips=0;
-  candev->nr_all_chips=2; 
+  candev->nr_all_chips=2;
   /* initialize device spinlock */
   can_spin_lock_init(&candev->device_lock);
 
@@ -410,32 +417,32 @@ int nsi_canpci_init_hw_data(struct candevice_t *candev)
                        {
                        pci_release_region(pcidev,0);
                        pci_release_region(pcidev,1);
-                       pci_release_region(pcidev,2);                   
-                       return -EIO;
+                       pci_release_region(pcidev,2);
+                       goto error_io;
                        }
                }
                else
                {
                pci_release_region(pcidev,0);
                pci_release_region(pcidev,1);
-               return -EIO;
+               goto error_io;
                }
        }
        else
        {
        pci_release_region(pcidev,0);
-       return -EIO;
+       goto error_io;
        }
-  }  
+  }
   else
   {
-       return -EIO;
+       goto error_io;
   }
-  candev->dev_base_addr=(unsigned long)(kmalloc(sizeof(t_CardArray),GFP_ATOMIC));  
-  
+  candev->dev_base_addr=(unsigned long)(kmalloc(sizeof(t_CardArray),GFP_ATOMIC));
+
   if((unsigned long)candev->dev_base_addr==0)
-       return -EIO;
-  //PLX register 
+       goto error_io;
+  //PLX register
   ((t_CardArray*)(candev->dev_base_addr))->addr_BAR_remap[0]=ioremap(pci_resource_start(pcidev,0),pci_resource_len(pcidev,0) );
   //PLX IO
   ((t_CardArray*)(candev->dev_base_addr))->addr_BAR_remap[1]=ioremap(pci_resource_start(pcidev,1),pci_resource_len(pcidev,1) );
@@ -443,12 +450,24 @@ int nsi_canpci_init_hw_data(struct candevice_t *candev)
   ((t_CardArray*)(candev->dev_base_addr))->addr_BAR_remap[2]=ioremap(pci_resource_start(pcidev,2),pci_resource_len(pcidev,2) );
   //Chip 1
   ((t_CardArray*)(candev->dev_base_addr))->addr_BAR_remap[3]=ioremap(pci_resource_start(pcidev,3),pci_resource_len(pcidev,3) );
-  
+
   //Short acces to plx register
   candev->io_addr=(unsigned long)(((t_CardArray*)(candev->dev_base_addr))->addr_BAR_remap[0]);
-  return 0;  
+  return 0;
+
+error_io:
+       can_pci_dev_put(pcidev);
+       return -EIO;
+}
+
+
+void nsi_canpci_done_hw_data(struct candevice_t *candev)
+{
+       struct pci_dev *pcidev = candev->sysdevptr.pcidev;
+       can_pci_dev_put(pcidev);
 }
 
+
 /* The function template_init_chip_data is used to initialize the hardware
  * structure containing information about the CAN chips.
  * CHIP_TYPE represents the type of CAN chip. CHIP_TYPE can be "i82527" or
@@ -464,14 +483,14 @@ int nsi_canpci_init_chip_data(struct candevice_t *candev, int chipnr)
        //u8 irq_line;
        CANMSG ("NSI chip data init %d\n",chipnr);
        i82527_fill_chipspecops(candev->chip[chipnr]);
-       
+
        candev->chip[chipnr]->chipspecops->chip_config =nsi_canpci_i82527_chip_config;
        candev->chip[chipnr]->chipspecops->start_chip=nsi_canpci_start_chip;
        candev->chip[chipnr]->chipspecops->stop_chip=nsi_canpci_stop_chip;
        candev->chip[chipnr]->chipspecops->config_irqs=nsi_canpci_config_irqs;
        candev->chip[chipnr]->chipspecops->irq_handler=nsi_canpci_irq_handler;
-       candev->chip[chipnr]->chip_data =candev;
-       
+       /*candev->chip[chipnr]->chip_data = NULL;*/
+
        candev->chip[chipnr]->chip_base_addr= (unsigned long) (((t_CardArray*)(candev->dev_base_addr))->addr_BAR_remap[chipnr+2]);
        candev->chip[chipnr]->clock = iCLOCK;
        candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq;
@@ -487,7 +506,7 @@ int nsi_canpci_init_chip_data(struct candevice_t *candev, int chipnr)
  * CAN chip. In case of the sja1000 there's only one message object but on the
  * i82527 chip there are 15.
  * The code below is for a i82527 chip and initializes the object base addresses
- * The entry obj_base_addr represents the first memory address of the message 
+ * The entry obj_base_addr represents the first memory address of the message
  * object. In case of the sja1000 obj_base_addr is taken the same as the chips
  * base address.
  * Unless the hardware uses a segmented memory map, flags can be set zero.
@@ -495,10 +514,10 @@ int nsi_canpci_init_chip_data(struct candevice_t *candev, int chipnr)
 int nsi_canpci_init_obj_data(struct canchip_t *chip, int objnr)
 {
 
-       
+
        chip->msgobj[objnr]->obj_base_addr=
            chip->chip_base_addr+(objnr+1)*0x10;
-       
+
        return 0;
 }
 
@@ -517,7 +536,7 @@ int nsi_canpci_program_irq(struct candevice_t *candev)
  * on the CAN chip. You should only have to edit this function if your hardware
  * uses some specific write process.
  */
-void nsi_canpci_write_register(unsigned data, unsigned long address)
+void nsi_canpci_write_register(unsigned data, can_ioptr_t address)
 {
        iowrite8((u8)data,(void*)address);
 }
@@ -526,12 +545,8 @@ void nsi_canpci_write_register(unsigned data, unsigned long address)
  * on the CAN chip. You should only have to edit this function if your hardware
  * uses some specific read process.
  */
-unsigned nsi_canpci_read_register(unsigned long address)
+unsigned nsi_canpci_read_register(can_ioptr_t address)
 {
-    /* this is the same thing that the function write_register.
-       We use the two register, we write the address where we 
-       want to read in a first time. In a second time we read the
-       data */
        return ioread8((void*)address);
 }
 
@@ -543,6 +558,7 @@ int nsi_canpci_register(struct hwspecops_t *hwspecops)
        hwspecops->release_io = nsi_canpci_release_io;
        hwspecops->reset = nsi_canpci_reset;
        hwspecops->init_hw_data = nsi_canpci_init_hw_data;
+       hwspecops->done_hw_data = nsi_canpci_done_hw_data;
        hwspecops->init_chip_data = nsi_canpci_init_chip_data;
        hwspecops->init_obj_data = nsi_canpci_init_obj_data;
        hwspecops->write_register = nsi_canpci_write_register;