xref: /openbmc/linux/drivers/tty/serial/rda-uart.c (revision 3d4d8384)
1c10b1332SManivannan Sadhasivam // SPDX-License-Identifier: GPL-2.0+
2c10b1332SManivannan Sadhasivam /*
3c10b1332SManivannan Sadhasivam  * RDA8810PL serial device driver
4c10b1332SManivannan Sadhasivam  *
5c10b1332SManivannan Sadhasivam  * Copyright RDA Microelectronics Company Limited
6c10b1332SManivannan Sadhasivam  * Copyright (c) 2017 Andreas Färber
7c10b1332SManivannan Sadhasivam  * Copyright (c) 2018 Manivannan Sadhasivam
8c10b1332SManivannan Sadhasivam  */
9c10b1332SManivannan Sadhasivam 
10c10b1332SManivannan Sadhasivam #include <linux/clk.h>
11c10b1332SManivannan Sadhasivam #include <linux/console.h>
12c10b1332SManivannan Sadhasivam #include <linux/delay.h>
13c10b1332SManivannan Sadhasivam #include <linux/io.h>
14c10b1332SManivannan Sadhasivam #include <linux/module.h>
15c10b1332SManivannan Sadhasivam #include <linux/of.h>
16c10b1332SManivannan Sadhasivam #include <linux/platform_device.h>
17c10b1332SManivannan Sadhasivam #include <linux/serial.h>
18c10b1332SManivannan Sadhasivam #include <linux/serial_core.h>
19c10b1332SManivannan Sadhasivam #include <linux/tty.h>
20c10b1332SManivannan Sadhasivam #include <linux/tty_flip.h>
21c10b1332SManivannan Sadhasivam 
22c10b1332SManivannan Sadhasivam #define RDA_UART_PORT_NUM 3
23c10b1332SManivannan Sadhasivam #define RDA_UART_DEV_NAME "ttyRDA"
24c10b1332SManivannan Sadhasivam 
25c10b1332SManivannan Sadhasivam #define RDA_UART_CTRL		0x00
26c10b1332SManivannan Sadhasivam #define RDA_UART_STATUS		0x04
27c10b1332SManivannan Sadhasivam #define RDA_UART_RXTX_BUFFER	0x08
28c10b1332SManivannan Sadhasivam #define RDA_UART_IRQ_MASK	0x0c
29c10b1332SManivannan Sadhasivam #define RDA_UART_IRQ_CAUSE	0x10
30c10b1332SManivannan Sadhasivam #define RDA_UART_IRQ_TRIGGERS	0x14
31c10b1332SManivannan Sadhasivam #define RDA_UART_CMD_SET	0x18
32c10b1332SManivannan Sadhasivam #define RDA_UART_CMD_CLR	0x1c
33c10b1332SManivannan Sadhasivam 
34c10b1332SManivannan Sadhasivam /* UART_CTRL Bits */
35c10b1332SManivannan Sadhasivam #define RDA_UART_ENABLE			BIT(0)
36c10b1332SManivannan Sadhasivam #define RDA_UART_DBITS_8		BIT(1)
37c10b1332SManivannan Sadhasivam #define RDA_UART_TX_SBITS_2		BIT(2)
38c10b1332SManivannan Sadhasivam #define RDA_UART_PARITY_EN		BIT(3)
39c10b1332SManivannan Sadhasivam #define RDA_UART_PARITY(x)		(((x) & 0x3) << 4)
40c10b1332SManivannan Sadhasivam #define RDA_UART_PARITY_ODD		RDA_UART_PARITY(0)
41c10b1332SManivannan Sadhasivam #define RDA_UART_PARITY_EVEN		RDA_UART_PARITY(1)
42c10b1332SManivannan Sadhasivam #define RDA_UART_PARITY_SPACE		RDA_UART_PARITY(2)
43c10b1332SManivannan Sadhasivam #define RDA_UART_PARITY_MARK		RDA_UART_PARITY(3)
44c10b1332SManivannan Sadhasivam #define RDA_UART_DIV_MODE		BIT(20)
45c10b1332SManivannan Sadhasivam #define RDA_UART_IRDA_EN		BIT(21)
46c10b1332SManivannan Sadhasivam #define RDA_UART_DMA_EN			BIT(22)
47c10b1332SManivannan Sadhasivam #define RDA_UART_FLOW_CNT_EN		BIT(23)
48c10b1332SManivannan Sadhasivam #define RDA_UART_LOOP_BACK_EN		BIT(24)
49c10b1332SManivannan Sadhasivam #define RDA_UART_RX_LOCK_ERR		BIT(25)
50c10b1332SManivannan Sadhasivam #define RDA_UART_RX_BREAK_LEN(x)	(((x) & 0xf) << 28)
51c10b1332SManivannan Sadhasivam 
52c10b1332SManivannan Sadhasivam /* UART_STATUS Bits */
53c10b1332SManivannan Sadhasivam #define RDA_UART_RX_FIFO(x)		(((x) & 0x7f) << 0)
54c10b1332SManivannan Sadhasivam #define RDA_UART_RX_FIFO_MASK		(0x7f << 0)
55c10b1332SManivannan Sadhasivam #define RDA_UART_TX_FIFO(x)		(((x) & 0x1f) << 8)
56c10b1332SManivannan Sadhasivam #define RDA_UART_TX_FIFO_MASK		(0x1f << 8)
57c10b1332SManivannan Sadhasivam #define RDA_UART_TX_ACTIVE		BIT(14)
58c10b1332SManivannan Sadhasivam #define RDA_UART_RX_ACTIVE		BIT(15)
59c10b1332SManivannan Sadhasivam #define RDA_UART_RX_OVERFLOW_ERR	BIT(16)
60c10b1332SManivannan Sadhasivam #define RDA_UART_TX_OVERFLOW_ERR	BIT(17)
61c10b1332SManivannan Sadhasivam #define RDA_UART_RX_PARITY_ERR		BIT(18)
62c10b1332SManivannan Sadhasivam #define RDA_UART_RX_FRAMING_ERR		BIT(19)
63c10b1332SManivannan Sadhasivam #define RDA_UART_RX_BREAK_INT		BIT(20)
64c10b1332SManivannan Sadhasivam #define RDA_UART_DCTS			BIT(24)
65c10b1332SManivannan Sadhasivam #define RDA_UART_CTS			BIT(25)
66c10b1332SManivannan Sadhasivam #define RDA_UART_DTR			BIT(28)
67c10b1332SManivannan Sadhasivam #define RDA_UART_CLK_ENABLED		BIT(31)
68c10b1332SManivannan Sadhasivam 
69c10b1332SManivannan Sadhasivam /* UART_RXTX_BUFFER Bits */
70c10b1332SManivannan Sadhasivam #define RDA_UART_RX_DATA(x)		(((x) & 0xff) << 0)
71c10b1332SManivannan Sadhasivam #define RDA_UART_TX_DATA(x)		(((x) & 0xff) << 0)
72c10b1332SManivannan Sadhasivam 
73c10b1332SManivannan Sadhasivam /* UART_IRQ_MASK Bits */
74c10b1332SManivannan Sadhasivam #define RDA_UART_TX_MODEM_STATUS	BIT(0)
75c10b1332SManivannan Sadhasivam #define RDA_UART_RX_DATA_AVAILABLE	BIT(1)
76c10b1332SManivannan Sadhasivam #define RDA_UART_TX_DATA_NEEDED		BIT(2)
77c10b1332SManivannan Sadhasivam #define RDA_UART_RX_TIMEOUT		BIT(3)
78c10b1332SManivannan Sadhasivam #define RDA_UART_RX_LINE_ERR		BIT(4)
79c10b1332SManivannan Sadhasivam #define RDA_UART_TX_DMA_DONE		BIT(5)
80c10b1332SManivannan Sadhasivam #define RDA_UART_RX_DMA_DONE		BIT(6)
81c10b1332SManivannan Sadhasivam #define RDA_UART_RX_DMA_TIMEOUT		BIT(7)
82c10b1332SManivannan Sadhasivam #define RDA_UART_DTR_RISE		BIT(8)
83c10b1332SManivannan Sadhasivam #define RDA_UART_DTR_FALL		BIT(9)
84c10b1332SManivannan Sadhasivam 
85c10b1332SManivannan Sadhasivam /* UART_IRQ_CAUSE Bits */
86c10b1332SManivannan Sadhasivam #define RDA_UART_TX_MODEM_STATUS_U	BIT(16)
87c10b1332SManivannan Sadhasivam #define RDA_UART_RX_DATA_AVAILABLE_U	BIT(17)
88c10b1332SManivannan Sadhasivam #define RDA_UART_TX_DATA_NEEDED_U	BIT(18)
89c10b1332SManivannan Sadhasivam #define RDA_UART_RX_TIMEOUT_U		BIT(19)
90c10b1332SManivannan Sadhasivam #define RDA_UART_RX_LINE_ERR_U		BIT(20)
91c10b1332SManivannan Sadhasivam #define RDA_UART_TX_DMA_DONE_U		BIT(21)
92c10b1332SManivannan Sadhasivam #define RDA_UART_RX_DMA_DONE_U		BIT(22)
93c10b1332SManivannan Sadhasivam #define RDA_UART_RX_DMA_TIMEOUT_U	BIT(23)
94c10b1332SManivannan Sadhasivam #define RDA_UART_DTR_RISE_U		BIT(24)
95c10b1332SManivannan Sadhasivam #define RDA_UART_DTR_FALL_U		BIT(25)
96c10b1332SManivannan Sadhasivam 
97c10b1332SManivannan Sadhasivam /* UART_TRIGGERS Bits */
98c10b1332SManivannan Sadhasivam #define RDA_UART_RX_TRIGGER(x)		(((x) & 0x1f) << 0)
99c10b1332SManivannan Sadhasivam #define RDA_UART_TX_TRIGGER(x)		(((x) & 0xf) << 8)
100c10b1332SManivannan Sadhasivam #define RDA_UART_AFC_LEVEL(x)		(((x) & 0x1f) << 16)
101c10b1332SManivannan Sadhasivam 
102c10b1332SManivannan Sadhasivam /* UART_CMD_SET Bits */
103c10b1332SManivannan Sadhasivam #define RDA_UART_RI			BIT(0)
104c10b1332SManivannan Sadhasivam #define RDA_UART_DCD			BIT(1)
105c10b1332SManivannan Sadhasivam #define RDA_UART_DSR			BIT(2)
106c10b1332SManivannan Sadhasivam #define RDA_UART_TX_BREAK_CONTROL	BIT(3)
107c10b1332SManivannan Sadhasivam #define RDA_UART_TX_FINISH_N_WAIT	BIT(4)
108c10b1332SManivannan Sadhasivam #define RDA_UART_RTS			BIT(5)
109c10b1332SManivannan Sadhasivam #define RDA_UART_RX_FIFO_RESET		BIT(6)
110c10b1332SManivannan Sadhasivam #define RDA_UART_TX_FIFO_RESET		BIT(7)
111c10b1332SManivannan Sadhasivam 
112c10b1332SManivannan Sadhasivam #define RDA_UART_TX_FIFO_SIZE	16
113c10b1332SManivannan Sadhasivam 
114c10b1332SManivannan Sadhasivam static struct uart_driver rda_uart_driver;
115c10b1332SManivannan Sadhasivam 
116c10b1332SManivannan Sadhasivam struct rda_uart_port {
117c10b1332SManivannan Sadhasivam 	struct uart_port port;
118c10b1332SManivannan Sadhasivam 	struct clk *clk;
119c10b1332SManivannan Sadhasivam };
120c10b1332SManivannan Sadhasivam 
121c10b1332SManivannan Sadhasivam #define to_rda_uart_port(port) container_of(port, struct rda_uart_port, port)
122c10b1332SManivannan Sadhasivam 
123c10b1332SManivannan Sadhasivam static struct rda_uart_port *rda_uart_ports[RDA_UART_PORT_NUM];
124c10b1332SManivannan Sadhasivam 
rda_uart_write(struct uart_port * port,u32 val,unsigned int off)125c10b1332SManivannan Sadhasivam static inline void rda_uart_write(struct uart_port *port, u32 val,
126c10b1332SManivannan Sadhasivam 				  unsigned int off)
127c10b1332SManivannan Sadhasivam {
128c10b1332SManivannan Sadhasivam 	writel(val, port->membase + off);
129c10b1332SManivannan Sadhasivam }
130c10b1332SManivannan Sadhasivam 
rda_uart_read(struct uart_port * port,unsigned int off)131c10b1332SManivannan Sadhasivam static inline u32 rda_uart_read(struct uart_port *port, unsigned int off)
132c10b1332SManivannan Sadhasivam {
133c10b1332SManivannan Sadhasivam 	return readl(port->membase + off);
134c10b1332SManivannan Sadhasivam }
135c10b1332SManivannan Sadhasivam 
rda_uart_tx_empty(struct uart_port * port)136c10b1332SManivannan Sadhasivam static unsigned int rda_uart_tx_empty(struct uart_port *port)
137c10b1332SManivannan Sadhasivam {
138c10b1332SManivannan Sadhasivam 	unsigned long flags;
139c10b1332SManivannan Sadhasivam 	unsigned int ret;
140c10b1332SManivannan Sadhasivam 	u32 val;
141c10b1332SManivannan Sadhasivam 
142c10b1332SManivannan Sadhasivam 	spin_lock_irqsave(&port->lock, flags);
143c10b1332SManivannan Sadhasivam 
144c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_STATUS);
145c10b1332SManivannan Sadhasivam 	ret = (val & RDA_UART_TX_FIFO_MASK) ? TIOCSER_TEMT : 0;
146c10b1332SManivannan Sadhasivam 
147c10b1332SManivannan Sadhasivam 	spin_unlock_irqrestore(&port->lock, flags);
148c10b1332SManivannan Sadhasivam 
149c10b1332SManivannan Sadhasivam 	return ret;
150c10b1332SManivannan Sadhasivam }
151c10b1332SManivannan Sadhasivam 
rda_uart_get_mctrl(struct uart_port * port)152c10b1332SManivannan Sadhasivam static unsigned int rda_uart_get_mctrl(struct uart_port *port)
153c10b1332SManivannan Sadhasivam {
154c10b1332SManivannan Sadhasivam 	unsigned int mctrl = 0;
155c10b1332SManivannan Sadhasivam 	u32 cmd_set, status;
156c10b1332SManivannan Sadhasivam 
157c10b1332SManivannan Sadhasivam 	cmd_set = rda_uart_read(port, RDA_UART_CMD_SET);
158c10b1332SManivannan Sadhasivam 	status = rda_uart_read(port, RDA_UART_STATUS);
159c10b1332SManivannan Sadhasivam 	if (cmd_set & RDA_UART_RTS)
160c10b1332SManivannan Sadhasivam 		mctrl |= TIOCM_RTS;
161c10b1332SManivannan Sadhasivam 	if (!(status & RDA_UART_CTS))
162c10b1332SManivannan Sadhasivam 		mctrl |= TIOCM_CTS;
163c10b1332SManivannan Sadhasivam 
164c10b1332SManivannan Sadhasivam 	return mctrl;
165c10b1332SManivannan Sadhasivam }
166c10b1332SManivannan Sadhasivam 
rda_uart_set_mctrl(struct uart_port * port,unsigned int mctrl)167c10b1332SManivannan Sadhasivam static void rda_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
168c10b1332SManivannan Sadhasivam {
169c10b1332SManivannan Sadhasivam 	u32 val;
170c10b1332SManivannan Sadhasivam 
171c10b1332SManivannan Sadhasivam 	if (mctrl & TIOCM_RTS) {
172c10b1332SManivannan Sadhasivam 		val = rda_uart_read(port, RDA_UART_CMD_SET);
173c10b1332SManivannan Sadhasivam 		rda_uart_write(port, (val | RDA_UART_RTS), RDA_UART_CMD_SET);
174c10b1332SManivannan Sadhasivam 	} else {
175c10b1332SManivannan Sadhasivam 		/* Clear RTS to stop to receive. */
176c10b1332SManivannan Sadhasivam 		val = rda_uart_read(port, RDA_UART_CMD_CLR);
177c10b1332SManivannan Sadhasivam 		rda_uart_write(port, (val | RDA_UART_RTS), RDA_UART_CMD_CLR);
178c10b1332SManivannan Sadhasivam 	}
179c10b1332SManivannan Sadhasivam 
180c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_CTRL);
181c10b1332SManivannan Sadhasivam 
182c10b1332SManivannan Sadhasivam 	if (mctrl & TIOCM_LOOP)
183c10b1332SManivannan Sadhasivam 		val |= RDA_UART_LOOP_BACK_EN;
184c10b1332SManivannan Sadhasivam 	else
185c10b1332SManivannan Sadhasivam 		val &= ~RDA_UART_LOOP_BACK_EN;
186c10b1332SManivannan Sadhasivam 
187c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_CTRL);
188c10b1332SManivannan Sadhasivam }
189c10b1332SManivannan Sadhasivam 
rda_uart_stop_tx(struct uart_port * port)190c10b1332SManivannan Sadhasivam static void rda_uart_stop_tx(struct uart_port *port)
191c10b1332SManivannan Sadhasivam {
192c10b1332SManivannan Sadhasivam 	u32 val;
193c10b1332SManivannan Sadhasivam 
194c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_IRQ_MASK);
195c10b1332SManivannan Sadhasivam 	val &= ~RDA_UART_TX_DATA_NEEDED;
196c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_IRQ_MASK);
197c10b1332SManivannan Sadhasivam 
198c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_CMD_SET);
199c10b1332SManivannan Sadhasivam 	val |= RDA_UART_TX_FIFO_RESET;
200c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_CMD_SET);
201c10b1332SManivannan Sadhasivam }
202c10b1332SManivannan Sadhasivam 
rda_uart_stop_rx(struct uart_port * port)203c10b1332SManivannan Sadhasivam static void rda_uart_stop_rx(struct uart_port *port)
204c10b1332SManivannan Sadhasivam {
205c10b1332SManivannan Sadhasivam 	u32 val;
206c10b1332SManivannan Sadhasivam 
207c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_IRQ_MASK);
208c10b1332SManivannan Sadhasivam 	val &= ~(RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT);
209c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_IRQ_MASK);
210c10b1332SManivannan Sadhasivam 
211c10b1332SManivannan Sadhasivam 	/* Read Rx buffer before reset to avoid Rx timeout interrupt */
212c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_RXTX_BUFFER);
213c10b1332SManivannan Sadhasivam 
214c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_CMD_SET);
215c10b1332SManivannan Sadhasivam 	val |= RDA_UART_RX_FIFO_RESET;
216c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_CMD_SET);
217c10b1332SManivannan Sadhasivam }
218c10b1332SManivannan Sadhasivam 
rda_uart_start_tx(struct uart_port * port)219c10b1332SManivannan Sadhasivam static void rda_uart_start_tx(struct uart_port *port)
220c10b1332SManivannan Sadhasivam {
221c10b1332SManivannan Sadhasivam 	u32 val;
222c10b1332SManivannan Sadhasivam 
223c10b1332SManivannan Sadhasivam 	if (uart_tx_stopped(port)) {
224c10b1332SManivannan Sadhasivam 		rda_uart_stop_tx(port);
225c10b1332SManivannan Sadhasivam 		return;
226c10b1332SManivannan Sadhasivam 	}
227c10b1332SManivannan Sadhasivam 
228c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_IRQ_MASK);
229c10b1332SManivannan Sadhasivam 	val |= RDA_UART_TX_DATA_NEEDED;
230c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_IRQ_MASK);
231c10b1332SManivannan Sadhasivam }
232c10b1332SManivannan Sadhasivam 
rda_uart_change_baudrate(struct rda_uart_port * rda_port,unsigned long baud)233c10b1332SManivannan Sadhasivam static void rda_uart_change_baudrate(struct rda_uart_port *rda_port,
234c10b1332SManivannan Sadhasivam 				     unsigned long baud)
235c10b1332SManivannan Sadhasivam {
236c10b1332SManivannan Sadhasivam 	clk_set_rate(rda_port->clk, baud * 8);
237c10b1332SManivannan Sadhasivam }
238c10b1332SManivannan Sadhasivam 
rda_uart_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)239c10b1332SManivannan Sadhasivam static void rda_uart_set_termios(struct uart_port *port,
240c10b1332SManivannan Sadhasivam 				 struct ktermios *termios,
241bec5b814SIlpo Järvinen 				 const struct ktermios *old)
242c10b1332SManivannan Sadhasivam {
243c10b1332SManivannan Sadhasivam 	struct rda_uart_port *rda_port = to_rda_uart_port(port);
244c10b1332SManivannan Sadhasivam 	unsigned long flags;
245c10b1332SManivannan Sadhasivam 	unsigned int ctrl, cmd_set, cmd_clr, triggers;
246c10b1332SManivannan Sadhasivam 	unsigned int baud;
247c10b1332SManivannan Sadhasivam 	u32 irq_mask;
248c10b1332SManivannan Sadhasivam 
249c10b1332SManivannan Sadhasivam 	spin_lock_irqsave(&port->lock, flags);
250c10b1332SManivannan Sadhasivam 
251c10b1332SManivannan Sadhasivam 	baud = uart_get_baud_rate(port, termios, old, 9600, port->uartclk / 4);
252c10b1332SManivannan Sadhasivam 	rda_uart_change_baudrate(rda_port, baud);
253c10b1332SManivannan Sadhasivam 
254c10b1332SManivannan Sadhasivam 	ctrl = rda_uart_read(port, RDA_UART_CTRL);
255c10b1332SManivannan Sadhasivam 	cmd_set = rda_uart_read(port, RDA_UART_CMD_SET);
256c10b1332SManivannan Sadhasivam 	cmd_clr = rda_uart_read(port, RDA_UART_CMD_CLR);
257c10b1332SManivannan Sadhasivam 
258c10b1332SManivannan Sadhasivam 	switch (termios->c_cflag & CSIZE) {
259c10b1332SManivannan Sadhasivam 	case CS5:
260c10b1332SManivannan Sadhasivam 	case CS6:
261c10b1332SManivannan Sadhasivam 		dev_warn(port->dev, "bit size not supported, using 7 bits\n");
262df561f66SGustavo A. R. Silva 		fallthrough;
263c10b1332SManivannan Sadhasivam 	case CS7:
264c10b1332SManivannan Sadhasivam 		ctrl &= ~RDA_UART_DBITS_8;
265098333a9SIlpo Järvinen 		termios->c_cflag &= ~CSIZE;
266098333a9SIlpo Järvinen 		termios->c_cflag |= CS7;
267c10b1332SManivannan Sadhasivam 		break;
268c10b1332SManivannan Sadhasivam 	default:
269c10b1332SManivannan Sadhasivam 		ctrl |= RDA_UART_DBITS_8;
270c10b1332SManivannan Sadhasivam 		break;
271c10b1332SManivannan Sadhasivam 	}
272c10b1332SManivannan Sadhasivam 
273c10b1332SManivannan Sadhasivam 	/* stop bits */
274c10b1332SManivannan Sadhasivam 	if (termios->c_cflag & CSTOPB)
275c10b1332SManivannan Sadhasivam 		ctrl |= RDA_UART_TX_SBITS_2;
276c10b1332SManivannan Sadhasivam 	else
277c10b1332SManivannan Sadhasivam 		ctrl &= ~RDA_UART_TX_SBITS_2;
278c10b1332SManivannan Sadhasivam 
279c10b1332SManivannan Sadhasivam 	/* parity check */
280c10b1332SManivannan Sadhasivam 	if (termios->c_cflag & PARENB) {
281c10b1332SManivannan Sadhasivam 		ctrl |= RDA_UART_PARITY_EN;
282c10b1332SManivannan Sadhasivam 
283c10b1332SManivannan Sadhasivam 		/* Mark or Space parity */
284c10b1332SManivannan Sadhasivam 		if (termios->c_cflag & CMSPAR) {
285c10b1332SManivannan Sadhasivam 			if (termios->c_cflag & PARODD)
286c10b1332SManivannan Sadhasivam 				ctrl |= RDA_UART_PARITY_MARK;
287c10b1332SManivannan Sadhasivam 			else
288c10b1332SManivannan Sadhasivam 				ctrl |= RDA_UART_PARITY_SPACE;
289c10b1332SManivannan Sadhasivam 		} else if (termios->c_cflag & PARODD) {
290c10b1332SManivannan Sadhasivam 			ctrl |= RDA_UART_PARITY_ODD;
291c10b1332SManivannan Sadhasivam 		} else {
292c10b1332SManivannan Sadhasivam 			ctrl |= RDA_UART_PARITY_EVEN;
293c10b1332SManivannan Sadhasivam 		}
294c10b1332SManivannan Sadhasivam 	} else {
295c10b1332SManivannan Sadhasivam 		ctrl &= ~RDA_UART_PARITY_EN;
296c10b1332SManivannan Sadhasivam 	}
297c10b1332SManivannan Sadhasivam 
298c10b1332SManivannan Sadhasivam 	/* Hardware handshake (RTS/CTS) */
299c10b1332SManivannan Sadhasivam 	if (termios->c_cflag & CRTSCTS) {
300c10b1332SManivannan Sadhasivam 		ctrl   |= RDA_UART_FLOW_CNT_EN;
301c10b1332SManivannan Sadhasivam 		cmd_set |= RDA_UART_RTS;
302c10b1332SManivannan Sadhasivam 	} else {
303c10b1332SManivannan Sadhasivam 		ctrl   &= ~RDA_UART_FLOW_CNT_EN;
304c10b1332SManivannan Sadhasivam 		cmd_clr |= RDA_UART_RTS;
305c10b1332SManivannan Sadhasivam 	}
306c10b1332SManivannan Sadhasivam 
307c10b1332SManivannan Sadhasivam 	ctrl |= RDA_UART_ENABLE;
308c10b1332SManivannan Sadhasivam 	ctrl &= ~RDA_UART_DMA_EN;
309c10b1332SManivannan Sadhasivam 
310c10b1332SManivannan Sadhasivam 	triggers  = (RDA_UART_AFC_LEVEL(20) | RDA_UART_RX_TRIGGER(16));
311c10b1332SManivannan Sadhasivam 	irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK);
312c10b1332SManivannan Sadhasivam 	rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
313c10b1332SManivannan Sadhasivam 
314c10b1332SManivannan Sadhasivam 	rda_uart_write(port, triggers, RDA_UART_IRQ_TRIGGERS);
315c10b1332SManivannan Sadhasivam 	rda_uart_write(port, ctrl, RDA_UART_CTRL);
316c10b1332SManivannan Sadhasivam 	rda_uart_write(port, cmd_set, RDA_UART_CMD_SET);
317c10b1332SManivannan Sadhasivam 	rda_uart_write(port, cmd_clr, RDA_UART_CMD_CLR);
318c10b1332SManivannan Sadhasivam 
319c10b1332SManivannan Sadhasivam 	rda_uart_write(port, irq_mask, RDA_UART_IRQ_MASK);
320c10b1332SManivannan Sadhasivam 
321c10b1332SManivannan Sadhasivam 	/* Don't rewrite B0 */
322c10b1332SManivannan Sadhasivam 	if (tty_termios_baud_rate(termios))
323c10b1332SManivannan Sadhasivam 		tty_termios_encode_baud_rate(termios, baud, baud);
324c10b1332SManivannan Sadhasivam 
325c10b1332SManivannan Sadhasivam 	/* update the per-port timeout */
326c10b1332SManivannan Sadhasivam 	uart_update_timeout(port, termios->c_cflag, baud);
327c10b1332SManivannan Sadhasivam 
328c10b1332SManivannan Sadhasivam 	spin_unlock_irqrestore(&port->lock, flags);
329c10b1332SManivannan Sadhasivam }
330c10b1332SManivannan Sadhasivam 
rda_uart_send_chars(struct uart_port * port)331c10b1332SManivannan Sadhasivam static void rda_uart_send_chars(struct uart_port *port)
332c10b1332SManivannan Sadhasivam {
333c10b1332SManivannan Sadhasivam 	struct circ_buf *xmit = &port->state->xmit;
334c10b1332SManivannan Sadhasivam 	unsigned int ch;
335c10b1332SManivannan Sadhasivam 	u32 val;
336c10b1332SManivannan Sadhasivam 
337c10b1332SManivannan Sadhasivam 	if (uart_tx_stopped(port))
338c10b1332SManivannan Sadhasivam 		return;
339c10b1332SManivannan Sadhasivam 
340c10b1332SManivannan Sadhasivam 	if (port->x_char) {
341c10b1332SManivannan Sadhasivam 		while (!(rda_uart_read(port, RDA_UART_STATUS) &
342c10b1332SManivannan Sadhasivam 			 RDA_UART_TX_FIFO_MASK))
343c10b1332SManivannan Sadhasivam 			cpu_relax();
344c10b1332SManivannan Sadhasivam 
345c10b1332SManivannan Sadhasivam 		rda_uart_write(port, port->x_char, RDA_UART_RXTX_BUFFER);
346c10b1332SManivannan Sadhasivam 		port->icount.tx++;
347c10b1332SManivannan Sadhasivam 		port->x_char = 0;
348c10b1332SManivannan Sadhasivam 	}
349c10b1332SManivannan Sadhasivam 
350c10b1332SManivannan Sadhasivam 	while (rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) {
351c10b1332SManivannan Sadhasivam 		if (uart_circ_empty(xmit))
352c10b1332SManivannan Sadhasivam 			break;
353c10b1332SManivannan Sadhasivam 
354c10b1332SManivannan Sadhasivam 		ch = xmit->buf[xmit->tail];
355c10b1332SManivannan Sadhasivam 		rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER);
356*3d4d8384SIlpo Järvinen 		uart_xmit_advance(port, 1);
357c10b1332SManivannan Sadhasivam 	}
358c10b1332SManivannan Sadhasivam 
359c10b1332SManivannan Sadhasivam 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
360c10b1332SManivannan Sadhasivam 		uart_write_wakeup(port);
361c10b1332SManivannan Sadhasivam 
362c10b1332SManivannan Sadhasivam 	if (!uart_circ_empty(xmit)) {
363c10b1332SManivannan Sadhasivam 		/* Re-enable Tx FIFO interrupt */
364c10b1332SManivannan Sadhasivam 		val = rda_uart_read(port, RDA_UART_IRQ_MASK);
365c10b1332SManivannan Sadhasivam 		val |= RDA_UART_TX_DATA_NEEDED;
366c10b1332SManivannan Sadhasivam 		rda_uart_write(port, val, RDA_UART_IRQ_MASK);
367c10b1332SManivannan Sadhasivam 	}
368c10b1332SManivannan Sadhasivam }
369c10b1332SManivannan Sadhasivam 
rda_uart_receive_chars(struct uart_port * port)370c10b1332SManivannan Sadhasivam static void rda_uart_receive_chars(struct uart_port *port)
371c10b1332SManivannan Sadhasivam {
372c10b1332SManivannan Sadhasivam 	u32 status, val;
373c10b1332SManivannan Sadhasivam 
374c10b1332SManivannan Sadhasivam 	status = rda_uart_read(port, RDA_UART_STATUS);
375c10b1332SManivannan Sadhasivam 	while ((status & RDA_UART_RX_FIFO_MASK)) {
376c10b1332SManivannan Sadhasivam 		char flag = TTY_NORMAL;
377c10b1332SManivannan Sadhasivam 
378c10b1332SManivannan Sadhasivam 		if (status & RDA_UART_RX_PARITY_ERR) {
379c10b1332SManivannan Sadhasivam 			port->icount.parity++;
380c10b1332SManivannan Sadhasivam 			flag = TTY_PARITY;
381c10b1332SManivannan Sadhasivam 		}
382c10b1332SManivannan Sadhasivam 
383c10b1332SManivannan Sadhasivam 		if (status & RDA_UART_RX_FRAMING_ERR) {
384c10b1332SManivannan Sadhasivam 			port->icount.frame++;
385c10b1332SManivannan Sadhasivam 			flag = TTY_FRAME;
386c10b1332SManivannan Sadhasivam 		}
387c10b1332SManivannan Sadhasivam 
388c10b1332SManivannan Sadhasivam 		if (status & RDA_UART_RX_OVERFLOW_ERR) {
389c10b1332SManivannan Sadhasivam 			port->icount.overrun++;
390c10b1332SManivannan Sadhasivam 			flag = TTY_OVERRUN;
391c10b1332SManivannan Sadhasivam 		}
392c10b1332SManivannan Sadhasivam 
393c10b1332SManivannan Sadhasivam 		val = rda_uart_read(port, RDA_UART_RXTX_BUFFER);
394c10b1332SManivannan Sadhasivam 		val &= 0xff;
395c10b1332SManivannan Sadhasivam 
396c10b1332SManivannan Sadhasivam 		port->icount.rx++;
397c10b1332SManivannan Sadhasivam 		tty_insert_flip_char(&port->state->port, val, flag);
398c10b1332SManivannan Sadhasivam 
399c10b1332SManivannan Sadhasivam 		status = rda_uart_read(port, RDA_UART_STATUS);
400c10b1332SManivannan Sadhasivam 	}
401c10b1332SManivannan Sadhasivam 
402c10b1332SManivannan Sadhasivam 	tty_flip_buffer_push(&port->state->port);
403c10b1332SManivannan Sadhasivam }
404c10b1332SManivannan Sadhasivam 
rda_interrupt(int irq,void * dev_id)405c10b1332SManivannan Sadhasivam static irqreturn_t rda_interrupt(int irq, void *dev_id)
406c10b1332SManivannan Sadhasivam {
407c10b1332SManivannan Sadhasivam 	struct uart_port *port = dev_id;
408c10b1332SManivannan Sadhasivam 	unsigned long flags;
409c10b1332SManivannan Sadhasivam 	u32 val, irq_mask;
410c10b1332SManivannan Sadhasivam 
411c10b1332SManivannan Sadhasivam 	spin_lock_irqsave(&port->lock, flags);
412c10b1332SManivannan Sadhasivam 
413c10b1332SManivannan Sadhasivam 	/* Clear IRQ cause */
414c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_IRQ_CAUSE);
415c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_IRQ_CAUSE);
416c10b1332SManivannan Sadhasivam 
417c10b1332SManivannan Sadhasivam 	if (val & (RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT))
418c10b1332SManivannan Sadhasivam 		rda_uart_receive_chars(port);
419c10b1332SManivannan Sadhasivam 
420c10b1332SManivannan Sadhasivam 	if (val & (RDA_UART_TX_DATA_NEEDED)) {
421c10b1332SManivannan Sadhasivam 		irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK);
422c10b1332SManivannan Sadhasivam 		irq_mask &= ~RDA_UART_TX_DATA_NEEDED;
423c10b1332SManivannan Sadhasivam 		rda_uart_write(port, irq_mask, RDA_UART_IRQ_MASK);
424c10b1332SManivannan Sadhasivam 
425c10b1332SManivannan Sadhasivam 		rda_uart_send_chars(port);
426c10b1332SManivannan Sadhasivam 	}
427c10b1332SManivannan Sadhasivam 
428c10b1332SManivannan Sadhasivam 	spin_unlock_irqrestore(&port->lock, flags);
429c10b1332SManivannan Sadhasivam 
430c10b1332SManivannan Sadhasivam 	return IRQ_HANDLED;
431c10b1332SManivannan Sadhasivam }
432c10b1332SManivannan Sadhasivam 
rda_uart_startup(struct uart_port * port)433c10b1332SManivannan Sadhasivam static int rda_uart_startup(struct uart_port *port)
434c10b1332SManivannan Sadhasivam {
435c10b1332SManivannan Sadhasivam 	unsigned long flags;
436c10b1332SManivannan Sadhasivam 	int ret;
437c10b1332SManivannan Sadhasivam 	u32 val;
438c10b1332SManivannan Sadhasivam 
439c10b1332SManivannan Sadhasivam 	spin_lock_irqsave(&port->lock, flags);
440c10b1332SManivannan Sadhasivam 	rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
441c10b1332SManivannan Sadhasivam 	spin_unlock_irqrestore(&port->lock, flags);
442c10b1332SManivannan Sadhasivam 
443c10b1332SManivannan Sadhasivam 	ret = request_irq(port->irq, rda_interrupt, IRQF_NO_SUSPEND,
444c10b1332SManivannan Sadhasivam 			  "rda-uart", port);
445c10b1332SManivannan Sadhasivam 	if (ret)
446c10b1332SManivannan Sadhasivam 		return ret;
447c10b1332SManivannan Sadhasivam 
448c10b1332SManivannan Sadhasivam 	spin_lock_irqsave(&port->lock, flags);
449c10b1332SManivannan Sadhasivam 
450c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_CTRL);
451c10b1332SManivannan Sadhasivam 	val |= RDA_UART_ENABLE;
452c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_CTRL);
453c10b1332SManivannan Sadhasivam 
454c10b1332SManivannan Sadhasivam 	/* enable rx interrupt */
455c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_IRQ_MASK);
456c10b1332SManivannan Sadhasivam 	val |= (RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT);
457c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_IRQ_MASK);
458c10b1332SManivannan Sadhasivam 
459c10b1332SManivannan Sadhasivam 	spin_unlock_irqrestore(&port->lock, flags);
460c10b1332SManivannan Sadhasivam 
461c10b1332SManivannan Sadhasivam 	return 0;
462c10b1332SManivannan Sadhasivam }
463c10b1332SManivannan Sadhasivam 
rda_uart_shutdown(struct uart_port * port)464c10b1332SManivannan Sadhasivam static void rda_uart_shutdown(struct uart_port *port)
465c10b1332SManivannan Sadhasivam {
466c10b1332SManivannan Sadhasivam 	unsigned long flags;
467c10b1332SManivannan Sadhasivam 	u32 val;
468c10b1332SManivannan Sadhasivam 
469c10b1332SManivannan Sadhasivam 	spin_lock_irqsave(&port->lock, flags);
470c10b1332SManivannan Sadhasivam 
471c10b1332SManivannan Sadhasivam 	rda_uart_stop_tx(port);
472c10b1332SManivannan Sadhasivam 	rda_uart_stop_rx(port);
473c10b1332SManivannan Sadhasivam 
474c10b1332SManivannan Sadhasivam 	val = rda_uart_read(port, RDA_UART_CTRL);
475c10b1332SManivannan Sadhasivam 	val &= ~RDA_UART_ENABLE;
476c10b1332SManivannan Sadhasivam 	rda_uart_write(port, val, RDA_UART_CTRL);
477c10b1332SManivannan Sadhasivam 
478c10b1332SManivannan Sadhasivam 	spin_unlock_irqrestore(&port->lock, flags);
479c10b1332SManivannan Sadhasivam }
480c10b1332SManivannan Sadhasivam 
rda_uart_type(struct uart_port * port)481c10b1332SManivannan Sadhasivam static const char *rda_uart_type(struct uart_port *port)
482c10b1332SManivannan Sadhasivam {
483c10b1332SManivannan Sadhasivam 	return (port->type == PORT_RDA) ? "rda-uart" : NULL;
484c10b1332SManivannan Sadhasivam }
485c10b1332SManivannan Sadhasivam 
rda_uart_request_port(struct uart_port * port)486c10b1332SManivannan Sadhasivam static int rda_uart_request_port(struct uart_port *port)
487c10b1332SManivannan Sadhasivam {
488c10b1332SManivannan Sadhasivam 	struct platform_device *pdev = to_platform_device(port->dev);
489c10b1332SManivannan Sadhasivam 	struct resource *res;
490c10b1332SManivannan Sadhasivam 
491c10b1332SManivannan Sadhasivam 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
492c10b1332SManivannan Sadhasivam 	if (!res)
493c10b1332SManivannan Sadhasivam 		return -ENXIO;
494c10b1332SManivannan Sadhasivam 
495c10b1332SManivannan Sadhasivam 	if (!devm_request_mem_region(port->dev, port->mapbase,
496c10b1332SManivannan Sadhasivam 				     resource_size(res), dev_name(port->dev)))
497c10b1332SManivannan Sadhasivam 		return -EBUSY;
498c10b1332SManivannan Sadhasivam 
499c10b1332SManivannan Sadhasivam 	if (port->flags & UPF_IOREMAP) {
5004bdc0d67SChristoph Hellwig 		port->membase = devm_ioremap(port->dev, port->mapbase,
501c10b1332SManivannan Sadhasivam 						     resource_size(res));
502c10b1332SManivannan Sadhasivam 		if (!port->membase)
503c10b1332SManivannan Sadhasivam 			return -EBUSY;
504c10b1332SManivannan Sadhasivam 	}
505c10b1332SManivannan Sadhasivam 
506c10b1332SManivannan Sadhasivam 	return 0;
507c10b1332SManivannan Sadhasivam }
508c10b1332SManivannan Sadhasivam 
rda_uart_config_port(struct uart_port * port,int flags)509c10b1332SManivannan Sadhasivam static void rda_uart_config_port(struct uart_port *port, int flags)
510c10b1332SManivannan Sadhasivam {
511c10b1332SManivannan Sadhasivam 	unsigned long irq_flags;
512c10b1332SManivannan Sadhasivam 
513c10b1332SManivannan Sadhasivam 	if (flags & UART_CONFIG_TYPE) {
514c10b1332SManivannan Sadhasivam 		port->type = PORT_RDA;
515c10b1332SManivannan Sadhasivam 		rda_uart_request_port(port);
516c10b1332SManivannan Sadhasivam 	}
517c10b1332SManivannan Sadhasivam 
518c10b1332SManivannan Sadhasivam 	spin_lock_irqsave(&port->lock, irq_flags);
519c10b1332SManivannan Sadhasivam 
520c10b1332SManivannan Sadhasivam 	/* Clear mask, so no surprise interrupts. */
521c10b1332SManivannan Sadhasivam 	rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
522c10b1332SManivannan Sadhasivam 
523c10b1332SManivannan Sadhasivam 	/* Clear status register */
524c10b1332SManivannan Sadhasivam 	rda_uart_write(port, 0, RDA_UART_STATUS);
525c10b1332SManivannan Sadhasivam 
526c10b1332SManivannan Sadhasivam 	spin_unlock_irqrestore(&port->lock, irq_flags);
527c10b1332SManivannan Sadhasivam }
528c10b1332SManivannan Sadhasivam 
rda_uart_release_port(struct uart_port * port)529c10b1332SManivannan Sadhasivam static void rda_uart_release_port(struct uart_port *port)
530c10b1332SManivannan Sadhasivam {
531c10b1332SManivannan Sadhasivam 	struct platform_device *pdev = to_platform_device(port->dev);
532c10b1332SManivannan Sadhasivam 	struct resource *res;
533c10b1332SManivannan Sadhasivam 
534c10b1332SManivannan Sadhasivam 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
535c10b1332SManivannan Sadhasivam 	if (!res)
536c10b1332SManivannan Sadhasivam 		return;
537c10b1332SManivannan Sadhasivam 
538c10b1332SManivannan Sadhasivam 	if (port->flags & UPF_IOREMAP) {
539c10b1332SManivannan Sadhasivam 		devm_release_mem_region(port->dev, port->mapbase,
540c10b1332SManivannan Sadhasivam 					resource_size(res));
541c10b1332SManivannan Sadhasivam 		devm_iounmap(port->dev, port->membase);
542c10b1332SManivannan Sadhasivam 		port->membase = NULL;
543c10b1332SManivannan Sadhasivam 	}
544c10b1332SManivannan Sadhasivam }
545c10b1332SManivannan Sadhasivam 
rda_uart_verify_port(struct uart_port * port,struct serial_struct * ser)546c10b1332SManivannan Sadhasivam static int rda_uart_verify_port(struct uart_port *port,
547c10b1332SManivannan Sadhasivam 				struct serial_struct *ser)
548c10b1332SManivannan Sadhasivam {
549c10b1332SManivannan Sadhasivam 	if (port->type != PORT_RDA)
550c10b1332SManivannan Sadhasivam 		return -EINVAL;
551c10b1332SManivannan Sadhasivam 
552c10b1332SManivannan Sadhasivam 	if (port->irq != ser->irq)
553c10b1332SManivannan Sadhasivam 		return -EINVAL;
554c10b1332SManivannan Sadhasivam 
555c10b1332SManivannan Sadhasivam 	return 0;
556c10b1332SManivannan Sadhasivam }
557c10b1332SManivannan Sadhasivam 
558c10b1332SManivannan Sadhasivam static const struct uart_ops rda_uart_ops = {
559c10b1332SManivannan Sadhasivam 	.tx_empty       = rda_uart_tx_empty,
560c10b1332SManivannan Sadhasivam 	.get_mctrl      = rda_uart_get_mctrl,
561c10b1332SManivannan Sadhasivam 	.set_mctrl      = rda_uart_set_mctrl,
562c10b1332SManivannan Sadhasivam 	.start_tx       = rda_uart_start_tx,
563c10b1332SManivannan Sadhasivam 	.stop_tx        = rda_uart_stop_tx,
564c10b1332SManivannan Sadhasivam 	.stop_rx        = rda_uart_stop_rx,
565c10b1332SManivannan Sadhasivam 	.startup        = rda_uart_startup,
566c10b1332SManivannan Sadhasivam 	.shutdown       = rda_uart_shutdown,
567c10b1332SManivannan Sadhasivam 	.set_termios    = rda_uart_set_termios,
568c10b1332SManivannan Sadhasivam 	.type           = rda_uart_type,
569c10b1332SManivannan Sadhasivam 	.request_port	= rda_uart_request_port,
570c10b1332SManivannan Sadhasivam 	.release_port	= rda_uart_release_port,
571c10b1332SManivannan Sadhasivam 	.config_port	= rda_uart_config_port,
572c10b1332SManivannan Sadhasivam 	.verify_port	= rda_uart_verify_port,
573c10b1332SManivannan Sadhasivam };
574c10b1332SManivannan Sadhasivam 
575c10b1332SManivannan Sadhasivam #ifdef CONFIG_SERIAL_RDA_CONSOLE
576c10b1332SManivannan Sadhasivam 
rda_console_putchar(struct uart_port * port,unsigned char ch)5773f8bab17SJiri Slaby static void rda_console_putchar(struct uart_port *port, unsigned char ch)
578c10b1332SManivannan Sadhasivam {
579c10b1332SManivannan Sadhasivam 	if (!port->membase)
580c10b1332SManivannan Sadhasivam 		return;
581c10b1332SManivannan Sadhasivam 
582c10b1332SManivannan Sadhasivam 	while (!(rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK))
583c10b1332SManivannan Sadhasivam 		cpu_relax();
584c10b1332SManivannan Sadhasivam 
585c10b1332SManivannan Sadhasivam 	rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER);
586c10b1332SManivannan Sadhasivam }
587c10b1332SManivannan Sadhasivam 
rda_uart_port_write(struct uart_port * port,const char * s,u_int count)588c10b1332SManivannan Sadhasivam static void rda_uart_port_write(struct uart_port *port, const char *s,
589c10b1332SManivannan Sadhasivam 				u_int count)
590c10b1332SManivannan Sadhasivam {
591c10b1332SManivannan Sadhasivam 	u32 old_irq_mask;
592c10b1332SManivannan Sadhasivam 	unsigned long flags;
593c10b1332SManivannan Sadhasivam 	int locked;
594c10b1332SManivannan Sadhasivam 
595c10b1332SManivannan Sadhasivam 	local_irq_save(flags);
596c10b1332SManivannan Sadhasivam 
597c10b1332SManivannan Sadhasivam 	if (port->sysrq) {
598c10b1332SManivannan Sadhasivam 		locked = 0;
599c10b1332SManivannan Sadhasivam 	} else if (oops_in_progress) {
600c10b1332SManivannan Sadhasivam 		locked = spin_trylock(&port->lock);
601c10b1332SManivannan Sadhasivam 	} else {
602c10b1332SManivannan Sadhasivam 		spin_lock(&port->lock);
603c10b1332SManivannan Sadhasivam 		locked = 1;
604c10b1332SManivannan Sadhasivam 	}
605c10b1332SManivannan Sadhasivam 
606c10b1332SManivannan Sadhasivam 	old_irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK);
607c10b1332SManivannan Sadhasivam 	rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
608c10b1332SManivannan Sadhasivam 
609c10b1332SManivannan Sadhasivam 	uart_console_write(port, s, count, rda_console_putchar);
610c10b1332SManivannan Sadhasivam 
611c10b1332SManivannan Sadhasivam 	/* wait until all contents have been sent out */
612c10b1332SManivannan Sadhasivam 	while (!(rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK))
613c10b1332SManivannan Sadhasivam 		cpu_relax();
614c10b1332SManivannan Sadhasivam 
615c10b1332SManivannan Sadhasivam 	rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK);
616c10b1332SManivannan Sadhasivam 
617c10b1332SManivannan Sadhasivam 	if (locked)
618c10b1332SManivannan Sadhasivam 		spin_unlock(&port->lock);
619c10b1332SManivannan Sadhasivam 
620c10b1332SManivannan Sadhasivam 	local_irq_restore(flags);
621c10b1332SManivannan Sadhasivam }
622c10b1332SManivannan Sadhasivam 
rda_uart_console_write(struct console * co,const char * s,u_int count)623c10b1332SManivannan Sadhasivam static void rda_uart_console_write(struct console *co, const char *s,
624c10b1332SManivannan Sadhasivam 				   u_int count)
625c10b1332SManivannan Sadhasivam {
626c10b1332SManivannan Sadhasivam 	struct rda_uart_port *rda_port;
627c10b1332SManivannan Sadhasivam 
628c10b1332SManivannan Sadhasivam 	rda_port = rda_uart_ports[co->index];
629c10b1332SManivannan Sadhasivam 	if (!rda_port)
630c10b1332SManivannan Sadhasivam 		return;
631c10b1332SManivannan Sadhasivam 
632c10b1332SManivannan Sadhasivam 	rda_uart_port_write(&rda_port->port, s, count);
633c10b1332SManivannan Sadhasivam }
634c10b1332SManivannan Sadhasivam 
rda_uart_console_setup(struct console * co,char * options)635c10b1332SManivannan Sadhasivam static int rda_uart_console_setup(struct console *co, char *options)
636c10b1332SManivannan Sadhasivam {
637c10b1332SManivannan Sadhasivam 	struct rda_uart_port *rda_port;
638c10b1332SManivannan Sadhasivam 	int baud = 921600;
639c10b1332SManivannan Sadhasivam 	int bits = 8;
640c10b1332SManivannan Sadhasivam 	int parity = 'n';
641c10b1332SManivannan Sadhasivam 	int flow = 'n';
642c10b1332SManivannan Sadhasivam 
643c10b1332SManivannan Sadhasivam 	if (co->index < 0 || co->index >= RDA_UART_PORT_NUM)
644c10b1332SManivannan Sadhasivam 		return -EINVAL;
645c10b1332SManivannan Sadhasivam 
646c10b1332SManivannan Sadhasivam 	rda_port = rda_uart_ports[co->index];
647c10b1332SManivannan Sadhasivam 	if (!rda_port || !rda_port->port.membase)
648c10b1332SManivannan Sadhasivam 		return -ENODEV;
649c10b1332SManivannan Sadhasivam 
650c10b1332SManivannan Sadhasivam 	if (options)
651c10b1332SManivannan Sadhasivam 		uart_parse_options(options, &baud, &parity, &bits, &flow);
652c10b1332SManivannan Sadhasivam 
653c10b1332SManivannan Sadhasivam 	return uart_set_options(&rda_port->port, co, baud, parity, bits, flow);
654c10b1332SManivannan Sadhasivam }
655c10b1332SManivannan Sadhasivam 
656c10b1332SManivannan Sadhasivam static struct console rda_uart_console = {
657c10b1332SManivannan Sadhasivam 	.name = RDA_UART_DEV_NAME,
658c10b1332SManivannan Sadhasivam 	.write = rda_uart_console_write,
659c10b1332SManivannan Sadhasivam 	.device = uart_console_device,
660c10b1332SManivannan Sadhasivam 	.setup = rda_uart_console_setup,
661c10b1332SManivannan Sadhasivam 	.flags = CON_PRINTBUFFER,
662c10b1332SManivannan Sadhasivam 	.index = -1,
663c10b1332SManivannan Sadhasivam 	.data = &rda_uart_driver,
664c10b1332SManivannan Sadhasivam };
665c10b1332SManivannan Sadhasivam 
rda_uart_console_init(void)666c10b1332SManivannan Sadhasivam static int __init rda_uart_console_init(void)
667c10b1332SManivannan Sadhasivam {
668c10b1332SManivannan Sadhasivam 	register_console(&rda_uart_console);
669c10b1332SManivannan Sadhasivam 
670c10b1332SManivannan Sadhasivam 	return 0;
671c10b1332SManivannan Sadhasivam }
672c10b1332SManivannan Sadhasivam console_initcall(rda_uart_console_init);
673c10b1332SManivannan Sadhasivam 
rda_uart_early_console_write(struct console * co,const char * s,u_int count)674c10b1332SManivannan Sadhasivam static void rda_uart_early_console_write(struct console *co,
675c10b1332SManivannan Sadhasivam 					 const char *s,
676c10b1332SManivannan Sadhasivam 					 u_int count)
677c10b1332SManivannan Sadhasivam {
678c10b1332SManivannan Sadhasivam 	struct earlycon_device *dev = co->data;
679c10b1332SManivannan Sadhasivam 
680c10b1332SManivannan Sadhasivam 	rda_uart_port_write(&dev->port, s, count);
681c10b1332SManivannan Sadhasivam }
682c10b1332SManivannan Sadhasivam 
683c10b1332SManivannan Sadhasivam static int __init
rda_uart_early_console_setup(struct earlycon_device * device,const char * opt)684c10b1332SManivannan Sadhasivam rda_uart_early_console_setup(struct earlycon_device *device, const char *opt)
685c10b1332SManivannan Sadhasivam {
686c10b1332SManivannan Sadhasivam 	if (!device->port.membase)
687c10b1332SManivannan Sadhasivam 		return -ENODEV;
688c10b1332SManivannan Sadhasivam 
689c10b1332SManivannan Sadhasivam 	device->con->write = rda_uart_early_console_write;
690c10b1332SManivannan Sadhasivam 
691c10b1332SManivannan Sadhasivam 	return 0;
692c10b1332SManivannan Sadhasivam }
693c10b1332SManivannan Sadhasivam 
694c10b1332SManivannan Sadhasivam OF_EARLYCON_DECLARE(rda, "rda,8810pl-uart",
695c10b1332SManivannan Sadhasivam 		    rda_uart_early_console_setup);
696c10b1332SManivannan Sadhasivam 
697c10b1332SManivannan Sadhasivam #define RDA_UART_CONSOLE (&rda_uart_console)
698c10b1332SManivannan Sadhasivam #else
699c10b1332SManivannan Sadhasivam #define RDA_UART_CONSOLE NULL
700c10b1332SManivannan Sadhasivam #endif /* CONFIG_SERIAL_RDA_CONSOLE */
701c10b1332SManivannan Sadhasivam 
702c10b1332SManivannan Sadhasivam static struct uart_driver rda_uart_driver = {
703c10b1332SManivannan Sadhasivam 	.owner = THIS_MODULE,
704c10b1332SManivannan Sadhasivam 	.driver_name = "rda-uart",
705c10b1332SManivannan Sadhasivam 	.dev_name = RDA_UART_DEV_NAME,
706c10b1332SManivannan Sadhasivam 	.nr = RDA_UART_PORT_NUM,
707c10b1332SManivannan Sadhasivam 	.cons = RDA_UART_CONSOLE,
708c10b1332SManivannan Sadhasivam };
709c10b1332SManivannan Sadhasivam 
710c10b1332SManivannan Sadhasivam static const struct of_device_id rda_uart_dt_matches[] = {
711c10b1332SManivannan Sadhasivam 	{ .compatible = "rda,8810pl-uart" },
712c10b1332SManivannan Sadhasivam 	{ }
713c10b1332SManivannan Sadhasivam };
714c10b1332SManivannan Sadhasivam MODULE_DEVICE_TABLE(of, rda_uart_dt_matches);
715c10b1332SManivannan Sadhasivam 
rda_uart_probe(struct platform_device * pdev)716c10b1332SManivannan Sadhasivam static int rda_uart_probe(struct platform_device *pdev)
717c10b1332SManivannan Sadhasivam {
718c10b1332SManivannan Sadhasivam 	struct resource *res_mem;
719c10b1332SManivannan Sadhasivam 	struct rda_uart_port *rda_port;
720c10b1332SManivannan Sadhasivam 	int ret, irq;
721c10b1332SManivannan Sadhasivam 
722c10b1332SManivannan Sadhasivam 	if (pdev->dev.of_node)
723c10b1332SManivannan Sadhasivam 		pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
724c10b1332SManivannan Sadhasivam 
725c10b1332SManivannan Sadhasivam 	if (pdev->id < 0 || pdev->id >= RDA_UART_PORT_NUM) {
726c10b1332SManivannan Sadhasivam 		dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
727c10b1332SManivannan Sadhasivam 		return -EINVAL;
728c10b1332SManivannan Sadhasivam 	}
729c10b1332SManivannan Sadhasivam 
730c10b1332SManivannan Sadhasivam 	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
731c10b1332SManivannan Sadhasivam 	if (!res_mem) {
732c10b1332SManivannan Sadhasivam 		dev_err(&pdev->dev, "could not get mem\n");
733c10b1332SManivannan Sadhasivam 		return -ENODEV;
734c10b1332SManivannan Sadhasivam 	}
735c10b1332SManivannan Sadhasivam 
736c10b1332SManivannan Sadhasivam 	irq = platform_get_irq(pdev, 0);
7371df21786SStephen Boyd 	if (irq < 0)
738c10b1332SManivannan Sadhasivam 		return irq;
739c10b1332SManivannan Sadhasivam 
740c10b1332SManivannan Sadhasivam 	if (rda_uart_ports[pdev->id]) {
741c10b1332SManivannan Sadhasivam 		dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
742c10b1332SManivannan Sadhasivam 		return -EBUSY;
743c10b1332SManivannan Sadhasivam 	}
744c10b1332SManivannan Sadhasivam 
745c10b1332SManivannan Sadhasivam 	rda_port = devm_kzalloc(&pdev->dev, sizeof(*rda_port), GFP_KERNEL);
746c10b1332SManivannan Sadhasivam 	if (!rda_port)
747c10b1332SManivannan Sadhasivam 		return -ENOMEM;
748c10b1332SManivannan Sadhasivam 
749c10b1332SManivannan Sadhasivam 	rda_port->clk = devm_clk_get(&pdev->dev, NULL);
750c10b1332SManivannan Sadhasivam 	if (IS_ERR(rda_port->clk)) {
751c10b1332SManivannan Sadhasivam 		dev_err(&pdev->dev, "could not get clk\n");
752c10b1332SManivannan Sadhasivam 		return PTR_ERR(rda_port->clk);
753c10b1332SManivannan Sadhasivam 	}
754c10b1332SManivannan Sadhasivam 
755c10b1332SManivannan Sadhasivam 	rda_port->port.dev = &pdev->dev;
756c10b1332SManivannan Sadhasivam 	rda_port->port.regshift = 0;
757c10b1332SManivannan Sadhasivam 	rda_port->port.line = pdev->id;
758c10b1332SManivannan Sadhasivam 	rda_port->port.type = PORT_RDA;
759c10b1332SManivannan Sadhasivam 	rda_port->port.iotype = UPIO_MEM;
760c10b1332SManivannan Sadhasivam 	rda_port->port.mapbase = res_mem->start;
761c10b1332SManivannan Sadhasivam 	rda_port->port.irq = irq;
762c10b1332SManivannan Sadhasivam 	rda_port->port.uartclk = clk_get_rate(rda_port->clk);
763c10b1332SManivannan Sadhasivam 	if (rda_port->port.uartclk == 0) {
764c10b1332SManivannan Sadhasivam 		dev_err(&pdev->dev, "clock rate is zero\n");
765c10b1332SManivannan Sadhasivam 		return -EINVAL;
766c10b1332SManivannan Sadhasivam 	}
767c10b1332SManivannan Sadhasivam 	rda_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP |
768c10b1332SManivannan Sadhasivam 			       UPF_LOW_LATENCY;
769c10b1332SManivannan Sadhasivam 	rda_port->port.x_char = 0;
770c10b1332SManivannan Sadhasivam 	rda_port->port.fifosize = RDA_UART_TX_FIFO_SIZE;
771c10b1332SManivannan Sadhasivam 	rda_port->port.ops = &rda_uart_ops;
772c10b1332SManivannan Sadhasivam 
773c10b1332SManivannan Sadhasivam 	rda_uart_ports[pdev->id] = rda_port;
774c10b1332SManivannan Sadhasivam 	platform_set_drvdata(pdev, rda_port);
775c10b1332SManivannan Sadhasivam 
776c10b1332SManivannan Sadhasivam 	ret = uart_add_one_port(&rda_uart_driver, &rda_port->port);
777c10b1332SManivannan Sadhasivam 	if (ret)
778c10b1332SManivannan Sadhasivam 		rda_uart_ports[pdev->id] = NULL;
779c10b1332SManivannan Sadhasivam 
780c10b1332SManivannan Sadhasivam 	return ret;
781c10b1332SManivannan Sadhasivam }
782c10b1332SManivannan Sadhasivam 
rda_uart_remove(struct platform_device * pdev)783c10b1332SManivannan Sadhasivam static int rda_uart_remove(struct platform_device *pdev)
784c10b1332SManivannan Sadhasivam {
785c10b1332SManivannan Sadhasivam 	struct rda_uart_port *rda_port = platform_get_drvdata(pdev);
786c10b1332SManivannan Sadhasivam 
787c10b1332SManivannan Sadhasivam 	uart_remove_one_port(&rda_uart_driver, &rda_port->port);
788c10b1332SManivannan Sadhasivam 	rda_uart_ports[pdev->id] = NULL;
789c10b1332SManivannan Sadhasivam 
790c10b1332SManivannan Sadhasivam 	return 0;
791c10b1332SManivannan Sadhasivam }
792c10b1332SManivannan Sadhasivam 
793c10b1332SManivannan Sadhasivam static struct platform_driver rda_uart_platform_driver = {
794c10b1332SManivannan Sadhasivam 	.probe = rda_uart_probe,
795c10b1332SManivannan Sadhasivam 	.remove = rda_uart_remove,
796c10b1332SManivannan Sadhasivam 	.driver = {
797c10b1332SManivannan Sadhasivam 		.name = "rda-uart",
798c10b1332SManivannan Sadhasivam 		.of_match_table = rda_uart_dt_matches,
799c10b1332SManivannan Sadhasivam 	},
800c10b1332SManivannan Sadhasivam };
801c10b1332SManivannan Sadhasivam 
rda_uart_init(void)802c10b1332SManivannan Sadhasivam static int __init rda_uart_init(void)
803c10b1332SManivannan Sadhasivam {
804c10b1332SManivannan Sadhasivam 	int ret;
805c10b1332SManivannan Sadhasivam 
806c10b1332SManivannan Sadhasivam 	ret = uart_register_driver(&rda_uart_driver);
807c10b1332SManivannan Sadhasivam 	if (ret)
808c10b1332SManivannan Sadhasivam 		return ret;
809c10b1332SManivannan Sadhasivam 
810c10b1332SManivannan Sadhasivam 	ret = platform_driver_register(&rda_uart_platform_driver);
811c10b1332SManivannan Sadhasivam 	if (ret)
812c10b1332SManivannan Sadhasivam 		uart_unregister_driver(&rda_uart_driver);
813c10b1332SManivannan Sadhasivam 
814c10b1332SManivannan Sadhasivam 	return ret;
815c10b1332SManivannan Sadhasivam }
816c10b1332SManivannan Sadhasivam 
rda_uart_exit(void)8175080d127SChristophe JAILLET static void __exit rda_uart_exit(void)
818c10b1332SManivannan Sadhasivam {
819c10b1332SManivannan Sadhasivam 	platform_driver_unregister(&rda_uart_platform_driver);
820c10b1332SManivannan Sadhasivam 	uart_unregister_driver(&rda_uart_driver);
821c10b1332SManivannan Sadhasivam }
822c10b1332SManivannan Sadhasivam 
823c10b1332SManivannan Sadhasivam module_init(rda_uart_init);
824c10b1332SManivannan Sadhasivam module_exit(rda_uart_exit);
825c10b1332SManivannan Sadhasivam 
826c10b1332SManivannan Sadhasivam MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
827c10b1332SManivannan Sadhasivam MODULE_DESCRIPTION("RDA8810PL serial device driver");
828c10b1332SManivannan Sadhasivam MODULE_LICENSE("GPL");
829