X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/4e95a8113be1f7fb1538faec4d0d84e5c3fd4979..HEAD:/lincan/src/sja1000p.c diff --git a/lincan/src/sja1000p.c b/lincan/src/sja1000p.c index 36319a1..52b2ca5 100644 --- a/lincan/src/sja1000p.c +++ b/lincan/src/sja1000p.c @@ -1,13 +1,37 @@ -/* 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 */ +/* Copyright (C) 2002-2009 Pavel Pisa */ +/* Copyright (C) 2004-2005 Tomasz Motylewski (BFAD GmbH) */ +/* Funded by OCERA and FRESCOR IST projects */ +/* Based on CAN driver code by Arnaud Westenberg */ +/* */ +/* 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" @@ -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); @@ -381,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); @@ -416,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++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 +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) @@ -721,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 @@ -767,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); @@ -782,14 +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); 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 */ @@ -824,7 +849,7 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip) 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_PENDING) && !can_msgobj_test_fl(obj,TX_LOCK)) || + (can_msgobj_test_fl(obj,TX_REQUEST) && !can_msgobj_test_fl(obj,TX_LOCK)) || (status & sjaSR_RBS)); return CANCHIP_IRQ_HANDLED; @@ -843,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)){ @@ -855,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");