diff options
Diffstat (limited to 'drivers/tty/serial/ar933x_uart.c')
| -rw-r--r-- | drivers/tty/serial/ar933x_uart.c | 96 |
1 files changed, 88 insertions, 8 deletions
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index e4f60e2b87f3..505c490c0b44 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c | |||
| @@ -25,11 +25,19 @@ | |||
| 25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
| 26 | #include <linux/irq.h> | 26 | #include <linux/irq.h> |
| 27 | 27 | ||
| 28 | #include <asm/div64.h> | ||
| 29 | |||
| 28 | #include <asm/mach-ath79/ar933x_uart.h> | 30 | #include <asm/mach-ath79/ar933x_uart.h> |
| 29 | #include <asm/mach-ath79/ar933x_uart_platform.h> | 31 | #include <asm/mach-ath79/ar933x_uart_platform.h> |
| 30 | 32 | ||
| 31 | #define DRIVER_NAME "ar933x-uart" | 33 | #define DRIVER_NAME "ar933x-uart" |
| 32 | 34 | ||
| 35 | #define AR933X_UART_MAX_SCALE 0xff | ||
| 36 | #define AR933X_UART_MAX_STEP 0xffff | ||
| 37 | |||
| 38 | #define AR933X_UART_MIN_BAUD 300 | ||
| 39 | #define AR933X_UART_MAX_BAUD 3000000 | ||
| 40 | |||
| 33 | #define AR933X_DUMMY_STATUS_RD 0x01 | 41 | #define AR933X_DUMMY_STATUS_RD 0x01 |
| 34 | 42 | ||
| 35 | static struct uart_driver ar933x_uart_driver; | 43 | static struct uart_driver ar933x_uart_driver; |
| @@ -37,6 +45,8 @@ static struct uart_driver ar933x_uart_driver; | |||
| 37 | struct ar933x_uart_port { | 45 | struct ar933x_uart_port { |
| 38 | struct uart_port port; | 46 | struct uart_port port; |
| 39 | unsigned int ier; /* shadow Interrupt Enable Register */ | 47 | unsigned int ier; /* shadow Interrupt Enable Register */ |
| 48 | unsigned int min_baud; | ||
| 49 | unsigned int max_baud; | ||
| 40 | }; | 50 | }; |
| 41 | 51 | ||
| 42 | static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, | 52 | static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, |
| @@ -162,6 +172,57 @@ static void ar933x_uart_enable_ms(struct uart_port *port) | |||
| 162 | { | 172 | { |
| 163 | } | 173 | } |
| 164 | 174 | ||
| 175 | /* | ||
| 176 | * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17)) | ||
| 177 | */ | ||
| 178 | static unsigned long ar933x_uart_get_baud(unsigned int clk, | ||
| 179 | unsigned int scale, | ||
| 180 | unsigned int step) | ||
| 181 | { | ||
| 182 | u64 t; | ||
| 183 | u32 div; | ||
| 184 | |||
| 185 | div = (2 << 16) * (scale + 1); | ||
| 186 | t = clk; | ||
| 187 | t *= step; | ||
| 188 | t += (div / 2); | ||
| 189 | do_div(t, div); | ||
| 190 | |||
| 191 | return t; | ||
| 192 | } | ||
| 193 | |||
| 194 | static void ar933x_uart_get_scale_step(unsigned int clk, | ||
| 195 | unsigned int baud, | ||
| 196 | unsigned int *scale, | ||
| 197 | unsigned int *step) | ||
| 198 | { | ||
| 199 | unsigned int tscale; | ||
| 200 | long min_diff; | ||
| 201 | |||
| 202 | *scale = 0; | ||
| 203 | *step = 0; | ||
| 204 | |||
| 205 | min_diff = baud; | ||
| 206 | for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) { | ||
| 207 | u64 tstep; | ||
| 208 | int diff; | ||
| 209 | |||
| 210 | tstep = baud * (tscale + 1); | ||
| 211 | tstep *= (2 << 16); | ||
| 212 | do_div(tstep, clk); | ||
| 213 | |||
| 214 | if (tstep > AR933X_UART_MAX_STEP) | ||
| 215 | break; | ||
| 216 | |||
| 217 | diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud); | ||
| 218 | if (diff < min_diff) { | ||
| 219 | min_diff = diff; | ||
| 220 | *scale = tscale; | ||
| 221 | *step = tstep; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 165 | static void ar933x_uart_set_termios(struct uart_port *port, | 226 | static void ar933x_uart_set_termios(struct uart_port *port, |
| 166 | struct ktermios *new, | 227 | struct ktermios *new, |
| 167 | struct ktermios *old) | 228 | struct ktermios *old) |
| @@ -169,7 +230,7 @@ static void ar933x_uart_set_termios(struct uart_port *port, | |||
| 169 | struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; | 230 | struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; |
| 170 | unsigned int cs; | 231 | unsigned int cs; |
| 171 | unsigned long flags; | 232 | unsigned long flags; |
| 172 | unsigned int baud, scale; | 233 | unsigned int baud, scale, step; |
| 173 | 234 | ||
| 174 | /* Only CS8 is supported */ | 235 | /* Only CS8 is supported */ |
| 175 | new->c_cflag &= ~CSIZE; | 236 | new->c_cflag &= ~CSIZE; |
| @@ -191,8 +252,8 @@ static void ar933x_uart_set_termios(struct uart_port *port, | |||
| 191 | /* Mark/space parity is not supported */ | 252 | /* Mark/space parity is not supported */ |
| 192 | new->c_cflag &= ~CMSPAR; | 253 | new->c_cflag &= ~CMSPAR; |
| 193 | 254 | ||
| 194 | baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); | 255 | baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud); |
| 195 | scale = (port->uartclk / (16 * baud)) - 1; | 256 | ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step); |
| 196 | 257 | ||
| 197 | /* | 258 | /* |
| 198 | * Ok, we're now changing the port state. Do it with | 259 | * Ok, we're now changing the port state. Do it with |
| @@ -200,6 +261,10 @@ static void ar933x_uart_set_termios(struct uart_port *port, | |||
| 200 | */ | 261 | */ |
| 201 | spin_lock_irqsave(&up->port.lock, flags); | 262 | spin_lock_irqsave(&up->port.lock, flags); |
| 202 | 263 | ||
| 264 | /* disable the UART */ | ||
| 265 | ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, | ||
| 266 | AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S); | ||
| 267 | |||
| 203 | /* Update the per-port timeout. */ | 268 | /* Update the per-port timeout. */ |
| 204 | uart_update_timeout(port, new->c_cflag, baud); | 269 | uart_update_timeout(port, new->c_cflag, baud); |
| 205 | 270 | ||
| @@ -210,7 +275,7 @@ static void ar933x_uart_set_termios(struct uart_port *port, | |||
| 210 | up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD; | 275 | up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD; |
| 211 | 276 | ||
| 212 | ar933x_uart_write(up, AR933X_UART_CLOCK_REG, | 277 | ar933x_uart_write(up, AR933X_UART_CLOCK_REG, |
| 213 | scale << AR933X_UART_CLOCK_SCALE_S | 8192); | 278 | scale << AR933X_UART_CLOCK_SCALE_S | step); |
| 214 | 279 | ||
| 215 | /* setup configuration register */ | 280 | /* setup configuration register */ |
| 216 | ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs); | 281 | ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs); |
| @@ -219,6 +284,11 @@ static void ar933x_uart_set_termios(struct uart_port *port, | |||
| 219 | ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, | 284 | ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, |
| 220 | AR933X_UART_CS_HOST_INT_EN); | 285 | AR933X_UART_CS_HOST_INT_EN); |
| 221 | 286 | ||
| 287 | /* reenable the UART */ | ||
| 288 | ar933x_uart_rmw(up, AR933X_UART_CS_REG, | ||
| 289 | AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S, | ||
| 290 | AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S); | ||
| 291 | |||
| 222 | spin_unlock_irqrestore(&up->port.lock, flags); | 292 | spin_unlock_irqrestore(&up->port.lock, flags); |
| 223 | 293 | ||
| 224 | if (tty_termios_baud_rate(new)) | 294 | if (tty_termios_baud_rate(new)) |
| @@ -401,6 +471,8 @@ static void ar933x_uart_config_port(struct uart_port *port, int flags) | |||
| 401 | static int ar933x_uart_verify_port(struct uart_port *port, | 471 | static int ar933x_uart_verify_port(struct uart_port *port, |
| 402 | struct serial_struct *ser) | 472 | struct serial_struct *ser) |
| 403 | { | 473 | { |
| 474 | struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; | ||
| 475 | |||
| 404 | if (ser->type != PORT_UNKNOWN && | 476 | if (ser->type != PORT_UNKNOWN && |
| 405 | ser->type != PORT_AR933X) | 477 | ser->type != PORT_AR933X) |
| 406 | return -EINVAL; | 478 | return -EINVAL; |
| @@ -408,7 +480,8 @@ static int ar933x_uart_verify_port(struct uart_port *port, | |||
| 408 | if (ser->irq < 0 || ser->irq >= NR_IRQS) | 480 | if (ser->irq < 0 || ser->irq >= NR_IRQS) |
| 409 | return -EINVAL; | 481 | return -EINVAL; |
| 410 | 482 | ||
| 411 | if (ser->baud_base < 28800) | 483 | if (ser->baud_base < up->min_baud || |
| 484 | ser->baud_base > up->max_baud) | ||
| 412 | return -EINVAL; | 485 | return -EINVAL; |
| 413 | 486 | ||
| 414 | return 0; | 487 | return 0; |
| @@ -554,13 +627,14 @@ static struct uart_driver ar933x_uart_driver = { | |||
| 554 | .cons = AR933X_SERIAL_CONSOLE, | 627 | .cons = AR933X_SERIAL_CONSOLE, |
| 555 | }; | 628 | }; |
| 556 | 629 | ||
| 557 | static int __devinit ar933x_uart_probe(struct platform_device *pdev) | 630 | static int ar933x_uart_probe(struct platform_device *pdev) |
| 558 | { | 631 | { |
| 559 | struct ar933x_uart_platform_data *pdata; | 632 | struct ar933x_uart_platform_data *pdata; |
| 560 | struct ar933x_uart_port *up; | 633 | struct ar933x_uart_port *up; |
| 561 | struct uart_port *port; | 634 | struct uart_port *port; |
| 562 | struct resource *mem_res; | 635 | struct resource *mem_res; |
| 563 | struct resource *irq_res; | 636 | struct resource *irq_res; |
| 637 | unsigned int baud; | ||
| 564 | int id; | 638 | int id; |
| 565 | int ret; | 639 | int ret; |
| 566 | 640 | ||
| @@ -611,6 +685,12 @@ static int __devinit ar933x_uart_probe(struct platform_device *pdev) | |||
| 611 | port->fifosize = AR933X_UART_FIFO_SIZE; | 685 | port->fifosize = AR933X_UART_FIFO_SIZE; |
| 612 | port->ops = &ar933x_uart_ops; | 686 | port->ops = &ar933x_uart_ops; |
| 613 | 687 | ||
| 688 | baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); | ||
| 689 | up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); | ||
| 690 | |||
| 691 | baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); | ||
| 692 | up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); | ||
| 693 | |||
| 614 | ar933x_uart_add_console_port(up); | 694 | ar933x_uart_add_console_port(up); |
| 615 | 695 | ||
| 616 | ret = uart_add_one_port(&ar933x_uart_driver, &up->port); | 696 | ret = uart_add_one_port(&ar933x_uart_driver, &up->port); |
| @@ -627,7 +707,7 @@ err_free_up: | |||
| 627 | return ret; | 707 | return ret; |
| 628 | } | 708 | } |
| 629 | 709 | ||
| 630 | static int __devexit ar933x_uart_remove(struct platform_device *pdev) | 710 | static int ar933x_uart_remove(struct platform_device *pdev) |
| 631 | { | 711 | { |
| 632 | struct ar933x_uart_port *up; | 712 | struct ar933x_uart_port *up; |
| 633 | 713 | ||
| @@ -645,7 +725,7 @@ static int __devexit ar933x_uart_remove(struct platform_device *pdev) | |||
| 645 | 725 | ||
| 646 | static struct platform_driver ar933x_uart_platform_driver = { | 726 | static struct platform_driver ar933x_uart_platform_driver = { |
| 647 | .probe = ar933x_uart_probe, | 727 | .probe = ar933x_uart_probe, |
| 648 | .remove = __devexit_p(ar933x_uart_remove), | 728 | .remove = ar933x_uart_remove, |
| 649 | .driver = { | 729 | .driver = { |
| 650 | .name = DRIVER_NAME, | 730 | .name = DRIVER_NAME, |
| 651 | .owner = THIS_MODULE, | 731 | .owner = THIS_MODULE, |
