msm_serial: Make baud_code detection more dynamic
authorStephen Boyd <sboyd@codeaurora.org>
Wed, 24 Jul 2013 18:37:30 +0000 (11:37 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 26 Jul 2013 23:13:29 +0000 (16:13 -0700)
Currently msm_set_baud_rate() assumes the uart clock rate is
1.8432 MHz. This is not always true, and limits our options to
program the baud rate. Instead of assuming the rate and
hard-coding the baud_code based on it, calculate the divider that
we want and try to find the closest baud_code that matches. This
allows us to support uarts with faster clock speeds.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Acked-by: David Brown <davidb@codeaurora.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/msm_serial.c
drivers/tty/serial/msm_serial.h

index 4184c5164ab424b097ef91a1709dfc05f7632d40..ca2ae65811491d3b399b38b3b22c29e93cf41f7f 100644 (file)
@@ -322,70 +322,60 @@ static void msm_break_ctl(struct uart_port *port, int break_ctl)
                msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
 }
 
+struct msm_baud_map {
+       u16     divisor;
+       u8      code;
+       u8      rxstale;
+};
+
+static const struct msm_baud_map *
+msm_find_best_baud(struct uart_port *port, unsigned int baud)
+{
+       unsigned int i, divisor;
+       const struct msm_baud_map *entry;
+       static const struct msm_baud_map table[] = {
+               { 1536, 0x00,  1 },
+               {  768, 0x11,  1 },
+               {  384, 0x22,  1 },
+               {  192, 0x33,  1 },
+               {   96, 0x44,  1 },
+               {   48, 0x55,  1 },
+               {   32, 0x66,  1 },
+               {   24, 0x77,  1 },
+               {   16, 0x88,  1 },
+               {   12, 0x99,  6 },
+               {    8, 0xaa,  6 },
+               {    6, 0xbb,  6 },
+               {    4, 0xcc,  6 },
+               {    3, 0xdd,  8 },
+               {    2, 0xee, 16 },
+               {    1, 0xff, 31 },
+       };
+
+       divisor = uart_get_divisor(port, baud);
+
+       for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++)
+               if (entry->divisor <= divisor)
+                       break;
+
+       return entry; /* Default to smallest divider */
+}
+
 static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
 {
-       unsigned int baud_code, rxstale, watermark;
+       unsigned int rxstale, watermark;
        struct msm_port *msm_port = UART_TO_MSM(port);
+       const struct msm_baud_map *entry;
 
-       switch (baud) {
-       case 300:
-               baud_code = UART_CSR_300;
-               rxstale = 1;
-               break;
-       case 600:
-               baud_code = UART_CSR_600;
-               rxstale = 1;
-               break;
-       case 1200:
-               baud_code = UART_CSR_1200;
-               rxstale = 1;
-               break;
-       case 2400:
-               baud_code = UART_CSR_2400;
-               rxstale = 1;
-               break;
-       case 4800:
-               baud_code = UART_CSR_4800;
-               rxstale = 1;
-               break;
-       case 9600:
-               baud_code = UART_CSR_9600;
-               rxstale = 2;
-               break;
-       case 14400:
-               baud_code = UART_CSR_14400;
-               rxstale = 3;
-               break;
-       case 19200:
-               baud_code = UART_CSR_19200;
-               rxstale = 4;
-               break;
-       case 28800:
-               baud_code = UART_CSR_28800;
-               rxstale = 6;
-               break;
-       case 38400:
-               baud_code = UART_CSR_38400;
-               rxstale = 8;
-               break;
-       case 57600:
-               baud_code = UART_CSR_57600;
-               rxstale = 16;
-               break;
-       case 115200:
-       default:
-               baud_code = UART_CSR_115200;
-               baud = 115200;
-               rxstale = 31;
-               break;
-       }
+       entry = msm_find_best_baud(port, baud);
 
        if (msm_port->is_uartdm)
                msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
 
-       msm_write(port, baud_code, UART_CSR);
+       msm_write(port, entry->code, UART_CSR);
 
        /* RX stale watermark */
+       rxstale = entry->rxstale;
        watermark = UART_IPR_STALE_LSB & rxstale;
        watermark |= UART_IPR_RXSTALE_LAST;
        watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
index 15c186ecbd9e127ceea9a3e43517d3f125f301ad..469fda50ac63e9a4e832626239ec11786192fbb7 100644 (file)
 #define UART_MR2_PARITY_MODE_SPACE     0x3
 #define UART_MR2_PARITY_MODE           0x3
 
-#define UART_CSR       0x0008
-#define UART_CSR_115200        0xFF
-#define UART_CSR_57600 0xEE
-#define UART_CSR_38400 0xDD
-#define UART_CSR_28800 0xCC
-#define UART_CSR_19200 0xBB
-#define UART_CSR_14400 0xAA
-#define UART_CSR_9600  0x99
-#define UART_CSR_4800  0x77
-#define UART_CSR_2400  0x55
-#define UART_CSR_1200  0x44
-#define UART_CSR_600   0x33
-#define UART_CSR_300   0x22
+#define UART_CSR                       0x0008
 
 #define UART_TF                0x000C
 #define UARTDM_TF      0x0070
@@ -152,6 +140,7 @@ static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
        msm_write(port, 0xF1, UART_NREG);
        msm_write(port, 0x0F, UART_DREG);
        msm_write(port, 0x1A, UART_MNDREG);
+       port->uartclk = 1843200;
 }
 
 /*
@@ -163,6 +152,7 @@ static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
        msm_write(port, 0xF6, UART_NREG);
        msm_write(port, 0x0F, UART_DREG);
        msm_write(port, 0x0A, UART_MNDREG);
+       port->uartclk = 1843200;
 }
 
 static inline
@@ -170,7 +160,7 @@ void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
 {
        if (port->uartclk == 19200000)
                msm_serial_set_mnd_regs_tcxo(port);
-       else
+       else if (port->uartclk == 4800000)
                msm_serial_set_mnd_regs_tcxoby4(port);
 }