[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: I need to configure serial port to send 5 bit characters



Support for flexible baudrates was added to our elinux tree about a year ago
to test some bluetooth devices but it hasn't found it's way to the 2.4 tree 
yet.
I have attached the diff in that driver - it will most likely not apply to 
the 2.4 version but you might want to use it/look at it anyway.

/Johan


On Friday 04 October 2002 16.12, Per Zander wrote:
> The ETRAX 100LX supports baud rates down to 48 baud, but the
> 'standard baud rates' only range down to 300 baud. If you want
> to go lower, you need to use another internal baud rate generator.
> It seems like the linux driver doesn't have support for that.
>
> Note! The old ETRAX 100 doesn't support baud rates below 300 baud.
> The possibility to have lower baud rates was added in ETRAX 100LX.
>
> See ETRAX 100LX designer's reference chapter 12.5 for more information.
>
> Per Zander
>
> On Fri, 4 Oct 2002, Henry Minsky wrote:
> > OK, this trick worked for sending characters, however I have another
> > problem which
> > is that the B75 baud rate (75 baud) does not seem to work.
> >
> > I am using cfsetospeed with B75 but the baud still seems to be 9600
> > coming out of
> > the serial port.
> >
> > Is 75 baud not supported by the UART? Is there a way to manually set the
> > baud rate
> > divisor from a user program?
> >
> > Thanks,
> >          Henry
> >
> > At 09:27 AM 10/4/2002 +0200, gerhard@xxxxxxx.at wrote:
> > >Hello,
> > >
> > >even when the hardware does not support 5 bits (and that's a fact) you
> > > can send
> > >5 bit characters using a simple trick:
> > >
> > >1. Configure the serial port for 8 data bits
> > >2. Take your character and shift it left by 3
> > >3. Set the 3 lowest bits to 1
> > >4. Send it out
> > >
> > >This should basically work, but you have o live with some limitations.
> > >
> > >- Between two characters you have now 3 more stop bits, this means that
> > > you cannot send at the full data rate
> > >- This works only on transmitting. When you want that receiving works
> > > the same
> > >way you must ensure that the opposite system inserts also some pause
> > > time between two characters, and you have to mask off the "unused stop
> > > bits".
> > >
> > >Hope this may work for you,
> > >Gerhard
Index: etrax100ser.c
===================================================================
RCS file: /usr/local/cvs/cvsroot/os/elinux/drivers/char/etrax100ser.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -p -r1.65 -r1.66
--- etrax100ser.c	24 Sep 2001 09:26:08 -0000	1.65
+++ etrax100ser.c	3 Oct 2001 13:03:23 -0000	1.66
@@ -1,10 +1,17 @@
-/* $Id: etrax100ser.c,v 1.65 2001/09/24 09:26:08 pkj Exp $
+/* $Id: etrax100ser.c,v 1.66 2001/10/03 13:03:23 johana Exp $
  *
  * etrax100ser.c: Serial port driver for the Etrax100 
  *
  *      Copyright (C) 1998, 1999, 2000  Axis Communications AB
  *
  * $Log: etrax100ser.c,v $
+ * Revision 1.66  2001/10/03 13:03:23  johana
+ * R_DMA_CHx_STATUS is now a byte*.
+ * Added baud_base and custom_divisor and support for flexible baudrate
+ * settings using either the prescaler or an external baudrate
+ * (if configured).
+ * The flexible baudrate only works with ETRAX100LX.
+ *
  * Revision 1.65  2001/09/24 09:26:08  pkj
  * Completed ext_baud_table[] in cflag_to_baud() and cflag_to_etrax_baud().
  *
@@ -303,6 +310,14 @@ static int serial_refcount;
 
 #define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10)
 
+
+#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */
+#ifdef CONFIG_ETRAX100LX
+#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE
+#else
+#define DEF_BAUD_BASE 0
+#endif
+
 #ifdef DEBUG_LOG_INCLUDED
 /* The proc file can only currently hold one page, 
  * no use having the log bigger then we can print
@@ -969,8 +984,13 @@ e100_disable_dmaconfig(struct e100_seria
 		case 1:
 		genconfig_shadow &= ~(IO_MASK(R_GEN_CONFIG,dma9) | 
 		                      IO_MASK(R_GEN_CONFIG,dma8));
+#ifdef CONFIG_ETRAX100LX
+		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb) |
+		                    IO_STATE(R_GEN_CONFIG, dma8, usb);
+#else
 		genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, unused) |
 		                    IO_STATE(R_GEN_CONFIG, dma8, unused);
+#endif /* CONFIG_ETRAX100LX */
 		break;
 		case 2:
 		genconfig_shadow &= ~(IO_MASK(R_GEN_CONFIG,dma3) | 
@@ -2441,6 +2461,7 @@ static void 
 change_speed(struct e100_serial *info)
 {
 	unsigned int cflag;
+	int error = 0;
 
 	/* first some safety checks */
 	
@@ -2454,11 +2475,73 @@ change_speed(struct e100_serial *info)
 	/* possibly, the tx/rx should be disabled first to do this safely */
 	
 	/* change baud-rate and write it to the hardware */
-	
-	info->baud = cflag_to_baud(cflag);
-	
+#ifdef CONFIG_ETRAX100LX
+	if ((info->flags & S_SPD_MASK) == S_SPD_CUST){
+		/* Special baudrate (LX only) */
+		u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+		unsigned long alt_source = 
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec,normal)| 
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr,normal);
+		/* R_ALT_SER_BAUDRATE selects the source */
+		printk("Custom baudrate: divisor %i\n", info->custom_divisor);
+		if (info->baud_base == SERIAL_PRESCALE_BASE){
+			/* 0, 2-65535 (0=65536) */
+			u16 divisor = info->custom_divisor;
+			/* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */
+			/* baudrate is 3.125MHz/custom_divisor */
+			alt_source = 
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec,prescale)| 
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr,prescale);
+			alt_source = 0x11;
+			printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor);
+			*R_SERIAL_PRESCALE = divisor;
+		}
+#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
+		else if (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8){
+			if (info->custom_divisor == 1){
+				/* ext_clk selected */
+				alt_source = 
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec,extern)| 
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr,extern);
+				printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8);
+			}
+		}
+#endif
+		else
+		{
+			/* Bad baudbase, we don't support using timer0
+			 * for baudrate.
+			 */
+			printk("Bad baud_base: %lu\n", info->baud_base);
+		}
+		r_alt_ser_baudrate_shadow &= ~mask;
+		r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+		*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+		info->baud = info->baud_base/info->custom_divisor;
+	}
+	else
+#endif /* CONFIG_ETRAX100LX */
+	{
+		/* Normal baudrate */
+#ifdef CONFIG_ETRAX100LX
+		/* Make sure we use normal baudrate */
+		u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+		unsigned long alt_source = 
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec,normal)| 
+				IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr,normal);
+		r_alt_ser_baudrate_shadow &= ~mask;
+		r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+#ifndef CONFIG_SVINTO_SIM
+		*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+#endif /* CONFIG_SVINTO_SIM */ 
+#endif /* CONFIG_ETRAX100LX */
+
+		info->baud = cflag_to_baud(cflag);
+#ifndef CONFIG_SVINTO_SIM
+		info->port[REG_BAUD] = cflag_to_etrax_baud(cflag);
+#endif /* CONFIG_SVINTO_SIM */
+	}
 #ifndef CONFIG_SVINTO_SIM
-	info->port[REG_BAUD] = cflag_to_etrax_baud(cflag);
 	/* start with default settings and then fill in changes */
 	
 	info->rx_ctrl &= ~(0x0F); /* 8 bit, normal/even/no parity */
@@ -2731,10 +2814,10 @@ get_serial_info(struct e100_serial * inf
 	tmp.port = (int)info->port;
 	tmp.irq = info->irq;
 	tmp.flags = info->flags;
-	tmp.baud_base = 0; /* FIXME should return a Bxxxx ? */
+	tmp.baud_base = info->baud_base; 
 	tmp.close_delay = info->close_delay;
 	tmp.closing_wait = info->closing_wait;
-	tmp.custom_divisor = 0;
+	tmp.custom_divisor = info->custom_divisor;
 	memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
 	return 0;
 }
@@ -2760,6 +2843,7 @@ set_serial_info(struct e100_serial * inf
 			return -EPERM;
 		info->flags = ((info->flags & ~S_USR_MASK) |
 			       (new_serial.flags & S_USR_MASK));
+		info->custom_divisor = new_serial.custom_divisor;
 		goto check_and_exit;
 	}
 
@@ -2771,8 +2855,10 @@ set_serial_info(struct e100_serial * inf
 	 * At this point, we start making changes.....
 	 */
 
+	info->baud_base = new_serial.baud_base;
 	info->flags = ((info->flags & ~S_FLAGS) |
 		       (new_serial.flags & S_FLAGS));
+	info->custom_divisor = new_serial.custom_divisor;
 	info->type = new_serial.type;
 	info->close_delay = new_serial.close_delay;
 	info->closing_wait = new_serial.closing_wait;
@@ -3596,6 +3682,12 @@ rs_e100_init(void)
 	callout_driver.name = "cua";
 	callout_driver.major = TTYAUX_MAJOR;
 	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
+	/* Only works in ETRAX100LX */
+	genconfig_ii_shadow |= IO_STATE (R_GEN_CONFIG_II, ext_clk, select);
+	*R_GEN_CONFIG_II = genconfig_ii_shadow;
+#endif /* CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED */
   
 	if (tty_register_driver(&serial_driver))
 		panic("Couldn't register serial driver\n");
@@ -3611,6 +3703,8 @@ rs_e100_init(void)
 		info->tr_running = 0;
 		info->fifo_magic = 0;
 		info->fifo_didmagic = 0;
+		info->baud_base = DEF_BAUD_BASE;
+		info->custom_divisor = 0;
 		info->flags = 0;
 		info->close_delay = 50;
 		info->closing_wait = 3000;