]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - embedded/app/usbcan/sja1000p.c
embedded: reintroduce missing emulated bus initialization for UL_USB1 board.
[lincan.git] / embedded / app / usbcan / sja1000p.c
index ffadb6c74347aceebec1510aa675ca524690a3f1..76ad469a80a3622542664fcf694bf01fe335bcb2 100644 (file)
@@ -1,18 +1,42 @@
-/* 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
- */
-
-#include "../include/can.h"
-#include "../include/can_sysdep.h"
-#include "../include/main.h"
-#include "../include/sja1000p.h"
+/**************************************************************************/
+/* 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 "./can/can.h"
+#include "./can/can_sysdep.h"
+#include "./can/main.h"
+#include "./can/sja1000p.h"
 
 #ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS
 
@@ -168,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
@@ -177,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);
@@ -202,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;
 }
 
@@ -236,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);
@@ -270,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;
 
@@ -316,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);
@@ -324,6 +348,70 @@ int sja1000p_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
        return 0;
 }
 
+
+/**
+ * sja1000p_set_bittiming: - set bittiming according to already computed parameters.
+ * @chip: pointer to chip state structure
+ * @bpr: baud rate prescaler
+ * @sjw: synchronization jump width in bittime quanta
+ * @tseg1: length of the segment 1 in bittime quanta
+ * @tseg2: length of the segment 2 in bittime quanta
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_set_bittiming(struct canchip_t *chip, int brp, int sjw, int tseg1, int tseg2)
+{
+       uint8_t sam3times = 0; /* 0 = the bus is sampled once */
+
+       if((--brp)<0)
+               return -EINVAL;
+
+       if((--sjw)<0)
+               return -EINVAL;
+
+       if((--tseg1)<0)
+               return -EINVAL;
+
+       if((--tseg2)<0)
+               return -EINVAL;
+       
+
+
+       if (sja1000p_enable_configuration(chip))
+               return -ENODEV;
+
+       can_write_reg(chip, sjw<<6 | brp, SJABTR0);
+       can_write_reg(chip, (sam3times<<7) | (tseg2<<4) | tseg1, SJABTR1);
+
+       sja1000p_disable_configuration(chip);
+       
+       return 0;
+}
+
+/**
+ * sja1000p_get_bittiming_const: - obtain description of chip bittiming calculation.
+ * @chip: pointer to chip state structure
+ * @btc: pointer to the structure filled by data
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_get_bittiming_const(struct canchip_t *chip, struct can_bittiming_const *btc)
+{
+       btc->tseg1_min = 1;
+       btc->tseg1_max = 16; /* sjaMAX_TSEG1+1 */
+       btc->tseg2_min = 1;
+       btc->tseg2_max = 8; /* sjaMAX_TSEG2+1 */
+       btc->sjw_max = 4;
+       btc->brp_min = 1;
+       btc->brp_max = 64;
+       btc->brp_inc = 1;
+
+       return 0;
+}
+
+
 /**
  * sja1000p_read: - reads and distributes one or more received messages
  * @chip: pointer to chip state structure
@@ -381,7 +469,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);
@@ -416,20 +504,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);
@@ -495,7 +583,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);
@@ -529,7 +617,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))
@@ -677,13 +765,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);
                }
@@ -691,7 +779,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)
@@ -721,7 +809,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
@@ -783,14 +871,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);
                        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;
-               
+
                        if(error_code == 0xd9) {
                                obj->ret= -ENXIO;
                                /* no such device or address - no ACK received */
@@ -844,9 +932,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)){
@@ -856,7 +944,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");
@@ -891,6 +979,8 @@ int sja1000p_register(struct chipspecops_t *chipspecops)
        chipspecops->stop_chip=sja1000p_stop_chip;
        chipspecops->irq_handler=sja1000p_irq_handler;
        chipspecops->irq_accept=NULL;
+       chipspecops->set_bittiming=sja1000p_set_bittiming;
+       chipspecops->get_bittiming_const=sja1000p_get_bittiming_const;
        return 0;
 }