xref: /linux/drivers/tty/serial/qcom_geni_serial.c (revision 205b5bdda2090d4730dabf9c0d9646cb32f2551d)
1c4f52879SKarthikeyan Ramasubramanian // SPDX-License-Identifier: GPL-2.0
2c4f52879SKarthikeyan Ramasubramanian // Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
3c4f52879SKarthikeyan Ramasubramanian 
4c4f52879SKarthikeyan Ramasubramanian #include <linux/clk.h>
5c4f52879SKarthikeyan Ramasubramanian #include <linux/console.h>
6c4f52879SKarthikeyan Ramasubramanian #include <linux/io.h>
7c4f52879SKarthikeyan Ramasubramanian #include <linux/iopoll.h>
83e4aaea7SAkash Asthana #include <linux/irq.h>
9c4f52879SKarthikeyan Ramasubramanian #include <linux/module.h>
10c4f52879SKarthikeyan Ramasubramanian #include <linux/of.h>
11c4f52879SKarthikeyan Ramasubramanian #include <linux/of_device.h>
12c4f52879SKarthikeyan Ramasubramanian #include <linux/platform_device.h>
13f3974413SAkash Asthana #include <linux/pm_runtime.h>
148b7103f3SAkash Asthana #include <linux/pm_wakeirq.h>
15c4f52879SKarthikeyan Ramasubramanian #include <linux/qcom-geni-se.h>
16c4f52879SKarthikeyan Ramasubramanian #include <linux/serial.h>
17c4f52879SKarthikeyan Ramasubramanian #include <linux/serial_core.h>
18c4f52879SKarthikeyan Ramasubramanian #include <linux/slab.h>
19c4f52879SKarthikeyan Ramasubramanian #include <linux/tty.h>
20c4f52879SKarthikeyan Ramasubramanian #include <linux/tty_flip.h>
21c4f52879SKarthikeyan Ramasubramanian 
22c4f52879SKarthikeyan Ramasubramanian /* UART specific GENI registers */
238a8a66a1SGirish Mahadevan #define SE_UART_LOOPBACK_CFG		0x22c
249fa3c4b1SRoja Rani Yarubandi #define SE_UART_IO_MACRO_CTRL		0x240
25c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_TRANS_CFG		0x25c
26c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_WORD_LEN		0x268
27c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_STOP_BIT_LEN		0x26c
28c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_TRANS_LEN		0x270
29c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_TRANS_CFG		0x280
30c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_WORD_LEN		0x28c
31c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_STALE_CNT		0x294
32c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_PARITY_CFG		0x2a4
33c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_PARITY_CFG		0x2a8
348a8a66a1SGirish Mahadevan #define SE_UART_MANUAL_RFR		0x2ac
35c4f52879SKarthikeyan Ramasubramanian 
36c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TRANS_CFG */
37c4f52879SKarthikeyan Ramasubramanian #define UART_TX_PAR_EN		BIT(0)
38c4f52879SKarthikeyan Ramasubramanian #define UART_CTS_MASK		BIT(1)
39c4f52879SKarthikeyan Ramasubramanian 
40c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_WORD_LEN */
41c4f52879SKarthikeyan Ramasubramanian #define TX_WORD_LEN_MSK		GENMASK(9, 0)
42c4f52879SKarthikeyan Ramasubramanian 
43c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_STOP_BIT_LEN */
44c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_MSK	GENMASK(23, 0)
45c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_1	0
46c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_1_5	1
47c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_2	2
48c4f52879SKarthikeyan Ramasubramanian 
49c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_TRANS_LEN */
50c4f52879SKarthikeyan Ramasubramanian #define TX_TRANS_LEN_MSK	GENMASK(23, 0)
51c4f52879SKarthikeyan Ramasubramanian 
52c4f52879SKarthikeyan Ramasubramanian /* SE_UART_RX_TRANS_CFG */
53c4f52879SKarthikeyan Ramasubramanian #define UART_RX_INS_STATUS_BIT	BIT(2)
54c4f52879SKarthikeyan Ramasubramanian #define UART_RX_PAR_EN		BIT(3)
55c4f52879SKarthikeyan Ramasubramanian 
56c4f52879SKarthikeyan Ramasubramanian /* SE_UART_RX_WORD_LEN */
57c4f52879SKarthikeyan Ramasubramanian #define RX_WORD_LEN_MASK	GENMASK(9, 0)
58c4f52879SKarthikeyan Ramasubramanian 
59c4f52879SKarthikeyan Ramasubramanian /* SE_UART_RX_STALE_CNT */
60c4f52879SKarthikeyan Ramasubramanian #define RX_STALE_CNT		GENMASK(23, 0)
61c4f52879SKarthikeyan Ramasubramanian 
62c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */
63c4f52879SKarthikeyan Ramasubramanian #define PAR_CALC_EN		BIT(0)
64c4f52879SKarthikeyan Ramasubramanian #define PAR_MODE_MSK		GENMASK(2, 1)
65c4f52879SKarthikeyan Ramasubramanian #define PAR_MODE_SHFT		1
66c4f52879SKarthikeyan Ramasubramanian #define PAR_EVEN		0x00
67c4f52879SKarthikeyan Ramasubramanian #define PAR_ODD			0x01
68c4f52879SKarthikeyan Ramasubramanian #define PAR_SPACE		0x10
69c4f52879SKarthikeyan Ramasubramanian #define PAR_MARK		0x11
70c4f52879SKarthikeyan Ramasubramanian 
718a8a66a1SGirish Mahadevan /* SE_UART_MANUAL_RFR register fields */
728a8a66a1SGirish Mahadevan #define UART_MANUAL_RFR_EN	BIT(31)
738a8a66a1SGirish Mahadevan #define UART_RFR_NOT_READY	BIT(1)
748a8a66a1SGirish Mahadevan #define UART_RFR_READY		BIT(0)
758a8a66a1SGirish Mahadevan 
76c4f52879SKarthikeyan Ramasubramanian /* UART M_CMD OP codes */
77c4f52879SKarthikeyan Ramasubramanian #define UART_START_TX		0x1
78c4f52879SKarthikeyan Ramasubramanian #define UART_START_BREAK	0x4
79c4f52879SKarthikeyan Ramasubramanian #define UART_STOP_BREAK		0x5
80c4f52879SKarthikeyan Ramasubramanian /* UART S_CMD OP codes */
81c4f52879SKarthikeyan Ramasubramanian #define UART_START_READ		0x1
82c4f52879SKarthikeyan Ramasubramanian #define UART_PARAM		0x1
83c4f52879SKarthikeyan Ramasubramanian 
84c4f52879SKarthikeyan Ramasubramanian #define UART_OVERSAMPLING	32
85c4f52879SKarthikeyan Ramasubramanian #define STALE_TIMEOUT		16
86c4f52879SKarthikeyan Ramasubramanian #define DEFAULT_BITS_PER_CHAR	10
87c4f52879SKarthikeyan Ramasubramanian #define GENI_UART_CONS_PORTS	1
888a8a66a1SGirish Mahadevan #define GENI_UART_PORTS		3
89c4f52879SKarthikeyan Ramasubramanian #define DEF_FIFO_DEPTH_WORDS	16
90c4f52879SKarthikeyan Ramasubramanian #define DEF_TX_WM		2
91c4f52879SKarthikeyan Ramasubramanian #define DEF_FIFO_WIDTH_BITS	32
92a85fb9ceSRyan Case #define UART_RX_WM		2
9369bd1a4fSAkash Asthana 
9469bd1a4fSAkash Asthana /* SE_UART_LOOPBACK_CFG */
9569bd1a4fSAkash Asthana #define RX_TX_SORTED	BIT(0)
9669bd1a4fSAkash Asthana #define CTS_RTS_SORTED	BIT(1)
9769bd1a4fSAkash Asthana #define RX_TX_CTS_RTS_SORTED	(RX_TX_SORTED | CTS_RTS_SORTED)
98c4f52879SKarthikeyan Ramasubramanian 
999fa3c4b1SRoja Rani Yarubandi /* UART pin swap value */
1009fa3c4b1SRoja Rani Yarubandi #define DEFAULT_IO_MACRO_IO0_IO1_MASK		GENMASK(3, 0)
1019fa3c4b1SRoja Rani Yarubandi #define IO_MACRO_IO0_SEL		0x3
1029fa3c4b1SRoja Rani Yarubandi #define DEFAULT_IO_MACRO_IO2_IO3_MASK		GENMASK(15, 4)
1039fa3c4b1SRoja Rani Yarubandi #define IO_MACRO_IO2_IO3_SWAP		0x4640
1049fa3c4b1SRoja Rani Yarubandi 
105c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_CONSOLE_POLL
1069f641df4SDouglas Anderson #define CONSOLE_RX_BYTES_PW 1
107c4f52879SKarthikeyan Ramasubramanian #else
1089f641df4SDouglas Anderson #define CONSOLE_RX_BYTES_PW 4
109c4f52879SKarthikeyan Ramasubramanian #endif
110c4f52879SKarthikeyan Ramasubramanian 
111c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port {
112c4f52879SKarthikeyan Ramasubramanian 	struct uart_port uport;
113c4f52879SKarthikeyan Ramasubramanian 	struct geni_se se;
114f3974413SAkash Asthana 	const char *name;
115c4f52879SKarthikeyan Ramasubramanian 	u32 tx_fifo_depth;
116c4f52879SKarthikeyan Ramasubramanian 	u32 tx_fifo_width;
117c4f52879SKarthikeyan Ramasubramanian 	u32 rx_fifo_depth;
118c4f52879SKarthikeyan Ramasubramanian 	bool setup;
119c4f52879SKarthikeyan Ramasubramanian 	int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop);
120c4f52879SKarthikeyan Ramasubramanian 	unsigned int baud;
121c4f52879SKarthikeyan Ramasubramanian 	unsigned int tx_bytes_pw;
122c4f52879SKarthikeyan Ramasubramanian 	unsigned int rx_bytes_pw;
123f9d690b6Ssatya priya 	void *rx_fifo;
1248a8a66a1SGirish Mahadevan 	u32 loopback;
125c4f52879SKarthikeyan Ramasubramanian 	bool brk;
126a1fee899SRyan Case 
127a1fee899SRyan Case 	unsigned int tx_remaining;
1288b7103f3SAkash Asthana 	int wakeup_irq;
1299fa3c4b1SRoja Rani Yarubandi 	bool rx_tx_swap;
1309fa3c4b1SRoja Rani Yarubandi 	bool cts_rts_swap;
131c4f52879SKarthikeyan Ramasubramanian };
132c4f52879SKarthikeyan Ramasubramanian 
133f7371750SKarthikeyan Ramasubramanian static const struct uart_ops qcom_geni_console_pops;
1348a8a66a1SGirish Mahadevan static const struct uart_ops qcom_geni_uart_pops;
135c4f52879SKarthikeyan Ramasubramanian static struct uart_driver qcom_geni_console_driver;
1368a8a66a1SGirish Mahadevan static struct uart_driver qcom_geni_uart_driver;
137c4f52879SKarthikeyan Ramasubramanian static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop);
1388a8a66a1SGirish Mahadevan static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop);
139c4f52879SKarthikeyan Ramasubramanian static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port);
140c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_stop_rx(struct uart_port *uport);
141679aac5eSsatya priya static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop);
142c4f52879SKarthikeyan Ramasubramanian 
143c4f52879SKarthikeyan Ramasubramanian static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
144c4f52879SKarthikeyan Ramasubramanian 					32000000, 48000000, 64000000, 80000000,
1458a8a66a1SGirish Mahadevan 					96000000, 100000000, 102400000,
1468a8a66a1SGirish Mahadevan 					112000000, 120000000, 128000000};
147c4f52879SKarthikeyan Ramasubramanian 
148c4f52879SKarthikeyan Ramasubramanian #define to_dev_port(ptr, member) \
149c4f52879SKarthikeyan Ramasubramanian 		container_of(ptr, struct qcom_geni_serial_port, member)
150c4f52879SKarthikeyan Ramasubramanian 
1518a8a66a1SGirish Mahadevan static struct qcom_geni_serial_port qcom_geni_uart_ports[GENI_UART_PORTS] = {
1528a8a66a1SGirish Mahadevan 	[0] = {
1538a8a66a1SGirish Mahadevan 		.uport = {
1548a8a66a1SGirish Mahadevan 				.iotype = UPIO_MEM,
1558a8a66a1SGirish Mahadevan 				.ops = &qcom_geni_uart_pops,
1568a8a66a1SGirish Mahadevan 				.flags = UPF_BOOT_AUTOCONF,
1578a8a66a1SGirish Mahadevan 				.line = 0,
1588a8a66a1SGirish Mahadevan 		},
1598a8a66a1SGirish Mahadevan 	},
1608a8a66a1SGirish Mahadevan 	[1] = {
1618a8a66a1SGirish Mahadevan 		.uport = {
1628a8a66a1SGirish Mahadevan 				.iotype = UPIO_MEM,
1638a8a66a1SGirish Mahadevan 				.ops = &qcom_geni_uart_pops,
1648a8a66a1SGirish Mahadevan 				.flags = UPF_BOOT_AUTOCONF,
1658a8a66a1SGirish Mahadevan 				.line = 1,
1668a8a66a1SGirish Mahadevan 		},
1678a8a66a1SGirish Mahadevan 	},
1688a8a66a1SGirish Mahadevan 	[2] = {
1698a8a66a1SGirish Mahadevan 		.uport = {
1708a8a66a1SGirish Mahadevan 				.iotype = UPIO_MEM,
1718a8a66a1SGirish Mahadevan 				.ops = &qcom_geni_uart_pops,
1728a8a66a1SGirish Mahadevan 				.flags = UPF_BOOT_AUTOCONF,
1738a8a66a1SGirish Mahadevan 				.line = 2,
1748a8a66a1SGirish Mahadevan 		},
1758a8a66a1SGirish Mahadevan 	},
1768a8a66a1SGirish Mahadevan };
1778a8a66a1SGirish Mahadevan 
178f7371750SKarthikeyan Ramasubramanian static struct qcom_geni_serial_port qcom_geni_console_port = {
179f7371750SKarthikeyan Ramasubramanian 	.uport = {
180f7371750SKarthikeyan Ramasubramanian 		.iotype = UPIO_MEM,
181f7371750SKarthikeyan Ramasubramanian 		.ops = &qcom_geni_console_pops,
182f7371750SKarthikeyan Ramasubramanian 		.flags = UPF_BOOT_AUTOCONF,
183f7371750SKarthikeyan Ramasubramanian 		.line = 0,
184f7371750SKarthikeyan Ramasubramanian 	},
185f7371750SKarthikeyan Ramasubramanian };
186c4f52879SKarthikeyan Ramasubramanian 
187c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_request_port(struct uart_port *uport)
188c4f52879SKarthikeyan Ramasubramanian {
189c4f52879SKarthikeyan Ramasubramanian 	struct platform_device *pdev = to_platform_device(uport->dev);
190c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
191c4f52879SKarthikeyan Ramasubramanian 
19244e60d52SYueHaibing 	uport->membase = devm_platform_ioremap_resource(pdev, 0);
193c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(uport->membase))
194c4f52879SKarthikeyan Ramasubramanian 		return PTR_ERR(uport->membase);
195c4f52879SKarthikeyan Ramasubramanian 	port->se.base = uport->membase;
196c4f52879SKarthikeyan Ramasubramanian 	return 0;
197c4f52879SKarthikeyan Ramasubramanian }
198c4f52879SKarthikeyan Ramasubramanian 
199c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_config_port(struct uart_port *uport, int cfg_flags)
200c4f52879SKarthikeyan Ramasubramanian {
201c4f52879SKarthikeyan Ramasubramanian 	if (cfg_flags & UART_CONFIG_TYPE) {
202c4f52879SKarthikeyan Ramasubramanian 		uport->type = PORT_MSM;
203c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_request_port(uport);
204c4f52879SKarthikeyan Ramasubramanian 	}
205c4f52879SKarthikeyan Ramasubramanian }
206c4f52879SKarthikeyan Ramasubramanian 
2078a8a66a1SGirish Mahadevan static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport)
208c4f52879SKarthikeyan Ramasubramanian {
2098a8a66a1SGirish Mahadevan 	unsigned int mctrl = TIOCM_DSR | TIOCM_CAR;
2108a8a66a1SGirish Mahadevan 	u32 geni_ios;
2118a8a66a1SGirish Mahadevan 
212e8a6ca80SMatthias Kaehlcke 	if (uart_console(uport)) {
2138a8a66a1SGirish Mahadevan 		mctrl |= TIOCM_CTS;
2148a8a66a1SGirish Mahadevan 	} else {
2159e06d55fSRyan Case 		geni_ios = readl(uport->membase + SE_GENI_IOS);
2168a8a66a1SGirish Mahadevan 		if (!(geni_ios & IO2_DATA_IN))
2178a8a66a1SGirish Mahadevan 			mctrl |= TIOCM_CTS;
218c4f52879SKarthikeyan Ramasubramanian 	}
219c4f52879SKarthikeyan Ramasubramanian 
2208a8a66a1SGirish Mahadevan 	return mctrl;
2218a8a66a1SGirish Mahadevan }
2228a8a66a1SGirish Mahadevan 
2238a8a66a1SGirish Mahadevan static void qcom_geni_serial_set_mctrl(struct uart_port *uport,
224c4f52879SKarthikeyan Ramasubramanian 							unsigned int mctrl)
225c4f52879SKarthikeyan Ramasubramanian {
2268a8a66a1SGirish Mahadevan 	u32 uart_manual_rfr = 0;
22769bd1a4fSAkash Asthana 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
2288a8a66a1SGirish Mahadevan 
229e8a6ca80SMatthias Kaehlcke 	if (uart_console(uport))
2308a8a66a1SGirish Mahadevan 		return;
2318a8a66a1SGirish Mahadevan 
23269bd1a4fSAkash Asthana 	if (mctrl & TIOCM_LOOP)
23369bd1a4fSAkash Asthana 		port->loopback = RX_TX_CTS_RTS_SORTED;
23469bd1a4fSAkash Asthana 
2358a8a66a1SGirish Mahadevan 	if (!(mctrl & TIOCM_RTS))
2368a8a66a1SGirish Mahadevan 		uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY;
2379e06d55fSRyan Case 	writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR);
238c4f52879SKarthikeyan Ramasubramanian }
239c4f52879SKarthikeyan Ramasubramanian 
240c4f52879SKarthikeyan Ramasubramanian static const char *qcom_geni_serial_get_type(struct uart_port *uport)
241c4f52879SKarthikeyan Ramasubramanian {
242c4f52879SKarthikeyan Ramasubramanian 	return "MSM";
243c4f52879SKarthikeyan Ramasubramanian }
244c4f52879SKarthikeyan Ramasubramanian 
2458a8a66a1SGirish Mahadevan static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
246c4f52879SKarthikeyan Ramasubramanian {
2478a8a66a1SGirish Mahadevan 	struct qcom_geni_serial_port *port;
2488a8a66a1SGirish Mahadevan 	int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS;
2498a8a66a1SGirish Mahadevan 
2508a8a66a1SGirish Mahadevan 	if (line < 0 || line >= nr_ports)
251c4f52879SKarthikeyan Ramasubramanian 		return ERR_PTR(-ENXIO);
2528a8a66a1SGirish Mahadevan 
2538a8a66a1SGirish Mahadevan 	port = console ? &qcom_geni_console_port : &qcom_geni_uart_ports[line];
2548a8a66a1SGirish Mahadevan 	return port;
255c4f52879SKarthikeyan Ramasubramanian }
256c4f52879SKarthikeyan Ramasubramanian 
257c4f52879SKarthikeyan Ramasubramanian static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
258c4f52879SKarthikeyan Ramasubramanian 				int offset, int field, bool set)
259c4f52879SKarthikeyan Ramasubramanian {
260c4f52879SKarthikeyan Ramasubramanian 	u32 reg;
261c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port;
262c4f52879SKarthikeyan Ramasubramanian 	unsigned int baud;
263c4f52879SKarthikeyan Ramasubramanian 	unsigned int fifo_bits;
264c4f52879SKarthikeyan Ramasubramanian 	unsigned long timeout_us = 20000;
265c4f52879SKarthikeyan Ramasubramanian 
266c4f52879SKarthikeyan Ramasubramanian 	if (uport->private_data) {
267c4f52879SKarthikeyan Ramasubramanian 		port = to_dev_port(uport, uport);
268c4f52879SKarthikeyan Ramasubramanian 		baud = port->baud;
269c4f52879SKarthikeyan Ramasubramanian 		if (!baud)
270c4f52879SKarthikeyan Ramasubramanian 			baud = 115200;
271c4f52879SKarthikeyan Ramasubramanian 		fifo_bits = port->tx_fifo_depth * port->tx_fifo_width;
272c4f52879SKarthikeyan Ramasubramanian 		/*
273c4f52879SKarthikeyan Ramasubramanian 		 * Total polling iterations based on FIFO worth of bytes to be
274c4f52879SKarthikeyan Ramasubramanian 		 * sent at current baud. Add a little fluff to the wait.
275c4f52879SKarthikeyan Ramasubramanian 		 */
276c4f52879SKarthikeyan Ramasubramanian 		timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500;
277c4f52879SKarthikeyan Ramasubramanian 	}
278c4f52879SKarthikeyan Ramasubramanian 
27943f1831bSKarthikeyan Ramasubramanian 	/*
28043f1831bSKarthikeyan Ramasubramanian 	 * Use custom implementation instead of readl_poll_atomic since ktimer
28143f1831bSKarthikeyan Ramasubramanian 	 * is not ready at the time of early console.
28243f1831bSKarthikeyan Ramasubramanian 	 */
28343f1831bSKarthikeyan Ramasubramanian 	timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10;
28443f1831bSKarthikeyan Ramasubramanian 	while (timeout_us) {
2859e06d55fSRyan Case 		reg = readl(uport->membase + offset);
28643f1831bSKarthikeyan Ramasubramanian 		if ((bool)(reg & field) == set)
28743f1831bSKarthikeyan Ramasubramanian 			return true;
28843f1831bSKarthikeyan Ramasubramanian 		udelay(10);
28943f1831bSKarthikeyan Ramasubramanian 		timeout_us -= 10;
29043f1831bSKarthikeyan Ramasubramanian 	}
29143f1831bSKarthikeyan Ramasubramanian 	return false;
292c4f52879SKarthikeyan Ramasubramanian }
293c4f52879SKarthikeyan Ramasubramanian 
294c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
295c4f52879SKarthikeyan Ramasubramanian {
296c4f52879SKarthikeyan Ramasubramanian 	u32 m_cmd;
297c4f52879SKarthikeyan Ramasubramanian 
2989e06d55fSRyan Case 	writel(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN);
299c4f52879SKarthikeyan Ramasubramanian 	m_cmd = UART_START_TX << M_OPCODE_SHFT;
300c4f52879SKarthikeyan Ramasubramanian 	writel(m_cmd, uport->membase + SE_GENI_M_CMD0);
301c4f52879SKarthikeyan Ramasubramanian }
302c4f52879SKarthikeyan Ramasubramanian 
303c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_poll_tx_done(struct uart_port *uport)
304c4f52879SKarthikeyan Ramasubramanian {
305c4f52879SKarthikeyan Ramasubramanian 	int done;
306c4f52879SKarthikeyan Ramasubramanian 	u32 irq_clear = M_CMD_DONE_EN;
307c4f52879SKarthikeyan Ramasubramanian 
308c4f52879SKarthikeyan Ramasubramanian 	done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
309c4f52879SKarthikeyan Ramasubramanian 						M_CMD_DONE_EN, true);
310c4f52879SKarthikeyan Ramasubramanian 	if (!done) {
3119e06d55fSRyan Case 		writel(M_GENI_CMD_ABORT, uport->membase +
312c4f52879SKarthikeyan Ramasubramanian 						SE_GENI_M_CMD_CTRL_REG);
313c4f52879SKarthikeyan Ramasubramanian 		irq_clear |= M_CMD_ABORT_EN;
314c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
315c4f52879SKarthikeyan Ramasubramanian 							M_CMD_ABORT_EN, true);
316c4f52879SKarthikeyan Ramasubramanian 	}
3179e06d55fSRyan Case 	writel(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR);
318c4f52879SKarthikeyan Ramasubramanian }
319c4f52879SKarthikeyan Ramasubramanian 
320c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_abort_rx(struct uart_port *uport)
321c4f52879SKarthikeyan Ramasubramanian {
322c4f52879SKarthikeyan Ramasubramanian 	u32 irq_clear = S_CMD_DONE_EN | S_CMD_ABORT_EN;
323c4f52879SKarthikeyan Ramasubramanian 
324c4f52879SKarthikeyan Ramasubramanian 	writel(S_GENI_CMD_ABORT, uport->membase + SE_GENI_S_CMD_CTRL_REG);
325c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG,
326c4f52879SKarthikeyan Ramasubramanian 					S_GENI_CMD_ABORT, false);
3279e06d55fSRyan Case 	writel(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR);
3289e06d55fSRyan Case 	writel(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG);
329c4f52879SKarthikeyan Ramasubramanian }
330c4f52879SKarthikeyan Ramasubramanian 
331c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_CONSOLE_POLL
332c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_get_char(struct uart_port *uport)
333c4f52879SKarthikeyan Ramasubramanian {
334c4f52879SKarthikeyan Ramasubramanian 	u32 rx_fifo;
335c4f52879SKarthikeyan Ramasubramanian 	u32 status;
336c4f52879SKarthikeyan Ramasubramanian 
3379e06d55fSRyan Case 	status = readl(uport->membase + SE_GENI_M_IRQ_STATUS);
3389e06d55fSRyan Case 	writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR);
339c4f52879SKarthikeyan Ramasubramanian 
3409e06d55fSRyan Case 	status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
3419e06d55fSRyan Case 	writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR);
342c4f52879SKarthikeyan Ramasubramanian 
3439e06d55fSRyan Case 	status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS);
344c4f52879SKarthikeyan Ramasubramanian 	if (!(status & RX_FIFO_WC_MSK))
345c4f52879SKarthikeyan Ramasubramanian 		return NO_POLL_CHAR;
346c4f52879SKarthikeyan Ramasubramanian 
347c4f52879SKarthikeyan Ramasubramanian 	rx_fifo = readl(uport->membase + SE_GENI_RX_FIFOn);
348c4f52879SKarthikeyan Ramasubramanian 	return rx_fifo & 0xff;
349c4f52879SKarthikeyan Ramasubramanian }
350c4f52879SKarthikeyan Ramasubramanian 
351c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
352c4f52879SKarthikeyan Ramasubramanian 							unsigned char c)
353c4f52879SKarthikeyan Ramasubramanian {
354a85fb9ceSRyan Case 	writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
355c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_setup_tx(uport, 1);
356c4f52879SKarthikeyan Ramasubramanian 	WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
357c4f52879SKarthikeyan Ramasubramanian 						M_TX_FIFO_WATERMARK_EN, true));
3589e06d55fSRyan Case 	writel(c, uport->membase + SE_GENI_TX_FIFOn);
3599e06d55fSRyan Case 	writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
360c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_tx_done(uport);
361c4f52879SKarthikeyan Ramasubramanian }
362c4f52879SKarthikeyan Ramasubramanian #endif
363c4f52879SKarthikeyan Ramasubramanian 
364c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
365c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch)
366c4f52879SKarthikeyan Ramasubramanian {
3679e06d55fSRyan Case 	writel(ch, uport->membase + SE_GENI_TX_FIFOn);
368c4f52879SKarthikeyan Ramasubramanian }
369c4f52879SKarthikeyan Ramasubramanian 
370c4f52879SKarthikeyan Ramasubramanian static void
371c4f52879SKarthikeyan Ramasubramanian __qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
372c4f52879SKarthikeyan Ramasubramanian 				 unsigned int count)
373c4f52879SKarthikeyan Ramasubramanian {
374c4f52879SKarthikeyan Ramasubramanian 	int i;
375c4f52879SKarthikeyan Ramasubramanian 	u32 bytes_to_send = count;
376c4f52879SKarthikeyan Ramasubramanian 
377c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < count; i++) {
378f0262568SKarthikeyan Ramasubramanian 		/*
379f0262568SKarthikeyan Ramasubramanian 		 * uart_console_write() adds a carriage return for each newline.
380f0262568SKarthikeyan Ramasubramanian 		 * Account for additional bytes to be written.
381f0262568SKarthikeyan Ramasubramanian 		 */
382c4f52879SKarthikeyan Ramasubramanian 		if (s[i] == '\n')
383c4f52879SKarthikeyan Ramasubramanian 			bytes_to_send++;
384c4f52879SKarthikeyan Ramasubramanian 	}
385c4f52879SKarthikeyan Ramasubramanian 
3869e06d55fSRyan Case 	writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
387c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_setup_tx(uport, bytes_to_send);
388c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < count; ) {
389c4f52879SKarthikeyan Ramasubramanian 		size_t chars_to_write = 0;
390c4f52879SKarthikeyan Ramasubramanian 		size_t avail = DEF_FIFO_DEPTH_WORDS - DEF_TX_WM;
391c4f52879SKarthikeyan Ramasubramanian 
392c4f52879SKarthikeyan Ramasubramanian 		/*
393c4f52879SKarthikeyan Ramasubramanian 		 * If the WM bit never set, then the Tx state machine is not
394c4f52879SKarthikeyan Ramasubramanian 		 * in a valid state, so break, cancel/abort any existing
395c4f52879SKarthikeyan Ramasubramanian 		 * command. Unfortunately the current data being written is
396c4f52879SKarthikeyan Ramasubramanian 		 * lost.
397c4f52879SKarthikeyan Ramasubramanian 		 */
398c4f52879SKarthikeyan Ramasubramanian 		if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
399c4f52879SKarthikeyan Ramasubramanian 						M_TX_FIFO_WATERMARK_EN, true))
400c4f52879SKarthikeyan Ramasubramanian 			break;
4016a10635eSKarthikeyan Ramasubramanian 		chars_to_write = min_t(size_t, count - i, avail / 2);
402c4f52879SKarthikeyan Ramasubramanian 		uart_console_write(uport, s + i, chars_to_write,
403c4f52879SKarthikeyan Ramasubramanian 						qcom_geni_serial_wr_char);
4049e06d55fSRyan Case 		writel(M_TX_FIFO_WATERMARK_EN, uport->membase +
405c4f52879SKarthikeyan Ramasubramanian 							SE_GENI_M_IRQ_CLEAR);
406c4f52879SKarthikeyan Ramasubramanian 		i += chars_to_write;
407c4f52879SKarthikeyan Ramasubramanian 	}
408c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_tx_done(uport);
409c4f52879SKarthikeyan Ramasubramanian }
410c4f52879SKarthikeyan Ramasubramanian 
411c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_console_write(struct console *co, const char *s,
412c4f52879SKarthikeyan Ramasubramanian 			      unsigned int count)
413c4f52879SKarthikeyan Ramasubramanian {
414c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport;
415c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port;
416c4f52879SKarthikeyan Ramasubramanian 	bool locked = true;
417c4f52879SKarthikeyan Ramasubramanian 	unsigned long flags;
418a1fee899SRyan Case 	u32 geni_status;
419663abb1aSRyan Case 	u32 irq_en;
420c4f52879SKarthikeyan Ramasubramanian 
421c4f52879SKarthikeyan Ramasubramanian 	WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
422c4f52879SKarthikeyan Ramasubramanian 
4238a8a66a1SGirish Mahadevan 	port = get_port_from_line(co->index, true);
424c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(port))
425c4f52879SKarthikeyan Ramasubramanian 		return;
426c4f52879SKarthikeyan Ramasubramanian 
427c4f52879SKarthikeyan Ramasubramanian 	uport = &port->uport;
428c4f52879SKarthikeyan Ramasubramanian 	if (oops_in_progress)
429c4f52879SKarthikeyan Ramasubramanian 		locked = spin_trylock_irqsave(&uport->lock, flags);
430c4f52879SKarthikeyan Ramasubramanian 	else
431c4f52879SKarthikeyan Ramasubramanian 		spin_lock_irqsave(&uport->lock, flags);
432c4f52879SKarthikeyan Ramasubramanian 
4339e06d55fSRyan Case 	geni_status = readl(uport->membase + SE_GENI_STATUS);
434a1fee899SRyan Case 
435c4f52879SKarthikeyan Ramasubramanian 	/* Cancel the current write to log the fault */
436c4f52879SKarthikeyan Ramasubramanian 	if (!locked) {
437c4f52879SKarthikeyan Ramasubramanian 		geni_se_cancel_m_cmd(&port->se);
438c4f52879SKarthikeyan Ramasubramanian 		if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
439c4f52879SKarthikeyan Ramasubramanian 						M_CMD_CANCEL_EN, true)) {
440c4f52879SKarthikeyan Ramasubramanian 			geni_se_abort_m_cmd(&port->se);
441c4f52879SKarthikeyan Ramasubramanian 			qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
442c4f52879SKarthikeyan Ramasubramanian 							M_CMD_ABORT_EN, true);
4439e06d55fSRyan Case 			writel(M_CMD_ABORT_EN, uport->membase +
444c4f52879SKarthikeyan Ramasubramanian 							SE_GENI_M_IRQ_CLEAR);
445c4f52879SKarthikeyan Ramasubramanian 		}
4469e06d55fSRyan Case 		writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
447a1fee899SRyan Case 	} else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
448a1fee899SRyan Case 		/*
449a1fee899SRyan Case 		 * It seems we can't interrupt existing transfers if all data
450a1fee899SRyan Case 		 * has been sent, in which case we need to look for done first.
451a1fee899SRyan Case 		 */
452a1fee899SRyan Case 		qcom_geni_serial_poll_tx_done(uport);
453663abb1aSRyan Case 
454663abb1aSRyan Case 		if (uart_circ_chars_pending(&uport->state->xmit)) {
4559e06d55fSRyan Case 			irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
4569e06d55fSRyan Case 			writel(irq_en | M_TX_FIFO_WATERMARK_EN,
457663abb1aSRyan Case 					uport->membase + SE_GENI_M_IRQ_EN);
458663abb1aSRyan Case 		}
459c4f52879SKarthikeyan Ramasubramanian 	}
460c4f52879SKarthikeyan Ramasubramanian 
461c4f52879SKarthikeyan Ramasubramanian 	__qcom_geni_serial_console_write(uport, s, count);
462a1fee899SRyan Case 
463a1fee899SRyan Case 	if (port->tx_remaining)
464a1fee899SRyan Case 		qcom_geni_serial_setup_tx(uport, port->tx_remaining);
465a1fee899SRyan Case 
466c4f52879SKarthikeyan Ramasubramanian 	if (locked)
467c4f52879SKarthikeyan Ramasubramanian 		spin_unlock_irqrestore(&uport->lock, flags);
468c4f52879SKarthikeyan Ramasubramanian }
469c4f52879SKarthikeyan Ramasubramanian 
470c4f52879SKarthikeyan Ramasubramanian static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
471c4f52879SKarthikeyan Ramasubramanian {
472c4f52879SKarthikeyan Ramasubramanian 	u32 i;
473c4f52879SKarthikeyan Ramasubramanian 	unsigned char buf[sizeof(u32)];
474c4f52879SKarthikeyan Ramasubramanian 	struct tty_port *tport;
475c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
476c4f52879SKarthikeyan Ramasubramanian 
477c4f52879SKarthikeyan Ramasubramanian 	tport = &uport->state->port;
478c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < bytes; ) {
479c4f52879SKarthikeyan Ramasubramanian 		int c;
480c4f52879SKarthikeyan Ramasubramanian 		int chunk = min_t(int, bytes - i, port->rx_bytes_pw);
481c4f52879SKarthikeyan Ramasubramanian 
482c4f52879SKarthikeyan Ramasubramanian 		ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, buf, 1);
483c4f52879SKarthikeyan Ramasubramanian 		i += chunk;
484c4f52879SKarthikeyan Ramasubramanian 		if (drop)
485c4f52879SKarthikeyan Ramasubramanian 			continue;
486c4f52879SKarthikeyan Ramasubramanian 
487c4f52879SKarthikeyan Ramasubramanian 		for (c = 0; c < chunk; c++) {
488c4f52879SKarthikeyan Ramasubramanian 			int sysrq;
489c4f52879SKarthikeyan Ramasubramanian 
490c4f52879SKarthikeyan Ramasubramanian 			uport->icount.rx++;
491c4f52879SKarthikeyan Ramasubramanian 			if (port->brk && buf[c] == 0) {
492c4f52879SKarthikeyan Ramasubramanian 				port->brk = false;
493c4f52879SKarthikeyan Ramasubramanian 				if (uart_handle_break(uport))
494c4f52879SKarthikeyan Ramasubramanian 					continue;
495c4f52879SKarthikeyan Ramasubramanian 			}
496c4f52879SKarthikeyan Ramasubramanian 
497336447b3SDouglas Anderson 			sysrq = uart_prepare_sysrq_char(uport, buf[c]);
498babeca85SDouglas Anderson 
499c4f52879SKarthikeyan Ramasubramanian 			if (!sysrq)
500c4f52879SKarthikeyan Ramasubramanian 				tty_insert_flip_char(tport, buf[c], TTY_NORMAL);
501c4f52879SKarthikeyan Ramasubramanian 		}
502c4f52879SKarthikeyan Ramasubramanian 	}
503c4f52879SKarthikeyan Ramasubramanian 	if (!drop)
504c4f52879SKarthikeyan Ramasubramanian 		tty_flip_buffer_push(tport);
505c4f52879SKarthikeyan Ramasubramanian 	return 0;
506c4f52879SKarthikeyan Ramasubramanian }
507c4f52879SKarthikeyan Ramasubramanian #else
508c4f52879SKarthikeyan Ramasubramanian static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
509c4f52879SKarthikeyan Ramasubramanian {
510c4f52879SKarthikeyan Ramasubramanian 	return -EPERM;
511c4f52879SKarthikeyan Ramasubramanian }
512c4f52879SKarthikeyan Ramasubramanian 
513c4f52879SKarthikeyan Ramasubramanian #endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
514c4f52879SKarthikeyan Ramasubramanian 
5158a8a66a1SGirish Mahadevan static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
5168a8a66a1SGirish Mahadevan {
5178a8a66a1SGirish Mahadevan 	struct tty_port *tport;
5188a8a66a1SGirish Mahadevan 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
5198a8a66a1SGirish Mahadevan 	u32 num_bytes_pw = port->tx_fifo_width / BITS_PER_BYTE;
5208a8a66a1SGirish Mahadevan 	u32 words = ALIGN(bytes, num_bytes_pw) / num_bytes_pw;
5218a8a66a1SGirish Mahadevan 	int ret;
5228a8a66a1SGirish Mahadevan 
5238a8a66a1SGirish Mahadevan 	tport = &uport->state->port;
5248a8a66a1SGirish Mahadevan 	ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, port->rx_fifo, words);
5258a8a66a1SGirish Mahadevan 	if (drop)
5268a8a66a1SGirish Mahadevan 		return 0;
5278a8a66a1SGirish Mahadevan 
528f9d690b6Ssatya priya 	ret = tty_insert_flip_string(tport, port->rx_fifo, bytes);
5298a8a66a1SGirish Mahadevan 	if (ret != bytes) {
5308a8a66a1SGirish Mahadevan 		dev_err(uport->dev, "%s:Unable to push data ret %d_bytes %d\n",
5318a8a66a1SGirish Mahadevan 				__func__, ret, bytes);
5328a8a66a1SGirish Mahadevan 		WARN_ON_ONCE(1);
5338a8a66a1SGirish Mahadevan 	}
5348a8a66a1SGirish Mahadevan 	uport->icount.rx += ret;
5358a8a66a1SGirish Mahadevan 	tty_flip_buffer_push(tport);
5368a8a66a1SGirish Mahadevan 	return ret;
5378a8a66a1SGirish Mahadevan }
5388a8a66a1SGirish Mahadevan 
539c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_start_tx(struct uart_port *uport)
540c4f52879SKarthikeyan Ramasubramanian {
541c4f52879SKarthikeyan Ramasubramanian 	u32 irq_en;
542c4f52879SKarthikeyan Ramasubramanian 	u32 status;
543c4f52879SKarthikeyan Ramasubramanian 
5447fb5b880SKarthikeyan Ramasubramanian 	status = readl(uport->membase + SE_GENI_STATUS);
545c4f52879SKarthikeyan Ramasubramanian 	if (status & M_GENI_CMD_ACTIVE)
546c4f52879SKarthikeyan Ramasubramanian 		return;
547c4f52879SKarthikeyan Ramasubramanian 
548c4f52879SKarthikeyan Ramasubramanian 	if (!qcom_geni_serial_tx_empty(uport))
549c4f52879SKarthikeyan Ramasubramanian 		return;
550c4f52879SKarthikeyan Ramasubramanian 
5519e06d55fSRyan Case 	irq_en = readl(uport->membase +	SE_GENI_M_IRQ_EN);
552c4f52879SKarthikeyan Ramasubramanian 	irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN;
553c4f52879SKarthikeyan Ramasubramanian 
554bdc05a8aSRyan Case 	writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
5559e06d55fSRyan Case 	writel(irq_en, uport->membase +	SE_GENI_M_IRQ_EN);
556c4f52879SKarthikeyan Ramasubramanian }
557c4f52879SKarthikeyan Ramasubramanian 
558c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_stop_tx(struct uart_port *uport)
559c4f52879SKarthikeyan Ramasubramanian {
560c4f52879SKarthikeyan Ramasubramanian 	u32 irq_en;
561c4f52879SKarthikeyan Ramasubramanian 	u32 status;
562c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
563c4f52879SKarthikeyan Ramasubramanian 
5649e06d55fSRyan Case 	irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
565bdc05a8aSRyan Case 	irq_en &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
566bdc05a8aSRyan Case 	writel(0, uport->membase + SE_GENI_TX_WATERMARK_REG);
5679e06d55fSRyan Case 	writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
5689e06d55fSRyan Case 	status = readl(uport->membase + SE_GENI_STATUS);
569c4f52879SKarthikeyan Ramasubramanian 	/* Possible stop tx is called multiple times. */
570c4f52879SKarthikeyan Ramasubramanian 	if (!(status & M_GENI_CMD_ACTIVE))
571c4f52879SKarthikeyan Ramasubramanian 		return;
572c4f52879SKarthikeyan Ramasubramanian 
573c4f52879SKarthikeyan Ramasubramanian 	geni_se_cancel_m_cmd(&port->se);
574c4f52879SKarthikeyan Ramasubramanian 	if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
575c4f52879SKarthikeyan Ramasubramanian 						M_CMD_CANCEL_EN, true)) {
576c4f52879SKarthikeyan Ramasubramanian 		geni_se_abort_m_cmd(&port->se);
577c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
578c4f52879SKarthikeyan Ramasubramanian 						M_CMD_ABORT_EN, true);
5799e06d55fSRyan Case 		writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
580c4f52879SKarthikeyan Ramasubramanian 	}
5819e06d55fSRyan Case 	writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
582c4f52879SKarthikeyan Ramasubramanian }
583c4f52879SKarthikeyan Ramasubramanian 
584c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_start_rx(struct uart_port *uport)
585c4f52879SKarthikeyan Ramasubramanian {
586c4f52879SKarthikeyan Ramasubramanian 	u32 irq_en;
587c4f52879SKarthikeyan Ramasubramanian 	u32 status;
588c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
589c4f52879SKarthikeyan Ramasubramanian 
5909e06d55fSRyan Case 	status = readl(uport->membase + SE_GENI_STATUS);
591c4f52879SKarthikeyan Ramasubramanian 	if (status & S_GENI_CMD_ACTIVE)
592c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_stop_rx(uport);
593c4f52879SKarthikeyan Ramasubramanian 
594c4f52879SKarthikeyan Ramasubramanian 	geni_se_setup_s_cmd(&port->se, UART_START_READ, 0);
595c4f52879SKarthikeyan Ramasubramanian 
5969e06d55fSRyan Case 	irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN);
597c4f52879SKarthikeyan Ramasubramanian 	irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
5989e06d55fSRyan Case 	writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN);
599c4f52879SKarthikeyan Ramasubramanian 
6009e06d55fSRyan Case 	irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
601c4f52879SKarthikeyan Ramasubramanian 	irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
6029e06d55fSRyan Case 	writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
603c4f52879SKarthikeyan Ramasubramanian }
604c4f52879SKarthikeyan Ramasubramanian 
605c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_stop_rx(struct uart_port *uport)
606c4f52879SKarthikeyan Ramasubramanian {
607c4f52879SKarthikeyan Ramasubramanian 	u32 irq_en;
608c4f52879SKarthikeyan Ramasubramanian 	u32 status;
609c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
610679aac5eSsatya priya 	u32 s_irq_status;
611c4f52879SKarthikeyan Ramasubramanian 
6129e06d55fSRyan Case 	irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN);
613c4f52879SKarthikeyan Ramasubramanian 	irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN);
6149e06d55fSRyan Case 	writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN);
615c4f52879SKarthikeyan Ramasubramanian 
6169e06d55fSRyan Case 	irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
617c4f52879SKarthikeyan Ramasubramanian 	irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
6189e06d55fSRyan Case 	writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
619c4f52879SKarthikeyan Ramasubramanian 
6209e06d55fSRyan Case 	status = readl(uport->membase + SE_GENI_STATUS);
621c4f52879SKarthikeyan Ramasubramanian 	/* Possible stop rx is called multiple times. */
622c4f52879SKarthikeyan Ramasubramanian 	if (!(status & S_GENI_CMD_ACTIVE))
623c4f52879SKarthikeyan Ramasubramanian 		return;
624c4f52879SKarthikeyan Ramasubramanian 
625c4f52879SKarthikeyan Ramasubramanian 	geni_se_cancel_s_cmd(&port->se);
626679aac5eSsatya priya 	qcom_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
627679aac5eSsatya priya 					S_CMD_CANCEL_EN, true);
628679aac5eSsatya priya 	/*
629679aac5eSsatya priya 	 * If timeout occurs secondary engine remains active
630679aac5eSsatya priya 	 * and Abort sequence is executed.
631679aac5eSsatya priya 	 */
632679aac5eSsatya priya 	s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
633679aac5eSsatya priya 	/* Flush the Rx buffer */
634679aac5eSsatya priya 	if (s_irq_status & S_RX_FIFO_LAST_EN)
635679aac5eSsatya priya 		qcom_geni_serial_handle_rx(uport, true);
636679aac5eSsatya priya 	writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
637679aac5eSsatya priya 
6389e06d55fSRyan Case 	status = readl(uport->membase + SE_GENI_STATUS);
639c4f52879SKarthikeyan Ramasubramanian 	if (status & S_GENI_CMD_ACTIVE)
640c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_abort_rx(uport);
641c4f52879SKarthikeyan Ramasubramanian }
642c4f52879SKarthikeyan Ramasubramanian 
643c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop)
644c4f52879SKarthikeyan Ramasubramanian {
645c4f52879SKarthikeyan Ramasubramanian 	u32 status;
646c4f52879SKarthikeyan Ramasubramanian 	u32 word_cnt;
647c4f52879SKarthikeyan Ramasubramanian 	u32 last_word_byte_cnt;
648c4f52879SKarthikeyan Ramasubramanian 	u32 last_word_partial;
649c4f52879SKarthikeyan Ramasubramanian 	u32 total_bytes;
650c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
651c4f52879SKarthikeyan Ramasubramanian 
6529e06d55fSRyan Case 	status = readl(uport->membase +	SE_GENI_RX_FIFO_STATUS);
653c4f52879SKarthikeyan Ramasubramanian 	word_cnt = status & RX_FIFO_WC_MSK;
654c4f52879SKarthikeyan Ramasubramanian 	last_word_partial = status & RX_LAST;
655c4f52879SKarthikeyan Ramasubramanian 	last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >>
656c4f52879SKarthikeyan Ramasubramanian 						RX_LAST_BYTE_VALID_SHFT;
657c4f52879SKarthikeyan Ramasubramanian 
658c4f52879SKarthikeyan Ramasubramanian 	if (!word_cnt)
659c4f52879SKarthikeyan Ramasubramanian 		return;
660c4f52879SKarthikeyan Ramasubramanian 	total_bytes = port->rx_bytes_pw * (word_cnt - 1);
661c4f52879SKarthikeyan Ramasubramanian 	if (last_word_partial && last_word_byte_cnt)
662c4f52879SKarthikeyan Ramasubramanian 		total_bytes += last_word_byte_cnt;
663c4f52879SKarthikeyan Ramasubramanian 	else
664c4f52879SKarthikeyan Ramasubramanian 		total_bytes += port->rx_bytes_pw;
665c4f52879SKarthikeyan Ramasubramanian 	port->handle_rx(uport, total_bytes, drop);
666c4f52879SKarthikeyan Ramasubramanian }
667c4f52879SKarthikeyan Ramasubramanian 
668a1fee899SRyan Case static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done,
669a1fee899SRyan Case 		bool active)
670c4f52879SKarthikeyan Ramasubramanian {
671c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
672c4f52879SKarthikeyan Ramasubramanian 	struct circ_buf *xmit = &uport->state->xmit;
673c4f52879SKarthikeyan Ramasubramanian 	size_t avail;
674c4f52879SKarthikeyan Ramasubramanian 	size_t remaining;
675a1fee899SRyan Case 	size_t pending;
676c4f52879SKarthikeyan Ramasubramanian 	int i;
677c4f52879SKarthikeyan Ramasubramanian 	u32 status;
67864a42807SRyan Case 	u32 irq_en;
679c4f52879SKarthikeyan Ramasubramanian 	unsigned int chunk;
680c4f52879SKarthikeyan Ramasubramanian 	int tail;
681c4f52879SKarthikeyan Ramasubramanian 
6829e06d55fSRyan Case 	status = readl(uport->membase + SE_GENI_TX_FIFO_STATUS);
683a1fee899SRyan Case 
684a1fee899SRyan Case 	/* Complete the current tx command before taking newly added data */
685a1fee899SRyan Case 	if (active)
686a1fee899SRyan Case 		pending = port->tx_remaining;
687a1fee899SRyan Case 	else
688a1fee899SRyan Case 		pending = uart_circ_chars_pending(xmit);
689a1fee899SRyan Case 
690a1fee899SRyan Case 	/* All data has been transmitted and acknowledged as received */
691a1fee899SRyan Case 	if (!pending && !status && done) {
692c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_stop_tx(uport);
693c4f52879SKarthikeyan Ramasubramanian 		goto out_write_wakeup;
694c4f52879SKarthikeyan Ramasubramanian 	}
695c4f52879SKarthikeyan Ramasubramanian 
696a1fee899SRyan Case 	avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
697a1fee899SRyan Case 	avail *= port->tx_bytes_pw;
6988a8a66a1SGirish Mahadevan 
699638a6f4eSEvan Green 	tail = xmit->tail;
7003c66eb4bSMatthias Kaehlcke 	chunk = min(avail, pending);
701c4f52879SKarthikeyan Ramasubramanian 	if (!chunk)
702c4f52879SKarthikeyan Ramasubramanian 		goto out_write_wakeup;
703c4f52879SKarthikeyan Ramasubramanian 
704a1fee899SRyan Case 	if (!port->tx_remaining) {
705a1fee899SRyan Case 		qcom_geni_serial_setup_tx(uport, pending);
706a1fee899SRyan Case 		port->tx_remaining = pending;
70764a42807SRyan Case 
7089e06d55fSRyan Case 		irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
70964a42807SRyan Case 		if (!(irq_en & M_TX_FIFO_WATERMARK_EN))
7109e06d55fSRyan Case 			writel(irq_en | M_TX_FIFO_WATERMARK_EN,
71164a42807SRyan Case 					uport->membase + SE_GENI_M_IRQ_EN);
712a1fee899SRyan Case 	}
713c4f52879SKarthikeyan Ramasubramanian 
714c4f52879SKarthikeyan Ramasubramanian 	remaining = chunk;
715c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < chunk; ) {
716c4f52879SKarthikeyan Ramasubramanian 		unsigned int tx_bytes;
71769736b57SKarthikeyan Ramasubramanian 		u8 buf[sizeof(u32)];
718c4f52879SKarthikeyan Ramasubramanian 		int c;
719c4f52879SKarthikeyan Ramasubramanian 
72069736b57SKarthikeyan Ramasubramanian 		memset(buf, 0, ARRAY_SIZE(buf));
7216a10635eSKarthikeyan Ramasubramanian 		tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw);
7223c66eb4bSMatthias Kaehlcke 
7233c66eb4bSMatthias Kaehlcke 		for (c = 0; c < tx_bytes ; c++) {
7243c66eb4bSMatthias Kaehlcke 			buf[c] = xmit->buf[tail++];
7253c66eb4bSMatthias Kaehlcke 			tail &= UART_XMIT_SIZE - 1;
7263c66eb4bSMatthias Kaehlcke 		}
727c4f52879SKarthikeyan Ramasubramanian 
72869736b57SKarthikeyan Ramasubramanian 		iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
729c4f52879SKarthikeyan Ramasubramanian 
730c4f52879SKarthikeyan Ramasubramanian 		i += tx_bytes;
731c4f52879SKarthikeyan Ramasubramanian 		uport->icount.tx += tx_bytes;
732c4f52879SKarthikeyan Ramasubramanian 		remaining -= tx_bytes;
733a1fee899SRyan Case 		port->tx_remaining -= tx_bytes;
734c4f52879SKarthikeyan Ramasubramanian 	}
735638a6f4eSEvan Green 
7363c66eb4bSMatthias Kaehlcke 	xmit->tail = tail;
73764a42807SRyan Case 
73864a42807SRyan Case 	/*
73964a42807SRyan Case 	 * The tx fifo watermark is level triggered and latched. Though we had
74064a42807SRyan Case 	 * cleared it in qcom_geni_serial_isr it will have already reasserted
74164a42807SRyan Case 	 * so we must clear it again here after our writes.
74264a42807SRyan Case 	 */
7439e06d55fSRyan Case 	writel(M_TX_FIFO_WATERMARK_EN,
74464a42807SRyan Case 			uport->membase + SE_GENI_M_IRQ_CLEAR);
74564a42807SRyan Case 
746c4f52879SKarthikeyan Ramasubramanian out_write_wakeup:
74764a42807SRyan Case 	if (!port->tx_remaining) {
7489e06d55fSRyan Case 		irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
74964a42807SRyan Case 		if (irq_en & M_TX_FIFO_WATERMARK_EN)
7509e06d55fSRyan Case 			writel(irq_en & ~M_TX_FIFO_WATERMARK_EN,
75164a42807SRyan Case 					uport->membase + SE_GENI_M_IRQ_EN);
75264a42807SRyan Case 	}
75364a42807SRyan Case 
754638a6f4eSEvan Green 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
755c4f52879SKarthikeyan Ramasubramanian 		uart_write_wakeup(uport);
756c4f52879SKarthikeyan Ramasubramanian }
757c4f52879SKarthikeyan Ramasubramanian 
758c4f52879SKarthikeyan Ramasubramanian static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
759c4f52879SKarthikeyan Ramasubramanian {
760385298abSRyan Case 	u32 m_irq_en;
761385298abSRyan Case 	u32 m_irq_status;
762385298abSRyan Case 	u32 s_irq_status;
763385298abSRyan Case 	u32 geni_status;
764c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport = dev;
765c4f52879SKarthikeyan Ramasubramanian 	unsigned long flags;
766c4f52879SKarthikeyan Ramasubramanian 	bool drop_rx = false;
767c4f52879SKarthikeyan Ramasubramanian 	struct tty_port *tport = &uport->state->port;
768c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
769c4f52879SKarthikeyan Ramasubramanian 
770c4f52879SKarthikeyan Ramasubramanian 	if (uport->suspended)
771ec91df8dSKarthikeyan Ramasubramanian 		return IRQ_NONE;
772c4f52879SKarthikeyan Ramasubramanian 
773c4f52879SKarthikeyan Ramasubramanian 	spin_lock_irqsave(&uport->lock, flags);
7749e06d55fSRyan Case 	m_irq_status = readl(uport->membase + SE_GENI_M_IRQ_STATUS);
7759e06d55fSRyan Case 	s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
7769e06d55fSRyan Case 	geni_status = readl(uport->membase + SE_GENI_STATUS);
7779e06d55fSRyan Case 	m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
7789e06d55fSRyan Case 	writel(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR);
7799e06d55fSRyan Case 	writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
780c4f52879SKarthikeyan Ramasubramanian 
781c4f52879SKarthikeyan Ramasubramanian 	if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN))
782c4f52879SKarthikeyan Ramasubramanian 		goto out_unlock;
783c4f52879SKarthikeyan Ramasubramanian 
784c4f52879SKarthikeyan Ramasubramanian 	if (s_irq_status & S_RX_FIFO_WR_ERR_EN) {
785c4f52879SKarthikeyan Ramasubramanian 		uport->icount.overrun++;
786c4f52879SKarthikeyan Ramasubramanian 		tty_insert_flip_char(tport, 0, TTY_OVERRUN);
787c4f52879SKarthikeyan Ramasubramanian 	}
788c4f52879SKarthikeyan Ramasubramanian 
78964a42807SRyan Case 	if (m_irq_status & m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
790a1fee899SRyan Case 		qcom_geni_serial_handle_tx(uport, m_irq_status & M_CMD_DONE_EN,
791a1fee899SRyan Case 					geni_status & M_GENI_CMD_ACTIVE);
792c4f52879SKarthikeyan Ramasubramanian 
793c4f52879SKarthikeyan Ramasubramanian 	if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) {
794c4f52879SKarthikeyan Ramasubramanian 		if (s_irq_status & S_GP_IRQ_0_EN)
795c4f52879SKarthikeyan Ramasubramanian 			uport->icount.parity++;
796c4f52879SKarthikeyan Ramasubramanian 		drop_rx = true;
797c4f52879SKarthikeyan Ramasubramanian 	} else if (s_irq_status & S_GP_IRQ_2_EN ||
798c4f52879SKarthikeyan Ramasubramanian 					s_irq_status & S_GP_IRQ_3_EN) {
799c4f52879SKarthikeyan Ramasubramanian 		uport->icount.brk++;
800c4f52879SKarthikeyan Ramasubramanian 		port->brk = true;
801c4f52879SKarthikeyan Ramasubramanian 	}
802c4f52879SKarthikeyan Ramasubramanian 
803c4f52879SKarthikeyan Ramasubramanian 	if (s_irq_status & S_RX_FIFO_WATERMARK_EN ||
804c4f52879SKarthikeyan Ramasubramanian 					s_irq_status & S_RX_FIFO_LAST_EN)
805c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_handle_rx(uport, drop_rx);
806c4f52879SKarthikeyan Ramasubramanian 
807c4f52879SKarthikeyan Ramasubramanian out_unlock:
808336447b3SDouglas Anderson 	uart_unlock_and_check_sysrq(uport, flags);
809336447b3SDouglas Anderson 
810c4f52879SKarthikeyan Ramasubramanian 	return IRQ_HANDLED;
811c4f52879SKarthikeyan Ramasubramanian }
812c4f52879SKarthikeyan Ramasubramanian 
8136a10635eSKarthikeyan Ramasubramanian static void get_tx_fifo_size(struct qcom_geni_serial_port *port)
814c4f52879SKarthikeyan Ramasubramanian {
815c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport;
816c4f52879SKarthikeyan Ramasubramanian 
817c4f52879SKarthikeyan Ramasubramanian 	uport = &port->uport;
818c4f52879SKarthikeyan Ramasubramanian 	port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se);
819c4f52879SKarthikeyan Ramasubramanian 	port->tx_fifo_width = geni_se_get_tx_fifo_width(&port->se);
820c4f52879SKarthikeyan Ramasubramanian 	port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se);
821c4f52879SKarthikeyan Ramasubramanian 	uport->fifosize =
822c4f52879SKarthikeyan Ramasubramanian 		(port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE;
823c4f52879SKarthikeyan Ramasubramanian }
824c4f52879SKarthikeyan Ramasubramanian 
825c4f52879SKarthikeyan Ramasubramanian 
826c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_shutdown(struct uart_port *uport)
827c4f52879SKarthikeyan Ramasubramanian {
8283e4aaea7SAkash Asthana 	disable_irq(uport->irq);
829c4f52879SKarthikeyan Ramasubramanian }
830c4f52879SKarthikeyan Ramasubramanian 
831c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_port_setup(struct uart_port *uport)
832c4f52879SKarthikeyan Ramasubramanian {
833c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
834385298abSRyan Case 	u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
835c362272bSDouglas Anderson 	u32 proto;
8369fa3c4b1SRoja Rani Yarubandi 	u32 pin_swap;
837c362272bSDouglas Anderson 
8389f641df4SDouglas Anderson 	if (uart_console(uport)) {
839c362272bSDouglas Anderson 		port->tx_bytes_pw = 1;
8409f641df4SDouglas Anderson 		port->rx_bytes_pw = CONSOLE_RX_BYTES_PW;
8419f641df4SDouglas Anderson 	} else {
842c362272bSDouglas Anderson 		port->tx_bytes_pw = 4;
8439f641df4SDouglas Anderson 		port->rx_bytes_pw = 4;
8449f641df4SDouglas Anderson 	}
845c362272bSDouglas Anderson 
846c362272bSDouglas Anderson 	proto = geni_se_read_proto(&port->se);
847c362272bSDouglas Anderson 	if (proto != GENI_SE_UART) {
848c362272bSDouglas Anderson 		dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
849c362272bSDouglas Anderson 		return -ENXIO;
850c362272bSDouglas Anderson 	}
851c362272bSDouglas Anderson 
852c362272bSDouglas Anderson 	qcom_geni_serial_stop_rx(uport);
853c362272bSDouglas Anderson 
854c362272bSDouglas Anderson 	get_tx_fifo_size(port);
855c4f52879SKarthikeyan Ramasubramanian 
8569e06d55fSRyan Case 	writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
8579fa3c4b1SRoja Rani Yarubandi 
8589fa3c4b1SRoja Rani Yarubandi 	pin_swap = readl(uport->membase + SE_UART_IO_MACRO_CTRL);
8599fa3c4b1SRoja Rani Yarubandi 	if (port->rx_tx_swap) {
8609fa3c4b1SRoja Rani Yarubandi 		pin_swap &= ~DEFAULT_IO_MACRO_IO2_IO3_MASK;
8619fa3c4b1SRoja Rani Yarubandi 		pin_swap |= IO_MACRO_IO2_IO3_SWAP;
8629fa3c4b1SRoja Rani Yarubandi 	}
8639fa3c4b1SRoja Rani Yarubandi 	if (port->cts_rts_swap) {
8649fa3c4b1SRoja Rani Yarubandi 		pin_swap &= ~DEFAULT_IO_MACRO_IO0_IO1_MASK;
8659fa3c4b1SRoja Rani Yarubandi 		pin_swap |= IO_MACRO_IO0_SEL;
8669fa3c4b1SRoja Rani Yarubandi 	}
8679fa3c4b1SRoja Rani Yarubandi 	/* Configure this register if RX-TX, CTS-RTS pins are swapped */
8689fa3c4b1SRoja Rani Yarubandi 	if (port->rx_tx_swap || port->cts_rts_swap)
8699fa3c4b1SRoja Rani Yarubandi 		writel(pin_swap, uport->membase + SE_UART_IO_MACRO_CTRL);
8709fa3c4b1SRoja Rani Yarubandi 
871c4f52879SKarthikeyan Ramasubramanian 	/*
872c4f52879SKarthikeyan Ramasubramanian 	 * Make an unconditional cancel on the main sequencer to reset
873c4f52879SKarthikeyan Ramasubramanian 	 * it else we could end up in data loss scenarios.
874c4f52879SKarthikeyan Ramasubramanian 	 */
8758a8a66a1SGirish Mahadevan 	if (uart_console(uport))
876c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_poll_tx_done(uport);
877c4f52879SKarthikeyan Ramasubramanian 	geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw,
878c4f52879SKarthikeyan Ramasubramanian 						false, true, false);
879c4f52879SKarthikeyan Ramasubramanian 	geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw,
880c4f52879SKarthikeyan Ramasubramanian 						false, false, true);
881a85fb9ceSRyan Case 	geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
882bdc05a8aSRyan Case 	geni_se_select_mode(&port->se, GENI_SE_FIFO);
883c4f52879SKarthikeyan Ramasubramanian 	port->setup = true;
884c362272bSDouglas Anderson 
885c4f52879SKarthikeyan Ramasubramanian 	return 0;
886c4f52879SKarthikeyan Ramasubramanian }
887c4f52879SKarthikeyan Ramasubramanian 
888c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_startup(struct uart_port *uport)
889c4f52879SKarthikeyan Ramasubramanian {
890c4f52879SKarthikeyan Ramasubramanian 	int ret;
891c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
892c4f52879SKarthikeyan Ramasubramanian 
893c4f52879SKarthikeyan Ramasubramanian 	if (!port->setup) {
894c4f52879SKarthikeyan Ramasubramanian 		ret = qcom_geni_serial_port_setup(uport);
895c4f52879SKarthikeyan Ramasubramanian 		if (ret)
896c4f52879SKarthikeyan Ramasubramanian 			return ret;
897c4f52879SKarthikeyan Ramasubramanian 	}
8983e4aaea7SAkash Asthana 	enable_irq(uport->irq);
899c4f52879SKarthikeyan Ramasubramanian 
9003e4aaea7SAkash Asthana 	return 0;
901c4f52879SKarthikeyan Ramasubramanian }
902c4f52879SKarthikeyan Ramasubramanian 
903c4f52879SKarthikeyan Ramasubramanian static unsigned long get_clk_cfg(unsigned long clk_freq)
904c4f52879SKarthikeyan Ramasubramanian {
905c4f52879SKarthikeyan Ramasubramanian 	int i;
906c4f52879SKarthikeyan Ramasubramanian 
907c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < ARRAY_SIZE(root_freq); i++) {
908c4f52879SKarthikeyan Ramasubramanian 		if (!(root_freq[i] % clk_freq))
909c4f52879SKarthikeyan Ramasubramanian 			return root_freq[i];
910c4f52879SKarthikeyan Ramasubramanian 	}
911c4f52879SKarthikeyan Ramasubramanian 	return 0;
912c4f52879SKarthikeyan Ramasubramanian }
913c4f52879SKarthikeyan Ramasubramanian 
914ce734600SVivek Gautam static unsigned long get_clk_div_rate(unsigned int baud,
915ce734600SVivek Gautam 			unsigned int sampling_rate, unsigned int *clk_div)
916c4f52879SKarthikeyan Ramasubramanian {
917c4f52879SKarthikeyan Ramasubramanian 	unsigned long ser_clk;
918c4f52879SKarthikeyan Ramasubramanian 	unsigned long desired_clk;
919c4f52879SKarthikeyan Ramasubramanian 
920ce734600SVivek Gautam 	desired_clk = baud * sampling_rate;
921c4f52879SKarthikeyan Ramasubramanian 	ser_clk = get_clk_cfg(desired_clk);
922c4f52879SKarthikeyan Ramasubramanian 	if (!ser_clk) {
923c4f52879SKarthikeyan Ramasubramanian 		pr_err("%s: Can't find matching DFS entry for baud %d\n",
924c4f52879SKarthikeyan Ramasubramanian 								__func__, baud);
925c4f52879SKarthikeyan Ramasubramanian 		return ser_clk;
926c4f52879SKarthikeyan Ramasubramanian 	}
927c4f52879SKarthikeyan Ramasubramanian 
928c4f52879SKarthikeyan Ramasubramanian 	*clk_div = ser_clk / desired_clk;
929c4f52879SKarthikeyan Ramasubramanian 	return ser_clk;
930c4f52879SKarthikeyan Ramasubramanian }
931c4f52879SKarthikeyan Ramasubramanian 
932c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_set_termios(struct uart_port *uport,
933c4f52879SKarthikeyan Ramasubramanian 				struct ktermios *termios, struct ktermios *old)
934c4f52879SKarthikeyan Ramasubramanian {
935c4f52879SKarthikeyan Ramasubramanian 	unsigned int baud;
936385298abSRyan Case 	u32 bits_per_char;
937385298abSRyan Case 	u32 tx_trans_cfg;
938385298abSRyan Case 	u32 tx_parity_cfg;
939385298abSRyan Case 	u32 rx_trans_cfg;
940385298abSRyan Case 	u32 rx_parity_cfg;
941385298abSRyan Case 	u32 stop_bit_len;
942c4f52879SKarthikeyan Ramasubramanian 	unsigned int clk_div;
943385298abSRyan Case 	u32 ser_clk_cfg;
944c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
945c4f52879SKarthikeyan Ramasubramanian 	unsigned long clk_rate;
946ce734600SVivek Gautam 	u32 ver, sampling_rate;
947c4f52879SKarthikeyan Ramasubramanian 
948c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_stop_rx(uport);
949c4f52879SKarthikeyan Ramasubramanian 	/* baud rate */
950c4f52879SKarthikeyan Ramasubramanian 	baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
951c4f52879SKarthikeyan Ramasubramanian 	port->baud = baud;
952ce734600SVivek Gautam 
953ce734600SVivek Gautam 	sampling_rate = UART_OVERSAMPLING;
954ce734600SVivek Gautam 	/* Sampling rate is halved for IP versions >= 2.5 */
955ce734600SVivek Gautam 	ver = geni_se_get_qup_hw_version(&port->se);
956ce734600SVivek Gautam 	if (GENI_SE_VERSION_MAJOR(ver) >= 2 && GENI_SE_VERSION_MINOR(ver) >= 5)
957ce734600SVivek Gautam 		sampling_rate /= 2;
958ce734600SVivek Gautam 
959ce734600SVivek Gautam 	clk_rate = get_clk_div_rate(baud, sampling_rate, &clk_div);
960c4f52879SKarthikeyan Ramasubramanian 	if (!clk_rate)
961c4f52879SKarthikeyan Ramasubramanian 		goto out_restart_rx;
962c4f52879SKarthikeyan Ramasubramanian 
963c4f52879SKarthikeyan Ramasubramanian 	uport->uartclk = clk_rate;
964c4f52879SKarthikeyan Ramasubramanian 	clk_set_rate(port->se.clk, clk_rate);
965c4f52879SKarthikeyan Ramasubramanian 	ser_clk_cfg = SER_CLK_EN;
966c4f52879SKarthikeyan Ramasubramanian 	ser_clk_cfg |= clk_div << CLK_DIV_SHFT;
967c4f52879SKarthikeyan Ramasubramanian 
968c4f52879SKarthikeyan Ramasubramanian 	/* parity */
9699e06d55fSRyan Case 	tx_trans_cfg = readl(uport->membase + SE_UART_TX_TRANS_CFG);
9709e06d55fSRyan Case 	tx_parity_cfg = readl(uport->membase + SE_UART_TX_PARITY_CFG);
9719e06d55fSRyan Case 	rx_trans_cfg = readl(uport->membase + SE_UART_RX_TRANS_CFG);
9729e06d55fSRyan Case 	rx_parity_cfg = readl(uport->membase + SE_UART_RX_PARITY_CFG);
973c4f52879SKarthikeyan Ramasubramanian 	if (termios->c_cflag & PARENB) {
974c4f52879SKarthikeyan Ramasubramanian 		tx_trans_cfg |= UART_TX_PAR_EN;
975c4f52879SKarthikeyan Ramasubramanian 		rx_trans_cfg |= UART_RX_PAR_EN;
976c4f52879SKarthikeyan Ramasubramanian 		tx_parity_cfg |= PAR_CALC_EN;
977c4f52879SKarthikeyan Ramasubramanian 		rx_parity_cfg |= PAR_CALC_EN;
978c4f52879SKarthikeyan Ramasubramanian 		if (termios->c_cflag & PARODD) {
979c4f52879SKarthikeyan Ramasubramanian 			tx_parity_cfg |= PAR_ODD;
980c4f52879SKarthikeyan Ramasubramanian 			rx_parity_cfg |= PAR_ODD;
981c4f52879SKarthikeyan Ramasubramanian 		} else if (termios->c_cflag & CMSPAR) {
982c4f52879SKarthikeyan Ramasubramanian 			tx_parity_cfg |= PAR_SPACE;
983c4f52879SKarthikeyan Ramasubramanian 			rx_parity_cfg |= PAR_SPACE;
984c4f52879SKarthikeyan Ramasubramanian 		} else {
985c4f52879SKarthikeyan Ramasubramanian 			tx_parity_cfg |= PAR_EVEN;
986c4f52879SKarthikeyan Ramasubramanian 			rx_parity_cfg |= PAR_EVEN;
987c4f52879SKarthikeyan Ramasubramanian 		}
988c4f52879SKarthikeyan Ramasubramanian 	} else {
989c4f52879SKarthikeyan Ramasubramanian 		tx_trans_cfg &= ~UART_TX_PAR_EN;
990c4f52879SKarthikeyan Ramasubramanian 		rx_trans_cfg &= ~UART_RX_PAR_EN;
991c4f52879SKarthikeyan Ramasubramanian 		tx_parity_cfg &= ~PAR_CALC_EN;
992c4f52879SKarthikeyan Ramasubramanian 		rx_parity_cfg &= ~PAR_CALC_EN;
993c4f52879SKarthikeyan Ramasubramanian 	}
994c4f52879SKarthikeyan Ramasubramanian 
995c4f52879SKarthikeyan Ramasubramanian 	/* bits per char */
996c4f52879SKarthikeyan Ramasubramanian 	switch (termios->c_cflag & CSIZE) {
997c4f52879SKarthikeyan Ramasubramanian 	case CS5:
998c4f52879SKarthikeyan Ramasubramanian 		bits_per_char = 5;
999c4f52879SKarthikeyan Ramasubramanian 		break;
1000c4f52879SKarthikeyan Ramasubramanian 	case CS6:
1001c4f52879SKarthikeyan Ramasubramanian 		bits_per_char = 6;
1002c4f52879SKarthikeyan Ramasubramanian 		break;
1003c4f52879SKarthikeyan Ramasubramanian 	case CS7:
1004c4f52879SKarthikeyan Ramasubramanian 		bits_per_char = 7;
1005c4f52879SKarthikeyan Ramasubramanian 		break;
1006c4f52879SKarthikeyan Ramasubramanian 	case CS8:
1007c4f52879SKarthikeyan Ramasubramanian 	default:
1008c4f52879SKarthikeyan Ramasubramanian 		bits_per_char = 8;
1009c4f52879SKarthikeyan Ramasubramanian 		break;
1010c4f52879SKarthikeyan Ramasubramanian 	}
1011c4f52879SKarthikeyan Ramasubramanian 
1012c4f52879SKarthikeyan Ramasubramanian 	/* stop bits */
1013c4f52879SKarthikeyan Ramasubramanian 	if (termios->c_cflag & CSTOPB)
1014c4f52879SKarthikeyan Ramasubramanian 		stop_bit_len = TX_STOP_BIT_LEN_2;
1015c4f52879SKarthikeyan Ramasubramanian 	else
1016c4f52879SKarthikeyan Ramasubramanian 		stop_bit_len = TX_STOP_BIT_LEN_1;
1017c4f52879SKarthikeyan Ramasubramanian 
1018c4f52879SKarthikeyan Ramasubramanian 	/* flow control, clear the CTS_MASK bit if using flow control. */
1019c4f52879SKarthikeyan Ramasubramanian 	if (termios->c_cflag & CRTSCTS)
1020c4f52879SKarthikeyan Ramasubramanian 		tx_trans_cfg &= ~UART_CTS_MASK;
1021c4f52879SKarthikeyan Ramasubramanian 	else
1022c4f52879SKarthikeyan Ramasubramanian 		tx_trans_cfg |= UART_CTS_MASK;
1023c4f52879SKarthikeyan Ramasubramanian 
1024c4f52879SKarthikeyan Ramasubramanian 	if (baud)
1025c4f52879SKarthikeyan Ramasubramanian 		uart_update_timeout(uport, termios->c_cflag, baud);
1026c4f52879SKarthikeyan Ramasubramanian 
10278a8a66a1SGirish Mahadevan 	if (!uart_console(uport))
10289e06d55fSRyan Case 		writel(port->loopback,
10298a8a66a1SGirish Mahadevan 				uport->membase + SE_UART_LOOPBACK_CFG);
10309e06d55fSRyan Case 	writel(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG);
10319e06d55fSRyan Case 	writel(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG);
10329e06d55fSRyan Case 	writel(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG);
10339e06d55fSRyan Case 	writel(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG);
10349e06d55fSRyan Case 	writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN);
10359e06d55fSRyan Case 	writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN);
10369e06d55fSRyan Case 	writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
10379e06d55fSRyan Case 	writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
10389e06d55fSRyan Case 	writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
1039c4f52879SKarthikeyan Ramasubramanian out_restart_rx:
1040c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_start_rx(uport);
1041c4f52879SKarthikeyan Ramasubramanian }
1042c4f52879SKarthikeyan Ramasubramanian 
1043c4f52879SKarthikeyan Ramasubramanian static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
1044c4f52879SKarthikeyan Ramasubramanian {
10457fb5b880SKarthikeyan Ramasubramanian 	return !readl(uport->membase + SE_GENI_TX_FIFO_STATUS);
1046c4f52879SKarthikeyan Ramasubramanian }
1047c4f52879SKarthikeyan Ramasubramanian 
1048c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
1049c4f52879SKarthikeyan Ramasubramanian static int __init qcom_geni_console_setup(struct console *co, char *options)
1050c4f52879SKarthikeyan Ramasubramanian {
1051c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport;
1052c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port;
1053c5cbc78aSNathan Chancellor 	int baud = 9600;
1054c4f52879SKarthikeyan Ramasubramanian 	int bits = 8;
1055c4f52879SKarthikeyan Ramasubramanian 	int parity = 'n';
1056c4f52879SKarthikeyan Ramasubramanian 	int flow = 'n';
1057c362272bSDouglas Anderson 	int ret;
1058c4f52879SKarthikeyan Ramasubramanian 
1059c4f52879SKarthikeyan Ramasubramanian 	if (co->index >= GENI_UART_CONS_PORTS  || co->index < 0)
1060c4f52879SKarthikeyan Ramasubramanian 		return -ENXIO;
1061c4f52879SKarthikeyan Ramasubramanian 
10628a8a66a1SGirish Mahadevan 	port = get_port_from_line(co->index, true);
1063c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(port)) {
10646a10635eSKarthikeyan Ramasubramanian 		pr_err("Invalid line %d\n", co->index);
1065c4f52879SKarthikeyan Ramasubramanian 		return PTR_ERR(port);
1066c4f52879SKarthikeyan Ramasubramanian 	}
1067c4f52879SKarthikeyan Ramasubramanian 
1068c4f52879SKarthikeyan Ramasubramanian 	uport = &port->uport;
1069c4f52879SKarthikeyan Ramasubramanian 
1070c4f52879SKarthikeyan Ramasubramanian 	if (unlikely(!uport->membase))
1071c4f52879SKarthikeyan Ramasubramanian 		return -ENXIO;
1072c4f52879SKarthikeyan Ramasubramanian 
1073c4f52879SKarthikeyan Ramasubramanian 	if (!port->setup) {
1074c362272bSDouglas Anderson 		ret = qcom_geni_serial_port_setup(uport);
1075c362272bSDouglas Anderson 		if (ret)
1076c362272bSDouglas Anderson 			return ret;
1077c4f52879SKarthikeyan Ramasubramanian 	}
1078c4f52879SKarthikeyan Ramasubramanian 
1079c4f52879SKarthikeyan Ramasubramanian 	if (options)
1080c4f52879SKarthikeyan Ramasubramanian 		uart_parse_options(options, &baud, &parity, &bits, &flow);
1081c4f52879SKarthikeyan Ramasubramanian 
1082c4f52879SKarthikeyan Ramasubramanian 	return uart_set_options(uport, co, baud, parity, bits, flow);
1083c4f52879SKarthikeyan Ramasubramanian }
1084c4f52879SKarthikeyan Ramasubramanian 
108543f1831bSKarthikeyan Ramasubramanian static void qcom_geni_serial_earlycon_write(struct console *con,
108643f1831bSKarthikeyan Ramasubramanian 					const char *s, unsigned int n)
108743f1831bSKarthikeyan Ramasubramanian {
108843f1831bSKarthikeyan Ramasubramanian 	struct earlycon_device *dev = con->data;
108943f1831bSKarthikeyan Ramasubramanian 
109043f1831bSKarthikeyan Ramasubramanian 	__qcom_geni_serial_console_write(&dev->port, s, n);
109143f1831bSKarthikeyan Ramasubramanian }
109243f1831bSKarthikeyan Ramasubramanian 
1093*205b5bddSDouglas Anderson #ifdef CONFIG_CONSOLE_POLL
1094*205b5bddSDouglas Anderson static int qcom_geni_serial_earlycon_read(struct console *con,
1095*205b5bddSDouglas Anderson 					  char *s, unsigned int n)
1096*205b5bddSDouglas Anderson {
1097*205b5bddSDouglas Anderson 	struct earlycon_device *dev = con->data;
1098*205b5bddSDouglas Anderson 	struct uart_port *uport = &dev->port;
1099*205b5bddSDouglas Anderson 	int num_read = 0;
1100*205b5bddSDouglas Anderson 	int ch;
1101*205b5bddSDouglas Anderson 
1102*205b5bddSDouglas Anderson 	while (num_read < n) {
1103*205b5bddSDouglas Anderson 		ch = qcom_geni_serial_get_char(uport);
1104*205b5bddSDouglas Anderson 		if (ch == NO_POLL_CHAR)
1105*205b5bddSDouglas Anderson 			break;
1106*205b5bddSDouglas Anderson 		s[num_read++] = ch;
1107*205b5bddSDouglas Anderson 	}
1108*205b5bddSDouglas Anderson 
1109*205b5bddSDouglas Anderson 	return num_read;
1110*205b5bddSDouglas Anderson }
1111*205b5bddSDouglas Anderson 
1112*205b5bddSDouglas Anderson static void __init qcom_geni_serial_enable_early_read(struct geni_se *se,
1113*205b5bddSDouglas Anderson 						      struct console *con)
1114*205b5bddSDouglas Anderson {
1115*205b5bddSDouglas Anderson 	geni_se_setup_s_cmd(se, UART_START_READ, 0);
1116*205b5bddSDouglas Anderson 	con->read = qcom_geni_serial_earlycon_read;
1117*205b5bddSDouglas Anderson }
1118*205b5bddSDouglas Anderson #else
1119*205b5bddSDouglas Anderson static inline void qcom_geni_serial_enable_early_read(struct geni_se *se,
1120*205b5bddSDouglas Anderson 						      struct console *con) { }
1121*205b5bddSDouglas Anderson #endif
1122*205b5bddSDouglas Anderson 
112343f1831bSKarthikeyan Ramasubramanian static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev,
112443f1831bSKarthikeyan Ramasubramanian 								const char *opt)
112543f1831bSKarthikeyan Ramasubramanian {
112643f1831bSKarthikeyan Ramasubramanian 	struct uart_port *uport = &dev->port;
112743f1831bSKarthikeyan Ramasubramanian 	u32 tx_trans_cfg;
112843f1831bSKarthikeyan Ramasubramanian 	u32 tx_parity_cfg = 0;	/* Disable Tx Parity */
112943f1831bSKarthikeyan Ramasubramanian 	u32 rx_trans_cfg = 0;
113043f1831bSKarthikeyan Ramasubramanian 	u32 rx_parity_cfg = 0;	/* Disable Rx Parity */
113143f1831bSKarthikeyan Ramasubramanian 	u32 stop_bit_len = 0;	/* Default stop bit length - 1 bit */
113243f1831bSKarthikeyan Ramasubramanian 	u32 bits_per_char;
113343f1831bSKarthikeyan Ramasubramanian 	struct geni_se se;
113443f1831bSKarthikeyan Ramasubramanian 
113543f1831bSKarthikeyan Ramasubramanian 	if (!uport->membase)
113643f1831bSKarthikeyan Ramasubramanian 		return -EINVAL;
113743f1831bSKarthikeyan Ramasubramanian 
113843f1831bSKarthikeyan Ramasubramanian 	memset(&se, 0, sizeof(se));
113943f1831bSKarthikeyan Ramasubramanian 	se.base = uport->membase;
114043f1831bSKarthikeyan Ramasubramanian 	if (geni_se_read_proto(&se) != GENI_SE_UART)
114143f1831bSKarthikeyan Ramasubramanian 		return -ENXIO;
114243f1831bSKarthikeyan Ramasubramanian 	/*
114343f1831bSKarthikeyan Ramasubramanian 	 * Ignore Flow control.
114443f1831bSKarthikeyan Ramasubramanian 	 * n = 8.
114543f1831bSKarthikeyan Ramasubramanian 	 */
114643f1831bSKarthikeyan Ramasubramanian 	tx_trans_cfg = UART_CTS_MASK;
114743f1831bSKarthikeyan Ramasubramanian 	bits_per_char = BITS_PER_BYTE;
114843f1831bSKarthikeyan Ramasubramanian 
114943f1831bSKarthikeyan Ramasubramanian 	/*
115043f1831bSKarthikeyan Ramasubramanian 	 * Make an unconditional cancel on the main sequencer to reset
115143f1831bSKarthikeyan Ramasubramanian 	 * it else we could end up in data loss scenarios.
115243f1831bSKarthikeyan Ramasubramanian 	 */
115343f1831bSKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_tx_done(uport);
115443f1831bSKarthikeyan Ramasubramanian 	qcom_geni_serial_abort_rx(uport);
115543f1831bSKarthikeyan Ramasubramanian 	geni_se_config_packing(&se, BITS_PER_BYTE, 1, false, true, false);
115643f1831bSKarthikeyan Ramasubramanian 	geni_se_init(&se, DEF_FIFO_DEPTH_WORDS / 2, DEF_FIFO_DEPTH_WORDS - 2);
115743f1831bSKarthikeyan Ramasubramanian 	geni_se_select_mode(&se, GENI_SE_FIFO);
115843f1831bSKarthikeyan Ramasubramanian 
11599e06d55fSRyan Case 	writel(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG);
11609e06d55fSRyan Case 	writel(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG);
11619e06d55fSRyan Case 	writel(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG);
11629e06d55fSRyan Case 	writel(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG);
11639e06d55fSRyan Case 	writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN);
11649e06d55fSRyan Case 	writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN);
11659e06d55fSRyan Case 	writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
116643f1831bSKarthikeyan Ramasubramanian 
116743f1831bSKarthikeyan Ramasubramanian 	dev->con->write = qcom_geni_serial_earlycon_write;
116843f1831bSKarthikeyan Ramasubramanian 	dev->con->setup = NULL;
1169*205b5bddSDouglas Anderson 	qcom_geni_serial_enable_early_read(&se, dev->con);
1170*205b5bddSDouglas Anderson 
117143f1831bSKarthikeyan Ramasubramanian 	return 0;
117243f1831bSKarthikeyan Ramasubramanian }
117343f1831bSKarthikeyan Ramasubramanian OF_EARLYCON_DECLARE(qcom_geni, "qcom,geni-debug-uart",
117443f1831bSKarthikeyan Ramasubramanian 				qcom_geni_serial_earlycon_setup);
117543f1831bSKarthikeyan Ramasubramanian 
1176c4f52879SKarthikeyan Ramasubramanian static int __init console_register(struct uart_driver *drv)
1177c4f52879SKarthikeyan Ramasubramanian {
1178c4f52879SKarthikeyan Ramasubramanian 	return uart_register_driver(drv);
1179c4f52879SKarthikeyan Ramasubramanian }
1180c4f52879SKarthikeyan Ramasubramanian 
1181c4f52879SKarthikeyan Ramasubramanian static void console_unregister(struct uart_driver *drv)
1182c4f52879SKarthikeyan Ramasubramanian {
1183c4f52879SKarthikeyan Ramasubramanian 	uart_unregister_driver(drv);
1184c4f52879SKarthikeyan Ramasubramanian }
1185c4f52879SKarthikeyan Ramasubramanian 
1186c4f52879SKarthikeyan Ramasubramanian static struct console cons_ops = {
1187c4f52879SKarthikeyan Ramasubramanian 	.name = "ttyMSM",
1188c4f52879SKarthikeyan Ramasubramanian 	.write = qcom_geni_serial_console_write,
1189c4f52879SKarthikeyan Ramasubramanian 	.device = uart_console_device,
1190c4f52879SKarthikeyan Ramasubramanian 	.setup = qcom_geni_console_setup,
1191c4f52879SKarthikeyan Ramasubramanian 	.flags = CON_PRINTBUFFER,
1192c4f52879SKarthikeyan Ramasubramanian 	.index = -1,
1193c4f52879SKarthikeyan Ramasubramanian 	.data = &qcom_geni_console_driver,
1194c4f52879SKarthikeyan Ramasubramanian };
1195c4f52879SKarthikeyan Ramasubramanian 
1196c4f52879SKarthikeyan Ramasubramanian static struct uart_driver qcom_geni_console_driver = {
1197c4f52879SKarthikeyan Ramasubramanian 	.owner = THIS_MODULE,
1198c4f52879SKarthikeyan Ramasubramanian 	.driver_name = "qcom_geni_console",
1199c4f52879SKarthikeyan Ramasubramanian 	.dev_name = "ttyMSM",
1200c4f52879SKarthikeyan Ramasubramanian 	.nr =  GENI_UART_CONS_PORTS,
1201c4f52879SKarthikeyan Ramasubramanian 	.cons = &cons_ops,
1202c4f52879SKarthikeyan Ramasubramanian };
1203c4f52879SKarthikeyan Ramasubramanian #else
1204c4f52879SKarthikeyan Ramasubramanian static int console_register(struct uart_driver *drv)
1205c4f52879SKarthikeyan Ramasubramanian {
1206c4f52879SKarthikeyan Ramasubramanian 	return 0;
1207c4f52879SKarthikeyan Ramasubramanian }
1208c4f52879SKarthikeyan Ramasubramanian 
1209c4f52879SKarthikeyan Ramasubramanian static void console_unregister(struct uart_driver *drv)
1210c4f52879SKarthikeyan Ramasubramanian {
1211c4f52879SKarthikeyan Ramasubramanian }
1212c4f52879SKarthikeyan Ramasubramanian #endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
1213c4f52879SKarthikeyan Ramasubramanian 
12148a8a66a1SGirish Mahadevan static struct uart_driver qcom_geni_uart_driver = {
12158a8a66a1SGirish Mahadevan 	.owner = THIS_MODULE,
12168a8a66a1SGirish Mahadevan 	.driver_name = "qcom_geni_uart",
12178a8a66a1SGirish Mahadevan 	.dev_name = "ttyHS",
12188a8a66a1SGirish Mahadevan 	.nr =  GENI_UART_PORTS,
12198a8a66a1SGirish Mahadevan };
12208a8a66a1SGirish Mahadevan 
12218a8a66a1SGirish Mahadevan static void qcom_geni_serial_pm(struct uart_port *uport,
1222c4f52879SKarthikeyan Ramasubramanian 		unsigned int new_state, unsigned int old_state)
1223c4f52879SKarthikeyan Ramasubramanian {
1224c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
1225c4f52879SKarthikeyan Ramasubramanian 
1226c362272bSDouglas Anderson 	/* If we've never been called, treat it as off */
1227c362272bSDouglas Anderson 	if (old_state == UART_PM_STATE_UNDEFINED)
1228c362272bSDouglas Anderson 		old_state = UART_PM_STATE_OFF;
1229c362272bSDouglas Anderson 
1230c4f52879SKarthikeyan Ramasubramanian 	if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
1231c4f52879SKarthikeyan Ramasubramanian 		geni_se_resources_on(&port->se);
1232c4f52879SKarthikeyan Ramasubramanian 	else if (new_state == UART_PM_STATE_OFF &&
1233c4f52879SKarthikeyan Ramasubramanian 			old_state == UART_PM_STATE_ON)
1234c4f52879SKarthikeyan Ramasubramanian 		geni_se_resources_off(&port->se);
1235c4f52879SKarthikeyan Ramasubramanian }
1236c4f52879SKarthikeyan Ramasubramanian 
1237c4f52879SKarthikeyan Ramasubramanian static const struct uart_ops qcom_geni_console_pops = {
1238c4f52879SKarthikeyan Ramasubramanian 	.tx_empty = qcom_geni_serial_tx_empty,
1239c4f52879SKarthikeyan Ramasubramanian 	.stop_tx = qcom_geni_serial_stop_tx,
1240c4f52879SKarthikeyan Ramasubramanian 	.start_tx = qcom_geni_serial_start_tx,
1241c4f52879SKarthikeyan Ramasubramanian 	.stop_rx = qcom_geni_serial_stop_rx,
1242c4f52879SKarthikeyan Ramasubramanian 	.set_termios = qcom_geni_serial_set_termios,
1243c4f52879SKarthikeyan Ramasubramanian 	.startup = qcom_geni_serial_startup,
1244c4f52879SKarthikeyan Ramasubramanian 	.request_port = qcom_geni_serial_request_port,
1245c4f52879SKarthikeyan Ramasubramanian 	.config_port = qcom_geni_serial_config_port,
1246c4f52879SKarthikeyan Ramasubramanian 	.shutdown = qcom_geni_serial_shutdown,
1247c4f52879SKarthikeyan Ramasubramanian 	.type = qcom_geni_serial_get_type,
12488a8a66a1SGirish Mahadevan 	.set_mctrl = qcom_geni_serial_set_mctrl,
12498a8a66a1SGirish Mahadevan 	.get_mctrl = qcom_geni_serial_get_mctrl,
1250c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_CONSOLE_POLL
1251c4f52879SKarthikeyan Ramasubramanian 	.poll_get_char	= qcom_geni_serial_get_char,
1252c4f52879SKarthikeyan Ramasubramanian 	.poll_put_char	= qcom_geni_serial_poll_put_char,
1253c4f52879SKarthikeyan Ramasubramanian #endif
12548a8a66a1SGirish Mahadevan 	.pm = qcom_geni_serial_pm,
12558a8a66a1SGirish Mahadevan };
12568a8a66a1SGirish Mahadevan 
12578a8a66a1SGirish Mahadevan static const struct uart_ops qcom_geni_uart_pops = {
12588a8a66a1SGirish Mahadevan 	.tx_empty = qcom_geni_serial_tx_empty,
12598a8a66a1SGirish Mahadevan 	.stop_tx = qcom_geni_serial_stop_tx,
12608a8a66a1SGirish Mahadevan 	.start_tx = qcom_geni_serial_start_tx,
12618a8a66a1SGirish Mahadevan 	.stop_rx = qcom_geni_serial_stop_rx,
12628a8a66a1SGirish Mahadevan 	.set_termios = qcom_geni_serial_set_termios,
12638a8a66a1SGirish Mahadevan 	.startup = qcom_geni_serial_startup,
12648a8a66a1SGirish Mahadevan 	.request_port = qcom_geni_serial_request_port,
12658a8a66a1SGirish Mahadevan 	.config_port = qcom_geni_serial_config_port,
12668a8a66a1SGirish Mahadevan 	.shutdown = qcom_geni_serial_shutdown,
12678a8a66a1SGirish Mahadevan 	.type = qcom_geni_serial_get_type,
12688a8a66a1SGirish Mahadevan 	.set_mctrl = qcom_geni_serial_set_mctrl,
12698a8a66a1SGirish Mahadevan 	.get_mctrl = qcom_geni_serial_get_mctrl,
12708a8a66a1SGirish Mahadevan 	.pm = qcom_geni_serial_pm,
1271c4f52879SKarthikeyan Ramasubramanian };
1272c4f52879SKarthikeyan Ramasubramanian 
1273c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_probe(struct platform_device *pdev)
1274c4f52879SKarthikeyan Ramasubramanian {
1275c4f52879SKarthikeyan Ramasubramanian 	int ret = 0;
1276c4f52879SKarthikeyan Ramasubramanian 	int line = -1;
1277c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port;
1278c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport;
1279c4f52879SKarthikeyan Ramasubramanian 	struct resource *res;
1280066cd1c4SKarthikeyan Ramasubramanian 	int irq;
12818a8a66a1SGirish Mahadevan 	bool console = false;
12828a8a66a1SGirish Mahadevan 	struct uart_driver *drv;
1283c4f52879SKarthikeyan Ramasubramanian 
12848a8a66a1SGirish Mahadevan 	if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart"))
12858a8a66a1SGirish Mahadevan 		console = true;
12868a8a66a1SGirish Mahadevan 
12878a8a66a1SGirish Mahadevan 	if (console) {
12888a8a66a1SGirish Mahadevan 		drv = &qcom_geni_console_driver;
1289c4f52879SKarthikeyan Ramasubramanian 		line = of_alias_get_id(pdev->dev.of_node, "serial");
12908a8a66a1SGirish Mahadevan 	} else {
12918a8a66a1SGirish Mahadevan 		drv = &qcom_geni_uart_driver;
12928a8a66a1SGirish Mahadevan 		line = of_alias_get_id(pdev->dev.of_node, "hsuart");
12938a8a66a1SGirish Mahadevan 	}
1294c4f52879SKarthikeyan Ramasubramanian 
12958a8a66a1SGirish Mahadevan 	port = get_port_from_line(line, console);
1296c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(port)) {
12976a10635eSKarthikeyan Ramasubramanian 		dev_err(&pdev->dev, "Invalid line %d\n", line);
12986a10635eSKarthikeyan Ramasubramanian 		return PTR_ERR(port);
1299c4f52879SKarthikeyan Ramasubramanian 	}
1300c4f52879SKarthikeyan Ramasubramanian 
1301c4f52879SKarthikeyan Ramasubramanian 	uport = &port->uport;
1302c4f52879SKarthikeyan Ramasubramanian 	/* Don't allow 2 drivers to access the same port */
1303c4f52879SKarthikeyan Ramasubramanian 	if (uport->private_data)
1304c4f52879SKarthikeyan Ramasubramanian 		return -ENODEV;
1305c4f52879SKarthikeyan Ramasubramanian 
1306c4f52879SKarthikeyan Ramasubramanian 	uport->dev = &pdev->dev;
1307c4f52879SKarthikeyan Ramasubramanian 	port->se.dev = &pdev->dev;
1308c4f52879SKarthikeyan Ramasubramanian 	port->se.wrapper = dev_get_drvdata(pdev->dev.parent);
1309c4f52879SKarthikeyan Ramasubramanian 	port->se.clk = devm_clk_get(&pdev->dev, "se");
1310c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(port->se.clk)) {
1311c4f52879SKarthikeyan Ramasubramanian 		ret = PTR_ERR(port->se.clk);
1312c4f52879SKarthikeyan Ramasubramanian 		dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
1313c4f52879SKarthikeyan Ramasubramanian 		return ret;
1314c4f52879SKarthikeyan Ramasubramanian 	}
1315c4f52879SKarthikeyan Ramasubramanian 
1316c4f52879SKarthikeyan Ramasubramanian 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
13177693b331SWei Yongjun 	if (!res)
13187693b331SWei Yongjun 		return -EINVAL;
1319c4f52879SKarthikeyan Ramasubramanian 	uport->mapbase = res->start;
1320c4f52879SKarthikeyan Ramasubramanian 
1321c4f52879SKarthikeyan Ramasubramanian 	port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
1322c4f52879SKarthikeyan Ramasubramanian 	port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
1323c4f52879SKarthikeyan Ramasubramanian 	port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
1324c4f52879SKarthikeyan Ramasubramanian 
1325f9d690b6Ssatya priya 	if (!console) {
1326f9d690b6Ssatya priya 		port->rx_fifo = devm_kcalloc(uport->dev,
1327f9d690b6Ssatya priya 			port->rx_fifo_depth, sizeof(u32), GFP_KERNEL);
1328f9d690b6Ssatya priya 		if (!port->rx_fifo)
1329f9d690b6Ssatya priya 			return -ENOMEM;
1330f9d690b6Ssatya priya 	}
1331f9d690b6Ssatya priya 
1332f3974413SAkash Asthana 	port->name = devm_kasprintf(uport->dev, GFP_KERNEL,
1333f3974413SAkash Asthana 			"qcom_geni_serial_%s%d",
1334f3974413SAkash Asthana 			uart_console(uport) ? "console" : "uart", uport->line);
1335f3974413SAkash Asthana 	if (!port->name)
1336f3974413SAkash Asthana 		return -ENOMEM;
1337f3974413SAkash Asthana 
1338066cd1c4SKarthikeyan Ramasubramanian 	irq = platform_get_irq(pdev, 0);
13391df21786SStephen Boyd 	if (irq < 0)
1340066cd1c4SKarthikeyan Ramasubramanian 		return irq;
1341066cd1c4SKarthikeyan Ramasubramanian 	uport->irq = irq;
13428f122698SDmitry Safonov 	uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE);
1343c4f52879SKarthikeyan Ramasubramanian 
1344f3974413SAkash Asthana 	if (!console)
1345f3974413SAkash Asthana 		port->wakeup_irq = platform_get_irq_optional(pdev, 1);
13463e4aaea7SAkash Asthana 
13479fa3c4b1SRoja Rani Yarubandi 	if (of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"))
13489fa3c4b1SRoja Rani Yarubandi 		port->rx_tx_swap = true;
13499fa3c4b1SRoja Rani Yarubandi 
13509fa3c4b1SRoja Rani Yarubandi 	if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap"))
13519fa3c4b1SRoja Rani Yarubandi 		port->cts_rts_swap = true;
13529fa3c4b1SRoja Rani Yarubandi 
13538a8a66a1SGirish Mahadevan 	uport->private_data = drv;
1354c4f52879SKarthikeyan Ramasubramanian 	platform_set_drvdata(pdev, port);
13558a8a66a1SGirish Mahadevan 	port->handle_rx = console ? handle_rx_console : handle_rx_uart;
1356f3974413SAkash Asthana 
1357f3974413SAkash Asthana 	ret = uart_add_one_port(drv, uport);
1358f3974413SAkash Asthana 	if (ret)
1359f3974413SAkash Asthana 		return ret;
1360f3974413SAkash Asthana 
1361f3974413SAkash Asthana 	irq_set_status_flags(uport->irq, IRQ_NOAUTOEN);
1362f3974413SAkash Asthana 	ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr,
1363f3974413SAkash Asthana 			IRQF_TRIGGER_HIGH, port->name, uport);
1364f3974413SAkash Asthana 	if (ret) {
1365f3974413SAkash Asthana 		dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
1366f3974413SAkash Asthana 		uart_remove_one_port(drv, uport);
1367f3974413SAkash Asthana 		return ret;
1368f3974413SAkash Asthana 	}
1369f3974413SAkash Asthana 
1370f3974413SAkash Asthana 	/*
1371f3974413SAkash Asthana 	 * Set pm_runtime status as ACTIVE so that wakeup_irq gets
1372f3974413SAkash Asthana 	 * enabled/disabled from dev_pm_arm_wake_irq during system
1373f3974413SAkash Asthana 	 * suspend/resume respectively.
1374f3974413SAkash Asthana 	 */
1375f3974413SAkash Asthana 	pm_runtime_set_active(&pdev->dev);
1376f3974413SAkash Asthana 
1377f3974413SAkash Asthana 	if (port->wakeup_irq > 0) {
1378f3974413SAkash Asthana 		device_init_wakeup(&pdev->dev, true);
1379f3974413SAkash Asthana 		ret = dev_pm_set_dedicated_wake_irq(&pdev->dev,
1380f3974413SAkash Asthana 						port->wakeup_irq);
1381f3974413SAkash Asthana 		if (ret) {
1382f3974413SAkash Asthana 			device_init_wakeup(&pdev->dev, false);
1383f3974413SAkash Asthana 			uart_remove_one_port(drv, uport);
1384f3974413SAkash Asthana 			return ret;
1385f3974413SAkash Asthana 		}
1386f3974413SAkash Asthana 	}
1387f3974413SAkash Asthana 
1388f3974413SAkash Asthana 	return 0;
1389c4f52879SKarthikeyan Ramasubramanian }
1390c4f52879SKarthikeyan Ramasubramanian 
1391c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_remove(struct platform_device *pdev)
1392c4f52879SKarthikeyan Ramasubramanian {
1393c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
1394c4f52879SKarthikeyan Ramasubramanian 	struct uart_driver *drv = port->uport.private_data;
1395c4f52879SKarthikeyan Ramasubramanian 
1396f3974413SAkash Asthana 	dev_pm_clear_wake_irq(&pdev->dev);
1397f3974413SAkash Asthana 	device_init_wakeup(&pdev->dev, false);
1398c4f52879SKarthikeyan Ramasubramanian 	uart_remove_one_port(drv, &port->uport);
1399f3974413SAkash Asthana 
1400c4f52879SKarthikeyan Ramasubramanian 	return 0;
1401c4f52879SKarthikeyan Ramasubramanian }
1402c4f52879SKarthikeyan Ramasubramanian 
1403b1f84dd3SMukesh Kumar Savaliya static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev)
1404c4f52879SKarthikeyan Ramasubramanian {
1405a406c4b8SWolfram Sang 	struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
1406c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport = &port->uport;
1407c4f52879SKarthikeyan Ramasubramanian 
1408f3974413SAkash Asthana 	return uart_suspend_port(uport->private_data, uport);
14098a8a66a1SGirish Mahadevan }
14108a8a66a1SGirish Mahadevan 
1411b1f84dd3SMukesh Kumar Savaliya static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
1412c4f52879SKarthikeyan Ramasubramanian {
1413a406c4b8SWolfram Sang 	struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
1414c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport = &port->uport;
1415c4f52879SKarthikeyan Ramasubramanian 
1416b1f84dd3SMukesh Kumar Savaliya 	return uart_resume_port(uport->private_data, uport);
1417c4f52879SKarthikeyan Ramasubramanian }
1418c4f52879SKarthikeyan Ramasubramanian 
1419c4f52879SKarthikeyan Ramasubramanian static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
1420b1f84dd3SMukesh Kumar Savaliya 	SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend,
1421b1f84dd3SMukesh Kumar Savaliya 					qcom_geni_serial_sys_resume)
1422c4f52879SKarthikeyan Ramasubramanian };
1423c4f52879SKarthikeyan Ramasubramanian 
1424c4f52879SKarthikeyan Ramasubramanian static const struct of_device_id qcom_geni_serial_match_table[] = {
1425c4f52879SKarthikeyan Ramasubramanian 	{ .compatible = "qcom,geni-debug-uart", },
14268a8a66a1SGirish Mahadevan 	{ .compatible = "qcom,geni-uart", },
1427c4f52879SKarthikeyan Ramasubramanian 	{}
1428c4f52879SKarthikeyan Ramasubramanian };
1429c4f52879SKarthikeyan Ramasubramanian MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table);
1430c4f52879SKarthikeyan Ramasubramanian 
1431c4f52879SKarthikeyan Ramasubramanian static struct platform_driver qcom_geni_serial_platform_driver = {
1432c4f52879SKarthikeyan Ramasubramanian 	.remove = qcom_geni_serial_remove,
1433c4f52879SKarthikeyan Ramasubramanian 	.probe = qcom_geni_serial_probe,
1434c4f52879SKarthikeyan Ramasubramanian 	.driver = {
1435c4f52879SKarthikeyan Ramasubramanian 		.name = "qcom_geni_serial",
1436c4f52879SKarthikeyan Ramasubramanian 		.of_match_table = qcom_geni_serial_match_table,
1437c4f52879SKarthikeyan Ramasubramanian 		.pm = &qcom_geni_serial_pm_ops,
1438c4f52879SKarthikeyan Ramasubramanian 	},
1439c4f52879SKarthikeyan Ramasubramanian };
1440c4f52879SKarthikeyan Ramasubramanian 
1441c4f52879SKarthikeyan Ramasubramanian static int __init qcom_geni_serial_init(void)
1442c4f52879SKarthikeyan Ramasubramanian {
1443c4f52879SKarthikeyan Ramasubramanian 	int ret;
1444c4f52879SKarthikeyan Ramasubramanian 
1445c4f52879SKarthikeyan Ramasubramanian 	ret = console_register(&qcom_geni_console_driver);
1446c4f52879SKarthikeyan Ramasubramanian 	if (ret)
1447c4f52879SKarthikeyan Ramasubramanian 		return ret;
1448c4f52879SKarthikeyan Ramasubramanian 
14498a8a66a1SGirish Mahadevan 	ret = uart_register_driver(&qcom_geni_uart_driver);
14508a8a66a1SGirish Mahadevan 	if (ret) {
1451c4f52879SKarthikeyan Ramasubramanian 		console_unregister(&qcom_geni_console_driver);
1452c4f52879SKarthikeyan Ramasubramanian 		return ret;
1453c4f52879SKarthikeyan Ramasubramanian 	}
14548a8a66a1SGirish Mahadevan 
14558a8a66a1SGirish Mahadevan 	ret = platform_driver_register(&qcom_geni_serial_platform_driver);
14568a8a66a1SGirish Mahadevan 	if (ret) {
14578a8a66a1SGirish Mahadevan 		console_unregister(&qcom_geni_console_driver);
14588a8a66a1SGirish Mahadevan 		uart_unregister_driver(&qcom_geni_uart_driver);
14598a8a66a1SGirish Mahadevan 	}
14608a8a66a1SGirish Mahadevan 	return ret;
14618a8a66a1SGirish Mahadevan }
1462c4f52879SKarthikeyan Ramasubramanian module_init(qcom_geni_serial_init);
1463c4f52879SKarthikeyan Ramasubramanian 
1464c4f52879SKarthikeyan Ramasubramanian static void __exit qcom_geni_serial_exit(void)
1465c4f52879SKarthikeyan Ramasubramanian {
1466c4f52879SKarthikeyan Ramasubramanian 	platform_driver_unregister(&qcom_geni_serial_platform_driver);
1467c4f52879SKarthikeyan Ramasubramanian 	console_unregister(&qcom_geni_console_driver);
14688a8a66a1SGirish Mahadevan 	uart_unregister_driver(&qcom_geni_uart_driver);
1469c4f52879SKarthikeyan Ramasubramanian }
1470c4f52879SKarthikeyan Ramasubramanian module_exit(qcom_geni_serial_exit);
1471c4f52879SKarthikeyan Ramasubramanian 
1472c4f52879SKarthikeyan Ramasubramanian MODULE_DESCRIPTION("Serial driver for GENI based QUP cores");
1473c4f52879SKarthikeyan Ramasubramanian MODULE_LICENSE("GPL v2");
1474