]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/sja1000p.c
LinCAN sources go through big white-space cleanup.
[lincan.git] / lincan / src / sja1000p.c
index 59fa68dcb39ed4a807ca054fd9a04445c2f165a8..52b2ca5d9602c612aaa98bf39b88d622961a843f 100644 (file)
-/* sja1000.c
- * Linux CAN-bus device driver.
- * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
- * Changed for PeliCan mode SJA1000 by Tomasz Motylewski (BFAD GmbH)
- * T.Motylewski@bfad.de
- * 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
- */
+/**************************************************************************/
+/* File: sja1000p.c - Philips/NXP SJA1000 chip PeliCanCAN mode 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) 2004-2005 Tomasz Motylewski (BFAD GmbH)                  */
+/* 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"
 #include "../include/main.h"
 #include "../include/sja1000p.h"
 
+#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS
+
+static const char *sja1000_ecc_errc_str[]={
+       "bit error",
+       "form error",
+       "stuff error",
+       "other type of error"
+};
+
+static const char *sja1000_ecc_seg_str[]={
+       "?0?",
+       "?1?",
+       "ID.28 to ID.21",
+       "start of frame",
+       "bit SRTR",
+       "bit IDE",
+       "ID.20 to ID.18",
+       "ID.17 to ID.13",
+       "CRC sequence",
+       "reserved bit 0",
+       "data field",
+       "data length code",
+       "bit RTR",
+       "reserved bit 1",
+       "ID.4 to ID.0",
+       "ID.12 to ID.5",
+       "?16?"
+       "active error flag",
+       "intermission",
+       "tolerate dominant bits",
+       "?20?",
+       "?21?",
+       "passive error flag",
+       "error delimiter",
+       "CRC delimiter",
+       "acknowledge slot",
+       "end of frame",
+       "acknowledge delimiter",
+       "overload flag",
+       "?29?",
+       "?30?",
+       "?31?"
+};
+
+#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/
+
+static int sja1000_report_error_limit_counter;
+
+static void sja1000_report_error(struct canchip_t *chip,
+                               unsigned sr, unsigned ir, unsigned ecc)
+{
+       if(sja1000_report_error_limit_counter>=100)
+               return;
+
+       CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n",
+               sr, ir, ecc);
+
+       sja1000_report_error_limit_counter+=10;
+
+       if(sja1000_report_error_limit_counter>=100){
+               sja1000_report_error_limit_counter+=10;
+               CANMSG("Error: too many errors, reporting disabled\n");
+               return;
+       }
+
+#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS
+       CANMSG("SR: BS=%c  ES=%c  TS=%c  RS=%c  TCS=%c TBS=%c DOS=%c RBS=%c\n",
+               sr&sjaSR_BS?'1':'0',sr&sjaSR_ES?'1':'0',
+               sr&sjaSR_TS?'1':'0',sr&sjaSR_RS?'1':'0',
+               sr&sjaSR_TCS?'1':'0',sr&sjaSR_TBS?'1':'0',
+               sr&sjaSR_DOS?'1':'0',sr&sjaSR_RBS?'1':'0');
+       CANMSG("IR: BEI=%c ALI=%c EPI=%c WUI=%c DOI=%c EI=%c  TI=%c  RI=%c\n",
+               sr&sjaIR_BEI?'1':'0',sr&sjaIR_ALI?'1':'0',
+               sr&sjaIR_EPI?'1':'0',sr&sjaIR_WUI?'1':'0',
+               sr&sjaIR_DOI?'1':'0',sr&sjaIR_EI?'1':'0',
+               sr&sjaIR_TI?'1':'0',sr&sjaIR_RI?'1':'0');
+       if((sr&sjaIR_EI) || 1){
+               CANMSG("EI: %s %s %s\n",
+                      sja1000_ecc_errc_str[(ecc&(sjaECC_ERCC1|sjaECC_ERCC0))/sjaECC_ERCC0],
+                      ecc&sjaECC_DIR?"RX":"TX",
+                      sja1000_ecc_seg_str[ecc&sjaECC_SEG_M]
+                     );
+       }
+#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/
+}
+
+
 /**
  * sja1000p_enable_configuration - enable chip configuration mode
  * @chip: pointer to chip state structure
@@ -81,7 +192,7 @@ int sja1000p_disable_configuration(struct canchip_t *chip)
  * This function configures chip and prepares it for message
  * transmission and reception. The function resets chip,
  * resets mask for acceptance of all messages by call to
- * sja1000p_extended_mask() function and then 
+ * sja1000p_extended_mask() function and then
  * computes and sets baudrate with use of function sja1000p_baud_rate().
  * Return Value: negative value reports error.
  * File: src/sja1000p.c
@@ -90,19 +201,19 @@ int sja1000p_chip_config(struct canchip_t *chip)
 {
        int i;
        unsigned char n, r;
-       
+
        if (sja1000p_enable_configuration(chip))
                return -ENODEV;
 
        /* Set mode, clock out, comparator */
-       can_write_reg(chip,sjaCDR_PELICAN|chip->sja_cdr_reg,SJACDR); 
+       can_write_reg(chip,sjaCDR_PELICAN|chip->sja_cdr_reg,SJACDR);
 
        /* Ensure, that interrupts are disabled even on the chip level now */
        can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER);
 
        /* Set driver output configuration */
-       can_write_reg(chip,chip->sja_ocr_reg,SJAOCR); 
-       
+       can_write_reg(chip,chip->sja_ocr_reg,SJAOCR);
+
        /* Simple check for chip presence */
        for (i=0, n=0x5a; i<8; i++, n+=0xf) {
                can_write_reg(chip,n,SJAACR0+i);
@@ -115,21 +226,21 @@ int sja1000p_chip_config(struct canchip_t *chip)
                        return -ENODEV;
                }
        }
-       
+
 
        if (sja1000p_extended_mask(chip,0x00000000, 0xffffffff))
                return -ENODEV;
-       
+
        if (!chip->baudrate)
                chip->baudrate=1000000;
        if (sja1000p_baud_rate(chip,chip->baudrate,chip->clock,0,75,0))
                return -ENODEV;
 
        /* Enable hardware interrupts */
-       can_write_reg(chip, sjaENABLE_INTERRUPTS, SJAIER); 
+       can_write_reg(chip, sjaENABLE_INTERRUPTS, SJAIER);
 
        sja1000p_disable_configuration(chip);
-       
+
        return 0;
 }
 
@@ -149,7 +260,7 @@ int sja1000p_extended_mask(struct canchip_t *chip, unsigned long code, unsigned
        if (sja1000p_enable_configuration(chip))
                return -ENODEV;
 
-// LSB to +3, MSB to +0        
+// LSB to +3, MSB to +0
        for(i=SJA_PeliCAN_AC_LEN; --i>=0;) {
                can_write_reg(chip,code&0xff,SJAACR0+i);
                can_write_reg(chip,mask&0xff,SJAAMR0+i);
@@ -183,7 +294,7 @@ int sja1000p_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
        int best_error = 1000000000, error;
        int best_tseg=0, best_brp=0, best_rate=0, brp=0;
        int tseg=0, tseg1=0, tseg2=0;
-       
+
        if (sja1000p_enable_configuration(chip))
                return -ENODEV;
 
@@ -229,7 +340,7 @@ int sja1000p_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
 
 
        can_write_reg(chip, sjw<<6 | best_brp, SJABTR0);
-       can_write_reg(chip, ((flags & BTR1_SAM) != 0)<<7 | (tseg2<<4) 
+       can_write_reg(chip, ((flags & BTR1_SAM) != 0)<<7 | (tseg2<<4)
                                        | tseg1, SJABTR1);
 
        sja1000p_disable_configuration(chip);
@@ -294,7 +405,7 @@ int sja1000p_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
 {
        int status;
        status=can_read_reg(chip,SJASR);
-       
+
        if(status  & sjaSR_BS) {
                /* Try to recover from error condition */
                DEBUGMSG("sja1000p_pre_read_config bus-off recover 0x%x\n",status);
@@ -329,20 +440,20 @@ int sja1000p_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
  * Return Value: negative value reports error.
  * File: src/sja1000p.c
  */
-int sja1000p_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, 
+int sja1000p_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
                                                        struct canmsg_t *msg)
 {
-       int i=0; 
+       int i=0;
        unsigned int id;
        int status;
        int len;
 
        /* Wait until Transmit Buffer Status is released */
-       while ( !((status=can_read_reg(chip, SJASR)) & sjaSR_TBS) && 
+       while ( !((status=can_read_reg(chip, SJASR)) & sjaSR_TBS) &&
                                                i++<MAX_TRANSMIT_WAIT_LOOPS) {
                udelay(i);
        }
-       
+
        if(status & sjaSR_BS) {
                /* Try to recover from error condition */
                DEBUGMSG("sja1000p_pre_write_config bus-off recover 0x%x\n",status);
@@ -408,7 +519,7 @@ int sja1000p_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
  * Return Value: negative value reports error.
  * File: src/sja1000p.c
  */
-int sja1000p_send_msg(struct canchip_t *chip, struct msgobj_t *obj, 
+int sja1000p_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
                                                        struct canmsg_t *msg)
 {
        can_write_reg(chip, sjaCMR_TR, SJACMR);
@@ -442,7 +553,7 @@ int sja1000p_check_tx_stat(struct canchip_t *chip)
  * Return Value: negative value reports error.
  * File: src/sja1000p.c
  */
-int sja1000p_set_btregs(struct canchip_t *chip, unsigned short btr0, 
+int sja1000p_set_btregs(struct canchip_t *chip, unsigned short btr0,
                                                        unsigned short btr1)
 {
        if (sja1000p_enable_configuration(chip))
@@ -470,6 +581,8 @@ int sja1000p_start_chip(struct canchip_t *chip)
        flags = can_read_reg(chip, SJAMOD) & (sjaMOD_LOM|sjaMOD_STM|sjaMOD_AFM|sjaMOD_SM);
        can_write_reg(chip, flags, SJAMOD);
 
+       sja1000_report_error_limit_counter=0;
+
        return 0;
 }
 
@@ -588,13 +701,13 @@ int sja1000p_config_irqs(struct canchip_t *chip, short irqs)
 void sja1000p_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
 {
        int cmd;
-       
+
        if(obj->tx_slot){
                /* Do local transmitted message distribution if enabled */
                if (processlocal){
                        /* fill CAN message timestamp */
                        can_filltimestamp(&obj->tx_slot->msg.timestamp);
-                       
+
                        obj->tx_slot->msg.flags |= MSG_LOCAL;
                        canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
                }
@@ -602,7 +715,7 @@ void sja1000p_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
                canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
                obj->tx_slot=NULL;
        }
-       
+
        can_msgobj_clear_fl(obj,TX_PENDING);
        cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
        if(cmd<0)
@@ -632,7 +745,7 @@ void sja1000p_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
  * sja1000p_irq_handler: - interrupt service routine
  * @irq: interrupt vector number, this value is system specific
  * @chip: pointer to chip state structure
- * 
+ *
  * Interrupt handler is activated when state of CAN controller chip changes,
  * there is message to be read or there is more space for new messages or
  * error occurs. The receive events results in reading of the message from
@@ -678,7 +791,8 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
 
                /* (irq_register & sjaIR_TI) */
                /*      old variant using SJAIR, collides with intended use with irq_accept */
-               if ((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) {
+               if (((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING))||
+                   (can_msgobj_test_fl(obj,TX_REQUEST))) {
                        DEBUGMSG("sja1000_irq_handler: TI or TX_PENDING and TBS\n");
                        obj->ret = 0;
                        can_msgobj_set_fl(obj,TX_REQUEST);
@@ -693,15 +807,14 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
                                DEBUGMSG("TX looping in sja1000_irq_handler\n");
                        }
                }
-               if ((irq_register & (sjaIR_EI|sjaIR_BEI|sjaIR_EPI|sjaIR_DOI)) != 0) { 
+               if ((irq_register & (sjaIR_EI|sjaIR_BEI|sjaIR_EPI|sjaIR_DOI)) != 0) {
                        // Some error happened
                        error_code=can_read_reg(chip,SJAECC);
-                       CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n",
-                               status, irq_register, error_code);
+                       sja1000_report_error(chip, status, irq_register, error_code);
 // FIXME: chip should be brought to usable state. Transmission cancelled if in progress.
 // Reset flag set to 0 if chip is already off the bus. Full state report
-               obj->ret=-1;
-               
+                       obj->ret=-1;
+
                        if(error_code == 0xd9) {
                                obj->ret= -ENXIO;
                                /* no such device or address - no ACK received */
@@ -722,15 +835,21 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
                        }
 
                } else {
+                       if(sja1000_report_error_limit_counter)
+                               sja1000_report_error_limit_counter--;
                        obj->tx_retry_cnt=0;
                }
 
                irq_register=can_read_reg(chip,SJAIR);
-       
+
                status=can_read_reg(chip,SJASR);
 
-       } while((irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)) ||
-               ((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) ||
+               if(((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) ||
+                  (irq_register & sjaIR_TI))
+                        can_msgobj_set_fl(obj,TX_REQUEST);
+
+       } while((irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_RI)) ||
+               (can_msgobj_test_fl(obj,TX_REQUEST) && !can_msgobj_test_fl(obj,TX_LOCK)) ||
                (status & sjaSR_RBS));
 
        return CANCHIP_IRQ_HANDLED;
@@ -749,9 +868,9 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
  */
 int sja1000p_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
 {
-       
+
        can_preempt_disable();
-       
+
        can_msgobj_set_fl(obj,TX_PENDING);
        can_msgobj_set_fl(obj,TX_REQUEST);
        while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
@@ -761,7 +880,7 @@ int sja1000p_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
                        obj->tx_retry_cnt=0;
                        sja1000p_irq_write_handler(chip, obj);
                }
-       
+
                can_msgobj_clear_fl(obj,TX_LOCK);
                if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
                DEBUGMSG("TX looping in sja1000p_wakeup_tx\n");