diff options
Diffstat (limited to 'drivers/tty/serial/vt8500_serial.c')
| -rw-r--r-- | drivers/tty/serial/vt8500_serial.c | 70 |
1 files changed, 56 insertions, 14 deletions
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 15ad6fcda88b..f22571915185 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c | |||
| @@ -33,8 +33,8 @@ | |||
| 33 | #include <linux/serial.h> | 33 | #include <linux/serial.h> |
| 34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
| 35 | #include <linux/clk.h> | 35 | #include <linux/clk.h> |
| 36 | #include <linux/platform_device.h> | ||
| 37 | #include <linux/of.h> | 36 | #include <linux/of.h> |
| 37 | #include <linux/of_device.h> | ||
| 38 | #include <linux/err.h> | 38 | #include <linux/err.h> |
| 39 | 39 | ||
| 40 | /* | 40 | /* |
| @@ -78,6 +78,29 @@ | |||
| 78 | #define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) | 78 | #define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) |
| 79 | #define TX_FIFO_INTS (TXFAE | TXFE | TXUDR) | 79 | #define TX_FIFO_INTS (TXFAE | TXFE | TXUDR) |
| 80 | 80 | ||
| 81 | /* | ||
| 82 | * Line control bits | ||
| 83 | */ | ||
| 84 | |||
| 85 | #define VT8500_TXEN (1 << 0) /* Enable transmit logic */ | ||
| 86 | #define VT8500_RXEN (1 << 1) /* Enable receive logic */ | ||
| 87 | #define VT8500_CS8 (1 << 2) /* 8-bit data length (vs. 7-bit) */ | ||
| 88 | #define VT8500_CSTOPB (1 << 3) /* 2 stop bits (vs. 1) */ | ||
| 89 | #define VT8500_PARENB (1 << 4) /* Enable parity */ | ||
| 90 | #define VT8500_PARODD (1 << 5) /* Odd parity (vs. even) */ | ||
| 91 | #define VT8500_RTS (1 << 6) /* Ready to send */ | ||
| 92 | #define VT8500_LOOPBK (1 << 7) /* Enable internal loopback */ | ||
| 93 | #define VT8500_DMA (1 << 8) /* Enable DMA mode (needs FIFO) */ | ||
| 94 | #define VT8500_BREAK (1 << 9) /* Initiate break signal */ | ||
| 95 | #define VT8500_PSLVERR (1 << 10) /* APB error upon empty RX FIFO read */ | ||
| 96 | #define VT8500_SWRTSCTS (1 << 11) /* Software-controlled RTS/CTS */ | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Capability flags (driver-internal) | ||
| 100 | */ | ||
| 101 | |||
| 102 | #define VT8500_HAS_SWRTSCTS_SWITCH (1 << 1) | ||
| 103 | |||
| 81 | #define VT8500_MAX_PORTS 6 | 104 | #define VT8500_MAX_PORTS 6 |
| 82 | 105 | ||
| 83 | struct vt8500_port { | 106 | struct vt8500_port { |
| @@ -85,6 +108,7 @@ struct vt8500_port { | |||
| 85 | char name[16]; | 108 | char name[16]; |
| 86 | struct clk *clk; | 109 | struct clk *clk; |
| 87 | unsigned int ier; | 110 | unsigned int ier; |
| 111 | unsigned int vt8500_uart_flags; | ||
| 88 | }; | 112 | }; |
| 89 | 113 | ||
| 90 | /* | 114 | /* |
| @@ -272,7 +296,8 @@ static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl) | |||
| 272 | static void vt8500_break_ctl(struct uart_port *port, int break_ctl) | 296 | static void vt8500_break_ctl(struct uart_port *port, int break_ctl) |
| 273 | { | 297 | { |
| 274 | if (break_ctl) | 298 | if (break_ctl) |
| 275 | vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9), | 299 | vt8500_write(port, |
| 300 | vt8500_read(port, VT8500_URLCR) | VT8500_BREAK, | ||
| 276 | VT8500_URLCR); | 301 | VT8500_URLCR); |
| 277 | } | 302 | } |
| 278 | 303 | ||
| @@ -347,31 +372,35 @@ static void vt8500_set_termios(struct uart_port *port, | |||
| 347 | 372 | ||
| 348 | /* calculate parity */ | 373 | /* calculate parity */ |
| 349 | lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR); | 374 | lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR); |
| 350 | lcr &= ~((1 << 5) | (1 << 4)); | 375 | lcr &= ~(VT8500_PARENB | VT8500_PARODD); |
| 351 | if (termios->c_cflag & PARENB) { | 376 | if (termios->c_cflag & PARENB) { |
| 352 | lcr |= (1 << 4); | 377 | lcr |= VT8500_PARENB; |
| 353 | termios->c_cflag &= ~CMSPAR; | 378 | termios->c_cflag &= ~CMSPAR; |
| 354 | if (termios->c_cflag & PARODD) | 379 | if (termios->c_cflag & PARODD) |
| 355 | lcr |= (1 << 5); | 380 | lcr |= VT8500_PARODD; |
| 356 | } | 381 | } |
| 357 | 382 | ||
| 358 | /* calculate bits per char */ | 383 | /* calculate bits per char */ |
| 359 | lcr &= ~(1 << 2); | 384 | lcr &= ~VT8500_CS8; |
| 360 | switch (termios->c_cflag & CSIZE) { | 385 | switch (termios->c_cflag & CSIZE) { |
| 361 | case CS7: | 386 | case CS7: |
| 362 | break; | 387 | break; |
| 363 | case CS8: | 388 | case CS8: |
| 364 | default: | 389 | default: |
| 365 | lcr |= (1 << 2); | 390 | lcr |= VT8500_CS8; |
| 366 | termios->c_cflag &= ~CSIZE; | 391 | termios->c_cflag &= ~CSIZE; |
| 367 | termios->c_cflag |= CS8; | 392 | termios->c_cflag |= CS8; |
| 368 | break; | 393 | break; |
| 369 | } | 394 | } |
| 370 | 395 | ||
| 371 | /* calculate stop bits */ | 396 | /* calculate stop bits */ |
| 372 | lcr &= ~(1 << 3); | 397 | lcr &= ~VT8500_CSTOPB; |
| 373 | if (termios->c_cflag & CSTOPB) | 398 | if (termios->c_cflag & CSTOPB) |
| 374 | lcr |= (1 << 3); | 399 | lcr |= VT8500_CSTOPB; |
| 400 | |||
| 401 | lcr &= ~VT8500_SWRTSCTS; | ||
| 402 | if (vt8500_port->vt8500_uart_flags & VT8500_HAS_SWRTSCTS_SWITCH) | ||
| 403 | lcr |= VT8500_SWRTSCTS; | ||
| 375 | 404 | ||
| 376 | /* set parity, bits per char, and stop bit */ | 405 | /* set parity, bits per char, and stop bit */ |
| 377 | vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR); | 406 | vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR); |
| @@ -548,14 +577,31 @@ static struct uart_driver vt8500_uart_driver = { | |||
| 548 | .cons = VT8500_CONSOLE, | 577 | .cons = VT8500_CONSOLE, |
| 549 | }; | 578 | }; |
| 550 | 579 | ||
| 580 | static unsigned int vt8500_flags; /* none required so far */ | ||
| 581 | static unsigned int wm8880_flags = VT8500_HAS_SWRTSCTS_SWITCH; | ||
| 582 | |||
| 583 | static const struct of_device_id wmt_dt_ids[] = { | ||
| 584 | { .compatible = "via,vt8500-uart", .data = &vt8500_flags}, | ||
| 585 | { .compatible = "wm,wm8880-uart", .data = &wm8880_flags}, | ||
| 586 | {} | ||
| 587 | }; | ||
| 588 | |||
| 551 | static int vt8500_serial_probe(struct platform_device *pdev) | 589 | static int vt8500_serial_probe(struct platform_device *pdev) |
| 552 | { | 590 | { |
| 553 | struct vt8500_port *vt8500_port; | 591 | struct vt8500_port *vt8500_port; |
| 554 | struct resource *mmres, *irqres; | 592 | struct resource *mmres, *irqres; |
| 555 | struct device_node *np = pdev->dev.of_node; | 593 | struct device_node *np = pdev->dev.of_node; |
| 594 | const struct of_device_id *match; | ||
| 595 | const unsigned int *flags; | ||
| 556 | int ret; | 596 | int ret; |
| 557 | int port; | 597 | int port; |
| 558 | 598 | ||
| 599 | match = of_match_device(wmt_dt_ids, &pdev->dev); | ||
| 600 | if (!match) | ||
| 601 | return -EINVAL; | ||
| 602 | |||
| 603 | flags = match->data; | ||
| 604 | |||
| 559 | mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 605 | mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 560 | irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 606 | irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| 561 | if (!mmres || !irqres) | 607 | if (!mmres || !irqres) |
| @@ -605,6 +651,7 @@ static int vt8500_serial_probe(struct platform_device *pdev) | |||
| 605 | return ret; | 651 | return ret; |
| 606 | } | 652 | } |
| 607 | 653 | ||
| 654 | vt8500_port->vt8500_uart_flags = *flags; | ||
| 608 | vt8500_port->uart.type = PORT_VT8500; | 655 | vt8500_port->uart.type = PORT_VT8500; |
| 609 | vt8500_port->uart.iotype = UPIO_MEM; | 656 | vt8500_port->uart.iotype = UPIO_MEM; |
| 610 | vt8500_port->uart.mapbase = mmres->start; | 657 | vt8500_port->uart.mapbase = mmres->start; |
| @@ -639,11 +686,6 @@ static int vt8500_serial_remove(struct platform_device *pdev) | |||
| 639 | return 0; | 686 | return 0; |
| 640 | } | 687 | } |
| 641 | 688 | ||
| 642 | static const struct of_device_id wmt_dt_ids[] = { | ||
| 643 | { .compatible = "via,vt8500-uart", }, | ||
| 644 | {} | ||
| 645 | }; | ||
| 646 | |||
| 647 | static struct platform_driver vt8500_platform_driver = { | 689 | static struct platform_driver vt8500_platform_driver = { |
| 648 | .probe = vt8500_serial_probe, | 690 | .probe = vt8500_serial_probe, |
| 649 | .remove = vt8500_serial_remove, | 691 | .remove = vt8500_serial_remove, |
