2722168ada
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@3595 311d38ba-8fff-0310-9ca6-ca027cbcb966
156 lines
5.1 KiB
Diff
156 lines
5.1 KiB
Diff
|
|
From: Petr Vandrovec <vandrove@vc.cvut.cz>
|
|
|
|
Patch below adds support for using different prescaler than 16 for 16c950
|
|
chips. This is needed for using Fujitsu-Siemens Connect2Air compact-flash
|
|
card, which comes (apparently) with 806kHz clocks, and so you have to
|
|
program prescaler for division by 7, and DLAB to 1, to get 115200Bd.
|
|
|
|
To get card properly running you also have to add lines below to
|
|
/etc/pcmcia/serial.opts so kernel knows that base speed is not 115200 but
|
|
50400 (50400 * 16 = 806400; 806400 / 7 = 115200). As I've found no code
|
|
specifying baud_rate in serial_cs, I assume that specifying it in
|
|
serial.opts is right way to do this type of things.
|
|
|
|
Patch also fixes problem that for UPF_MAGIC_MULTIPLIER maximum possible
|
|
baud rate passed to uart code was uartclk / 16 while correct value for
|
|
these devices (and for 16c950) is uartclk / 4.
|
|
|
|
Patch also fixes problem that for UPF_MAGIC_MULTIPLIER devices with
|
|
baud_rate 19200 or 9600 spd_cust did not work correctly. Not that such
|
|
devices exist, but we should not ignore spd_cust, user probably knows why
|
|
he asked for spd_cust.
|
|
|
|
serial.opts:
|
|
|
|
case "$MANFID-$FUNCID-$PRODID_1-$PRODID_2-$PRODID_3-$PRODID_4" in
|
|
'0279,950b-2-GPRS Modem---')
|
|
SERIAL_OPTS="baud_base 50400"
|
|
;;
|
|
esac
|
|
|
|
Cc: David Woodhouse <dwmw2@infradead.org>
|
|
Signed-off-by: Andrew Morton <akpm@osdl.org>
|
|
---
|
|
|
|
drivers/serial/8250.c | 82 +++++++++++++++++++++++++++++++++++++++-----------
|
|
1 file changed, 64 insertions(+), 18 deletions(-)
|
|
|
|
Index: linux-2.6.21/drivers/serial/8250.c
|
|
===================================================================
|
|
--- linux-2.6.21.orig/drivers/serial/8250.c 2007-07-01 16:59:52.000000000 +0100
|
|
+++ linux-2.6.21/drivers/serial/8250.c 2007-07-01 17:01:21.000000000 +0100
|
|
@@ -1964,24 +1964,58 @@ static void serial8250_shutdown(struct u
|
|
serial_unlink_irq_chain(up);
|
|
}
|
|
|
|
-static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
|
|
+static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud,
|
|
+ unsigned int *prescaler)
|
|
{
|
|
- unsigned int quot;
|
|
-
|
|
- /*
|
|
- * Handle magic divisors for baud rates above baud_base on
|
|
- * SMSC SuperIO chips.
|
|
+ /*
|
|
+ * Use special handling only if user did not supply its own divider.
|
|
+ * spd_cust is defined in terms of baud_base, so always use default
|
|
+ * prescaler when spd_cust is requested.
|
|
*/
|
|
- if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
|
|
- baud == (port->uartclk/4))
|
|
- quot = 0x8001;
|
|
- else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
|
|
- baud == (port->uartclk/8))
|
|
- quot = 0x8002;
|
|
- else
|
|
- quot = uart_get_divisor(port, baud);
|
|
|
|
- return quot;
|
|
+ *prescaler = 16;
|
|
+ if (baud != 38400 || (port->flags & UPF_SPD_MASK) != UPF_SPD_CUST) {
|
|
+ unsigned int quot = port->uartclk / baud;
|
|
+
|
|
+ /*
|
|
+ * Handle magic divisors for baud rates above baud_base on
|
|
+ * SMSC SuperIO chips.
|
|
+ */
|
|
+ if (port->flags & UPF_MAGIC_MULTIPLIER) {
|
|
+ if (quot == 4) {
|
|
+ return 0x8001;
|
|
+ } else if (quot == 8) {
|
|
+ return 0x8002;
|
|
+ }
|
|
+ }
|
|
+ if (port->type == PORT_16C950) {
|
|
+ /*
|
|
+ * This computes TCR value (4 to 16), not CPR value (which can
|
|
+ * be between 1.000 and 31.875) - chip I have uses XTAL of
|
|
+ * 806400Hz, and so a division by 7 is required to get 115200Bd.
|
|
+ * I'm leaving CPR disabled for now, until someone will
|
|
+ * hit even more exotic XTAL (it is needed to get 500kbps
|
|
+ * or 1000kbps from 18.432MHz XTAL, but I have no device
|
|
+ * which would benefit from doing that).
|
|
+ *
|
|
+ * If we can use divide by 16, use it. Otherwise look for
|
|
+ * better prescaler, from 15 to 4. If quotient cannot
|
|
+ * be divided by any integer value between 4 and 15, use 4.
|
|
+ */
|
|
+ if (quot & 0x0F) {
|
|
+ unsigned int div;
|
|
+
|
|
+ for (div = 15; div > 4; div--) {
|
|
+ if (quot % div == 0) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ *prescaler = div;
|
|
+ return quot / div;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return uart_get_divisor(port, baud);
|
|
}
|
|
|
|
static void
|
|
@@ -1991,7 +2025,7 @@ serial8250_set_termios(struct uart_port
|
|
struct uart_8250_port *up = (struct uart_8250_port *)port;
|
|
unsigned char cval, fcr = 0;
|
|
unsigned long flags;
|
|
- unsigned int baud, quot;
|
|
+ unsigned int baud, quot, prescaler;
|
|
|
|
switch (termios->c_cflag & CSIZE) {
|
|
case CS5:
|
|
@@ -2023,8 +2057,13 @@ serial8250_set_termios(struct uart_port
|
|
/*
|
|
* Ask the core to calculate the divisor for us.
|
|
*/
|
|
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
|
|
- quot = serial8250_get_divisor(port, baud);
|
|
+ if (port->type == PORT_16C950 || (port->flags & UPF_MAGIC_MULTIPLIER)) {
|
|
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/4);
|
|
+ } else {
|
|
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
|
|
+ }
|
|
+ quot = serial8250_get_divisor(port, baud, &prescaler);
|
|
+
|
|
|
|
/*
|
|
* Oxford Semi 952 rev B workaround
|
|
@@ -2139,6 +2178,13 @@ serial8250_set_termios(struct uart_port
|
|
serial_dl_write(up, quot);
|
|
|
|
/*
|
|
+ * Program prescaler for 16C950 chips.
|
|
+ */
|
|
+ if (up->port.type == PORT_16C950) {
|
|
+ serial_icr_write(up, UART_TCR, prescaler == 16 ? 0 : prescaler);
|
|
+ }
|
|
+
|
|
+ /*
|
|
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
|
|
* is written without DLAB set, this mode will be disabled.
|
|
*/
|