xref: /openbmc/linux/drivers/tty/serial/liteuart.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11da81e55SFilip Kokosinski // SPDX-License-Identifier: GPL-2.0
21da81e55SFilip Kokosinski /*
31da81e55SFilip Kokosinski  * LiteUART serial controller (LiteX) Driver
41da81e55SFilip Kokosinski  *
51da81e55SFilip Kokosinski  * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
61da81e55SFilip Kokosinski  */
71da81e55SFilip Kokosinski 
85996b2e3SGabriel Somlo #include <linux/bits.h>
91da81e55SFilip Kokosinski #include <linux/console.h>
105602cf99SGabriel Somlo #include <linux/interrupt.h>
111da81e55SFilip Kokosinski #include <linux/litex.h>
121da81e55SFilip Kokosinski #include <linux/module.h>
131da81e55SFilip Kokosinski #include <linux/of.h>
14*29e5c442SRob Herring #include <linux/platform_device.h>
151da81e55SFilip Kokosinski #include <linux/serial.h>
161da81e55SFilip Kokosinski #include <linux/serial_core.h>
171da81e55SFilip Kokosinski #include <linux/slab.h>
181da81e55SFilip Kokosinski #include <linux/timer.h>
191da81e55SFilip Kokosinski #include <linux/tty_flip.h>
201da81e55SFilip Kokosinski #include <linux/xarray.h>
211da81e55SFilip Kokosinski 
221da81e55SFilip Kokosinski /*
231da81e55SFilip Kokosinski  * CSRs definitions (base address offsets + width)
241da81e55SFilip Kokosinski  *
251da81e55SFilip Kokosinski  * The definitions below are true for LiteX SoC configured for 8-bit CSR Bus,
261da81e55SFilip Kokosinski  * 32-bit aligned.
271da81e55SFilip Kokosinski  *
281da81e55SFilip Kokosinski  * Supporting other configurations might require new definitions or a more
291da81e55SFilip Kokosinski  * generic way of indexing the LiteX CSRs.
301da81e55SFilip Kokosinski  *
311da81e55SFilip Kokosinski  * For more details on how CSRs are defined and handled in LiteX, see comments
321da81e55SFilip Kokosinski  * in the LiteX SoC Driver: drivers/soc/litex/litex_soc_ctrl.c
331da81e55SFilip Kokosinski  */
341da81e55SFilip Kokosinski #define OFF_RXTX	0x00
351da81e55SFilip Kokosinski #define OFF_TXFULL	0x04
361da81e55SFilip Kokosinski #define OFF_RXEMPTY	0x08
371da81e55SFilip Kokosinski #define OFF_EV_STATUS	0x0c
381da81e55SFilip Kokosinski #define OFF_EV_PENDING	0x10
391da81e55SFilip Kokosinski #define OFF_EV_ENABLE	0x14
401da81e55SFilip Kokosinski 
411da81e55SFilip Kokosinski /* events */
425996b2e3SGabriel Somlo #define EV_TX		BIT(0)
435996b2e3SGabriel Somlo #define EV_RX		BIT(1)
441da81e55SFilip Kokosinski 
451da81e55SFilip Kokosinski struct liteuart_port {
461da81e55SFilip Kokosinski 	struct uart_port port;
471da81e55SFilip Kokosinski 	struct timer_list timer;
485602cf99SGabriel Somlo 	u8 irq_reg;
491da81e55SFilip Kokosinski };
501da81e55SFilip Kokosinski 
511da81e55SFilip Kokosinski #define to_liteuart_port(port)	container_of(port, struct liteuart_port, port)
521da81e55SFilip Kokosinski 
531da81e55SFilip Kokosinski static DEFINE_XARRAY_FLAGS(liteuart_array, XA_FLAGS_ALLOC);
541da81e55SFilip Kokosinski 
551da81e55SFilip Kokosinski #ifdef CONFIG_SERIAL_LITEUART_CONSOLE
561da81e55SFilip Kokosinski static struct console liteuart_console;
571da81e55SFilip Kokosinski #endif
581da81e55SFilip Kokosinski 
591da81e55SFilip Kokosinski static struct uart_driver liteuart_driver = {
601da81e55SFilip Kokosinski 	.owner = THIS_MODULE,
612696216bSGabriel Somlo 	.driver_name = KBUILD_MODNAME,
621da81e55SFilip Kokosinski 	.dev_name = "ttyLXU",
631da81e55SFilip Kokosinski 	.major = 0,
641da81e55SFilip Kokosinski 	.minor = 0,
651da81e55SFilip Kokosinski 	.nr = CONFIG_SERIAL_LITEUART_MAX_PORTS,
661da81e55SFilip Kokosinski #ifdef CONFIG_SERIAL_LITEUART_CONSOLE
671da81e55SFilip Kokosinski 	.cons = &liteuart_console,
681da81e55SFilip Kokosinski #endif
691da81e55SFilip Kokosinski };
701da81e55SFilip Kokosinski 
liteuart_update_irq_reg(struct uart_port * port,bool set,u8 mask)715602cf99SGabriel Somlo static void liteuart_update_irq_reg(struct uart_port *port, bool set, u8 mask)
725602cf99SGabriel Somlo {
735602cf99SGabriel Somlo 	struct liteuart_port *uart = to_liteuart_port(port);
745602cf99SGabriel Somlo 
755602cf99SGabriel Somlo 	if (set)
765602cf99SGabriel Somlo 		uart->irq_reg |= mask;
775602cf99SGabriel Somlo 	else
785602cf99SGabriel Somlo 		uart->irq_reg &= ~mask;
795602cf99SGabriel Somlo 
805602cf99SGabriel Somlo 	if (port->irq)
815602cf99SGabriel Somlo 		litex_write8(port->membase + OFF_EV_ENABLE, uart->irq_reg);
825602cf99SGabriel Somlo }
835602cf99SGabriel Somlo 
liteuart_stop_tx(struct uart_port * port)841da81e55SFilip Kokosinski static void liteuart_stop_tx(struct uart_port *port)
851da81e55SFilip Kokosinski {
8601a305a3SGabriel Somlo 	liteuart_update_irq_reg(port, false, EV_TX);
871da81e55SFilip Kokosinski }
881da81e55SFilip Kokosinski 
liteuart_start_tx(struct uart_port * port)891da81e55SFilip Kokosinski static void liteuart_start_tx(struct uart_port *port)
901da81e55SFilip Kokosinski {
9101a305a3SGabriel Somlo 	liteuart_update_irq_reg(port, true, EV_TX);
921da81e55SFilip Kokosinski }
931da81e55SFilip Kokosinski 
liteuart_stop_rx(struct uart_port * port)941da81e55SFilip Kokosinski static void liteuart_stop_rx(struct uart_port *port)
951da81e55SFilip Kokosinski {
961da81e55SFilip Kokosinski 	struct liteuart_port *uart = to_liteuart_port(port);
971da81e55SFilip Kokosinski 
981da81e55SFilip Kokosinski 	/* just delete timer */
991da81e55SFilip Kokosinski 	del_timer(&uart->timer);
1001da81e55SFilip Kokosinski }
1011da81e55SFilip Kokosinski 
liteuart_rx_chars(struct uart_port * port)1027121d86eSGabriel Somlo static void liteuart_rx_chars(struct uart_port *port)
1037121d86eSGabriel Somlo {
1047121d86eSGabriel Somlo 	unsigned char __iomem *membase = port->membase;
1057121d86eSGabriel Somlo 	u8 ch;
1067121d86eSGabriel Somlo 
1077121d86eSGabriel Somlo 	while (!litex_read8(membase + OFF_RXEMPTY)) {
1087121d86eSGabriel Somlo 		ch = litex_read8(membase + OFF_RXTX);
1097121d86eSGabriel Somlo 		port->icount.rx++;
1107121d86eSGabriel Somlo 
1117121d86eSGabriel Somlo 		/* necessary for RXEMPTY to refresh its value */
1127121d86eSGabriel Somlo 		litex_write8(membase + OFF_EV_PENDING, EV_RX);
1137121d86eSGabriel Somlo 
1147121d86eSGabriel Somlo 		/* no overflow bits in status */
1157121d86eSGabriel Somlo 		if (!(uart_handle_sysrq_char(port, ch)))
1167121d86eSGabriel Somlo 			uart_insert_char(port, 1, 0, ch, TTY_NORMAL);
1177121d86eSGabriel Somlo 	}
1187121d86eSGabriel Somlo 
1197121d86eSGabriel Somlo 	tty_flip_buffer_push(&port->state->port);
1207121d86eSGabriel Somlo }
1217121d86eSGabriel Somlo 
liteuart_tx_chars(struct uart_port * port)12201a305a3SGabriel Somlo static void liteuart_tx_chars(struct uart_port *port)
12301a305a3SGabriel Somlo {
12401a305a3SGabriel Somlo 	u8 ch;
12501a305a3SGabriel Somlo 
12601a305a3SGabriel Somlo 	uart_port_tx(port, ch,
12701a305a3SGabriel Somlo 		!litex_read8(port->membase + OFF_TXFULL),
12801a305a3SGabriel Somlo 		litex_write8(port->membase + OFF_RXTX, ch));
12901a305a3SGabriel Somlo }
13001a305a3SGabriel Somlo 
liteuart_interrupt(int irq,void * data)1315602cf99SGabriel Somlo static irqreturn_t liteuart_interrupt(int irq, void *data)
1325602cf99SGabriel Somlo {
1335602cf99SGabriel Somlo 	struct liteuart_port *uart = data;
1345602cf99SGabriel Somlo 	struct uart_port *port = &uart->port;
1355602cf99SGabriel Somlo 	unsigned long flags;
1365602cf99SGabriel Somlo 	u8 isr;
1375602cf99SGabriel Somlo 
1385602cf99SGabriel Somlo 	/*
1395602cf99SGabriel Somlo 	 * if polling, the context would be "in_serving_softirq", so use
1405602cf99SGabriel Somlo 	 * irq[save|restore] spin_lock variants to cover all possibilities
1415602cf99SGabriel Somlo 	 */
1425602cf99SGabriel Somlo 	spin_lock_irqsave(&port->lock, flags);
1435602cf99SGabriel Somlo 	isr = litex_read8(port->membase + OFF_EV_PENDING) & uart->irq_reg;
1445602cf99SGabriel Somlo 	if (isr & EV_RX)
1455602cf99SGabriel Somlo 		liteuart_rx_chars(port);
14601a305a3SGabriel Somlo 	if (isr & EV_TX)
14701a305a3SGabriel Somlo 		liteuart_tx_chars(port);
1485602cf99SGabriel Somlo 	spin_unlock_irqrestore(&port->lock, flags);
1495602cf99SGabriel Somlo 
1505602cf99SGabriel Somlo 	return IRQ_RETVAL(isr);
1515602cf99SGabriel Somlo }
1525602cf99SGabriel Somlo 
liteuart_timer(struct timer_list * t)1537121d86eSGabriel Somlo static void liteuart_timer(struct timer_list *t)
1547121d86eSGabriel Somlo {
1557121d86eSGabriel Somlo 	struct liteuart_port *uart = from_timer(uart, t, timer);
1567121d86eSGabriel Somlo 	struct uart_port *port = &uart->port;
1577121d86eSGabriel Somlo 
1585602cf99SGabriel Somlo 	liteuart_interrupt(0, port);
1597121d86eSGabriel Somlo 	mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
1607121d86eSGabriel Somlo }
1617121d86eSGabriel Somlo 
liteuart_tx_empty(struct uart_port * port)1627121d86eSGabriel Somlo static unsigned int liteuart_tx_empty(struct uart_port *port)
1637121d86eSGabriel Somlo {
1647121d86eSGabriel Somlo 	/* not really tx empty, just checking if tx is not full */
1657121d86eSGabriel Somlo 	if (!litex_read8(port->membase + OFF_TXFULL))
1667121d86eSGabriel Somlo 		return TIOCSER_TEMT;
1677121d86eSGabriel Somlo 
1687121d86eSGabriel Somlo 	return 0;
1697121d86eSGabriel Somlo }
1707121d86eSGabriel Somlo 
liteuart_set_mctrl(struct uart_port * port,unsigned int mctrl)1717121d86eSGabriel Somlo static void liteuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
1727121d86eSGabriel Somlo {
1737121d86eSGabriel Somlo 	/* modem control register is not present in LiteUART */
1747121d86eSGabriel Somlo }
1757121d86eSGabriel Somlo 
liteuart_get_mctrl(struct uart_port * port)1767121d86eSGabriel Somlo static unsigned int liteuart_get_mctrl(struct uart_port *port)
1777121d86eSGabriel Somlo {
1787121d86eSGabriel Somlo 	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
1797121d86eSGabriel Somlo }
1807121d86eSGabriel Somlo 
liteuart_startup(struct uart_port * port)1811da81e55SFilip Kokosinski static int liteuart_startup(struct uart_port *port)
1821da81e55SFilip Kokosinski {
1831da81e55SFilip Kokosinski 	struct liteuart_port *uart = to_liteuart_port(port);
1845602cf99SGabriel Somlo 	unsigned long flags;
1855602cf99SGabriel Somlo 	int ret;
1861da81e55SFilip Kokosinski 
1875602cf99SGabriel Somlo 	if (port->irq) {
1885602cf99SGabriel Somlo 		ret = request_irq(port->irq, liteuart_interrupt, 0,
1895602cf99SGabriel Somlo 				  KBUILD_MODNAME, uart);
1905602cf99SGabriel Somlo 		if (ret) {
1915602cf99SGabriel Somlo 			dev_warn(port->dev,
1925602cf99SGabriel Somlo 				"line %d irq %d failed: switch to polling\n",
1935602cf99SGabriel Somlo 				port->line, port->irq);
1945602cf99SGabriel Somlo 			port->irq = 0;
1955602cf99SGabriel Somlo 		}
1965602cf99SGabriel Somlo 	}
1971da81e55SFilip Kokosinski 
1985602cf99SGabriel Somlo 	spin_lock_irqsave(&port->lock, flags);
1995602cf99SGabriel Somlo 	/* only enabling rx irqs during startup */
2005602cf99SGabriel Somlo 	liteuart_update_irq_reg(port, true, EV_RX);
2015602cf99SGabriel Somlo 	spin_unlock_irqrestore(&port->lock, flags);
2025602cf99SGabriel Somlo 
2035602cf99SGabriel Somlo 	if (!port->irq) {
2041da81e55SFilip Kokosinski 		timer_setup(&uart->timer, liteuart_timer, 0);
2051da81e55SFilip Kokosinski 		mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
2065602cf99SGabriel Somlo 	}
2071da81e55SFilip Kokosinski 
2081da81e55SFilip Kokosinski 	return 0;
2091da81e55SFilip Kokosinski }
2101da81e55SFilip Kokosinski 
liteuart_shutdown(struct uart_port * port)2111da81e55SFilip Kokosinski static void liteuart_shutdown(struct uart_port *port)
2121da81e55SFilip Kokosinski {
2135602cf99SGabriel Somlo 	struct liteuart_port *uart = to_liteuart_port(port);
2145602cf99SGabriel Somlo 	unsigned long flags;
2155602cf99SGabriel Somlo 
2165602cf99SGabriel Somlo 	spin_lock_irqsave(&port->lock, flags);
2175602cf99SGabriel Somlo 	liteuart_update_irq_reg(port, false, EV_RX | EV_TX);
2185602cf99SGabriel Somlo 	spin_unlock_irqrestore(&port->lock, flags);
2195602cf99SGabriel Somlo 
2205602cf99SGabriel Somlo 	if (port->irq)
2215602cf99SGabriel Somlo 		free_irq(port->irq, port);
2225602cf99SGabriel Somlo 	else
2235602cf99SGabriel Somlo 		del_timer_sync(&uart->timer);
2241da81e55SFilip Kokosinski }
2251da81e55SFilip Kokosinski 
liteuart_set_termios(struct uart_port * port,struct ktermios * new,const struct ktermios * old)2261da81e55SFilip Kokosinski static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
227bec5b814SIlpo Järvinen 				 const struct ktermios *old)
2281da81e55SFilip Kokosinski {
2291da81e55SFilip Kokosinski 	unsigned int baud;
2301da81e55SFilip Kokosinski 	unsigned long flags;
2311da81e55SFilip Kokosinski 
2321da81e55SFilip Kokosinski 	spin_lock_irqsave(&port->lock, flags);
2331da81e55SFilip Kokosinski 
2341da81e55SFilip Kokosinski 	/* update baudrate */
2351da81e55SFilip Kokosinski 	baud = uart_get_baud_rate(port, new, old, 0, 460800);
2361da81e55SFilip Kokosinski 	uart_update_timeout(port, new->c_cflag, baud);
2371da81e55SFilip Kokosinski 
2381da81e55SFilip Kokosinski 	spin_unlock_irqrestore(&port->lock, flags);
2391da81e55SFilip Kokosinski }
2401da81e55SFilip Kokosinski 
liteuart_type(struct uart_port * port)2411da81e55SFilip Kokosinski static const char *liteuart_type(struct uart_port *port)
2421da81e55SFilip Kokosinski {
2431da81e55SFilip Kokosinski 	return "liteuart";
2441da81e55SFilip Kokosinski }
2451da81e55SFilip Kokosinski 
liteuart_config_port(struct uart_port * port,int flags)2461da81e55SFilip Kokosinski static void liteuart_config_port(struct uart_port *port, int flags)
2471da81e55SFilip Kokosinski {
2481da81e55SFilip Kokosinski 	/*
2491da81e55SFilip Kokosinski 	 * Driver core for serial ports forces a non-zero value for port type.
2501da81e55SFilip Kokosinski 	 * Write an arbitrary value here to accommodate the serial core driver,
2511da81e55SFilip Kokosinski 	 * as ID part of UAPI is redundant.
2521da81e55SFilip Kokosinski 	 */
2531da81e55SFilip Kokosinski 	port->type = 1;
2541da81e55SFilip Kokosinski }
2551da81e55SFilip Kokosinski 
liteuart_verify_port(struct uart_port * port,struct serial_struct * ser)2561da81e55SFilip Kokosinski static int liteuart_verify_port(struct uart_port *port,
2571da81e55SFilip Kokosinski 				struct serial_struct *ser)
2581da81e55SFilip Kokosinski {
2591da81e55SFilip Kokosinski 	if (port->type != PORT_UNKNOWN && ser->type != 1)
2601da81e55SFilip Kokosinski 		return -EINVAL;
2611da81e55SFilip Kokosinski 
2621da81e55SFilip Kokosinski 	return 0;
2631da81e55SFilip Kokosinski }
2641da81e55SFilip Kokosinski 
2651da81e55SFilip Kokosinski static const struct uart_ops liteuart_ops = {
2661da81e55SFilip Kokosinski 	.tx_empty	= liteuart_tx_empty,
2671da81e55SFilip Kokosinski 	.set_mctrl	= liteuart_set_mctrl,
2681da81e55SFilip Kokosinski 	.get_mctrl	= liteuart_get_mctrl,
2691da81e55SFilip Kokosinski 	.stop_tx	= liteuart_stop_tx,
2701da81e55SFilip Kokosinski 	.start_tx	= liteuart_start_tx,
2711da81e55SFilip Kokosinski 	.stop_rx	= liteuart_stop_rx,
2721da81e55SFilip Kokosinski 	.startup	= liteuart_startup,
2731da81e55SFilip Kokosinski 	.shutdown	= liteuart_shutdown,
2741da81e55SFilip Kokosinski 	.set_termios	= liteuart_set_termios,
2751da81e55SFilip Kokosinski 	.type		= liteuart_type,
2761da81e55SFilip Kokosinski 	.config_port	= liteuart_config_port,
2771da81e55SFilip Kokosinski 	.verify_port	= liteuart_verify_port,
2781da81e55SFilip Kokosinski };
2791da81e55SFilip Kokosinski 
liteuart_probe(struct platform_device * pdev)2801da81e55SFilip Kokosinski static int liteuart_probe(struct platform_device *pdev)
2811da81e55SFilip Kokosinski {
2821da81e55SFilip Kokosinski 	struct liteuart_port *uart;
2831da81e55SFilip Kokosinski 	struct uart_port *port;
2841da81e55SFilip Kokosinski 	struct xa_limit limit;
2851da81e55SFilip Kokosinski 	int dev_id, ret;
2861da81e55SFilip Kokosinski 
287297cb3f0SAndy Shevchenko 	uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL);
288297cb3f0SAndy Shevchenko 	if (!uart)
289297cb3f0SAndy Shevchenko 		return -ENOMEM;
290297cb3f0SAndy Shevchenko 
291297cb3f0SAndy Shevchenko 	port = &uart->port;
292297cb3f0SAndy Shevchenko 
293297cb3f0SAndy Shevchenko 	/* get membase */
294297cb3f0SAndy Shevchenko 	port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
295297cb3f0SAndy Shevchenko 	if (IS_ERR(port->membase))
296297cb3f0SAndy Shevchenko 		return PTR_ERR(port->membase);
297297cb3f0SAndy Shevchenko 
298297cb3f0SAndy Shevchenko 	ret = platform_get_irq_optional(pdev, 0);
299297cb3f0SAndy Shevchenko 	if (ret < 0 && ret != -ENXIO)
300297cb3f0SAndy Shevchenko 		return ret;
301297cb3f0SAndy Shevchenko 	if (ret > 0)
302297cb3f0SAndy Shevchenko 		port->irq = ret;
303297cb3f0SAndy Shevchenko 
3041da81e55SFilip Kokosinski 	/* look for aliases; auto-enumerate for free index if not found */
3051da81e55SFilip Kokosinski 	dev_id = of_alias_get_id(pdev->dev.of_node, "serial");
3061da81e55SFilip Kokosinski 	if (dev_id < 0)
3071da81e55SFilip Kokosinski 		limit = XA_LIMIT(0, CONFIG_SERIAL_LITEUART_MAX_PORTS);
3081da81e55SFilip Kokosinski 	else
3091da81e55SFilip Kokosinski 		limit = XA_LIMIT(dev_id, dev_id);
3101da81e55SFilip Kokosinski 
3111da81e55SFilip Kokosinski 	ret = xa_alloc(&liteuart_array, &dev_id, uart, limit, GFP_KERNEL);
3121da81e55SFilip Kokosinski 	if (ret)
3131da81e55SFilip Kokosinski 		return ret;
3141da81e55SFilip Kokosinski 
3151da81e55SFilip Kokosinski 	/* values not from device tree */
3161da81e55SFilip Kokosinski 	port->dev = &pdev->dev;
3171da81e55SFilip Kokosinski 	port->iotype = UPIO_MEM;
3181da81e55SFilip Kokosinski 	port->flags = UPF_BOOT_AUTOCONF;
3191da81e55SFilip Kokosinski 	port->ops = &liteuart_ops;
3201da81e55SFilip Kokosinski 	port->fifosize = 16;
3211da81e55SFilip Kokosinski 	port->type = PORT_UNKNOWN;
3221da81e55SFilip Kokosinski 	port->line = dev_id;
3231da81e55SFilip Kokosinski 	spin_lock_init(&port->lock);
3241da81e55SFilip Kokosinski 
3250f55f89dSIlia Sergachev 	platform_set_drvdata(pdev, port);
3260f55f89dSIlia Sergachev 
327dd5e90b1SJohan Hovold 	ret = uart_add_one_port(&liteuart_driver, &uart->port);
328dd5e90b1SJohan Hovold 	if (ret)
329dd5e90b1SJohan Hovold 		goto err_erase_id;
330dd5e90b1SJohan Hovold 
331dd5e90b1SJohan Hovold 	return 0;
332dd5e90b1SJohan Hovold 
333dd5e90b1SJohan Hovold err_erase_id:
334646b4cd9SAndy Shevchenko 	xa_erase(&liteuart_array, dev_id);
335dd5e90b1SJohan Hovold 
336dd5e90b1SJohan Hovold 	return ret;
3371da81e55SFilip Kokosinski }
3381da81e55SFilip Kokosinski 
liteuart_remove(struct platform_device * pdev)3391da81e55SFilip Kokosinski static int liteuart_remove(struct platform_device *pdev)
3401da81e55SFilip Kokosinski {
3411da81e55SFilip Kokosinski 	struct uart_port *port = platform_get_drvdata(pdev);
342646b4cd9SAndy Shevchenko 	unsigned int line = port->line;
3431da81e55SFilip Kokosinski 
34405f929b3SJohan Hovold 	uart_remove_one_port(&liteuart_driver, port);
345646b4cd9SAndy Shevchenko 	xa_erase(&liteuart_array, line);
3461da81e55SFilip Kokosinski 
3471da81e55SFilip Kokosinski 	return 0;
3481da81e55SFilip Kokosinski }
3491da81e55SFilip Kokosinski 
3501da81e55SFilip Kokosinski static const struct of_device_id liteuart_of_match[] = {
3511da81e55SFilip Kokosinski 	{ .compatible = "litex,liteuart" },
3521da81e55SFilip Kokosinski 	{}
3531da81e55SFilip Kokosinski };
3541da81e55SFilip Kokosinski MODULE_DEVICE_TABLE(of, liteuart_of_match);
3551da81e55SFilip Kokosinski 
3561da81e55SFilip Kokosinski static struct platform_driver liteuart_platform_driver = {
3571da81e55SFilip Kokosinski 	.probe = liteuart_probe,
3581da81e55SFilip Kokosinski 	.remove = liteuart_remove,
3591da81e55SFilip Kokosinski 	.driver = {
3602696216bSGabriel Somlo 		.name = KBUILD_MODNAME,
3611da81e55SFilip Kokosinski 		.of_match_table = liteuart_of_match,
3621da81e55SFilip Kokosinski 	},
3631da81e55SFilip Kokosinski };
3641da81e55SFilip Kokosinski 
3651da81e55SFilip Kokosinski #ifdef CONFIG_SERIAL_LITEUART_CONSOLE
3661da81e55SFilip Kokosinski 
liteuart_putchar(struct uart_port * port,unsigned char ch)367f1c6c8b1SGabriel Somlo static void liteuart_putchar(struct uart_port *port, unsigned char ch)
368f1c6c8b1SGabriel Somlo {
369f1c6c8b1SGabriel Somlo 	while (litex_read8(port->membase + OFF_TXFULL))
370f1c6c8b1SGabriel Somlo 		cpu_relax();
371f1c6c8b1SGabriel Somlo 
372f1c6c8b1SGabriel Somlo 	litex_write8(port->membase + OFF_RXTX, ch);
373f1c6c8b1SGabriel Somlo }
374f1c6c8b1SGabriel Somlo 
liteuart_console_write(struct console * co,const char * s,unsigned int count)3751da81e55SFilip Kokosinski static void liteuart_console_write(struct console *co, const char *s,
3761da81e55SFilip Kokosinski 	unsigned int count)
3771da81e55SFilip Kokosinski {
3781da81e55SFilip Kokosinski 	struct liteuart_port *uart;
3791da81e55SFilip Kokosinski 	struct uart_port *port;
3801da81e55SFilip Kokosinski 	unsigned long flags;
3811da81e55SFilip Kokosinski 
3821da81e55SFilip Kokosinski 	uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index);
3831da81e55SFilip Kokosinski 	port = &uart->port;
3841da81e55SFilip Kokosinski 
3851da81e55SFilip Kokosinski 	spin_lock_irqsave(&port->lock, flags);
3861da81e55SFilip Kokosinski 	uart_console_write(port, s, count, liteuart_putchar);
3871da81e55SFilip Kokosinski 	spin_unlock_irqrestore(&port->lock, flags);
3881da81e55SFilip Kokosinski }
3891da81e55SFilip Kokosinski 
liteuart_console_setup(struct console * co,char * options)3901da81e55SFilip Kokosinski static int liteuart_console_setup(struct console *co, char *options)
3911da81e55SFilip Kokosinski {
3921da81e55SFilip Kokosinski 	struct liteuart_port *uart;
3931da81e55SFilip Kokosinski 	struct uart_port *port;
3941da81e55SFilip Kokosinski 	int baud = 115200;
3951da81e55SFilip Kokosinski 	int bits = 8;
3961da81e55SFilip Kokosinski 	int parity = 'n';
3971da81e55SFilip Kokosinski 	int flow = 'n';
3981da81e55SFilip Kokosinski 
3991da81e55SFilip Kokosinski 	uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index);
4001da81e55SFilip Kokosinski 	if (!uart)
4011da81e55SFilip Kokosinski 		return -ENODEV;
4021da81e55SFilip Kokosinski 
4031da81e55SFilip Kokosinski 	port = &uart->port;
4041da81e55SFilip Kokosinski 	if (!port->membase)
4051da81e55SFilip Kokosinski 		return -ENODEV;
4061da81e55SFilip Kokosinski 
4071da81e55SFilip Kokosinski 	if (options)
4081da81e55SFilip Kokosinski 		uart_parse_options(options, &baud, &parity, &bits, &flow);
4091da81e55SFilip Kokosinski 
4101da81e55SFilip Kokosinski 	return uart_set_options(port, co, baud, parity, bits, flow);
4111da81e55SFilip Kokosinski }
4121da81e55SFilip Kokosinski 
4131da81e55SFilip Kokosinski static struct console liteuart_console = {
4142696216bSGabriel Somlo 	.name = KBUILD_MODNAME,
4151da81e55SFilip Kokosinski 	.write = liteuart_console_write,
4161da81e55SFilip Kokosinski 	.device = uart_console_device,
4171da81e55SFilip Kokosinski 	.setup = liteuart_console_setup,
4181da81e55SFilip Kokosinski 	.flags = CON_PRINTBUFFER,
4191da81e55SFilip Kokosinski 	.index = -1,
4201da81e55SFilip Kokosinski 	.data = &liteuart_driver,
4211da81e55SFilip Kokosinski };
4221da81e55SFilip Kokosinski 
liteuart_console_init(void)4231da81e55SFilip Kokosinski static int __init liteuart_console_init(void)
4241da81e55SFilip Kokosinski {
4251da81e55SFilip Kokosinski 	register_console(&liteuart_console);
4261da81e55SFilip Kokosinski 
4271da81e55SFilip Kokosinski 	return 0;
4281da81e55SFilip Kokosinski }
4291da81e55SFilip Kokosinski console_initcall(liteuart_console_init);
4304bc2bd5aSStafford Horne 
early_liteuart_write(struct console * console,const char * s,unsigned int count)4314bc2bd5aSStafford Horne static void early_liteuart_write(struct console *console, const char *s,
4324bc2bd5aSStafford Horne 				    unsigned int count)
4334bc2bd5aSStafford Horne {
4344bc2bd5aSStafford Horne 	struct earlycon_device *device = console->data;
4354bc2bd5aSStafford Horne 	struct uart_port *port = &device->port;
4364bc2bd5aSStafford Horne 
4374bc2bd5aSStafford Horne 	uart_console_write(port, s, count, liteuart_putchar);
4384bc2bd5aSStafford Horne }
4394bc2bd5aSStafford Horne 
early_liteuart_setup(struct earlycon_device * device,const char * options)4404bc2bd5aSStafford Horne static int __init early_liteuart_setup(struct earlycon_device *device,
4414bc2bd5aSStafford Horne 				       const char *options)
4424bc2bd5aSStafford Horne {
4434bc2bd5aSStafford Horne 	if (!device->port.membase)
4444bc2bd5aSStafford Horne 		return -ENODEV;
4454bc2bd5aSStafford Horne 
4464bc2bd5aSStafford Horne 	device->con->write = early_liteuart_write;
4474bc2bd5aSStafford Horne 	return 0;
4484bc2bd5aSStafford Horne }
4494bc2bd5aSStafford Horne 
4504bc2bd5aSStafford Horne OF_EARLYCON_DECLARE(liteuart, "litex,liteuart", early_liteuart_setup);
4511da81e55SFilip Kokosinski #endif /* CONFIG_SERIAL_LITEUART_CONSOLE */
4521da81e55SFilip Kokosinski 
liteuart_init(void)4531da81e55SFilip Kokosinski static int __init liteuart_init(void)
4541da81e55SFilip Kokosinski {
4551da81e55SFilip Kokosinski 	int res;
4561da81e55SFilip Kokosinski 
4571da81e55SFilip Kokosinski 	res = uart_register_driver(&liteuart_driver);
4581da81e55SFilip Kokosinski 	if (res)
4591da81e55SFilip Kokosinski 		return res;
4601da81e55SFilip Kokosinski 
4611da81e55SFilip Kokosinski 	res = platform_driver_register(&liteuart_platform_driver);
462b9f5a18aSGabriel Somlo 	if (res)
4631da81e55SFilip Kokosinski 		uart_unregister_driver(&liteuart_driver);
4641da81e55SFilip Kokosinski 
465b9f5a18aSGabriel Somlo 	return res;
4661da81e55SFilip Kokosinski }
4671da81e55SFilip Kokosinski 
liteuart_exit(void)4681da81e55SFilip Kokosinski static void __exit liteuart_exit(void)
4691da81e55SFilip Kokosinski {
4701da81e55SFilip Kokosinski 	platform_driver_unregister(&liteuart_platform_driver);
4711da81e55SFilip Kokosinski 	uart_unregister_driver(&liteuart_driver);
4721da81e55SFilip Kokosinski }
4731da81e55SFilip Kokosinski 
4741da81e55SFilip Kokosinski module_init(liteuart_init);
4751da81e55SFilip Kokosinski module_exit(liteuart_exit);
4761da81e55SFilip Kokosinski 
4771da81e55SFilip Kokosinski MODULE_AUTHOR("Antmicro <www.antmicro.com>");
4781da81e55SFilip Kokosinski MODULE_DESCRIPTION("LiteUART serial driver");
4791da81e55SFilip Kokosinski MODULE_LICENSE("GPL v2");
4801da81e55SFilip Kokosinski MODULE_ALIAS("platform:liteuart");
481