]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/hcan2.c
Merge branch 'master' into can-usb1
[lincan.git] / lincan / src / hcan2.c
index a31490f7caccee587058c3322aabde2ef1842054..279a4e98d16184e03de1d7d7dda3e1bed312664c 100644 (file)
@@ -1,7 +1,37 @@
-/* hcan2.c
- * Linux CAN-bus device driver.
- * This software is released under the GPL-License.
- */
+/**************************************************************************/
+/* File: hcan2.c - Renesas SH7760 HCAN2 controller support                */
+/*                                                                        */
+/* 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) 2007-2008 Martin Petera <peterm4@fel.cvut.cz>            */
+/* Funded by OCERA and FRESCOR IST projects                               */
+/* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl>      */
+/*                                                                        */
+/* 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"
@@ -46,7 +76,7 @@ uint16_t IRQs = ~(HCAN2_IRR_DFRI + HCAN2_IRR_MBEI + HCAN2_IRR_BOI + HCAN2_IRR_EP
 int hcan2_chip_config(struct canchip_t *chip)
 {
        DEBUGMSG("Configuring chip...\n");
-       
+
        if (hcan2_enable_configuration(chip))
                return -ENODEV;
 
@@ -206,7 +236,7 @@ int hcan2_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, int sa
        bcr1 = (((tseg1 - 1) & 0x000f) << 12) + (((tseg2 - 1) & 0x0007) << 8) + ((sjw & 0x0003) << 4);
        bcr0 = (best_brp - 1) & 0x00ff;
 
-       hcan2_set_btregs(chip, bcr0, bcr1);     
+       hcan2_set_btregs(chip, bcr0, bcr1);
 
        hcan2_disable_configuration(chip);
 
@@ -224,7 +254,7 @@ int hcan2_set_btregs(struct canchip_t *chip, unsigned short bcr0, unsigned short
 
        can_write_reg_w(chip, bcr1, HCAN2_BCR1);
        can_write_reg_w(chip, bcr0, HCAN2_BCR0);
-       
+
 /*     DEBUGMSG("BCR0 and BCR1 successfully set.\n"); */
        return 0;
 }
@@ -259,8 +289,8 @@ int hcan2_stop_chip(struct canchip_t *chip)
 int hcan2_attach_to_chip(struct canchip_t *chip)
 {
 /*     DEBUGMSG("Attaching to chip %d.\n", chip->chip_idx); */
-       
-       /* initialize chip */   
+
+       /* initialize chip */
 
        if (hcan2_enable_configuration(chip))
                return -ENODEV;
@@ -288,9 +318,9 @@ int hcan2_release_chip(struct canchip_t *chip)
 {
        hcan2_stop_chip(chip);
        can_disable_irq(chip->chip_irq);
-       
+
        hcan2_clear_objects(chip);
-       
+
        DEBUGMSG("Chip released [%02d]\n", chip->chip_idx);
        return 0;
 }
@@ -302,27 +332,28 @@ int hcan2_standard_mask(struct canchip_t *chip, unsigned short code, unsigned sh
        struct msgobj_t * obj;
        int obj_idx = (int) (chip->chip_data);
 
-       if (code & 0x1ffff800)  
+       if (code & 0x1ffff800)
            return hcan2_extended_mask(chip, code, mask);
 
-       
+
        if (obj_idx > 0 && obj_idx <= 32)
            obj = chip->msgobj[obj_idx - 1];
        else
            return -ENODEV;
 
-       chip->chip_data = (void*)0; /* reset mbox number */
+       chip->chip_data = (void*)0;     /* reset mbox number */
 
 
        ctrl0 = ((code & 0x07ff) << 4);
        lafm0 = ((mask & 0x07ff) << 4);
-       
+       lafm0 |= 0x0003;                /* ignore Ext ID 17:16  */
+
        can_write_reg_w(chip, ctrl0, (int) obj->obj_base_addr + HCAN2_MB_CTRL0);
        can_write_reg_w(chip, 0x0000, (int) obj->obj_base_addr + HCAN2_MB_CTRL1);
        can_write_reg_w(chip, lafm0, (int) obj->obj_base_addr + HCAN2_MB_MASK);
        can_write_reg_w(chip, 0xffff, (int) obj->obj_base_addr + HCAN2_MB_MASK + 2);
 
-       DEBUGMSG("Set standard_mask [id:0x%04x, m:0x%04x]\n", code, mask);
+       DEBUGMSG("MB%02d: Set standard_mask [id:0x%04x, m:0x%04x]\n", obj_idx, code, lafm0);
        return 0;
 }
 
@@ -333,7 +364,7 @@ int hcan2_extended_mask(struct canchip_t *chip, unsigned long code, unsigned lon
        struct msgobj_t * obj;
 
        int obj_idx = (int) (chip->chip_data);
-       
+
        if (obj_idx > 0 && obj_idx <= 32)
            obj = chip->msgobj[obj_idx - 1];
        else
@@ -349,14 +380,14 @@ int hcan2_extended_mask(struct canchip_t *chip, unsigned long code, unsigned lon
        lafm0 = ((mask & 0x1ffc0000) >> 14);
        lafm0 |=((mask & 0x00030000) >> 16);
        lafm1 =  (mask & 0x0000ffff);
-       
+
        can_write_reg_w(chip, ctrl0, (int) obj->obj_base_addr + HCAN2_MB_CTRL0);
        can_write_reg_w(chip, ctrl1, (int) obj->obj_base_addr + HCAN2_MB_CTRL1);
        can_write_reg_w(chip, lafm0, (int) obj->obj_base_addr + HCAN2_MB_MASK);
        can_write_reg_w(chip, lafm1, (int) obj->obj_base_addr + HCAN2_MB_MASK + 2);
-       
-       DEBUGMSG("Set extended_mask [id:0x%08x, m:0x%08x]\n", (uint32_t)code, (uint32_t)mask);
-    
+
+       DEBUGMSG("MB%02d: Set extended_mask [id:0x%08x, m:0x%08x]\n", obj_idx, (uint32_t)code, (uint32_t)mask);
+
         return 0;
 }
 
@@ -369,7 +400,7 @@ int hcan2_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
 
        /* clears mailbox and setup LFA to accept all Exted Messages */
        hcan2_setup_mbox4read(obj);
-       
+
        hcan2_disable_configuration(chip);
 
        return 0;
@@ -379,15 +410,15 @@ int hcan2_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct
 {
        DEBUGMSG("Pre write config\n");
 
-       /* change Mailbox header only if neccessary */  
+       /* change Mailbox header only if neccessary */
        /* otherwise change only data */
        if (hcan2_compare_msg(obj, msg))
        {
                if (hcan2_enable_configuration(chip))
                        return -ENODEV;
-       
+
                hcan2_setup_mbox4write(obj, msg);
-               
+
                if (hcan2_disable_configuration(chip))
                        return -ENODEV;
        }
@@ -400,10 +431,10 @@ int hcan2_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct
 int hcan2_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg)
 {
        unsigned obj_bit;
-       int b_addr = ((obj->object - 1) / 16) * (-2); 
+       int b_addr = ((obj->object - 1) / 16) * (-2);
 
        obj_bit = (1 << ((obj->object - 1) % 16));
-       
+
 /*     CANMSG("Sending message [obj: %d]\n", obj->object - 1); */
 
        can_write_reg_w(chip, obj_bit, b_addr + HCAN2_TXPR0);
@@ -454,25 +485,24 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
                /* Received message */
                if (irq_reg & HCAN2_IRR_DFRI)
                {
-                       rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
-                           can_read_reg_w(chip, HCAN2_RXPR0);
+                       rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
+                               can_read_reg_w(chip, HCAN2_RXPR0);
 
-                       DEBUGMSG("Received message [0x%08x]\n", rxdf);
+                       while(rxdf) {
+                               DEBUGMSG("Received message [0x%08x]\n", rxdf);
 
-                       while (rxdf) {
                                /* find the message object */
-                               for (idx = 0; (idx < chip->max_objects) && !(rxdf & (1<<idx)); idx++) { }
-                               
-                               /* realy i got one? */
-                               if (idx < chip->max_objects) {
-                                       hcan2_irq_read_handler(chip, chip->msgobj[idx]);
-                               
-                                       /* clear RXPR flag for this msgobj */
-                                       can_write_reg_w(chip, (1 << (idx % 16)), HCAN2_RXPR0 - 2*(idx / 16));
-                                       
-                                       rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
+                               for (idx = 0; (idx < chip->max_objects) && rxdf; idx++)
+                                       if ((rxdf & (1<<idx))) {
+                                               hcan2_irq_read_handler(chip, chip->msgobj[idx]);
+                                               /* RXPR flag for this msgobj is cleared during irq_read_handler*/
+                                               rxdf &= ~(1 << idx);
+                                       }
+
+
+                               DEBUGMSG("Before reset flags [0x%08x]\n", rxdf);
+                               rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
                                        can_read_reg_w(chip, HCAN2_RXPR0);
-                               }
                        }
                }
 
@@ -503,7 +533,7 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
 
                        CANMSG("Warning: entering ERROR PASSIVE state\nTEC: %d REC: %d\n",
                                (uint16_t)((tecrec >> 8) & 0x00ff), (uint16_t)(tecrec & 0x00ff));
-                       
+
                        /* Show warning only */
 
                        /* reset flag - by writing '1' */
@@ -511,17 +541,17 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
                }
 
                /* Message Overrun/Overwritten */
-               if (irq_reg & HCAN2_IRR_MOOI) { 
+               if (irq_reg & HCAN2_IRR_MOOI) {
                        /* put get Unread Message Status Register */
                        rxdf =  (can_read_reg_w(chip, HCAN2_UMSR1) << 16) + can_read_reg_w(chip, HCAN2_UMSR0);
 
                        /* find the message object */
                        for (idx = 0; (idx < chip->max_objects) && !(rxdf & (1<<idx)); idx++) { }
-                       
+
                        CANMSG("Error: MESSAGE OVERRUN/OVERWRITTEN [MB: %d]\n",idx);
-                       
+
                        /* notify only injured RXqueue-end */
-                       if (idx < chip->max_objects) 
+                       if (idx < chip->max_objects)
                                hcan2_notifyRXends(chip->msgobj[idx], CANQUEUE_NOTIFY_ERROR);
 
                        /* reset flag */
@@ -543,12 +573,12 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
                        can_write_reg_w(chip, 0xffff, HCAN2_ABACK0);
                        can_write_reg_w(chip, 0xffff, HCAN2_ABACK1);
                        return CANCHIP_IRQ_HANDLED;
-                   } 
+                   }
 
-                   /* Clear TXACK flag */                  
+                   /* Clear TXACK flag */
                    can_write_reg_w(chip, 1 << (idx % 16), HCAN2_TXACK0 - 2 * (idx / 16));
 
-                   /* sends message */     
+                   /* sends message */
                    hcan2_wakeup_tx(chip, chip->msgobj[idx]);
                }
 
@@ -569,11 +599,11 @@ int hcan2_config_irqs(struct canchip_t *chip, short irqs)
        hcan2_clear_irq_flags(chip);
 
        can_write_reg_w(chip, irqs, HCAN2_IMR);
-       
+
        /* allow all mailboxes to generate IRQ */
        can_write_reg_w(chip, 0, HCAN2_MBIMR0);
        can_write_reg_w(chip, 0, HCAN2_MBIMR1);
-       
+
 /*     CANMSG("IRQ Mask set [0x%02x]\n", irqs); */
        return 0;
 }
@@ -603,7 +633,7 @@ int hcan2_check_tx_stat(struct canchip_t *chip)
 int hcan2_check_MB_tx_stat(struct canchip_t *chip, struct msgobj_t *obj)
 {
        /* Transmition is complete return 0 - no error */
-       
+
        /* MB1-MB15 are in CANTXPR0 and MB16-MB31 are in CANTXPR1
           CANTXPR0 = CANTXPR1 + 0x0002
           MB0 - receive only */
@@ -618,9 +648,9 @@ int hcan2_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
 
        if (obj->object == 1)   /* msgbox 0 cant transmit only receive ! */
            return -ENODEV;
-    
+
        can_preempt_disable();
-       
+
        can_msgobj_set_fl(obj,TX_REQUEST);
        if(!can_msgobj_test_and_set_fl(obj,TX_LOCK) &&
                !hcan2_check_MB_tx_stat(chip, obj))
@@ -628,7 +658,7 @@ int hcan2_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
                can_msgobj_clear_fl(obj,TX_REQUEST);
 
                hcan2_irq_write_handler(chip, obj);
-       
+
                can_msgobj_clear_fl(obj,TX_LOCK);
        }
        else
@@ -657,7 +687,9 @@ int hcan2_filtch_rq(struct canchip_t *chip, struct msgobj_t * obj)
 
        /* HCAN2 uses oposite logic for LAFM: 1-ignore bit, 0-use bit as mask */
 
+#if myDEBUG
        DEBUGMSG("CNT: %d ID: 0x%08x MASK: 0x%08x\n", num, (uint32_t) (filter.id) & 0x1fffffff, (uint32_t) (~filter.mask) & 0x1fffffff);
+#endif
 
        if (filter.flags & MSG_EXT)             /* Extended ID */
                return hcan2_extended_mask(chip, filter.id, ~filter.mask);
@@ -672,7 +704,7 @@ void hcan2_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj)
        unsigned ctrl0, ctrl2, data;
        unsigned long flag_addr;
        uint16_t mb_offset;
-       
+
 
        mb_offset = (int ) obj->obj_base_addr;
 
@@ -684,7 +716,7 @@ void hcan2_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj)
        obj->rx_msg.length = len = ctrl2 & HCAN2_MBCT2_DLC;
        obj->rx_msg.flags = (ctrl0 & HCAN2_MBCT0_RTR) ? MSG_RTR : 0;
        obj->rx_msg.cob = obj->object - 1;
-               
+
        /* get ID of received message */
        if (ctrl0 & HCAN2_MBCT0_IDE)
        {
@@ -695,23 +727,23 @@ void hcan2_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj)
        }
        else
            obj->rx_msg.id = (ctrl0 & HCAN2_MBCT0_STDID)>>4;
-           
+
 
        if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
        for (i = 0; i < len; i++)
        {
                /* rcanqueue_ends_filt_conjuctionead 16bit data - two data bytes*/
                data = can_read_reg_w(chip, (int) obj->obj_base_addr + HCAN2_MB_DATA1 + i);
-               obj->rx_msg.data[i] = (data & 0xff00) >> 8;
-               if (++i < len) obj->rx_msg.data[i] = data & 0x00ff;
+               obj->rx_msg.data[i] = (data & 0xff00) >> 8;             // one data byte
+               if (++i < len) obj->rx_msg.data[i] = data & 0x00ff;     // second data byte
        }
 
        /* Computes correct offset address of register from MSGBOX_IDX and RTR flag
         * result is one of these:
         * HCAN2_RXPR1, HCAN2_RXPR0, HCAN2_RFPR1, HCAN2_RFPR0
         */
-       flag_addr = ((ctrl0 & HCAN2_MBCT0_RTR) << 3) + HCAN2_RXPR0 - ((obj->object - 1) / 16) * 2;
-               
+       flag_addr = HCAN2_RXPR0 - (int)((obj->object - 1) / 16) * 2;
+
        /* Reset flag by writing 1 to its position */
        can_write_reg_w(chip, (1 << ((obj->object - 1) % 16)), flag_addr);
 
@@ -800,7 +832,7 @@ int hcan2_fill_chipspecops(struct canchip_t *chip)
        chip->max_objects = 32;
        chip->write_register = chip->hostdevice->hwspecops->write_register;
        chip->read_register = chip->hostdevice->hwspecops->read_register;
-       
+
        /*
        chip->flags;
        chip->baudrate;
@@ -832,7 +864,7 @@ int hcan2_reset_chip(struct canchip_t *chip)
         * 11 recessive bits to join CAN bus activity
         */
 
-       int i; 
+       int i;
        unsigned gsr_reset;
 
        DEBUGMSG("Resetting HCAN2 chip %d...\n", chip->chip_idx);
@@ -840,7 +872,7 @@ int hcan2_reset_chip(struct canchip_t *chip)
        /* send Reset Request */
        can_write_reg_w(chip, HCAN2_MCR_RESET, HCAN2_MCR );
 
-       /* Check hardware reset status */ 
+       /* Check hardware reset status */
        i = 0;
        gsr_reset = can_read_reg_w(chip, HCAN2_GSR) & HCAN2_GSR_RESET;
        while (!(gsr_reset) && ((i++) <= MAX_SETTING_WAIT_LOOPS))
@@ -947,14 +979,14 @@ void hcan2_clear_mbox(struct canchip_t *chip, int msgobj_idx)
 void hcan2_setup_mbox4write(struct msgobj_t * obj, struct canmsg_t * msg)
 {
        int mb_offset;
-       uint16_t ctrl0, ctrl1, ctrl2; 
+       uint16_t ctrl0, ctrl1, ctrl2;
 
        struct canchip_t * chip = obj->hostchip;
 
        DEBUGMSG("Change Header\n");
 
        mb_offset = (int) obj->obj_base_addr;
-       
+
        hcan2_setup_ctrl_regs(msg, &ctrl0, &ctrl1, &ctrl2);
 
        can_write_reg_w(chip, ctrl0, mb_offset + HCAN2_MB_CTRL0);
@@ -968,17 +1000,17 @@ void hcan2_setup_mbox4write(struct msgobj_t * obj, struct canmsg_t * msg)
 void hcan2_setup_mbox4write_data(struct msgobj_t * obj, struct canmsg_t * msg)
 {
        int len,i, mb_offset;
-       uint16_t data; 
-       
+       uint16_t data;
+
        struct canchip_t * chip = obj->hostchip;
 
        DEBUGMSG("Change Data\n");
 
        mb_offset = (int) obj->obj_base_addr;
-       
+
        len = msg->length;
        if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
-       
+
        for (i = 0; i < len; i+=2)
        {
                data = (msg->data[i] << 8) + (i+1 < len ? msg->data[i+1] : 0);
@@ -989,7 +1021,7 @@ void hcan2_setup_mbox4write_data(struct msgobj_t * obj, struct canmsg_t * msg)
 void hcan2_setup_mbox4read(struct msgobj_t * obj)
 {
        struct canchip_t * chip = obj->hostchip;
-    
+
        hcan2_clear_mbox(chip, obj->object - 1);
 
        // in structure chip->chip_data is Mailbox number
@@ -1034,7 +1066,7 @@ int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg)
        uint16_t ctrl0, ctrl1, ctrl2;
        uint16_t mb_offset;
        uint16_t c0,c1,c2;
-       
+
        struct canchip_t * chip = obj->hostchip;
 
        mb_offset = (int) obj->obj_base_addr;
@@ -1048,7 +1080,7 @@ int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg)
        /* if using EXT ID conpare also ctrl1 */
        if (msg->flags & MSG_EXT && ctrl1 ^ c1)
                return 1;
-               
+
 
        DEBUGMSG("C0 0x%04x HW: 0x%04x\n", ctrl0, c0);
        DEBUGMSG("C1 0x%04x HW: 0x%04x\n", ctrl1, c1);