summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/uartlite.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/uartlite.c')
-rw-r--r--drivers/tty/serial/uartlite.c280
1 files changed, 160 insertions, 120 deletions
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index b8b912b5a8b9..39c1fd1ff9ce 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -8,6 +8,7 @@
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/bitfield.h>
#include <linux/console.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
@@ -17,23 +18,26 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#define ULITE_NAME "ttyUL"
+#if CONFIG_SERIAL_UARTLITE_NR_UARTS > 4
+#define ULITE_MAJOR 0 /* use dynamic node allocation */
+#define ULITE_MINOR 0
+#else
#define ULITE_MAJOR 204
#define ULITE_MINOR 187
+#endif
#define ULITE_NR_UARTS CONFIG_SERIAL_UARTLITE_NR_UARTS
/* ---------------------------------------------------------------------
* Register definitions
*
* For register details see datasheet:
- * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
+ * https://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
*/
#define ULITE_RX 0x00
@@ -55,17 +59,25 @@
#define ULITE_CONTROL_RST_TX 0x01
#define ULITE_CONTROL_RST_RX 0x02
#define ULITE_CONTROL_IE 0x10
-#define UART_AUTOSUSPEND_TIMEOUT 3000
+#define UART_AUTOSUSPEND_TIMEOUT 3000 /* ms */
/* Static pointer to console port */
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
static struct uart_port *console_port;
#endif
+/**
+ * struct uartlite_data - Driver private data
+ * @reg_ops: Functions to read/write registers
+ * @clk: Our parent clock, if present
+ * @baud: The baud rate configured when this device was synthesized
+ * @cflags: The cflags for parity and data bits
+ */
struct uartlite_data {
const struct uartlite_reg_ops *reg_ops;
struct clk *clk;
- struct uart_driver *ulite_uart_driver;
+ unsigned int baud;
+ tcflag_t cflags;
};
struct uartlite_reg_ops {
@@ -119,6 +131,8 @@ static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
static struct uart_port ulite_ports[ULITE_NR_UARTS];
+static struct uart_driver ulite_uart_driver;
+
/* ---------------------------------------------------------------------
* Core UART driver operations
*/
@@ -175,7 +189,8 @@ static int ulite_receive(struct uart_port *port, int stat)
static int ulite_transmit(struct uart_port *port, int stat)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
+ unsigned char ch;
if (stat & ULITE_STATUS_TXFULL)
return 0;
@@ -187,15 +202,16 @@ static int ulite_transmit(struct uart_port *port, int stat)
return 1;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ if (uart_tx_stopped(port))
return 0;
- uart_out32(xmit->buf[xmit->tail], ULITE_TX, port);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
- port->icount.tx++;
+ if (!uart_fifo_get(port, &ch))
+ return 0;
+
+ uart_out32(ch, ULITE_TX, port);
/* wake up */
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
return 1;
@@ -208,11 +224,11 @@ static irqreturn_t ulite_isr(int irq, void *dev_id)
unsigned long flags;
do {
- spin_lock_irqsave(&port->lock, flags);
+ uart_port_lock_irqsave(port, &flags);
stat = uart_in32(ULITE_STATUS, port);
busy = ulite_receive(port, stat);
busy |= ulite_transmit(port, stat);
- spin_unlock_irqrestore(&port->lock, flags);
+ uart_port_unlock_irqrestore(port, flags);
n++;
} while (busy);
@@ -230,9 +246,9 @@ static unsigned int ulite_tx_empty(struct uart_port *port)
unsigned long flags;
unsigned int ret;
- spin_lock_irqsave(&port->lock, flags);
+ uart_port_lock_irqsave(port, &flags);
ret = uart_in32(ULITE_STATUS, port);
- spin_unlock_irqrestore(&port->lock, flags);
+ uart_port_unlock_irqrestore(port, flags);
return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
}
@@ -302,13 +318,20 @@ static void ulite_shutdown(struct uart_port *port)
clk_disable(pdata->clk);
}
-static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+static void ulite_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ const struct ktermios *old)
{
unsigned long flags;
- unsigned int baud;
+ struct uartlite_data *pdata = port->private_data;
+
+ /* Set termios to what the hardware supports */
+ termios->c_iflag &= ~BRKINT;
+ termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE);
+ termios->c_cflag |= pdata->cflags & (PARENB | PARODD | CSIZE);
+ tty_termios_encode_baud_rate(termios, pdata->baud, pdata->baud);
- spin_lock_irqsave(&port->lock, flags);
+ uart_port_lock_irqsave(port, &flags);
port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
| ULITE_STATUS_TXFULL;
@@ -329,10 +352,9 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
/* update timeout */
- baud = uart_get_baud_rate(port, termios, old, 0, 460800);
- uart_update_timeout(port, termios->c_cflag, baud);
+ uart_update_timeout(port, termios->c_cflag, pdata->baud);
- spin_unlock_irqrestore(&port->lock, flags);
+ uart_port_unlock_irqrestore(port, flags);
}
static const char *ulite_type(struct uart_port *port)
@@ -393,8 +415,12 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
static void ulite_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
+ int ret;
+
if (!state) {
- pm_runtime_get_sync(port->dev);
+ ret = pm_runtime_get_sync(port->dev);
+ if (ret < 0)
+ dev_err(port->dev, "Failed to enable clocks\n");
} else {
pm_runtime_mark_last_busy(port->dev);
pm_runtime_put_autosuspend(port->dev);
@@ -451,27 +477,18 @@ static const struct uart_ops ulite_ops = {
static void ulite_console_wait_tx(struct uart_port *port)
{
u8 val;
- unsigned long timeout;
/*
* Spin waiting for TX fifo to have space available.
* When using the Microblaze Debug Module this can take up to 1s
*/
- timeout = jiffies + msecs_to_jiffies(1000);
- while (1) {
- val = uart_in32(ULITE_STATUS, port);
- if ((val & ULITE_STATUS_TXFULL) == 0)
- break;
- if (time_after(jiffies, timeout)) {
- dev_warn(port->dev,
- "timeout waiting for TX buffer empty\n");
- break;
- }
- cpu_relax();
- }
+ if (read_poll_timeout_atomic(uart_in32, val, !(val & ULITE_STATUS_TXFULL),
+ 0, 1000000, false, ULITE_STATUS, port))
+ dev_warn(port->dev,
+ "timeout waiting for TX buffer empty\n");
}
-static void ulite_console_putchar(struct uart_port *port, int ch)
+static void ulite_console_putchar(struct uart_port *port, unsigned char ch)
{
ulite_console_wait_tx(port);
uart_out32(ch, ULITE_TX, port);
@@ -486,9 +503,9 @@ static void ulite_console_write(struct console *co, const char *s,
int locked = 1;
if (oops_in_progress) {
- locked = spin_trylock_irqsave(&port->lock, flags);
+ locked = uart_port_trylock_irqsave(port, &flags);
} else
- spin_lock_irqsave(&port->lock, flags);
+ uart_port_lock_irqsave(port, &flags);
/* save and disable interrupt */
ier = uart_in32(ULITE_STATUS, port) & ULITE_STATUS_IE;
@@ -503,26 +520,28 @@ static void ulite_console_write(struct console *co, const char *s,
uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port);
if (locked)
- spin_unlock_irqrestore(&port->lock, flags);
+ uart_port_unlock_irqrestore(port, flags);
}
static int ulite_console_setup(struct console *co, char *options)
{
- struct uart_port *port;
+ struct uart_port *port = NULL;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
-
- port = console_port;
+ if (co->index >= 0 && co->index < ULITE_NR_UARTS)
+ port = ulite_ports + co->index;
/* Has the device been initialized yet? */
- if (!port->mapbase) {
+ if (!port || !port->mapbase) {
pr_debug("console on ttyUL%i not present\n", co->index);
return -ENODEV;
}
+ console_port = port;
+
/* not initialized yet? */
if (!port->membase) {
if (ulite_request_port(port))
@@ -535,8 +554,6 @@ static int ulite_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
-static struct uart_driver ulite_uart_driver;
-
static struct console ulite_console = {
.name = ULITE_NAME,
.write = ulite_console_write,
@@ -547,7 +564,7 @@ static struct console ulite_console = {
.data = &ulite_uart_driver,
};
-static void early_uartlite_putc(struct uart_port *port, int c)
+static void early_uartlite_putc(struct uart_port *port, unsigned char c)
{
/*
* Limit how many times we'll spin waiting for TX FIFO status.
@@ -556,16 +573,15 @@ static void early_uartlite_putc(struct uart_port *port, int c)
* This limit is pretty arbitrary, unless we are at about 10 baud
* we'll never timeout on a working UART.
*/
-
unsigned retries = 1000000;
- /* read status bit - 0x8 offset */
- while (--retries && (readl(port->membase + 8) & (1 << 3)))
+
+ while (--retries &&
+ (readl(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL))
;
/* Only attempt the iowrite if we didn't timeout */
- /* write to TX_FIFO - 0x4 offset */
if (retries)
- writel(c & 0xff, port->membase + 4);
+ writel(c & 0xff, port->membase + ULITE_TX);
}
static void early_uartlite_write(struct console *console,
@@ -616,7 +632,7 @@ static struct uart_driver ulite_uart_driver = {
*
* Returns: 0 on success, <0 otherwise
*/
-static int ulite_assign(struct device *dev, int id, u32 base, int irq,
+static int ulite_assign(struct device *dev, int id, phys_addr_t base, int irq,
struct uartlite_data *pdata)
{
struct uart_port *port;
@@ -658,17 +674,6 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
dev_set_drvdata(dev, port);
-#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
- /*
- * If console hasn't been found yet try to assign this port
- * because it is required to be assigned for console setup function.
- * If register_console() don't assign value, then console_port pointer
- * is cleanup.
- */
- if (ulite_uart_driver.cons->index == -1)
- console_port = port;
-#endif
-
/* Register the port */
rc = uart_add_one_port(&ulite_uart_driver, port);
if (rc) {
@@ -678,12 +683,6 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
return rc;
}
-#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
- /* This is not port which is used for console that's why clean it up */
- if (ulite_uart_driver.cons->index == -1)
- console_port = NULL;
-#endif
-
return 0;
}
@@ -691,20 +690,15 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
*
* @dev: pointer to device structure
*/
-static int ulite_release(struct device *dev)
+static void ulite_release(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
- int rc = 0;
if (port) {
- struct uartlite_data *pdata = port->private_data;
-
- rc = uart_remove_one_port(pdata->ulite_uart_driver, port);
+ uart_remove_one_port(&ulite_uart_driver, port);
dev_set_drvdata(dev, NULL);
port->mapbase = 0;
}
-
- return rc;
}
/**
@@ -717,11 +711,8 @@ static int __maybe_unused ulite_suspend(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
- if (port) {
- struct uartlite_data *pdata = port->private_data;
-
- uart_suspend_port(pdata->ulite_uart_driver, port);
- }
+ if (port)
+ uart_suspend_port(&ulite_uart_driver, port);
return 0;
}
@@ -736,11 +727,8 @@ static int __maybe_unused ulite_resume(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
- if (port) {
- struct uartlite_data *pdata = port->private_data;
-
- uart_resume_port(pdata->ulite_uart_driver, port);
- }
+ if (port)
+ uart_resume_port(&ulite_uart_driver, port);
return 0;
}
@@ -758,10 +746,16 @@ static int __maybe_unused ulite_runtime_resume(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
struct uartlite_data *pdata = port->private_data;
+ int ret;
- clk_enable(pdata->clk);
+ ret = clk_enable(pdata->clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ return ret;
+ }
return 0;
}
+
/* ---------------------------------------------------------------------
* Platform bus binding
*/
@@ -788,41 +782,80 @@ static int ulite_probe(struct platform_device *pdev)
struct uartlite_data *pdata;
int irq, ret;
int id = pdev->id;
-#ifdef CONFIG_OF
- const __be32 *prop;
-
- prop = of_get_property(pdev->dev.of_node, "port-number", NULL);
- if (prop)
- id = be32_to_cpup(prop);
-#endif
- if (id < 0) {
- /* Look for a serialN alias */
- id = of_alias_get_id(pdev->dev.of_node, "serial");
- if (id < 0)
- id = 0;
- }
-
- if (!ulite_uart_driver.state) {
- dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
- ret = uart_register_driver(&ulite_uart_driver);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register driver\n");
- return ret;
- }
- }
pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
+ if (IS_ENABLED(CONFIG_OF)) {
+ const char *prop;
+ struct device_node *np = pdev->dev.of_node;
+ u32 val = 0;
+
+ prop = "port-number";
+ ret = of_property_read_u32(np, prop, &id);
+ if (ret && ret != -EINVAL)
+of_err:
+ return dev_err_probe(&pdev->dev, ret,
+ "could not read %s\n", prop);
+
+ prop = "current-speed";
+ ret = of_property_read_u32(np, prop, &pdata->baud);
+ if (ret)
+ goto of_err;
+
+ prop = "xlnx,use-parity";
+ ret = of_property_read_u32(np, prop, &val);
+ if (ret && ret != -EINVAL)
+ goto of_err;
+
+ if (val) {
+ prop = "xlnx,odd-parity";
+ ret = of_property_read_u32(np, prop, &val);
+ if (ret)
+ goto of_err;
+
+ if (val)
+ pdata->cflags |= PARODD;
+ pdata->cflags |= PARENB;
+ }
+
+ val = 8;
+ prop = "xlnx,data-bits";
+ ret = of_property_read_u32(np, prop, &val);
+ if (ret && ret != -EINVAL)
+ goto of_err;
+
+ switch (val) {
+ case 5:
+ pdata->cflags |= CS5;
+ break;
+ case 6:
+ pdata->cflags |= CS6;
+ break;
+ case 7:
+ pdata->cflags |= CS7;
+ break;
+ case 8:
+ pdata->cflags |= CS8;
+ break;
+ default:
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "bad data bits %d\n", val);
+ }
+ } else {
+ pdata->baud = 9600;
+ pdata->cflags = CS8;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -ENXIO;
+ if (irq < 0)
+ return irq;
pdata->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
if (IS_ERR(pdata->clk)) {
@@ -836,7 +869,6 @@ static int ulite_probe(struct platform_device *pdev)
pdata->clk = NULL;
}
- pdata->ulite_uart_driver = &ulite_uart_driver;
ret = clk_prepare_enable(pdata->clk);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare clock\n");
@@ -856,18 +888,16 @@ static int ulite_probe(struct platform_device *pdev)
return ret;
}
-static int ulite_remove(struct platform_device *pdev)
+static void ulite_remove(struct platform_device *pdev)
{
struct uart_port *port = dev_get_drvdata(&pdev->dev);
struct uartlite_data *pdata = port->private_data;
- int rc;
- clk_unprepare(pdata->clk);
- rc = ulite_release(&pdev->dev);
+ clk_disable_unprepare(pdata->clk);
+ ulite_release(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
- return rc;
}
/* work with hotplug and coldplug */
@@ -889,9 +919,19 @@ static struct platform_driver ulite_platform_driver = {
static int __init ulite_init(void)
{
+ int ret;
+
+ pr_debug("uartlite: calling uart_register_driver()\n");
+ ret = uart_register_driver(&ulite_uart_driver);
+ if (ret)
+ return ret;
pr_debug("uartlite: calling platform_driver_register()\n");
- return platform_driver_register(&ulite_platform_driver);
+ ret = platform_driver_register(&ulite_platform_driver);
+ if (ret)
+ uart_unregister_driver(&ulite_uart_driver);
+
+ return ret;
}
static void __exit ulite_exit(void)