public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Patch for supporting CPR register in 16C950 UART
@ 2001-05-18 16:14 fabrizio.gennari
  0 siblings, 0 replies; only message in thread
From: fabrizio.gennari @ 2001-05-18 16:14 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: MEMO 05/18/01 18:00:46 --]
[-- Type: text/plain, Size: 909 bytes --]

Hello.

Here is a patch (tested on kernels 2.4.3 and 2.4.4) that adds 2 ioctl's in serial.c. One, TCSSERCPR, sets the CPR register in 16C950 UARTs. This register is a pre-scaler (that is, a divisor) for the clock. If the value is N, the clock is divided by N/8. 
If N<8, pre-scaling is disabled by setting bit 7 of MCR to 0. The other one, TCGSERCPR,, reads the value of CPR. If pre-scaling is disabled, it returns 8 (i.e., the clock frequency is left intact).

The patch also disables resetting the UART via the CSR register every time the serial device is opened (in the startup() function). This would reset the content of CPR.
---------------------------------------------------------
Fabrizio Gennari          tel. +39 039 203 7816
Philips Research Monza    fax. +39 039 203 7800
via G. Casati 23          fabrizio.gennari@philips.com
20052 Monza (MI) Italy    http://www.research.philips.com

[-- Attachment #2: serial-patch --]
[-- Type: application/octet-stream, Size: 3666 bytes --]

diff -ruN linux-2.4.3/drivers/char/serial.c linux-2.4.3-patched/drivers/char/serial.c
--- linux-2.4.3/drivers/char/serial.c	Wed Mar  7 05:13:51 2001
+++ linux-2.4.3-patched/drivers/char/serial.c	Fri May 18 16:28:30 2001
@@ -1259,7 +1259,7 @@
 		serial_outp(info, UART_EFR, UART_EFR_ECB);
 		serial_outp(info, UART_IER, 0);
 		serial_outp(info, UART_LCR, 0);
-		serial_icr_write(info, UART_CSR, 0); /* Reset the UART */
+		/*		serial_icr_write(info, UART_CSR, 0); */ /* Reset the UART */
 		serial_outp(info, UART_LCR, 0xBF);
 		serial_outp(info, UART_EFR, UART_EFR_ECB);
 		serial_outp(info, UART_LCR, 0);
@@ -1364,9 +1364,12 @@
 	 */
 	serial_outp(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
 
-	info->MCR = 0;
+	if (state->type == PORT_16C950)
+		info->MCR &= UART_MCR_PRESCALER;
+	else
+		info->MCR = 0;
 	if (info->tty->termios->c_cflag & CBAUD)
-		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+		info->MCR |= UART_MCR_DTR | UART_MCR_RTS;
 #ifdef CONFIG_SERIAL_MANY_PORTS
 	if (info->flags & ASYNC_FOURPORT) {
 		if (state->irq == 0)
@@ -2514,6 +2517,41 @@
 }
 #endif
 
+static int get_clock_prescaler(struct async_struct * info, unsigned char *value)
+{
+	unsigned char cpr;
+
+	if (!(serial_in(info, UART_MCR) & UART_MCR_PRESCALER))
+		cpr = 8;
+	else
+		cpr = serial_icr_read(info, UART_CPR);
+
+	if (copy_to_user(value,&cpr,sizeof(unsigned char)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int set_clock_prescaler(struct async_struct * info, unsigned char *value)
+{
+	unsigned char cpr;
+	
+	if (copy_from_user(&cpr,value,sizeof(unsigned char)))
+		return -EFAULT;
+
+	if (cpr < 8){
+		info->MCR &= ~UART_MCR_PRESCALER;
+	}
+	else{
+		info->MCR |= UART_MCR_PRESCALER;
+	}
+	
+	serial_out(info, UART_MCR, info->MCR);
+	serial_icr_write(info, UART_CPR, cpr);
+
+	return 0;
+}
+
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
@@ -2668,6 +2706,14 @@
 			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
 				return -EFAULT;
 			return 0;
+		case TIOCGSERCPR: /* Get serial clock prescaler */
+			if (info->state->type == PORT_16C950)
+				return get_clock_prescaler(info, (unsigned char *) arg);
+			return -ENXIO;
+		case TIOCSSERCPR: /* Set serial clock prescaler */
+			if (info->state->type == PORT_16C950)
+				return set_clock_prescaler(info, (unsigned char *) arg);
+			return -ENXIO;
 		case TIOCSERGWILD:
 		case TIOCSERSWILD:
 			/* "setserial -W" is called in Debian boot */
diff -ruN linux-2.4.3/include/asm-i386/ioctls.h linux-2.4.3-patched/include/asm-i386/ioctls.h
--- linux-2.4.3/include/asm-i386/ioctls.h	Fri Jul 24 20:10:16 1998
+++ linux-2.4.3-patched/include/asm-i386/ioctls.h	Thu May 17 16:34:08 2001
@@ -67,6 +67,8 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define TIOCGSERCPR   0x5460  /* Get serial clock prescaler*/
+#define TIOCSSERCPR   0x5461  /* Set serial clock prescaler*/
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -ruN linux-2.4.3/include/linux/serial_reg.h linux-2.4.3-patched/include/linux/serial_reg.h
--- linux-2.4.3/include/linux/serial_reg.h	Wed Mar  7 04:28:35 2001
+++ linux-2.4.3-patched/include/linux/serial_reg.h	Thu May 17 16:23:32 2001
@@ -121,6 +121,7 @@
 /*
  * These are the definitions for the Modem Control Register
  */
+#define UART_MCR_PRESCALER	0x80	/* Enable clock prescaler */
 #define UART_MCR_LOOP	0x10	/* Enable loopback test mode */
 #define UART_MCR_OUT2	0x08	/* Out2 complement */
 #define UART_MCR_OUT1	0x04	/* Out1 complement */

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2001-05-18 16:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2001-05-18 16:14 Patch for supporting CPR register in 16C950 UART fabrizio.gennari

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox