www.pudn.com > 422.rar > s16c554.c
/* s16c554.c * Linux serial-bus device driver. * Written by wang song yue--bupt email:wsy5228@sina.com * This software is released under the GPL-License. * Version 0.1 28 october 2005 */ #include#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) #define MODVERSIONS #endif #if defined (MODVERSIONS) #include #endif #include #include #include "../include/main.h" #include "../include/s16c554.h" int s16c554_enable_configuration(struct chip_t *chip) { int i=0; unsigned flags; //enable config buardrate!! disable_irq(chip->chip_irq); flags=serial_read_reg(chip,LCR); while ((!(flags & DLAB)) && (i<=10)) { serial_write_reg(chip,flags|DLAB,LCR); udelay(100); i++; flags=serial_read_reg(chip,LCR); } if (i>=10) { CANMSG("Reset error\n"); enable_irq(chip->chip_irq); return -ENODEV; } return 0; } int s16c554_disable_configuration(struct chip_t *chip) { int i=0; unsigned flags=0; disable_irq(chip->chip_irq); //disable config buardrate!!!!! flags=serial_read_reg(chip,LCR); while ( (flags & DLAB) && (i<=10) ) { serial_write_reg(chip,flags &(0x7f),LCR); udelay(100); i++; flags=serial_read_reg(chip,LCR); } if (i>=10) { CANMSG("Error leaving reset status\n"); return -ENODEV; } enable_irq(chip->chip_irq); return 0; } int s16c554_chip_config(struct chip_t *chip) { if (s16c554_enable_configuration(chip)) return -ENODEV; if (!baudrate) baudrate=9600; if (s16c554_baud_rate(chip,baudrate,chip->clock,0,75,0)) //config baudrate!!!!! return -ENODEV; s16c554_disable_configuration(chip); /* set the FCR register mode 0 clear the THR and RHR fifo enable fifo!! set in aim104.c*/ serial_write_reg(chip,chip->c554_fcr_reg,FCR); //oxc7 if (s16c554_standard_mask(chip,0x03, 0x0e)) //set the LCR and MCR register!! return -ENODEV; /* Enable hardware interrupts */ /* Set the IER register enable all intrupt set in aim104.c */ serial_write_reg(chip,chip->c554_ier_reg,IER); //0x0f s16c554_disable_configuration(chip); return 0; } int s16c554_standard_mask(struct chip_t *chip, unsigned short lcr, unsigned short mcr) { unsigned char write_lcr, write_mcr; if (s16c554_disable_configuration(chip)) //enable config mcr lcr return -ENODEV; write_lcr=(unsigned char)lcr; write_mcr=(unsigned char)mcr; //printk("write_code-code===0x%x\n",write_code); //printk("write_mask-mask===0x%x\n",write_mask); serial_write_reg(chip,write_lcr,LCR); serial_write_reg(chip,write_mcr,MCR); DEBUGMSG("Setting LCR register to 0x%lx\n",(unsigned long)lcr); DEBUGMSG("Setting MCR register to 0x%lx\n",(unsigned long)mcr); return 0; } /* Set communication parameters. * param rate baud rate in Hz * param clock frequency of s16c554 clock in Hz (ISA osc is 14318000) * param sjw synchronization jump width (0-3) prescaled clock cycles * 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 s16c554_baud_rate(struct chip_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 (s16c554_enable_configuration(chip)) return -ENODEV; clock /=2; /* tseg even = round down, odd = round up */ for (tseg=(0+0+2)*2; tseg<=(MAX_TSEG2+MAX_TSEG1+2)*2+1; tseg++) { brp = clock/((1+tseg/2)*rate)+tseg%2; if (brp == 0 || brp > 64) continue; error = rate - clock/(brp*(1+tseg/2)); if (error < 0) error = -error; if (error <= best_error) { best_error = error; best_tseg = tseg/2; best_brp = brp-1; best_rate = clock/(brp*(1+tseg/2)); } } // if (best_error && (rate/best_error < 10)) { // CANMSG("baud rate %d is not possible with %d Hz clock\n", // rate, 2*clock); // CANMSG("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n", // best_rate, best_brp, best_tseg, tseg1, tseg2); // return -EINVAL; // } tseg2 = best_tseg-(sampl_pt*(best_tseg+1))/100; if (tseg2 < 0) tseg2 = 0; if (tseg2 > MAX_TSEG2) tseg2 = MAX_TSEG2; tseg1 = best_tseg-tseg2-2; if (tseg1 > MAX_TSEG1) { tseg1 = MAX_TSEG1; tseg2 = best_tseg-tseg1-2; } DEBUGMSG("Setting %d bps.\n", rate); // DEBUGMSG("brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d, sampl_pt=%d\n", // best_brp, best_tseg, tseg1, tseg2, // (100*(best_tseg-tseg2)/(best_tseg+1))); serial_write_reg(chip, 0x00, MSB); //sjw<<6 | best_brp, //setbundata by wangsy serial_write_reg(chip, 0x0c, LSB); //((flags & BTR1_SAM) != 0)<<7 | tseg2<<4 | tseg1, /* BASIC mode, bypass input comparator */ s16c554_disable_configuration(chip); return 0; } int s16c554_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) { int i=0; struct canfifo_t *fifo = chip->msgobj[0]->fifo; // i=can_read_reg(chip,LSR); // if (!(i&(0x01))) { while (!((serial_read_reg(chip, LSR) & (0x01)) && (i<20))) { i++; udelay(i); if(i==20){ CANMSG("Receive time out ! There is no message to read!\n"); for (i=0; i<0x08; i++) CANMSG("0x%x is 0x%x\n",i,serial_read_reg(chip,i)); return 0;} } //while(!(serial_read_reg(chip,SJASR)&SR_RBS)) {printk("delay");} s16c554_start_chip(chip); // printk("qian sr===================0x%x\n",serial_read_reg(chip,LSR)); serial_write_reg(chip, 0x00, IER); // disable interrupts for a moment // TODO: this would be best s16c554_irq_read_handler(chip); // now just duplicate the code. i=0; do //while (serial_read_reg(chip, LSR) & (0x01)) { fifo->head=0; fifo->buf_rx_entry[fifo->head].data[i]=serial_read_reg(chip,RHR); //printk("\nfifo->buf_rx_entry[fifo->head].data[%d] =0x%x\n", i,fifo->buf_rx_entry[fifo->head].data[i]); i++; fifo->buf_rx_entry[fifo->head].length=i; //printk("length==================%d\n",fifo->buf_rx_entry[fifo->head].length); // i++; // fifo->head++; //if(fifo->head==63) // {fifo->head=0;} }while (serial_read_reg(chip, LSR) & (0x01));//&&(i<16)); // printk("hou sr===================0x%x\n",serial_read_reg(chip,SJASR)); // enable interrupts serial_write_reg(chip, 0x0f, IER); return 1; } #define MAX_TRANSMIT_WAIT_LOOPS 200 int s16c554_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, struct serialmsg_t *msg) { int i=0; s16c554_start_chip(chip); //s16c554 goes automatically into reset mode on errors /* Wait until Transmit Buffer Status is released */ while ( !(serial_read_reg(chip, LSR) & (0x20)) && i++ length===========%d\n",msg->length); for (i=0; i length; i++){ while(!(serial_read_reg(chip,LSR) & (0x20))){;} serial_write_reg(chip, msg->data[i], THR); //printk("msg->data[%d]=========%d\n",i,msg->data[i]); } //printk("i am in pre_write_config\n"); return 0; } int s16c554_send_msg(struct chip_t *chip, struct msgobj_t *obj, struct serialmsg_t *msg) { int i; for (i=0; i length; i++){ while(!(serial_read_reg(chip,LSR) & (0x20))){;} serial_write_reg(chip, msg->data[i], THR); udelay(100);} return 0; } int s16c554_check_tx_stat(struct chip_t *chip) { if (serial_read_reg(chip,ISR) &(0x01)) //check ISR=0x01 THR is empty; return 0; else return 1; } int s16c554_set_btregs(struct chip_t *chip, unsigned short lsb, unsigned short msb) { if (s16c554_enable_configuration(chip)) return -ENODEV; printk("s16c554_set_bregs lsb==0x%x,msb=0x%x\n",lsb,msb); serial_write_reg(chip, lsb, LSB); serial_write_reg(chip, msb, MSB); s16c554_disable_configuration(chip); return 0; } int s16c554_start_chip(struct chip_t *chip) { //unsigned short flags = 0; // printk("i am in s16c554_start_chip\n"); s16c554_disable_configuration(chip); return 0; } int s16c554_stop_chip(struct chip_t *chip) { //unsigned short flags = 0; serial_write_reg(chip, 0xc6, FCR); return 0; } int s16c554_remote_request(struct chip_t *chip, struct msgobj_t *obj) { CANMSG("s16c554_remote_request not implemented\n"); return -ENOSYS; } int s16c554_extended_mask(struct chip_t *chip, unsigned long code, unsigned long mask) { CANMSG("s16c554_extended_mask not implemented\n"); return -ENOSYS; } int s16c554_clear_objects(struct chip_t *chip) { CANMSG("s16c554_clear_objects not implemented\n"); return -ENOSYS; } int s16c554_config_irqs(struct chip_t *chip, short irqs) { CANMSG("s16c554_config_irqs not implemented\n"); return -ENOSYS; } int s16c554_register(struct chipspecops_t *chipspecops) { chipspecops->chip_config = s16c554_chip_config; chipspecops->baud_rate = s16c554_baud_rate; chipspecops->standard_mask = s16c554_standard_mask; chipspecops->extended_mask = s16c554_extended_mask; chipspecops->message15_mask = s16c554_extended_mask; chipspecops->clear_objects = s16c554_clear_objects; chipspecops->config_irqs = s16c554_config_irqs; chipspecops->pre_read_config = s16c554_pre_read_config; chipspecops->pre_write_config = s16c554_pre_write_config; chipspecops->send_msg = s16c554_send_msg; chipspecops->check_tx_stat = s16c554_check_tx_stat; chipspecops->remote_request = s16c554_remote_request; chipspecops->enable_configuration = s16c554_enable_configuration; chipspecops->disable_configuration = s16c554_disable_configuration; chipspecops->set_btregs = s16c554_set_btregs; chipspecops->start_chip = s16c554_start_chip; chipspecops->stop_chip = s16c554_stop_chip; chipspecops->irq_handler = s16c554_irq_handler; return 0; }