X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/258e4a224adc90317b3d11622a3076ba6d61b0d2..50e9e47fc21191ea9ea758fea1e7f2bd5a275e98:/lincan/src/sja1000.c diff --git a/lincan/src/sja1000.c b/lincan/src/sja1000.c index dfc47a2..507d911 100644 --- a/lincan/src/sja1000.c +++ b/lincan/src/sja1000.c @@ -1,21 +1,46 @@ -/* sja1000.c - * Linux CAN-bus device driver. - * Written by Arnaud Westenberg email:arnaud@wanadoo.nl - * 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: sja1000.c - Philips/NXP SJA1000 chip legacy mode (deprecated) */ +/* */ +/* LinCAN - (Not only) Linux CAN bus driver */ +/* Copyright (C) 2002-2009 DCE FEE CTU Prague */ +/* Copyright (C) 2002-2009 Pavel Pisa */ +/* 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" #include "../include/main.h" #include "../include/sja1000.h" -void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj); -void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj); +void sja1000_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj); +void sja1000_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj); -int sja1000_enable_configuration(struct chip_t *chip) +int sja1000_enable_configuration(struct canchip_t *chip) { int i=0; unsigned flags; @@ -39,7 +64,7 @@ int sja1000_enable_configuration(struct chip_t *chip) return 0; } -int sja1000_disable_configuration(struct chip_t *chip) +int sja1000_disable_configuration(struct canchip_t *chip) { int i=0; unsigned flags; @@ -62,49 +87,49 @@ int sja1000_disable_configuration(struct chip_t *chip) return 0; } -int sja1000_chip_config(struct chip_t *chip) +int sja1000_chip_config(struct canchip_t *chip) { if (sja1000_enable_configuration(chip)) return -ENODEV; /* Set mode, clock out, comparator */ - can_write_reg(chip,chip->sja_cdr_reg,SJACDR); + can_write_reg(chip,chip->sja_cdr_reg,SJACDR); /* Set driver output configuration */ - can_write_reg(chip,chip->sja_ocr_reg,SJAOCR); + can_write_reg(chip,chip->sja_ocr_reg,SJAOCR); if (sja1000_standard_mask(chip,0x0000, 0xffff)) return -ENODEV; - + if (!chip->baudrate) chip->baudrate=1000000; if (sja1000_baud_rate(chip,chip->baudrate,chip->clock,0,75,0)) return -ENODEV; /* Enable hardware interrupts */ - can_write_reg(chip,(sjaCR_RIE|sjaCR_TIE|sjaCR_EIE|sjaCR_OIE),SJACR); + can_write_reg(chip,(sjaCR_RIE|sjaCR_TIE|sjaCR_EIE|sjaCR_OIE),SJACR); sja1000_disable_configuration(chip); - + return 0; } -int sja1000_standard_mask(struct chip_t *chip, unsigned short code, unsigned short mask) +int sja1000_standard_mask(struct canchip_t *chip, unsigned short code, unsigned short mask) { unsigned char write_code, write_mask; if (sja1000_enable_configuration(chip)) return -ENODEV; - /* The acceptance code bits (SJAACR bits 0-7) and the eight most + /* The acceptance code bits (SJAACR bits 0-7) and the eight most * significant bits of the message identifier (id.10 to id.3) must be - * equal to those bit positions which are marked relevant by the + * equal to those bit positions which are marked relevant by the * acceptance mask bits (SJAAMR bits 0-7). * (id.10 to id.3) = (SJAACR.7 to SJAACR.0) v (SJAAMR.7 to SJAAMR.0) * (Taken from Philips sja1000 Data Sheet) */ write_code = (unsigned char) code >> 3; write_mask = (unsigned char) mask >> 3; - + can_write_reg(chip,write_code,SJAACR); can_write_reg(chip,write_mask,SJAAMR); @@ -123,13 +148,13 @@ int sja1000_standard_mask(struct chip_t *chip, unsigned short code, unsigned sho * param sampl_pt sample point in % (0-100) sets (TSEG1+2)/(TSEG1+TSEG2+3) ratio * param flags fields BTR1_SAM, OCMODE, OCPOL, OCTP, OCTN, CLK_OFF, CBP */ -int sja1000_baud_rate(struct chip_t *chip, int rate, int clock, int sjw, +int sja1000_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, int sampl_pt, int flags) { 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 (sja1000_enable_configuration(chip)) return -ENODEV; @@ -186,12 +211,12 @@ int sja1000_baud_rate(struct chip_t *chip, int rate, int clock, int sjw, return 0; } -int sja1000_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) +int sja1000_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj) { int i; - + i=can_read_reg(chip,SJASR); - + if (!(i&sjaSR_RBS)) { //Temp for (i=0; i<0x20; i++) @@ -201,7 +226,7 @@ int sja1000_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) sja1000_start_chip(chip); // disable interrupts for a moment - can_write_reg(chip, 0, SJACR); + can_write_reg(chip, 0, SJACR); sja1000_irq_read_handler(chip, obj); @@ -214,7 +239,7 @@ int sja1000_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) #define MAX_TRANSMIT_WAIT_LOOPS 10 -int sja1000_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, +int sja1000_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { int i=0, id=0; @@ -223,11 +248,11 @@ int sja1000_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, sja1000_start_chip(chip); //sja1000 goes automatically into reset mode on errors /* Wait until Transmit Buffer Status is released */ - while ( !(can_read_reg(chip, SJASR) & sjaSR_TBS) && + while ( !(can_read_reg(chip, SJASR) & sjaSR_TBS) && i++msgobj[0]; + int loop_cnt=CHIP_MAX_IRQLOOP; irq_register=can_read_reg(chip, SJAIR); // DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register); @@ -344,41 +383,52 @@ int sja1000_irq_handler(int irq, struct chip_t *chip) if ((irq_register & (sjaIR_WUI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)) == 0) return CANCHIP_IRQ_NONE; - if ((irq_register & sjaIR_RI) != 0) - sja1000_irq_read_handler(chip, obj); + do { - if ((irq_register & sjaIR_TI) != 0) { - can_msgobj_set_fl(obj,TX_REQUEST); - while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ - can_msgobj_clear_fl(obj,TX_REQUEST); + if(!loop_cnt--) { + CANMSG("sja1000_irq_handler IRQ %d stuck\n",irq); + return CANCHIP_IRQ_STUCK; + } - if (can_read_reg(chip, SJASR) & sjaSR_TBS) - sja1000_irq_write_handler(chip, obj); + if ((irq_register & sjaIR_RI) != 0) + sja1000_irq_read_handler(chip, obj); - can_msgobj_clear_fl(obj,TX_LOCK); - if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; + if ((irq_register & sjaIR_TI) != 0) { + can_msgobj_set_fl(obj,TX_REQUEST); + while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ + can_msgobj_clear_fl(obj,TX_REQUEST); + + if (can_read_reg(chip, SJASR) & sjaSR_TBS) + sja1000_irq_write_handler(chip, obj); + + can_msgobj_clear_fl(obj,TX_LOCK); + if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; + } } - } - if ((irq_register & (sjaIR_EI|sjaIR_DOI)) != 0) { - // Some error happened + if ((irq_register & (sjaIR_EI|sjaIR_DOI)) != 0) { + // Some error happened // 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 - CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n", - can_read_reg(chip, SJASR), irq_register); - obj->ret=-1; - - if(obj->tx_slot){ - canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_BUS); - /*canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); - obj->tx_slot=NULL;*/ + CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n", + can_read_reg(chip, SJASR), irq_register); + obj->ret=-1; + + if(obj->tx_slot){ + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_BUS); + /*canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL;*/ + } } - } + + irq_register=can_read_reg(chip, SJAIR); + + } while(irq_register & (sjaIR_WUI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)); return CANCHIP_IRQ_HANDLED; } -void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj) +void sja1000_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj) { int i=0, id=0, len; @@ -402,16 +452,16 @@ void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj) } while(can_read_reg(chip, SJASR) & sjaSR_RBS); } -void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj) +void sja1000_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); } @@ -448,17 +498,17 @@ void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj) * Return Value: negative value reports error. * File: src/sja1000.c */ -int sja1000_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj) +int sja1000_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj) { can_preempt_disable(); - + can_msgobj_set_fl(obj,TX_REQUEST); while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){ can_msgobj_clear_fl(obj,TX_REQUEST); if (can_read_reg(chip, SJASR) & sjaSR_TBS) sja1000_irq_write_handler(chip, obj); - + can_msgobj_clear_fl(obj,TX_LOCK); if(!can_msgobj_test_fl(obj,TX_REQUEST)) break; } @@ -485,13 +535,16 @@ int sja1000_register(struct chipspecops_t *chipspecops) chipspecops->enable_configuration = sja1000_enable_configuration; chipspecops->disable_configuration = sja1000_disable_configuration; chipspecops->set_btregs = sja1000_set_btregs; + chipspecops->attach_to_chip=sja1000_attach_to_chip; + chipspecops->release_chip=sja1000_release_chip; chipspecops->start_chip = sja1000_start_chip; chipspecops->stop_chip = sja1000_stop_chip; chipspecops->irq_handler = sja1000_irq_handler; + chipspecops->irq_accept = NULL; return 0; } -int sja1000_fill_chipspecops(struct chip_t *chip) +int sja1000_fill_chipspecops(struct canchip_t *chip) { chip->chip_type="sja1000"; chip->max_objects=1;