X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/786c7d54e8d820e89997e507c29ea716c0d55fd9..95c031e101c74ae6472a7e538f3128f67a490082:/lincan/src/sja1000.c diff --git a/lincan/src/sja1000.c b/lincan/src/sja1000.c index 0955c76..27eebca 100644 --- a/lincan/src/sja1000.c +++ b/lincan/src/sja1000.c @@ -1,58 +1,53 @@ /* 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 0.6 18 Sept 2000 + * Version lincan-0.3 17 Jun 2004 */ -#include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif - -#include -#include - +#include "../include/can.h" +#include "../include/can_sysdep.h" #include "../include/main.h" #include "../include/sja1000.h" -int sja1000_enable_configuration(struct chip_t *chip) +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 canchip_t *chip) { int i=0; unsigned flags; - disable_irq(chip->chip_irq); + can_disable_irq(chip->chip_irq); flags=can_read_reg(chip,SJACR); - while ((!(flags & CR_RR)) && (i<=10)) { - can_write_reg(chip,flags|CR_RR,SJACR); + while ((!(flags & sjaCR_RR)) && (i<=10)) { + can_write_reg(chip,flags|sjaCR_RR,SJACR); udelay(100); i++; flags=can_read_reg(chip,SJACR); } if (i>=10) { CANMSG("Reset error\n"); - enable_irq(chip->chip_irq); + can_enable_irq(chip->chip_irq); return -ENODEV; } return 0; } -int sja1000_disable_configuration(struct chip_t *chip) +int sja1000_disable_configuration(struct canchip_t *chip) { int i=0; unsigned flags; flags=can_read_reg(chip,SJACR); - while ( (flags & CR_RR) && (i<=10) ) { - can_write_reg(chip,flags & (CR_RIE|CR_TIE|CR_EIE|CR_OIE),SJACR); + while ( (flags & sjaCR_RR) && (i<=10) ) { + can_write_reg(chip,flags & (sjaCR_RIE|sjaCR_TIE|sjaCR_EIE|sjaCR_OIE),SJACR); udelay(100); i++; flags=can_read_reg(chip,SJACR); @@ -62,12 +57,12 @@ int sja1000_disable_configuration(struct chip_t *chip) return -ENODEV; } - enable_irq(chip->chip_irq); + can_enable_irq(chip->chip_irq); 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; @@ -80,20 +75,20 @@ int sja1000_chip_config(struct chip_t *chip) if (sja1000_standard_mask(chip,0x0000, 0xffff)) return -ENODEV; - if (!baudrate) - baudrate=1000; - if (sja1000_baud_rate(chip,1000*baudrate,chip->clock,0,75,0)) + 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,(CR_RIE|CR_TIE|CR_EIE|CR_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; @@ -128,7 +123,7 @@ 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; @@ -182,115 +177,101 @@ int sja1000_baud_rate(struct chip_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 | tseg1, SJABTR1); -// can_write_reg(chip, OCR_MODE_NORMAL | OCR_TX0_LH | OCR_TX1_ZZ, SJAOCR); +// can_write_reg(chip, sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH | sjaOCR_TX1_ZZ, SJAOCR); /* BASIC mode, bypass input comparator */ -// can_write_reg(chip, CDR_CBP| /* CDR_CLK_OFF | */ 7, SJACDR); +// can_write_reg(chip, sjaCDR_CBP| /* sjaCDR_CLK_OFF | */ 7, SJACDR); sja1000_disable_configuration(chip); 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; - struct canfifo_t *fifo = chip->msgobj[0]->fifo; - int id; + i=can_read_reg(chip,SJASR); - if (!(i&SR_RBS)) { + if (!(i&sjaSR_RBS)) { //Temp - for (i=0; i<0x20; i++) - CANMSG("0x%x is 0x%x\n",i,can_read_reg(chip,i)); - return 0; + for (i=0; i<0x20; i++) + CANMSG("0x%x is 0x%x\n",i,can_read_reg(chip,i)); + return 0; } sja1000_start_chip(chip); - can_write_reg(chip, 0, SJACR); // disable interrupts for a moment -// TODO: this would be best sja1000_irq_read_handler(chip); -// now just duplicate the code. - do { - id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8); - fifo->rx_writep->length = id & 0x0f; - fifo->rx_writep->flags = id&ID0_RTR ? MSG_RTR : 0; - fifo->rx_writep->timestamp = 0; - fifo->rx_writep->cob = 0; - fifo->rx_writep->id = id>>5; - - for (i=0; irx_writep->length; i++) - fifo->rx_writep->data[i]=can_read_reg(chip, SJARXDAT0 + i); - - fifo->rx_writep++; - if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH) - fifo->rx_writep = fifo->buf_rx_entry; + // disable interrupts for a moment + can_write_reg(chip, 0, SJACR); - can_write_reg(chip, CMR_RRB, SJACMR); + sja1000_irq_read_handler(chip, obj); - } while (can_read_reg(chip, SJASR) & SR_RBS); - -// enable interrupts - can_write_reg(chip, CR_OIE | CR_EIE | CR_TIE | CR_RIE, SJACR); + // enable interrupts + can_write_reg(chip, sjaCR_OIE | sjaCR_EIE | sjaCR_TIE | sjaCR_RIE, SJACR); return 1; } -#define MAX_TRANSMIT_WAIT_LOOPS 200 -int sja1000_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, +#define MAX_TRANSMIT_WAIT_LOOPS 10 + +int sja1000_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { int i=0, id=0; + int len; 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) & SR_TBS) && + while ( !(can_read_reg(chip, SJASR) & sjaSR_TBS) && i++id<<5) | ((msg->flags&MSG_RTR)?ID0_RTR:0) | msg->length; + len = msg->length; + if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; + id = (msg->id<<5) | ((msg->flags&MSG_RTR)?sjaID0_RTR:0) | len; can_write_reg(chip, id>>8, SJATXID1); can_write_reg(chip, id & 0xff , SJATXID0); - for (i=0; ilength; i++) + for (i=0; idata[i], SJATXDAT0+i); return 0; } -int sja1000_send_msg(struct chip_t *chip, struct msgobj_t *obj, +int sja1000_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { - can_write_reg(chip, CMR_TR, SJACMR); + can_write_reg(chip, sjaCMR_TR, SJACMR); return 0; } -int sja1000_check_tx_stat(struct chip_t *chip) +int sja1000_check_tx_stat(struct canchip_t *chip) { - if (can_read_reg(chip,SJASR) & SR_TCS) + if (can_read_reg(chip,SJASR) & sjaSR_TCS) return 0; else return 1; } -int sja1000_set_btregs(struct chip_t *chip, unsigned short btr0, +int sja1000_set_btregs(struct canchip_t *chip, unsigned short btr0, unsigned short btr1) { if (sja1000_enable_configuration(chip)) @@ -304,51 +285,188 @@ int sja1000_set_btregs(struct chip_t *chip, unsigned short btr0, return 0; } -int sja1000_start_chip(struct chip_t *chip) +int sja1000_start_chip(struct canchip_t *chip) { unsigned short flags = 0; - flags = can_read_reg(chip, SJACR) & (CR_RIE|CR_TIE|CR_EIE|CR_OIE); + flags = can_read_reg(chip, SJACR) & (sjaCR_RIE|sjaCR_TIE|sjaCR_EIE|sjaCR_OIE); can_write_reg(chip, flags, SJACR); return 0; } -int sja1000_stop_chip(struct chip_t *chip) +int sja1000_stop_chip(struct canchip_t *chip) { unsigned short flags = 0; - flags = can_read_reg(chip, SJACR) & (CR_RIE|CR_TIE|CR_EIE|CR_OIE); - can_write_reg(chip, flags|CR_RR, SJACR); + flags = can_read_reg(chip, SJACR) & (sjaCR_RIE|sjaCR_TIE|sjaCR_EIE|sjaCR_OIE); + can_write_reg(chip, flags|sjaCR_RR, SJACR); return 0; } -int sja1000_remote_request(struct chip_t *chip, struct msgobj_t *obj) +int sja1000_remote_request(struct canchip_t *chip, struct msgobj_t *obj) { CANMSG("sja1000_remote_request not implemented\n"); return -ENOSYS; } -int sja1000_extended_mask(struct chip_t *chip, unsigned long code, +int sja1000_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask) { CANMSG("sja1000_extended_mask not implemented\n"); return -ENOSYS; } -int sja1000_clear_objects(struct chip_t *chip) +int sja1000_clear_objects(struct canchip_t *chip) { CANMSG("sja1000_clear_objects not implemented\n"); return -ENOSYS; } -int sja1000_config_irqs(struct chip_t *chip, short irqs) +int sja1000_config_irqs(struct canchip_t *chip, short irqs) { CANMSG("sja1000_config_irqs not implemented\n"); return -ENOSYS; } + +int sja1000_irq_handler(int irq, struct canchip_t *chip) +{ + unsigned irq_register; + struct msgobj_t *obj=chip->msgobj[0]; + + irq_register=can_read_reg(chip, SJAIR); +// DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register); +// DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n", +// can_read_reg(chip, SJASR)); + + 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); + + 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 +// 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;*/ + } + } + + return CANCHIP_IRQ_HANDLED; +} + +void sja1000_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj) +{ + int i=0, id=0, len; + + do { + id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8); + obj->rx_msg.length = len = id & 0x0f; + obj->rx_msg.flags = id&sjaID0_RTR ? MSG_RTR : 0; + obj->rx_msg.cob = 0; + obj->rx_msg.id = id>>5; + + if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; + for (i=0; irx_msg.data[i]=can_read_reg(chip, SJARXDAT0 + i); + + can_write_reg(chip, sjaCMR_RRB, SJACMR); + + /* fill CAN message timestamp */ + can_filltimestamp(&obj->rx_msg.timestamp); + + canque_filter_msg2edges(obj->qends, &obj->rx_msg); + } while(can_read_reg(chip, SJASR) & sjaSR_RBS); +} + +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); + } + /* Free transmitted slot */ + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + } + + cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot); + if(cmd<0) + return; + + if (chip->chipspecops->pre_write_config(chip, obj, &obj->tx_slot->msg)) { + obj->ret = -1; + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_PREP); + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + return; + } + if (chip->chipspecops->send_msg(chip, obj, &obj->tx_slot->msg)) { + obj->ret = -1; + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND); + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + return; + } +} + +/** + * sja1000_wakeup_tx: - wakeups TX processing + * @chip: pointer to chip state structure + * @obj: pointer to message object structure + * + * Return Value: negative value reports error. + * File: src/sja1000.c + */ +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; + } + + can_preempt_enable(); + return 0; +} + int sja1000_register(struct chipspecops_t *chipspecops) { chipspecops->chip_config = sja1000_chip_config; @@ -362,6 +480,7 @@ int sja1000_register(struct chipspecops_t *chipspecops) chipspecops->pre_write_config = sja1000_pre_write_config; chipspecops->send_msg = sja1000_send_msg; chipspecops->check_tx_stat = sja1000_check_tx_stat; + chipspecops->wakeup_tx=sja1000_wakeup_tx; chipspecops->remote_request = sja1000_remote_request; chipspecops->enable_configuration = sja1000_enable_configuration; chipspecops->disable_configuration = sja1000_disable_configuration; @@ -371,3 +490,12 @@ int sja1000_register(struct chipspecops_t *chipspecops) chipspecops->irq_handler = sja1000_irq_handler; return 0; } + +int sja1000_fill_chipspecops(struct canchip_t *chip) +{ + chip->chip_type="sja1000"; + chip->max_objects=1; + sja1000_register(chip->chipspecops); + return 0; +} +