Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty: vt8500_serial: add support for UART in WM8880 chips

Newer WonderMedia chips introduced another flag in the UART line control
register, which controls whether RTS/CTS signalling should be handled in
the driver or by the hardware itself.

This patch ensures that the kernel can control RTS/CTS (including
disabling it altogether) by forcing this flag to software mode on affected
chips (only WM8880 so far).

Also remove the redundant copy of the binding doc, while we are here.

Signed-off-by: Alexey Charkov <alchark@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alexey Charkov and committed by
Greg Kroah-Hartman
ae382735 7d480ef7

+58 -32
-17
Documentation/devicetree/bindings/serial/via,vt8500-uart.txt
··· 1 - VIA/Wondermedia VT8500 UART Controller 2 - ----------------------------------------------------- 3 - 4 - Required properties: 5 - - compatible : "via,vt8500-uart" 6 - - reg : Should contain 1 register ranges(address and length) 7 - - interrupts : UART interrupt 8 - - clocks : phandle to the uart source clock (usually a 24Mhz fixed clock) 9 - 10 - Example: 11 - 12 - uart@d8210000 { 13 - compatible = "via,vt8500-uart"; 14 - reg = <0xd8210000 0x1040>; 15 - interrupts = <47>; 16 - clocks = <&ref24>; 17 - };
+2 -1
Documentation/devicetree/bindings/serial/vt8500-uart.txt
··· 1 1 * VIA VT8500 and WonderMedia WM8xxx UART Controller 2 2 3 3 Required properties: 4 - - compatible: should be "via,vt8500-uart" 4 + - compatible: should be "via,vt8500-uart" (for VIA/WonderMedia chips up to and 5 + including WM8850/WM8950), or "wm,wm8880-uart" (for WM8880 and later) 5 6 6 7 - reg: base physical address of the controller and length of memory mapped 7 8 region.
+56 -14
drivers/tty/serial/vt8500_serial.c
··· 33 33 #include <linux/serial.h> 34 34 #include <linux/slab.h> 35 35 #include <linux/clk.h> 36 - #include <linux/platform_device.h> 37 36 #include <linux/of.h> 37 + #include <linux/of_device.h> 38 38 #include <linux/err.h> 39 39 40 40 /* ··· 78 78 #define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) 79 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 104 #define VT8500_MAX_PORTS 6 82 105 83 106 struct vt8500_port { ··· 108 85 char name[16]; 109 86 struct clk *clk; 110 87 unsigned int ier; 88 + unsigned int vt8500_uart_flags; 111 89 }; 112 90 113 91 /* ··· 296 272 static void vt8500_break_ctl(struct uart_port *port, int break_ctl) 297 273 { 298 274 if (break_ctl) 299 - vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9), 275 + vt8500_write(port, 276 + vt8500_read(port, VT8500_URLCR) | VT8500_BREAK, 300 277 VT8500_URLCR); 301 278 } 302 279 ··· 372 347 373 348 /* calculate parity */ 374 349 lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR); 375 - lcr &= ~((1 << 5) | (1 << 4)); 350 + lcr &= ~(VT8500_PARENB | VT8500_PARODD); 376 351 if (termios->c_cflag & PARENB) { 377 - lcr |= (1 << 4); 352 + lcr |= VT8500_PARENB; 378 353 termios->c_cflag &= ~CMSPAR; 379 354 if (termios->c_cflag & PARODD) 380 - lcr |= (1 << 5); 355 + lcr |= VT8500_PARODD; 381 356 } 382 357 383 358 /* calculate bits per char */ 384 - lcr &= ~(1 << 2); 359 + lcr &= ~VT8500_CS8; 385 360 switch (termios->c_cflag & CSIZE) { 386 361 case CS7: 387 362 break; 388 363 case CS8: 389 364 default: 390 - lcr |= (1 << 2); 365 + lcr |= VT8500_CS8; 391 366 termios->c_cflag &= ~CSIZE; 392 367 termios->c_cflag |= CS8; 393 368 break; 394 369 } 395 370 396 371 /* calculate stop bits */ 397 - lcr &= ~(1 << 3); 372 + lcr &= ~VT8500_CSTOPB; 398 373 if (termios->c_cflag & CSTOPB) 399 - lcr |= (1 << 3); 374 + lcr |= VT8500_CSTOPB; 375 + 376 + lcr &= ~VT8500_SWRTSCTS; 377 + if (vt8500_port->vt8500_uart_flags & VT8500_HAS_SWRTSCTS_SWITCH) 378 + lcr |= VT8500_SWRTSCTS; 400 379 401 380 /* set parity, bits per char, and stop bit */ 402 381 vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR); ··· 577 548 .cons = VT8500_CONSOLE, 578 549 }; 579 550 551 + static unsigned int vt8500_flags; /* none required so far */ 552 + static unsigned int wm8880_flags = VT8500_HAS_SWRTSCTS_SWITCH; 553 + 554 + static const struct of_device_id wmt_dt_ids[] = { 555 + { .compatible = "via,vt8500-uart", .data = &vt8500_flags}, 556 + { .compatible = "wm,wm8880-uart", .data = &wm8880_flags}, 557 + {} 558 + }; 559 + 580 560 static int vt8500_serial_probe(struct platform_device *pdev) 581 561 { 582 562 struct vt8500_port *vt8500_port; 583 563 struct resource *mmres, *irqres; 584 564 struct device_node *np = pdev->dev.of_node; 565 + const struct of_device_id *match; 566 + const unsigned int *flags; 585 567 int ret; 586 568 int port; 569 + 570 + match = of_match_device(wmt_dt_ids, &pdev->dev); 571 + if (!match) 572 + return -EINVAL; 573 + 574 + flags = match->data; 587 575 588 576 mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); 589 577 irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ··· 651 605 return ret; 652 606 } 653 607 608 + vt8500_port->vt8500_uart_flags = *flags; 654 609 vt8500_port->uart.type = PORT_VT8500; 655 610 vt8500_port->uart.iotype = UPIO_MEM; 656 611 vt8500_port->uart.mapbase = mmres->start; ··· 685 638 686 639 return 0; 687 640 } 688 - 689 - static const struct of_device_id wmt_dt_ids[] = { 690 - { .compatible = "via,vt8500-uart", }, 691 - {} 692 - }; 693 641 694 642 static struct platform_driver vt8500_platform_driver = { 695 643 .probe = vt8500_serial_probe,