|
@@ -33,8 +33,8 @@
|
|
|
#include <linux/serial.h>
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/clk.h>
|
|
|
-#include <linux/platform_device.h>
|
|
|
#include <linux/of.h>
|
|
|
+#include <linux/of_device.h>
|
|
|
#include <linux/err.h>
|
|
|
|
|
|
/*
|
|
@@ -78,6 +78,29 @@
|
|
|
#define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
|
|
|
#define TX_FIFO_INTS (TXFAE | TXFE | TXUDR)
|
|
|
|
|
|
+/*
|
|
|
+ * Line control bits
|
|
|
+ */
|
|
|
+
|
|
|
+#define VT8500_TXEN (1 << 0) /* Enable transmit logic */
|
|
|
+#define VT8500_RXEN (1 << 1) /* Enable receive logic */
|
|
|
+#define VT8500_CS8 (1 << 2) /* 8-bit data length (vs. 7-bit) */
|
|
|
+#define VT8500_CSTOPB (1 << 3) /* 2 stop bits (vs. 1) */
|
|
|
+#define VT8500_PARENB (1 << 4) /* Enable parity */
|
|
|
+#define VT8500_PARODD (1 << 5) /* Odd parity (vs. even) */
|
|
|
+#define VT8500_RTS (1 << 6) /* Ready to send */
|
|
|
+#define VT8500_LOOPBK (1 << 7) /* Enable internal loopback */
|
|
|
+#define VT8500_DMA (1 << 8) /* Enable DMA mode (needs FIFO) */
|
|
|
+#define VT8500_BREAK (1 << 9) /* Initiate break signal */
|
|
|
+#define VT8500_PSLVERR (1 << 10) /* APB error upon empty RX FIFO read */
|
|
|
+#define VT8500_SWRTSCTS (1 << 11) /* Software-controlled RTS/CTS */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Capability flags (driver-internal)
|
|
|
+ */
|
|
|
+
|
|
|
+#define VT8500_HAS_SWRTSCTS_SWITCH (1 << 1)
|
|
|
+
|
|
|
#define VT8500_MAX_PORTS 6
|
|
|
|
|
|
struct vt8500_port {
|
|
@@ -85,6 +108,7 @@ struct vt8500_port {
|
|
|
char name[16];
|
|
|
struct clk *clk;
|
|
|
unsigned int ier;
|
|
|
+ unsigned int vt8500_uart_flags;
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -272,7 +296,8 @@ static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|
|
static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
|
|
|
{
|
|
|
if (break_ctl)
|
|
|
- vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9),
|
|
|
+ vt8500_write(port,
|
|
|
+ vt8500_read(port, VT8500_URLCR) | VT8500_BREAK,
|
|
|
VT8500_URLCR);
|
|
|
}
|
|
|
|
|
@@ -347,31 +372,35 @@ static void vt8500_set_termios(struct uart_port *port,
|
|
|
|
|
|
/* calculate parity */
|
|
|
lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
|
|
|
- lcr &= ~((1 << 5) | (1 << 4));
|
|
|
+ lcr &= ~(VT8500_PARENB | VT8500_PARODD);
|
|
|
if (termios->c_cflag & PARENB) {
|
|
|
- lcr |= (1 << 4);
|
|
|
+ lcr |= VT8500_PARENB;
|
|
|
termios->c_cflag &= ~CMSPAR;
|
|
|
if (termios->c_cflag & PARODD)
|
|
|
- lcr |= (1 << 5);
|
|
|
+ lcr |= VT8500_PARODD;
|
|
|
}
|
|
|
|
|
|
/* calculate bits per char */
|
|
|
- lcr &= ~(1 << 2);
|
|
|
+ lcr &= ~VT8500_CS8;
|
|
|
switch (termios->c_cflag & CSIZE) {
|
|
|
case CS7:
|
|
|
break;
|
|
|
case CS8:
|
|
|
default:
|
|
|
- lcr |= (1 << 2);
|
|
|
+ lcr |= VT8500_CS8;
|
|
|
termios->c_cflag &= ~CSIZE;
|
|
|
termios->c_cflag |= CS8;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
/* calculate stop bits */
|
|
|
- lcr &= ~(1 << 3);
|
|
|
+ lcr &= ~VT8500_CSTOPB;
|
|
|
if (termios->c_cflag & CSTOPB)
|
|
|
- lcr |= (1 << 3);
|
|
|
+ lcr |= VT8500_CSTOPB;
|
|
|
+
|
|
|
+ lcr &= ~VT8500_SWRTSCTS;
|
|
|
+ if (vt8500_port->vt8500_uart_flags & VT8500_HAS_SWRTSCTS_SWITCH)
|
|
|
+ lcr |= VT8500_SWRTSCTS;
|
|
|
|
|
|
/* set parity, bits per char, and stop bit */
|
|
|
vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
|
|
@@ -548,14 +577,31 @@ static struct uart_driver vt8500_uart_driver = {
|
|
|
.cons = VT8500_CONSOLE,
|
|
|
};
|
|
|
|
|
|
+static unsigned int vt8500_flags; /* none required so far */
|
|
|
+static unsigned int wm8880_flags = VT8500_HAS_SWRTSCTS_SWITCH;
|
|
|
+
|
|
|
+static const struct of_device_id wmt_dt_ids[] = {
|
|
|
+ { .compatible = "via,vt8500-uart", .data = &vt8500_flags},
|
|
|
+ { .compatible = "wm,wm8880-uart", .data = &wm8880_flags},
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
static int vt8500_serial_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct vt8500_port *vt8500_port;
|
|
|
struct resource *mmres, *irqres;
|
|
|
struct device_node *np = pdev->dev.of_node;
|
|
|
+ const struct of_device_id *match;
|
|
|
+ const unsigned int *flags;
|
|
|
int ret;
|
|
|
int port;
|
|
|
|
|
|
+ match = of_match_device(wmt_dt_ids, &pdev->dev);
|
|
|
+ if (!match)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ flags = match->data;
|
|
|
+
|
|
|
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
|
|
if (!mmres || !irqres)
|
|
@@ -605,6 +651,7 @@ static int vt8500_serial_probe(struct platform_device *pdev)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+ vt8500_port->vt8500_uart_flags = *flags;
|
|
|
vt8500_port->uart.type = PORT_VT8500;
|
|
|
vt8500_port->uart.iotype = UPIO_MEM;
|
|
|
vt8500_port->uart.mapbase = mmres->start;
|
|
@@ -639,11 +686,6 @@ static int vt8500_serial_remove(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static const struct of_device_id wmt_dt_ids[] = {
|
|
|
- { .compatible = "via,vt8500-uart", },
|
|
|
- {}
|
|
|
-};
|
|
|
-
|
|
|
static struct platform_driver vt8500_platform_driver = {
|
|
|
.probe = vt8500_serial_probe,
|
|
|
.remove = vt8500_serial_remove,
|