xref: /openbmc/linux/drivers/tty/serial/ar933x_uart.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2d57f341bSGabor Juhos /*
3d57f341bSGabor Juhos  *  Atheros AR933X SoC built-in UART driver
4d57f341bSGabor Juhos  *
5d57f341bSGabor Juhos  *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
6d57f341bSGabor Juhos  *
7d57f341bSGabor Juhos  *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
8d57f341bSGabor Juhos  */
9d57f341bSGabor Juhos 
10d57f341bSGabor Juhos #include <linux/module.h>
11d57f341bSGabor Juhos #include <linux/ioport.h>
12d57f341bSGabor Juhos #include <linux/init.h>
13d57f341bSGabor Juhos #include <linux/console.h>
14d57f341bSGabor Juhos #include <linux/sysrq.h>
15d57f341bSGabor Juhos #include <linux/delay.h>
169be1064fSDaniel Golle #include <linux/gpio/consumer.h>
17d57f341bSGabor Juhos #include <linux/platform_device.h>
18dd910d98SGabor Juhos #include <linux/of.h>
19dd910d98SGabor Juhos #include <linux/of_platform.h>
20d57f341bSGabor Juhos #include <linux/tty.h>
21d57f341bSGabor Juhos #include <linux/tty_flip.h>
22d57f341bSGabor Juhos #include <linux/serial_core.h>
23d57f341bSGabor Juhos #include <linux/serial.h>
24d57f341bSGabor Juhos #include <linux/slab.h>
25d57f341bSGabor Juhos #include <linux/io.h>
26d57f341bSGabor Juhos #include <linux/irq.h>
2715ef17f6SGabor Juhos #include <linux/clk.h>
28d57f341bSGabor Juhos 
292dff8ad9SGabor Juhos #include <asm/div64.h>
302dff8ad9SGabor Juhos 
31d57f341bSGabor Juhos #include <asm/mach-ath79/ar933x_uart.h>
32d57f341bSGabor Juhos 
339be1064fSDaniel Golle #include "serial_mctrl_gpio.h"
349be1064fSDaniel Golle 
35d57f341bSGabor Juhos #define DRIVER_NAME "ar933x-uart"
36d57f341bSGabor Juhos 
372dff8ad9SGabor Juhos #define AR933X_UART_MAX_SCALE	0xff
382dff8ad9SGabor Juhos #define AR933X_UART_MAX_STEP	0xffff
392dff8ad9SGabor Juhos 
402dff8ad9SGabor Juhos #define AR933X_UART_MIN_BAUD	300
412dff8ad9SGabor Juhos #define AR933X_UART_MAX_BAUD	3000000
422dff8ad9SGabor Juhos 
43d57f341bSGabor Juhos #define AR933X_DUMMY_STATUS_RD	0x01
44d57f341bSGabor Juhos 
45d57f341bSGabor Juhos static struct uart_driver ar933x_uart_driver;
46d57f341bSGabor Juhos 
47d57f341bSGabor Juhos struct ar933x_uart_port {
48d57f341bSGabor Juhos 	struct uart_port	port;
49d57f341bSGabor Juhos 	unsigned int		ier;	/* shadow Interrupt Enable Register */
502dff8ad9SGabor Juhos 	unsigned int		min_baud;
512dff8ad9SGabor Juhos 	unsigned int		max_baud;
5215ef17f6SGabor Juhos 	struct clk		*clk;
539be1064fSDaniel Golle 	struct mctrl_gpios	*gpios;
549be1064fSDaniel Golle 	struct gpio_desc	*rts_gpiod;
55d57f341bSGabor Juhos };
56d57f341bSGabor Juhos 
ar933x_uart_read(struct ar933x_uart_port * up,int offset)57d57f341bSGabor Juhos static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
58d57f341bSGabor Juhos 					    int offset)
59d57f341bSGabor Juhos {
60d57f341bSGabor Juhos 	return readl(up->port.membase + offset);
61d57f341bSGabor Juhos }
62d57f341bSGabor Juhos 
ar933x_uart_write(struct ar933x_uart_port * up,int offset,unsigned int value)63d57f341bSGabor Juhos static inline void ar933x_uart_write(struct ar933x_uart_port *up,
64d57f341bSGabor Juhos 				     int offset, unsigned int value)
65d57f341bSGabor Juhos {
66d57f341bSGabor Juhos 	writel(value, up->port.membase + offset);
67d57f341bSGabor Juhos }
68d57f341bSGabor Juhos 
ar933x_uart_rmw(struct ar933x_uart_port * up,unsigned int offset,unsigned int mask,unsigned int val)69d57f341bSGabor Juhos static inline void ar933x_uart_rmw(struct ar933x_uart_port *up,
70d57f341bSGabor Juhos 				  unsigned int offset,
71d57f341bSGabor Juhos 				  unsigned int mask,
72d57f341bSGabor Juhos 				  unsigned int val)
73d57f341bSGabor Juhos {
74d57f341bSGabor Juhos 	unsigned int t;
75d57f341bSGabor Juhos 
76d57f341bSGabor Juhos 	t = ar933x_uart_read(up, offset);
77d57f341bSGabor Juhos 	t &= ~mask;
78d57f341bSGabor Juhos 	t |= val;
79d57f341bSGabor Juhos 	ar933x_uart_write(up, offset, t);
80d57f341bSGabor Juhos }
81d57f341bSGabor Juhos 
ar933x_uart_rmw_set(struct ar933x_uart_port * up,unsigned int offset,unsigned int val)82d57f341bSGabor Juhos static inline void ar933x_uart_rmw_set(struct ar933x_uart_port *up,
83d57f341bSGabor Juhos 				       unsigned int offset,
84d57f341bSGabor Juhos 				       unsigned int val)
85d57f341bSGabor Juhos {
86d57f341bSGabor Juhos 	ar933x_uart_rmw(up, offset, 0, val);
87d57f341bSGabor Juhos }
88d57f341bSGabor Juhos 
ar933x_uart_rmw_clear(struct ar933x_uart_port * up,unsigned int offset,unsigned int val)89d57f341bSGabor Juhos static inline void ar933x_uart_rmw_clear(struct ar933x_uart_port *up,
90d57f341bSGabor Juhos 					 unsigned int offset,
91d57f341bSGabor Juhos 					 unsigned int val)
92d57f341bSGabor Juhos {
93d57f341bSGabor Juhos 	ar933x_uart_rmw(up, offset, val, 0);
94d57f341bSGabor Juhos }
95d57f341bSGabor Juhos 
ar933x_uart_start_tx_interrupt(struct ar933x_uart_port * up)96d57f341bSGabor Juhos static inline void ar933x_uart_start_tx_interrupt(struct ar933x_uart_port *up)
97d57f341bSGabor Juhos {
98d57f341bSGabor Juhos 	up->ier |= AR933X_UART_INT_TX_EMPTY;
99d57f341bSGabor Juhos 	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
100d57f341bSGabor Juhos }
101d57f341bSGabor Juhos 
ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port * up)102d57f341bSGabor Juhos static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up)
103d57f341bSGabor Juhos {
104d57f341bSGabor Juhos 	up->ier &= ~AR933X_UART_INT_TX_EMPTY;
105d57f341bSGabor Juhos 	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
106d57f341bSGabor Juhos }
107d57f341bSGabor Juhos 
ar933x_uart_start_rx_interrupt(struct ar933x_uart_port * up)1089be1064fSDaniel Golle static inline void ar933x_uart_start_rx_interrupt(struct ar933x_uart_port *up)
1099be1064fSDaniel Golle {
1109be1064fSDaniel Golle 	up->ier |= AR933X_UART_INT_RX_VALID;
1119be1064fSDaniel Golle 	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
1129be1064fSDaniel Golle }
1139be1064fSDaniel Golle 
ar933x_uart_stop_rx_interrupt(struct ar933x_uart_port * up)1149be1064fSDaniel Golle static inline void ar933x_uart_stop_rx_interrupt(struct ar933x_uart_port *up)
1159be1064fSDaniel Golle {
1169be1064fSDaniel Golle 	up->ier &= ~AR933X_UART_INT_RX_VALID;
1179be1064fSDaniel Golle 	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
1189be1064fSDaniel Golle }
1199be1064fSDaniel Golle 
ar933x_uart_putc(struct ar933x_uart_port * up,int ch)120d57f341bSGabor Juhos static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch)
121d57f341bSGabor Juhos {
122d57f341bSGabor Juhos 	unsigned int rdata;
123d57f341bSGabor Juhos 
124d57f341bSGabor Juhos 	rdata = ch & AR933X_UART_DATA_TX_RX_MASK;
125d57f341bSGabor Juhos 	rdata |= AR933X_UART_DATA_TX_CSR;
126d57f341bSGabor Juhos 	ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata);
127d57f341bSGabor Juhos }
128d57f341bSGabor Juhos 
ar933x_uart_tx_empty(struct uart_port * port)129d57f341bSGabor Juhos static unsigned int ar933x_uart_tx_empty(struct uart_port *port)
130d57f341bSGabor Juhos {
131f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
132f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
133d57f341bSGabor Juhos 	unsigned long flags;
134d57f341bSGabor Juhos 	unsigned int rdata;
135d57f341bSGabor Juhos 
136d57f341bSGabor Juhos 	spin_lock_irqsave(&up->port.lock, flags);
137d57f341bSGabor Juhos 	rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
138d57f341bSGabor Juhos 	spin_unlock_irqrestore(&up->port.lock, flags);
139d57f341bSGabor Juhos 
140d57f341bSGabor Juhos 	return (rdata & AR933X_UART_DATA_TX_CSR) ? 0 : TIOCSER_TEMT;
141d57f341bSGabor Juhos }
142d57f341bSGabor Juhos 
ar933x_uart_get_mctrl(struct uart_port * port)143d57f341bSGabor Juhos static unsigned int ar933x_uart_get_mctrl(struct uart_port *port)
144d57f341bSGabor Juhos {
1459be1064fSDaniel Golle 	struct ar933x_uart_port *up =
1469be1064fSDaniel Golle 		container_of(port, struct ar933x_uart_port, port);
1479be1064fSDaniel Golle 	int ret = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
1489be1064fSDaniel Golle 
1499be1064fSDaniel Golle 	mctrl_gpio_get(up->gpios, &ret);
1509be1064fSDaniel Golle 
1519be1064fSDaniel Golle 	return ret;
152d57f341bSGabor Juhos }
153d57f341bSGabor Juhos 
ar933x_uart_set_mctrl(struct uart_port * port,unsigned int mctrl)154d57f341bSGabor Juhos static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
155d57f341bSGabor Juhos {
1569be1064fSDaniel Golle 	struct ar933x_uart_port *up =
1579be1064fSDaniel Golle 		container_of(port, struct ar933x_uart_port, port);
1589be1064fSDaniel Golle 
1599be1064fSDaniel Golle 	mctrl_gpio_set(up->gpios, mctrl);
160d57f341bSGabor Juhos }
161d57f341bSGabor Juhos 
ar933x_uart_start_tx(struct uart_port * port)162d57f341bSGabor Juhos static void ar933x_uart_start_tx(struct uart_port *port)
163d57f341bSGabor Juhos {
164f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
165f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
166d57f341bSGabor Juhos 
167d57f341bSGabor Juhos 	ar933x_uart_start_tx_interrupt(up);
168d57f341bSGabor Juhos }
169d57f341bSGabor Juhos 
ar933x_uart_wait_tx_complete(struct ar933x_uart_port * up)1709be1064fSDaniel Golle static void ar933x_uart_wait_tx_complete(struct ar933x_uart_port *up)
1719be1064fSDaniel Golle {
1729be1064fSDaniel Golle 	unsigned int status;
1739be1064fSDaniel Golle 	unsigned int timeout = 60000;
1749be1064fSDaniel Golle 
1759be1064fSDaniel Golle 	/* Wait up to 60ms for the character(s) to be sent. */
1769be1064fSDaniel Golle 	do {
1779be1064fSDaniel Golle 		status = ar933x_uart_read(up, AR933X_UART_CS_REG);
1789be1064fSDaniel Golle 		if (--timeout == 0)
1799be1064fSDaniel Golle 			break;
1809be1064fSDaniel Golle 		udelay(1);
1819be1064fSDaniel Golle 	} while (status & AR933X_UART_CS_TX_BUSY);
1829be1064fSDaniel Golle 
1839be1064fSDaniel Golle 	if (timeout == 0)
1849be1064fSDaniel Golle 		dev_err(up->port.dev, "waiting for TX timed out\n");
1859be1064fSDaniel Golle }
1869be1064fSDaniel Golle 
ar933x_uart_rx_flush(struct ar933x_uart_port * up)1879be1064fSDaniel Golle static void ar933x_uart_rx_flush(struct ar933x_uart_port *up)
1889be1064fSDaniel Golle {
1899be1064fSDaniel Golle 	unsigned int status;
1909be1064fSDaniel Golle 
1919be1064fSDaniel Golle 	/* clear RX_VALID interrupt */
1929be1064fSDaniel Golle 	ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_RX_VALID);
1939be1064fSDaniel Golle 
1949be1064fSDaniel Golle 	/* remove characters from the RX FIFO */
1959be1064fSDaniel Golle 	do {
1969be1064fSDaniel Golle 		ar933x_uart_write(up, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR);
1979be1064fSDaniel Golle 		status = ar933x_uart_read(up, AR933X_UART_DATA_REG);
1989be1064fSDaniel Golle 	} while (status & AR933X_UART_DATA_RX_CSR);
1999be1064fSDaniel Golle }
2009be1064fSDaniel Golle 
ar933x_uart_stop_tx(struct uart_port * port)201d57f341bSGabor Juhos static void ar933x_uart_stop_tx(struct uart_port *port)
202d57f341bSGabor Juhos {
203f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
204f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
205d57f341bSGabor Juhos 
206d57f341bSGabor Juhos 	ar933x_uart_stop_tx_interrupt(up);
207d57f341bSGabor Juhos }
208d57f341bSGabor Juhos 
ar933x_uart_stop_rx(struct uart_port * port)209d57f341bSGabor Juhos static void ar933x_uart_stop_rx(struct uart_port *port)
210d57f341bSGabor Juhos {
211f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
212f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
213d57f341bSGabor Juhos 
2149be1064fSDaniel Golle 	ar933x_uart_stop_rx_interrupt(up);
215d57f341bSGabor Juhos }
216d57f341bSGabor Juhos 
ar933x_uart_break_ctl(struct uart_port * port,int break_state)217d57f341bSGabor Juhos static void ar933x_uart_break_ctl(struct uart_port *port, int break_state)
218d57f341bSGabor Juhos {
219f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
220f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
221d57f341bSGabor Juhos 	unsigned long flags;
222d57f341bSGabor Juhos 
223d57f341bSGabor Juhos 	spin_lock_irqsave(&up->port.lock, flags);
224d57f341bSGabor Juhos 	if (break_state == -1)
225d57f341bSGabor Juhos 		ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
226d57f341bSGabor Juhos 				    AR933X_UART_CS_TX_BREAK);
227d57f341bSGabor Juhos 	else
228d57f341bSGabor Juhos 		ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
229d57f341bSGabor Juhos 				      AR933X_UART_CS_TX_BREAK);
230d57f341bSGabor Juhos 	spin_unlock_irqrestore(&up->port.lock, flags);
231d57f341bSGabor Juhos }
232d57f341bSGabor Juhos 
2332dff8ad9SGabor Juhos /*
2342dff8ad9SGabor Juhos  * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
2352dff8ad9SGabor Juhos  */
ar933x_uart_get_baud(unsigned int clk,unsigned int scale,unsigned int step)2362dff8ad9SGabor Juhos static unsigned long ar933x_uart_get_baud(unsigned int clk,
2372dff8ad9SGabor Juhos 					  unsigned int scale,
2382dff8ad9SGabor Juhos 					  unsigned int step)
2392dff8ad9SGabor Juhos {
2402dff8ad9SGabor Juhos 	u64 t;
2412dff8ad9SGabor Juhos 	u32 div;
2422dff8ad9SGabor Juhos 
2432dff8ad9SGabor Juhos 	div = (2 << 16) * (scale + 1);
2442dff8ad9SGabor Juhos 	t = clk;
2452dff8ad9SGabor Juhos 	t *= step;
2462dff8ad9SGabor Juhos 	t += (div / 2);
2472dff8ad9SGabor Juhos 	do_div(t, div);
2482dff8ad9SGabor Juhos 
2492dff8ad9SGabor Juhos 	return t;
2502dff8ad9SGabor Juhos }
2512dff8ad9SGabor Juhos 
ar933x_uart_get_scale_step(unsigned int clk,unsigned int baud,unsigned int * scale,unsigned int * step)2522dff8ad9SGabor Juhos static void ar933x_uart_get_scale_step(unsigned int clk,
2532dff8ad9SGabor Juhos 				       unsigned int baud,
2542dff8ad9SGabor Juhos 				       unsigned int *scale,
2552dff8ad9SGabor Juhos 				       unsigned int *step)
2562dff8ad9SGabor Juhos {
2572dff8ad9SGabor Juhos 	unsigned int tscale;
2582dff8ad9SGabor Juhos 	long min_diff;
2592dff8ad9SGabor Juhos 
2602dff8ad9SGabor Juhos 	*scale = 0;
2612dff8ad9SGabor Juhos 	*step = 0;
2622dff8ad9SGabor Juhos 
2632dff8ad9SGabor Juhos 	min_diff = baud;
2642dff8ad9SGabor Juhos 	for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
2652dff8ad9SGabor Juhos 		u64 tstep;
2662dff8ad9SGabor Juhos 		int diff;
2672dff8ad9SGabor Juhos 
2682dff8ad9SGabor Juhos 		tstep = baud * (tscale + 1);
2692dff8ad9SGabor Juhos 		tstep *= (2 << 16);
2702dff8ad9SGabor Juhos 		do_div(tstep, clk);
2712dff8ad9SGabor Juhos 
2722dff8ad9SGabor Juhos 		if (tstep > AR933X_UART_MAX_STEP)
2732dff8ad9SGabor Juhos 			break;
2742dff8ad9SGabor Juhos 
2752dff8ad9SGabor Juhos 		diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
2762dff8ad9SGabor Juhos 		if (diff < min_diff) {
2772dff8ad9SGabor Juhos 			min_diff = diff;
2782dff8ad9SGabor Juhos 			*scale = tscale;
2792dff8ad9SGabor Juhos 			*step = tstep;
2802dff8ad9SGabor Juhos 		}
2812dff8ad9SGabor Juhos 	}
2822dff8ad9SGabor Juhos }
2832dff8ad9SGabor Juhos 
ar933x_uart_set_termios(struct uart_port * port,struct ktermios * new,const struct ktermios * old)284d57f341bSGabor Juhos static void ar933x_uart_set_termios(struct uart_port *port,
285d57f341bSGabor Juhos 				    struct ktermios *new,
286bec5b814SIlpo Järvinen 				    const struct ktermios *old)
287d57f341bSGabor Juhos {
288f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
289f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
290d57f341bSGabor Juhos 	unsigned int cs;
291d57f341bSGabor Juhos 	unsigned long flags;
2922dff8ad9SGabor Juhos 	unsigned int baud, scale, step;
293d57f341bSGabor Juhos 
294d57f341bSGabor Juhos 	/* Only CS8 is supported */
295d57f341bSGabor Juhos 	new->c_cflag &= ~CSIZE;
296d57f341bSGabor Juhos 	new->c_cflag |= CS8;
297d57f341bSGabor Juhos 
298d57f341bSGabor Juhos 	/* Only one stop bit is supported */
299d57f341bSGabor Juhos 	new->c_cflag &= ~CSTOPB;
300d57f341bSGabor Juhos 
301d57f341bSGabor Juhos 	cs = 0;
302d57f341bSGabor Juhos 	if (new->c_cflag & PARENB) {
303d57f341bSGabor Juhos 		if (!(new->c_cflag & PARODD))
304d57f341bSGabor Juhos 			cs |= AR933X_UART_CS_PARITY_EVEN;
305d57f341bSGabor Juhos 		else
306d57f341bSGabor Juhos 			cs |= AR933X_UART_CS_PARITY_ODD;
307d57f341bSGabor Juhos 	} else {
308d57f341bSGabor Juhos 		cs |= AR933X_UART_CS_PARITY_NONE;
309d57f341bSGabor Juhos 	}
310d57f341bSGabor Juhos 
311d57f341bSGabor Juhos 	/* Mark/space parity is not supported */
312d57f341bSGabor Juhos 	new->c_cflag &= ~CMSPAR;
313d57f341bSGabor Juhos 
3142dff8ad9SGabor Juhos 	baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud);
3152dff8ad9SGabor Juhos 	ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step);
316d57f341bSGabor Juhos 
317d57f341bSGabor Juhos 	/*
318d57f341bSGabor Juhos 	 * Ok, we're now changing the port state. Do it with
319d57f341bSGabor Juhos 	 * interrupts disabled.
320d57f341bSGabor Juhos 	 */
321d57f341bSGabor Juhos 	spin_lock_irqsave(&up->port.lock, flags);
322d57f341bSGabor Juhos 
3232dff8ad9SGabor Juhos 	/* disable the UART */
3242dff8ad9SGabor Juhos 	ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
3252dff8ad9SGabor Juhos 		      AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S);
3262dff8ad9SGabor Juhos 
327d57f341bSGabor Juhos 	/* Update the per-port timeout. */
328d57f341bSGabor Juhos 	uart_update_timeout(port, new->c_cflag, baud);
329d57f341bSGabor Juhos 
330d57f341bSGabor Juhos 	up->port.ignore_status_mask = 0;
331d57f341bSGabor Juhos 
332d57f341bSGabor Juhos 	/* ignore all characters if CREAD is not set */
333d57f341bSGabor Juhos 	if ((new->c_cflag & CREAD) == 0)
334d57f341bSGabor Juhos 		up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;
335d57f341bSGabor Juhos 
336d57f341bSGabor Juhos 	ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
3372dff8ad9SGabor Juhos 			  scale << AR933X_UART_CLOCK_SCALE_S | step);
338d57f341bSGabor Juhos 
339d57f341bSGabor Juhos 	/* setup configuration register */
340d57f341bSGabor Juhos 	ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);
341d57f341bSGabor Juhos 
342d57f341bSGabor Juhos 	/* enable host interrupt */
343d57f341bSGabor Juhos 	ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
344d57f341bSGabor Juhos 			    AR933X_UART_CS_HOST_INT_EN);
345d57f341bSGabor Juhos 
34687c5cbf7SDaniel Golle 	/* enable RX and TX ready overide */
34787c5cbf7SDaniel Golle 	ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
34887c5cbf7SDaniel Golle 		AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);
34987c5cbf7SDaniel Golle 
3502dff8ad9SGabor Juhos 	/* reenable the UART */
3512dff8ad9SGabor Juhos 	ar933x_uart_rmw(up, AR933X_UART_CS_REG,
3522dff8ad9SGabor Juhos 			AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
3532dff8ad9SGabor Juhos 			AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
3542dff8ad9SGabor Juhos 
355d57f341bSGabor Juhos 	spin_unlock_irqrestore(&up->port.lock, flags);
356d57f341bSGabor Juhos 
357d57f341bSGabor Juhos 	if (tty_termios_baud_rate(new))
358d57f341bSGabor Juhos 		tty_termios_encode_baud_rate(new, baud, baud);
359d57f341bSGabor Juhos }
360d57f341bSGabor Juhos 
ar933x_uart_rx_chars(struct ar933x_uart_port * up)361d57f341bSGabor Juhos static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
362d57f341bSGabor Juhos {
36392a19f9cSJiri Slaby 	struct tty_port *port = &up->port.state->port;
364d57f341bSGabor Juhos 	int max_count = 256;
365d57f341bSGabor Juhos 
366d57f341bSGabor Juhos 	do {
367d57f341bSGabor Juhos 		unsigned int rdata;
368d57f341bSGabor Juhos 		unsigned char ch;
369d57f341bSGabor Juhos 
370d57f341bSGabor Juhos 		rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
371d57f341bSGabor Juhos 		if ((rdata & AR933X_UART_DATA_RX_CSR) == 0)
372d57f341bSGabor Juhos 			break;
373d57f341bSGabor Juhos 
374d57f341bSGabor Juhos 		/* remove the character from the FIFO */
375d57f341bSGabor Juhos 		ar933x_uart_write(up, AR933X_UART_DATA_REG,
376d57f341bSGabor Juhos 				  AR933X_UART_DATA_RX_CSR);
377d57f341bSGabor Juhos 
378d57f341bSGabor Juhos 		up->port.icount.rx++;
379d57f341bSGabor Juhos 		ch = rdata & AR933X_UART_DATA_TX_RX_MASK;
380d57f341bSGabor Juhos 
381d57f341bSGabor Juhos 		if (uart_handle_sysrq_char(&up->port, ch))
382d57f341bSGabor Juhos 			continue;
383d57f341bSGabor Juhos 
384d57f341bSGabor Juhos 		if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0)
38592a19f9cSJiri Slaby 			tty_insert_flip_char(port, ch, TTY_NORMAL);
386d57f341bSGabor Juhos 	} while (max_count-- > 0);
387d57f341bSGabor Juhos 
3882e124b4aSJiri Slaby 	tty_flip_buffer_push(port);
389d57f341bSGabor Juhos }
390d57f341bSGabor Juhos 
ar933x_uart_tx_chars(struct ar933x_uart_port * up)391d57f341bSGabor Juhos static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
392d57f341bSGabor Juhos {
393d57f341bSGabor Juhos 	struct circ_buf *xmit = &up->port.state->xmit;
3949be1064fSDaniel Golle 	struct serial_rs485 *rs485conf = &up->port.rs485;
395d57f341bSGabor Juhos 	int count;
3969be1064fSDaniel Golle 	bool half_duplex_send = false;
397d57f341bSGabor Juhos 
398d57f341bSGabor Juhos 	if (uart_tx_stopped(&up->port))
399d57f341bSGabor Juhos 		return;
400d57f341bSGabor Juhos 
4019be1064fSDaniel Golle 	if ((rs485conf->flags & SER_RS485_ENABLED) &&
4029be1064fSDaniel Golle 	    (up->port.x_char || !uart_circ_empty(xmit))) {
4039be1064fSDaniel Golle 		ar933x_uart_stop_rx_interrupt(up);
4049be1064fSDaniel Golle 		gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND));
4059be1064fSDaniel Golle 		half_duplex_send = true;
4069be1064fSDaniel Golle 	}
4079be1064fSDaniel Golle 
408d57f341bSGabor Juhos 	count = up->port.fifosize;
409d57f341bSGabor Juhos 	do {
410d57f341bSGabor Juhos 		unsigned int rdata;
411d57f341bSGabor Juhos 
412d57f341bSGabor Juhos 		rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
413d57f341bSGabor Juhos 		if ((rdata & AR933X_UART_DATA_TX_CSR) == 0)
414d57f341bSGabor Juhos 			break;
415d57f341bSGabor Juhos 
416d57f341bSGabor Juhos 		if (up->port.x_char) {
417d57f341bSGabor Juhos 			ar933x_uart_putc(up, up->port.x_char);
418d57f341bSGabor Juhos 			up->port.icount.tx++;
419d57f341bSGabor Juhos 			up->port.x_char = 0;
420d57f341bSGabor Juhos 			continue;
421d57f341bSGabor Juhos 		}
422d57f341bSGabor Juhos 
423d57f341bSGabor Juhos 		if (uart_circ_empty(xmit))
424d57f341bSGabor Juhos 			break;
425d57f341bSGabor Juhos 
426d57f341bSGabor Juhos 		ar933x_uart_putc(up, xmit->buf[xmit->tail]);
427d57f341bSGabor Juhos 
428d29d947cSIlpo Järvinen 		uart_xmit_advance(&up->port, 1);
429d57f341bSGabor Juhos 	} while (--count > 0);
430d57f341bSGabor Juhos 
431d57f341bSGabor Juhos 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
432d57f341bSGabor Juhos 		uart_write_wakeup(&up->port);
433d57f341bSGabor Juhos 
4349be1064fSDaniel Golle 	if (!uart_circ_empty(xmit)) {
435d57f341bSGabor Juhos 		ar933x_uart_start_tx_interrupt(up);
4369be1064fSDaniel Golle 	} else if (half_duplex_send) {
4379be1064fSDaniel Golle 		ar933x_uart_wait_tx_complete(up);
4389be1064fSDaniel Golle 		ar933x_uart_rx_flush(up);
4399be1064fSDaniel Golle 		ar933x_uart_start_rx_interrupt(up);
4409be1064fSDaniel Golle 		gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND));
4419be1064fSDaniel Golle 	}
442d57f341bSGabor Juhos }
443d57f341bSGabor Juhos 
ar933x_uart_interrupt(int irq,void * dev_id)444d57f341bSGabor Juhos static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
445d57f341bSGabor Juhos {
446d57f341bSGabor Juhos 	struct ar933x_uart_port *up = dev_id;
447d57f341bSGabor Juhos 	unsigned int status;
448d57f341bSGabor Juhos 
449d57f341bSGabor Juhos 	status = ar933x_uart_read(up, AR933X_UART_CS_REG);
450d57f341bSGabor Juhos 	if ((status & AR933X_UART_CS_HOST_INT) == 0)
451d57f341bSGabor Juhos 		return IRQ_NONE;
452d57f341bSGabor Juhos 
453d57f341bSGabor Juhos 	spin_lock(&up->port.lock);
454d57f341bSGabor Juhos 
455d57f341bSGabor Juhos 	status = ar933x_uart_read(up, AR933X_UART_INT_REG);
456d57f341bSGabor Juhos 	status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG);
457d57f341bSGabor Juhos 
458d57f341bSGabor Juhos 	if (status & AR933X_UART_INT_RX_VALID) {
459d57f341bSGabor Juhos 		ar933x_uart_write(up, AR933X_UART_INT_REG,
460d57f341bSGabor Juhos 				  AR933X_UART_INT_RX_VALID);
461d57f341bSGabor Juhos 		ar933x_uart_rx_chars(up);
462d57f341bSGabor Juhos 	}
463d57f341bSGabor Juhos 
464d57f341bSGabor Juhos 	if (status & AR933X_UART_INT_TX_EMPTY) {
465d57f341bSGabor Juhos 		ar933x_uart_write(up, AR933X_UART_INT_REG,
466d57f341bSGabor Juhos 				  AR933X_UART_INT_TX_EMPTY);
467d57f341bSGabor Juhos 		ar933x_uart_stop_tx_interrupt(up);
468d57f341bSGabor Juhos 		ar933x_uart_tx_chars(up);
469d57f341bSGabor Juhos 	}
470d57f341bSGabor Juhos 
471d57f341bSGabor Juhos 	spin_unlock(&up->port.lock);
472d57f341bSGabor Juhos 
473d57f341bSGabor Juhos 	return IRQ_HANDLED;
474d57f341bSGabor Juhos }
475d57f341bSGabor Juhos 
ar933x_uart_startup(struct uart_port * port)476d57f341bSGabor Juhos static int ar933x_uart_startup(struct uart_port *port)
477d57f341bSGabor Juhos {
478f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
479f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
480d57f341bSGabor Juhos 	unsigned long flags;
481d57f341bSGabor Juhos 	int ret;
482d57f341bSGabor Juhos 
483d57f341bSGabor Juhos 	ret = request_irq(up->port.irq, ar933x_uart_interrupt,
484d57f341bSGabor Juhos 			  up->port.irqflags, dev_name(up->port.dev), up);
485d57f341bSGabor Juhos 	if (ret)
486d57f341bSGabor Juhos 		return ret;
487d57f341bSGabor Juhos 
488d57f341bSGabor Juhos 	spin_lock_irqsave(&up->port.lock, flags);
489d57f341bSGabor Juhos 
490d57f341bSGabor Juhos 	/* Enable HOST interrupts */
491d57f341bSGabor Juhos 	ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
492d57f341bSGabor Juhos 			    AR933X_UART_CS_HOST_INT_EN);
493d57f341bSGabor Juhos 
49487c5cbf7SDaniel Golle 	/* enable RX and TX ready overide */
49587c5cbf7SDaniel Golle 	ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
49687c5cbf7SDaniel Golle 		AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);
49787c5cbf7SDaniel Golle 
498d57f341bSGabor Juhos 	/* Enable RX interrupts */
4999be1064fSDaniel Golle 	ar933x_uart_start_rx_interrupt(up);
500d57f341bSGabor Juhos 
501d57f341bSGabor Juhos 	spin_unlock_irqrestore(&up->port.lock, flags);
502d57f341bSGabor Juhos 
503d57f341bSGabor Juhos 	return 0;
504d57f341bSGabor Juhos }
505d57f341bSGabor Juhos 
ar933x_uart_shutdown(struct uart_port * port)506d57f341bSGabor Juhos static void ar933x_uart_shutdown(struct uart_port *port)
507d57f341bSGabor Juhos {
508f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
509f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
510d57f341bSGabor Juhos 
511d57f341bSGabor Juhos 	/* Disable all interrupts */
512d57f341bSGabor Juhos 	up->ier = 0;
513d57f341bSGabor Juhos 	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
514d57f341bSGabor Juhos 
515d57f341bSGabor Juhos 	/* Disable break condition */
516d57f341bSGabor Juhos 	ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
517d57f341bSGabor Juhos 			      AR933X_UART_CS_TX_BREAK);
518d57f341bSGabor Juhos 
519d57f341bSGabor Juhos 	free_irq(up->port.irq, up);
520d57f341bSGabor Juhos }
521d57f341bSGabor Juhos 
ar933x_uart_type(struct uart_port * port)522d57f341bSGabor Juhos static const char *ar933x_uart_type(struct uart_port *port)
523d57f341bSGabor Juhos {
524d57f341bSGabor Juhos 	return (port->type == PORT_AR933X) ? "AR933X UART" : NULL;
525d57f341bSGabor Juhos }
526d57f341bSGabor Juhos 
ar933x_uart_release_port(struct uart_port * port)527d57f341bSGabor Juhos static void ar933x_uart_release_port(struct uart_port *port)
528d57f341bSGabor Juhos {
529d57f341bSGabor Juhos 	/* Nothing to release ... */
530d57f341bSGabor Juhos }
531d57f341bSGabor Juhos 
ar933x_uart_request_port(struct uart_port * port)532d57f341bSGabor Juhos static int ar933x_uart_request_port(struct uart_port *port)
533d57f341bSGabor Juhos {
534d57f341bSGabor Juhos 	/* UARTs always present */
535d57f341bSGabor Juhos 	return 0;
536d57f341bSGabor Juhos }
537d57f341bSGabor Juhos 
ar933x_uart_config_port(struct uart_port * port,int flags)538d57f341bSGabor Juhos static void ar933x_uart_config_port(struct uart_port *port, int flags)
539d57f341bSGabor Juhos {
540d57f341bSGabor Juhos 	if (flags & UART_CONFIG_TYPE)
541d57f341bSGabor Juhos 		port->type = PORT_AR933X;
542d57f341bSGabor Juhos }
543d57f341bSGabor Juhos 
ar933x_uart_verify_port(struct uart_port * port,struct serial_struct * ser)544d57f341bSGabor Juhos static int ar933x_uart_verify_port(struct uart_port *port,
545d57f341bSGabor Juhos 				   struct serial_struct *ser)
546d57f341bSGabor Juhos {
547f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
548f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
5492dff8ad9SGabor Juhos 
550d57f341bSGabor Juhos 	if (ser->type != PORT_UNKNOWN &&
551d57f341bSGabor Juhos 	    ser->type != PORT_AR933X)
552d57f341bSGabor Juhos 		return -EINVAL;
553d57f341bSGabor Juhos 
554d57f341bSGabor Juhos 	if (ser->irq < 0 || ser->irq >= NR_IRQS)
555d57f341bSGabor Juhos 		return -EINVAL;
556d57f341bSGabor Juhos 
5572dff8ad9SGabor Juhos 	if (ser->baud_base < up->min_baud ||
5582dff8ad9SGabor Juhos 	    ser->baud_base > up->max_baud)
559d57f341bSGabor Juhos 		return -EINVAL;
560d57f341bSGabor Juhos 
561d57f341bSGabor Juhos 	return 0;
562d57f341bSGabor Juhos }
563d57f341bSGabor Juhos 
5642331e068SBhumika Goyal static const struct uart_ops ar933x_uart_ops = {
565d57f341bSGabor Juhos 	.tx_empty	= ar933x_uart_tx_empty,
566d57f341bSGabor Juhos 	.set_mctrl	= ar933x_uart_set_mctrl,
567d57f341bSGabor Juhos 	.get_mctrl	= ar933x_uart_get_mctrl,
568d57f341bSGabor Juhos 	.stop_tx	= ar933x_uart_stop_tx,
569d57f341bSGabor Juhos 	.start_tx	= ar933x_uart_start_tx,
570d57f341bSGabor Juhos 	.stop_rx	= ar933x_uart_stop_rx,
571d57f341bSGabor Juhos 	.break_ctl	= ar933x_uart_break_ctl,
572d57f341bSGabor Juhos 	.startup	= ar933x_uart_startup,
573d57f341bSGabor Juhos 	.shutdown	= ar933x_uart_shutdown,
574d57f341bSGabor Juhos 	.set_termios	= ar933x_uart_set_termios,
575d57f341bSGabor Juhos 	.type		= ar933x_uart_type,
576d57f341bSGabor Juhos 	.release_port	= ar933x_uart_release_port,
577d57f341bSGabor Juhos 	.request_port	= ar933x_uart_request_port,
578d57f341bSGabor Juhos 	.config_port	= ar933x_uart_config_port,
579d57f341bSGabor Juhos 	.verify_port	= ar933x_uart_verify_port,
580d57f341bSGabor Juhos };
581d57f341bSGabor Juhos 
ar933x_config_rs485(struct uart_port * port,struct ktermios * termios,struct serial_rs485 * rs485conf)582ae50bb27SIlpo Järvinen static int ar933x_config_rs485(struct uart_port *port, struct ktermios *termios,
5839be1064fSDaniel Golle 				struct serial_rs485 *rs485conf)
5849be1064fSDaniel Golle {
5853a939433SLukas Wunner 	struct ar933x_uart_port *up =
5863a939433SLukas Wunner 			container_of(port, struct ar933x_uart_port, port);
5873a939433SLukas Wunner 
5883a939433SLukas Wunner 	if (port->rs485.flags & SER_RS485_ENABLED)
5893a939433SLukas Wunner 		gpiod_set_value(up->rts_gpiod,
5903a939433SLukas Wunner 			!!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND));
5913a939433SLukas Wunner 
5929be1064fSDaniel Golle 	return 0;
5939be1064fSDaniel Golle }
5949be1064fSDaniel Golle 
59572ff51d8SPetr Štetiar #ifdef CONFIG_SERIAL_AR933X_CONSOLE
596d57f341bSGabor Juhos static struct ar933x_uart_port *
597d57f341bSGabor Juhos ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS];
598d57f341bSGabor Juhos 
ar933x_uart_wait_xmitr(struct ar933x_uart_port * up)599d57f341bSGabor Juhos static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up)
600d57f341bSGabor Juhos {
601d57f341bSGabor Juhos 	unsigned int status;
602d57f341bSGabor Juhos 	unsigned int timeout = 60000;
603d57f341bSGabor Juhos 
604d57f341bSGabor Juhos 	/* Wait up to 60ms for the character(s) to be sent. */
605d57f341bSGabor Juhos 	do {
606d57f341bSGabor Juhos 		status = ar933x_uart_read(up, AR933X_UART_DATA_REG);
607d57f341bSGabor Juhos 		if (--timeout == 0)
608d57f341bSGabor Juhos 			break;
609d57f341bSGabor Juhos 		udelay(1);
610d57f341bSGabor Juhos 	} while ((status & AR933X_UART_DATA_TX_CSR) == 0);
611d57f341bSGabor Juhos }
612d57f341bSGabor Juhos 
ar933x_uart_console_putchar(struct uart_port * port,unsigned char ch)6133f8bab17SJiri Slaby static void ar933x_uart_console_putchar(struct uart_port *port, unsigned char ch)
614d57f341bSGabor Juhos {
615f9c1b28eSFabian Frederick 	struct ar933x_uart_port *up =
616f9c1b28eSFabian Frederick 		container_of(port, struct ar933x_uart_port, port);
617d57f341bSGabor Juhos 
618d57f341bSGabor Juhos 	ar933x_uart_wait_xmitr(up);
619d57f341bSGabor Juhos 	ar933x_uart_putc(up, ch);
620d57f341bSGabor Juhos }
621d57f341bSGabor Juhos 
ar933x_uart_console_write(struct console * co,const char * s,unsigned int count)622d57f341bSGabor Juhos static void ar933x_uart_console_write(struct console *co, const char *s,
623d57f341bSGabor Juhos 				      unsigned int count)
624d57f341bSGabor Juhos {
625d57f341bSGabor Juhos 	struct ar933x_uart_port *up = ar933x_console_ports[co->index];
626d57f341bSGabor Juhos 	unsigned long flags;
627d57f341bSGabor Juhos 	unsigned int int_en;
628d57f341bSGabor Juhos 	int locked = 1;
629d57f341bSGabor Juhos 
630d57f341bSGabor Juhos 	local_irq_save(flags);
631d57f341bSGabor Juhos 
632d57f341bSGabor Juhos 	if (up->port.sysrq)
633d57f341bSGabor Juhos 		locked = 0;
634d57f341bSGabor Juhos 	else if (oops_in_progress)
635d57f341bSGabor Juhos 		locked = spin_trylock(&up->port.lock);
636d57f341bSGabor Juhos 	else
637d57f341bSGabor Juhos 		spin_lock(&up->port.lock);
638d57f341bSGabor Juhos 
639d57f341bSGabor Juhos 	/*
640d57f341bSGabor Juhos 	 * First save the IER then disable the interrupts
641d57f341bSGabor Juhos 	 */
642d57f341bSGabor Juhos 	int_en = ar933x_uart_read(up, AR933X_UART_INT_EN_REG);
643d57f341bSGabor Juhos 	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0);
644d57f341bSGabor Juhos 
645d57f341bSGabor Juhos 	uart_console_write(&up->port, s, count, ar933x_uart_console_putchar);
646d57f341bSGabor Juhos 
647d57f341bSGabor Juhos 	/*
648d57f341bSGabor Juhos 	 * Finally, wait for transmitter to become empty
649d57f341bSGabor Juhos 	 * and restore the IER
650d57f341bSGabor Juhos 	 */
651d57f341bSGabor Juhos 	ar933x_uart_wait_xmitr(up);
652d57f341bSGabor Juhos 	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, int_en);
653d57f341bSGabor Juhos 
654d57f341bSGabor Juhos 	ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS);
655d57f341bSGabor Juhos 
656d57f341bSGabor Juhos 	if (locked)
657d57f341bSGabor Juhos 		spin_unlock(&up->port.lock);
658d57f341bSGabor Juhos 
659d57f341bSGabor Juhos 	local_irq_restore(flags);
660d57f341bSGabor Juhos }
661d57f341bSGabor Juhos 
ar933x_uart_console_setup(struct console * co,char * options)662d57f341bSGabor Juhos static int ar933x_uart_console_setup(struct console *co, char *options)
663d57f341bSGabor Juhos {
664d57f341bSGabor Juhos 	struct ar933x_uart_port *up;
665d57f341bSGabor Juhos 	int baud = 115200;
666d57f341bSGabor Juhos 	int bits = 8;
667d57f341bSGabor Juhos 	int parity = 'n';
668d57f341bSGabor Juhos 	int flow = 'n';
669d57f341bSGabor Juhos 
670d57f341bSGabor Juhos 	if (co->index < 0 || co->index >= CONFIG_SERIAL_AR933X_NR_UARTS)
671d57f341bSGabor Juhos 		return -EINVAL;
672d57f341bSGabor Juhos 
673d57f341bSGabor Juhos 	up = ar933x_console_ports[co->index];
674d57f341bSGabor Juhos 	if (!up)
675d57f341bSGabor Juhos 		return -ENODEV;
676d57f341bSGabor Juhos 
677d57f341bSGabor Juhos 	if (options)
678d57f341bSGabor Juhos 		uart_parse_options(options, &baud, &parity, &bits, &flow);
679d57f341bSGabor Juhos 
680d57f341bSGabor Juhos 	return uart_set_options(&up->port, co, baud, parity, bits, flow);
681d57f341bSGabor Juhos }
682d57f341bSGabor Juhos 
683d57f341bSGabor Juhos static struct console ar933x_uart_console = {
684d57f341bSGabor Juhos 	.name		= "ttyATH",
685d57f341bSGabor Juhos 	.write		= ar933x_uart_console_write,
686d57f341bSGabor Juhos 	.device		= uart_console_device,
687d57f341bSGabor Juhos 	.setup		= ar933x_uart_console_setup,
688d57f341bSGabor Juhos 	.flags		= CON_PRINTBUFFER,
689d57f341bSGabor Juhos 	.index		= -1,
690d57f341bSGabor Juhos 	.data		= &ar933x_uart_driver,
691d57f341bSGabor Juhos };
69272ff51d8SPetr Štetiar #endif /* CONFIG_SERIAL_AR933X_CONSOLE */
693d57f341bSGabor Juhos 
694d57f341bSGabor Juhos static struct uart_driver ar933x_uart_driver = {
695d57f341bSGabor Juhos 	.owner		= THIS_MODULE,
696d57f341bSGabor Juhos 	.driver_name	= DRIVER_NAME,
697d57f341bSGabor Juhos 	.dev_name	= "ttyATH",
698d57f341bSGabor Juhos 	.nr		= CONFIG_SERIAL_AR933X_NR_UARTS,
69912415535SGabor Juhos 	.cons		= NULL, /* filled in runtime */
700d57f341bSGabor Juhos };
701d57f341bSGabor Juhos 
702e849145eSIlpo Järvinen static const struct serial_rs485 ar933x_no_rs485 = {};
703e849145eSIlpo Järvinen static const struct serial_rs485 ar933x_rs485_supported = {
704e849145eSIlpo Järvinen 	.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
705e849145eSIlpo Järvinen };
706e849145eSIlpo Järvinen 
ar933x_uart_probe(struct platform_device * pdev)7079671f099SBill Pemberton static int ar933x_uart_probe(struct platform_device *pdev)
708d57f341bSGabor Juhos {
709d57f341bSGabor Juhos 	struct ar933x_uart_port *up;
710d57f341bSGabor Juhos 	struct uart_port *port;
711d57f341bSGabor Juhos 	struct resource *mem_res;
712dd910d98SGabor Juhos 	struct device_node *np;
7132dff8ad9SGabor Juhos 	unsigned int baud;
714d57f341bSGabor Juhos 	int id;
715d57f341bSGabor Juhos 	int ret;
7161129a63eSLad Prabhakar 	int irq;
717d57f341bSGabor Juhos 
718dd910d98SGabor Juhos 	np = pdev->dev.of_node;
71997f2645fSMasahiro Yamada 	if (IS_ENABLED(CONFIG_OF) && np) {
720dd910d98SGabor Juhos 		id = of_alias_get_id(np, "serial");
721dd910d98SGabor Juhos 		if (id < 0) {
722dd910d98SGabor Juhos 			dev_err(&pdev->dev, "unable to get alias id, err=%d\n",
723dd910d98SGabor Juhos 				id);
724dd910d98SGabor Juhos 			return id;
725dd910d98SGabor Juhos 		}
726dd910d98SGabor Juhos 	} else {
727d57f341bSGabor Juhos 		id = pdev->id;
728d57f341bSGabor Juhos 		if (id == -1)
729d57f341bSGabor Juhos 			id = 0;
730dd910d98SGabor Juhos 	}
731d57f341bSGabor Juhos 
732bb8478d7SAxel Lin 	if (id >= CONFIG_SERIAL_AR933X_NR_UARTS)
733d57f341bSGabor Juhos 		return -EINVAL;
734d57f341bSGabor Juhos 
7351129a63eSLad Prabhakar 	irq = platform_get_irq(pdev, 0);
7361129a63eSLad Prabhakar 	if (irq < 0)
7371129a63eSLad Prabhakar 		return irq;
738d57f341bSGabor Juhos 
739a324e4deSGabor Juhos 	up = devm_kzalloc(&pdev->dev, sizeof(struct ar933x_uart_port),
740a324e4deSGabor Juhos 			  GFP_KERNEL);
741d57f341bSGabor Juhos 	if (!up)
742d57f341bSGabor Juhos 		return -ENOMEM;
743d57f341bSGabor Juhos 
74415ef17f6SGabor Juhos 	up->clk = devm_clk_get(&pdev->dev, "uart");
74515ef17f6SGabor Juhos 	if (IS_ERR(up->clk)) {
74615ef17f6SGabor Juhos 		dev_err(&pdev->dev, "unable to get UART clock\n");
74715ef17f6SGabor Juhos 		return PTR_ERR(up->clk);
74815ef17f6SGabor Juhos 	}
74915ef17f6SGabor Juhos 
750d57f341bSGabor Juhos 	port = &up->port;
751a324e4deSGabor Juhos 
752*7449c16dSYangtao Li 	port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
753a324e4deSGabor Juhos 	if (IS_ERR(port->membase))
754a324e4deSGabor Juhos 		return PTR_ERR(port->membase);
755a324e4deSGabor Juhos 
75615ef17f6SGabor Juhos 	ret = clk_prepare_enable(up->clk);
75715ef17f6SGabor Juhos 	if (ret)
75815ef17f6SGabor Juhos 		return ret;
75915ef17f6SGabor Juhos 
76015ef17f6SGabor Juhos 	port->uartclk = clk_get_rate(up->clk);
76115ef17f6SGabor Juhos 	if (!port->uartclk) {
76215ef17f6SGabor Juhos 		ret = -EINVAL;
76315ef17f6SGabor Juhos 		goto err_disable_clk;
76415ef17f6SGabor Juhos 	}
76515ef17f6SGabor Juhos 
766d57f341bSGabor Juhos 	port->mapbase = mem_res->start;
767d57f341bSGabor Juhos 	port->line = id;
7681129a63eSLad Prabhakar 	port->irq = irq;
769d57f341bSGabor Juhos 	port->dev = &pdev->dev;
770d57f341bSGabor Juhos 	port->type = PORT_AR933X;
771d57f341bSGabor Juhos 	port->iotype = UPIO_MEM32;
772d57f341bSGabor Juhos 
773d57f341bSGabor Juhos 	port->regshift = 2;
774d57f341bSGabor Juhos 	port->fifosize = AR933X_UART_FIFO_SIZE;
775d57f341bSGabor Juhos 	port->ops = &ar933x_uart_ops;
7769be1064fSDaniel Golle 	port->rs485_config = ar933x_config_rs485;
7770139da50SIlpo Järvinen 	port->rs485_supported = ar933x_rs485_supported;
778d57f341bSGabor Juhos 
7792dff8ad9SGabor Juhos 	baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
7802dff8ad9SGabor Juhos 	up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
7812dff8ad9SGabor Juhos 
7822dff8ad9SGabor Juhos 	baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
7832dff8ad9SGabor Juhos 	up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
7842dff8ad9SGabor Juhos 
785c150c0f3SLukas Wunner 	ret = uart_get_rs485_mode(port);
786c150c0f3SLukas Wunner 	if (ret)
787c150c0f3SLukas Wunner 		goto err_disable_clk;
788c150c0f3SLukas Wunner 
7899be1064fSDaniel Golle 	up->gpios = mctrl_gpio_init(port, 0);
790425af483SZheng Zengkai 	if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) {
791425af483SZheng Zengkai 		ret = PTR_ERR(up->gpios);
792425af483SZheng Zengkai 		goto err_disable_clk;
793425af483SZheng Zengkai 	}
7949be1064fSDaniel Golle 
7959be1064fSDaniel Golle 	up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS);
7969be1064fSDaniel Golle 
797996fd3cfSLino Sanfilippo 	if (!up->rts_gpiod) {
798996fd3cfSLino Sanfilippo 		port->rs485_supported = ar933x_no_rs485;
799996fd3cfSLino Sanfilippo 		if (port->rs485.flags & SER_RS485_ENABLED) {
8009be1064fSDaniel Golle 			dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
8019be1064fSDaniel Golle 			port->rs485.flags &= ~SER_RS485_ENABLED;
802996fd3cfSLino Sanfilippo 		}
8039be1064fSDaniel Golle 	}
8049be1064fSDaniel Golle 
80572ff51d8SPetr Štetiar #ifdef CONFIG_SERIAL_AR933X_CONSOLE
80672ff51d8SPetr Štetiar 	ar933x_console_ports[up->port.line] = up;
80772ff51d8SPetr Štetiar #endif
808d57f341bSGabor Juhos 
809d57f341bSGabor Juhos 	ret = uart_add_one_port(&ar933x_uart_driver, &up->port);
810d57f341bSGabor Juhos 	if (ret)
81115ef17f6SGabor Juhos 		goto err_disable_clk;
812d57f341bSGabor Juhos 
813d57f341bSGabor Juhos 	platform_set_drvdata(pdev, up);
814d57f341bSGabor Juhos 	return 0;
81515ef17f6SGabor Juhos 
81615ef17f6SGabor Juhos err_disable_clk:
81715ef17f6SGabor Juhos 	clk_disable_unprepare(up->clk);
81815ef17f6SGabor Juhos 	return ret;
819d57f341bSGabor Juhos }
820d57f341bSGabor Juhos 
ar933x_uart_remove(struct platform_device * pdev)821ae8d8a14SBill Pemberton static int ar933x_uart_remove(struct platform_device *pdev)
822d57f341bSGabor Juhos {
823d57f341bSGabor Juhos 	struct ar933x_uart_port *up;
824d57f341bSGabor Juhos 
825d57f341bSGabor Juhos 	up = platform_get_drvdata(pdev);
826d57f341bSGabor Juhos 
82715ef17f6SGabor Juhos 	if (up) {
828d57f341bSGabor Juhos 		uart_remove_one_port(&ar933x_uart_driver, &up->port);
82915ef17f6SGabor Juhos 		clk_disable_unprepare(up->clk);
83015ef17f6SGabor Juhos 	}
831d57f341bSGabor Juhos 
832d57f341bSGabor Juhos 	return 0;
833d57f341bSGabor Juhos }
834d57f341bSGabor Juhos 
835dd910d98SGabor Juhos #ifdef CONFIG_OF
836dd910d98SGabor Juhos static const struct of_device_id ar933x_uart_of_ids[] = {
837dd910d98SGabor Juhos 	{ .compatible = "qca,ar9330-uart" },
838dd910d98SGabor Juhos 	{},
839dd910d98SGabor Juhos };
840dd910d98SGabor Juhos MODULE_DEVICE_TABLE(of, ar933x_uart_of_ids);
841dd910d98SGabor Juhos #endif
842dd910d98SGabor Juhos 
843d57f341bSGabor Juhos static struct platform_driver ar933x_uart_platform_driver = {
844d57f341bSGabor Juhos 	.probe		= ar933x_uart_probe,
8452d47b716SBill Pemberton 	.remove		= ar933x_uart_remove,
846d57f341bSGabor Juhos 	.driver		= {
847d57f341bSGabor Juhos 		.name		= DRIVER_NAME,
848dd910d98SGabor Juhos 		.of_match_table = of_match_ptr(ar933x_uart_of_ids),
849d57f341bSGabor Juhos 	},
850d57f341bSGabor Juhos };
851d57f341bSGabor Juhos 
ar933x_uart_init(void)852d57f341bSGabor Juhos static int __init ar933x_uart_init(void)
853d57f341bSGabor Juhos {
854d57f341bSGabor Juhos 	int ret;
855d57f341bSGabor Juhos 
85672ff51d8SPetr Štetiar #ifdef CONFIG_SERIAL_AR933X_CONSOLE
85712415535SGabor Juhos 	ar933x_uart_driver.cons = &ar933x_uart_console;
85872ff51d8SPetr Štetiar #endif
85912415535SGabor Juhos 
860d57f341bSGabor Juhos 	ret = uart_register_driver(&ar933x_uart_driver);
861d57f341bSGabor Juhos 	if (ret)
862d57f341bSGabor Juhos 		goto err_out;
863d57f341bSGabor Juhos 
864d57f341bSGabor Juhos 	ret = platform_driver_register(&ar933x_uart_platform_driver);
865d57f341bSGabor Juhos 	if (ret)
866d57f341bSGabor Juhos 		goto err_unregister_uart_driver;
867d57f341bSGabor Juhos 
868d57f341bSGabor Juhos 	return 0;
869d57f341bSGabor Juhos 
870d57f341bSGabor Juhos err_unregister_uart_driver:
871d57f341bSGabor Juhos 	uart_unregister_driver(&ar933x_uart_driver);
872d57f341bSGabor Juhos err_out:
873d57f341bSGabor Juhos 	return ret;
874d57f341bSGabor Juhos }
875d57f341bSGabor Juhos 
ar933x_uart_exit(void)876d57f341bSGabor Juhos static void __exit ar933x_uart_exit(void)
877d57f341bSGabor Juhos {
878d57f341bSGabor Juhos 	platform_driver_unregister(&ar933x_uart_platform_driver);
879d57f341bSGabor Juhos 	uart_unregister_driver(&ar933x_uart_driver);
880d57f341bSGabor Juhos }
881d57f341bSGabor Juhos 
882d57f341bSGabor Juhos module_init(ar933x_uart_init);
883d57f341bSGabor Juhos module_exit(ar933x_uart_exit);
884d57f341bSGabor Juhos 
885d57f341bSGabor Juhos MODULE_DESCRIPTION("Atheros AR933X UART driver");
886d57f341bSGabor Juhos MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
887d57f341bSGabor Juhos MODULE_LICENSE("GPL v2");
888d57f341bSGabor Juhos MODULE_ALIAS("platform:" DRIVER_NAME);
889