ar71xx: build image for the TL-MR3220 v2
[openwrt.git] / target / linux / ar71xx / patches-3.6 / 211-ar933x_uart-improve-serial-clock-calculation.patch
1 --- a/drivers/tty/serial/ar933x_uart.c
2 +++ b/drivers/tty/serial/ar933x_uart.c
3 @@ -25,11 +25,19 @@
4  #include <linux/io.h>
5  #include <linux/irq.h>
6  
7 +#include <asm/div64.h>
8 +
9  #include <asm/mach-ath79/ar933x_uart.h>
10  #include <asm/mach-ath79/ar933x_uart_platform.h>
11  
12  #define DRIVER_NAME "ar933x-uart"
13  
14 +#define AR933X_UART_MAX_SCALE  0xff
15 +#define AR933X_UART_MAX_STEP   0xffff
16 +
17 +#define AR933X_UART_MIN_BAUD   300
18 +#define AR933X_UART_MAX_BAUD   3000000
19 +
20  #define AR933X_DUMMY_STATUS_RD 0x01
21  
22  static struct uart_driver ar933x_uart_driver;
23 @@ -37,6 +45,8 @@ static struct uart_driver ar933x_uart_dr
24  struct ar933x_uart_port {
25         struct uart_port        port;
26         unsigned int            ier;    /* shadow Interrupt Enable Register */
27 +       unsigned int            min_baud;
28 +       unsigned int            max_baud;
29  };
30  
31  static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
32 @@ -162,6 +172,57 @@ static void ar933x_uart_enable_ms(struct
33  {
34  }
35  
36 +/*
37 + * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
38 + */
39 +static unsigned long ar933x_uart_get_baud(unsigned int clk,
40 +                                         unsigned int scale,
41 +                                         unsigned int step)
42 +{
43 +       u64 t;
44 +       u32 div;
45 +
46 +       div = (2 << 16) * (scale + 1);
47 +       t = clk;
48 +       t *= step;
49 +       t += (div / 2);
50 +       do_div(t, div);
51 +
52 +       return t;
53 +}
54 +
55 +static void ar933x_uart_get_scale_step(unsigned int clk,
56 +                                      unsigned int baud,
57 +                                      unsigned int *scale,
58 +                                      unsigned int *step)
59 +{
60 +       unsigned int tscale;
61 +       long min_diff;
62 +
63 +       *scale = 0;
64 +       *step = 0;
65 +
66 +       min_diff = baud;
67 +       for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
68 +               u64 tstep;
69 +               int diff;
70 +
71 +               tstep = baud * (tscale + 1);
72 +               tstep *= (2 << 16);
73 +               do_div(tstep, clk);
74 +
75 +               if (tstep > AR933X_UART_MAX_STEP)
76 +                       break;
77 +
78 +               diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
79 +               if (diff < min_diff) {
80 +                       min_diff = diff;
81 +                       *scale = tscale;
82 +                       *step = tstep;
83 +               }
84 +       }
85 +}
86 +
87  static void ar933x_uart_set_termios(struct uart_port *port,
88                                     struct ktermios *new,
89                                     struct ktermios *old)
90 @@ -169,7 +230,7 @@ static void ar933x_uart_set_termios(stru
91         struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
92         unsigned int cs;
93         unsigned long flags;
94 -       unsigned int baud, scale;
95 +       unsigned int baud, scale, step;
96  
97         /* Only CS8 is supported */
98         new->c_cflag &= ~CSIZE;
99 @@ -191,8 +252,8 @@ static void ar933x_uart_set_termios(stru
100         /* Mark/space parity is not supported */
101         new->c_cflag &= ~CMSPAR;
102  
103 -       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
104 -       scale = (port->uartclk / (16 * baud)) - 1;
105 +       baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud);
106 +       ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step);
107  
108         /*
109          * Ok, we're now changing the port state. Do it with
110 @@ -200,6 +261,10 @@ static void ar933x_uart_set_termios(stru
111          */
112         spin_lock_irqsave(&up->port.lock, flags);
113  
114 +       /* disable the UART */
115 +       ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
116 +                     AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S);
117 +
118         /* Update the per-port timeout. */
119         uart_update_timeout(port, new->c_cflag, baud);
120  
121 @@ -210,7 +275,7 @@ static void ar933x_uart_set_termios(stru
122                 up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;
123  
124         ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
125 -                         scale << AR933X_UART_CLOCK_SCALE_S | 8192);
126 +                         scale << AR933X_UART_CLOCK_SCALE_S | step);
127  
128         /* setup configuration register */
129         ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);
130 @@ -219,6 +284,11 @@ static void ar933x_uart_set_termios(stru
131         ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
132                             AR933X_UART_CS_HOST_INT_EN);
133  
134 +       /* reenable the UART */
135 +       ar933x_uart_rmw(up, AR933X_UART_CS_REG,
136 +                       AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
137 +                       AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
138 +
139         spin_unlock_irqrestore(&up->port.lock, flags);
140  
141         if (tty_termios_baud_rate(new))
142 @@ -401,6 +471,8 @@ static void ar933x_uart_config_port(stru
143  static int ar933x_uart_verify_port(struct uart_port *port,
144                                    struct serial_struct *ser)
145  {
146 +       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
147 +
148         if (ser->type != PORT_UNKNOWN &&
149             ser->type != PORT_AR933X)
150                 return -EINVAL;
151 @@ -408,7 +480,8 @@ static int ar933x_uart_verify_port(struc
152         if (ser->irq < 0 || ser->irq >= NR_IRQS)
153                 return -EINVAL;
154  
155 -       if (ser->baud_base < 28800)
156 +       if (ser->baud_base < up->min_baud ||
157 +           ser->baud_base > up->max_baud)
158                 return -EINVAL;
159  
160         return 0;
161 @@ -561,6 +634,7 @@ static int __devinit ar933x_uart_probe(s
162         struct uart_port *port;
163         struct resource *mem_res;
164         struct resource *irq_res;
165 +       unsigned int baud;
166         int id;
167         int ret;
168  
169 @@ -611,6 +685,12 @@ static int __devinit ar933x_uart_probe(s
170         port->fifosize = AR933X_UART_FIFO_SIZE;
171         port->ops = &ar933x_uart_ops;
172  
173 +       baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
174 +       up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
175 +
176 +       baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
177 +       up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
178 +
179         ar933x_uart_add_console_port(up);
180  
181         ret = uart_add_one_port(&ar933x_uart_driver, &up->port);