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; ilength; 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; ilength; 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;
}