From 1e664d4740009ac49c2a2f85ffc994c12ee040bd Mon Sep 17 00:00:00 2001 From: merge Date: Wed, 3 Dec 2008 11:20:14 +0000 Subject: MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-MERGE-via-master-1228302402-1228302766-1228303138 pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-MERGE-via-master-1228302402-1228302766-1228303138 / 27d86638fe294ef1d1a8f527564ec37bb20e7ef2 ... parent commitmessage: From: merge MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-MERGE-via-master-1228302402-1228302766 stable-tracking-hist top was MERGE-via-mokopatches-tracking-MERGE-via-master-1228302402-1228302766 / 66e84c4be853030f1cea816a124cf76a741ecc08 ... parent commitmessage: From: merge MERGE-via-mokopatches-tracking-hist-MERGE-via-master-1228302402 mokopatches-tracking-hist top was MERGE-via-master-1228302402 / de9177f7bd127e9b6fa6213018c7c731b8ca0d0c ... parent commitmessage: From: merge MERGE-via-master- master top was / 3838a80929f91d35c6d987e518bf9ea397f3e13c ... parent commitmessage: From: Andy Green fix-wm8753-DBG.patch Signed-off-by: Andy Green --- drivers/serial/s3c6400.c | 1 + drivers/serial/samsung.c | 62 +++++++++++++++++++++++++++++++++++++++++++++--- drivers/serial/samsung.h | 4 ++++ 3 files changed, 64 insertions(+), 3 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c index 06936d13393..3e378523368 100644 --- a/drivers/serial/s3c6400.c +++ b/drivers/serial/s3c6400.c @@ -102,6 +102,7 @@ static struct s3c24xx_uart_info s3c6400_uart_inf = { .name = "Samsung S3C6400 UART", .type = PORT_S3C6400, .fifosize = 64, + .has_divslot = 1, .rx_fifomask = S3C2440_UFSTAT_RXMASK, .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, .rx_fifofull = S3C2440_UFSTAT_RXFULL, diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index c262eb1ae20..eca6cab0e20 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c @@ -512,6 +512,7 @@ s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c) struct baud_calc { struct s3c24xx_uart_clksrc *clksrc; unsigned int calc; + unsigned int divslot; unsigned int quot; struct clk *src; }; @@ -521,6 +522,7 @@ static int s3c24xx_serial_calcbaud(struct baud_calc *calc, struct s3c24xx_uart_clksrc *clksrc, unsigned int baud) { + struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned long rate; calc->src = clk_get(port->dev, clksrc->name); @@ -531,8 +533,24 @@ static int s3c24xx_serial_calcbaud(struct baud_calc *calc, rate /= clksrc->divisor; calc->clksrc = clksrc; - calc->quot = (rate + (8 * baud)) / (16 * baud); - calc->calc = (rate / (calc->quot * 16)); + + if (ourport->info->has_divslot) { + unsigned long div = rate / baud; + + /* The UDIVSLOT register on the newer UARTs allows us to + * get a divisor adjustment of 1/16th on the baud clock. + * + * We don't keep the UDIVSLOT value (the 16ths we calculated + * by not multiplying the baud by 16) as it is easy enough + * to recalculate. + */ + + calc->quot = div / 16; + calc->calc = rate / div; + } else { + calc->quot = (rate + (8 * baud)) / (16 * baud); + calc->calc = (rate / (calc->quot * 16)); + } calc->quot--; return 1; @@ -615,6 +633,30 @@ static unsigned int s3c24xx_serial_getclk(struct uart_port *port, return best->quot; } +/* udivslot_table[] + * + * This table takes the fractional value of the baud divisor and gives + * the recommended setting for the UDIVSLOT register. + */ +static u16 udivslot_table[16] = { + [0] = 0x0000, + [1] = 0x0080, + [2] = 0x0808, + [3] = 0x0888, + [4] = 0x2222, + [5] = 0x4924, + [6] = 0x4A52, + [7] = 0x54AA, + [8] = 0x5555, + [9] = 0xD555, + [10] = 0xD5D5, + [11] = 0xDDD5, + [12] = 0xDDDD, + [13] = 0xDFDD, + [14] = 0xDFDF, + [15] = 0xFFDF, +}; + static void s3c24xx_serial_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -627,6 +669,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, unsigned int baud, quot; unsigned int ulcon; unsigned int umcon; + unsigned int udivslot = 0; /* * We don't support modem control lines. @@ -648,6 +691,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, /* check to see if we need to change clock source */ if (ourport->clksrc != clksrc || ourport->baudclk != clk) { + dbg("selecting clock %p\n", clk); s3c24xx_serial_setsource(port, clksrc); if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { @@ -655,6 +699,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, ourport->baudclk = NULL; } + //dbg("calling clk_enable() for new baud clock\n"); clk_enable(clk); ourport->clksrc = clksrc; @@ -662,6 +707,13 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; } + if (ourport->info->has_divslot) { + unsigned int div = ourport->baudclk_rate / baud; + + udivslot = udivslot_table[div & 15]; + dbg("udivslot = %04x (div %d)\n", udivslot, div & 15); + } + switch (termios->c_cflag & CSIZE) { case CS5: dbg("config: 5bits/char\n"); @@ -701,12 +753,16 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, spin_lock_irqsave(&port->lock, flags); - dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot); + dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n", + ulcon, quot, udivslot); wr_regl(port, S3C2410_ULCON, ulcon); wr_regl(port, S3C2410_UBRDIV, quot); wr_regl(port, S3C2410_UMCON, umcon); + if (ourport->info->has_divslot) + wr_regl(port, S3C2443_DIVSLOT, udivslot); + dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", rd_regl(port, S3C2410_ULCON), rd_regl(port, S3C2410_UCON), diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h index 9675b2fa267..f259211279f 100644 --- a/drivers/serial/samsung.h +++ b/drivers/serial/samsung.h @@ -23,6 +23,10 @@ struct s3c24xx_uart_info { unsigned long tx_fifoshift; unsigned long tx_fifofull; + /* uart port features */ + + unsigned int has_divslot:1; + /* clock source control */ int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk); -- cgit v1.2.3