blob: 57c66d2c347141e596b2240f00049413d31e9754 [file] [log] [blame]
Greg Kroah-Hartmane3b3d0f2017-11-06 18:11:51 +01001// SPDX-License-Identifier: GPL-2.0+
John Linn61ec9012011-04-30 00:07:43 -04002/*
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07003 * Cadence UART driver (found in Xilinx Zynq)
John Linn61ec9012011-04-30 00:07:43 -04004 *
Soren Brinkmanne555a212014-04-04 17:23:39 -07005 * 2011 - 2014 (C) Xilinx Inc.
John Linn61ec9012011-04-30 00:07:43 -04006 *
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07007 * This driver has originally been pushed by Xilinx using a Zynq-branding. This
8 * still shows in the naming of this file, the kconfig symbols and some symbols
9 * in the code.
John Linn61ec9012011-04-30 00:07:43 -040010 */
11
Vlad Lungu0c0c47b2013-10-17 14:08:06 -070012#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
13#define SUPPORT_SYSRQ
14#endif
15
John Linn61ec9012011-04-30 00:07:43 -040016#include <linux/platform_device.h>
John Linn61ec9012011-04-30 00:07:43 -040017#include <linux/serial.h>
Vlad Lungu0c0c47b2013-10-17 14:08:06 -070018#include <linux/console.h>
Jiri Slabyee160a32011-09-01 16:20:57 +020019#include <linux/serial_core.h>
Soren Brinkmann30e1e282013-05-13 10:46:38 -070020#include <linux/slab.h>
Jiri Slabyee160a32011-09-01 16:20:57 +020021#include <linux/tty.h>
22#include <linux/tty_flip.h>
Josh Cartwright2326669c2013-01-21 19:57:41 +010023#include <linux/clk.h>
John Linn61ec9012011-04-30 00:07:43 -040024#include <linux/irq.h>
25#include <linux/io.h>
26#include <linux/of.h>
Paul Gortmaker578b9ce2011-05-27 16:14:23 -040027#include <linux/module.h>
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +053028#include <linux/pm_runtime.h>
John Linn61ec9012011-04-30 00:07:43 -040029
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070030#define CDNS_UART_TTY_NAME "ttyPS"
31#define CDNS_UART_NAME "xuartps"
32#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070033#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */
Thomas Betker9646e4f2015-03-11 22:39:25 +010034#define CDNS_UART_REGISTER_SPACE 0x1000
John Linn61ec9012011-04-30 00:07:43 -040035
Suneel85baf542013-10-17 14:08:08 -070036/* Rx Trigger level */
37static int rx_trigger_level = 56;
38module_param(rx_trigger_level, uint, S_IRUGO);
39MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes");
40
41/* Rx Timeout */
42static int rx_timeout = 10;
43module_param(rx_timeout, uint, S_IRUGO);
44MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
45
Soren Brinkmanne555a212014-04-04 17:23:39 -070046/* Register offsets for the UART. */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -080047#define CDNS_UART_CR 0x00 /* Control Register */
48#define CDNS_UART_MR 0x04 /* Mode Register */
49#define CDNS_UART_IER 0x08 /* Interrupt Enable */
50#define CDNS_UART_IDR 0x0C /* Interrupt Disable */
51#define CDNS_UART_IMR 0x10 /* Interrupt Mask */
52#define CDNS_UART_ISR 0x14 /* Interrupt Status */
53#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */
Nava kishore Manne3816b2f82016-09-15 14:45:29 +053054#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -080055#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */
56#define CDNS_UART_MODEMCR 0x24 /* Modem Control */
57#define CDNS_UART_MODEMSR 0x28 /* Modem Status */
58#define CDNS_UART_SR 0x2C /* Channel Status */
59#define CDNS_UART_FIFO 0x30 /* FIFO */
60#define CDNS_UART_BAUDDIV 0x34 /* Baud Rate Divider */
61#define CDNS_UART_FLOWDEL 0x38 /* Flow Delay */
62#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
63#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
64#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
Nava kishore Manne3816b2f82016-09-15 14:45:29 +053065#define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */
John Linn61ec9012011-04-30 00:07:43 -040066
Soren Brinkmanne555a212014-04-04 17:23:39 -070067/* Control Register Bit Definitions */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070068#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
69#define CDNS_UART_CR_STARTBRK 0x00000080 /* Set TX break */
70#define CDNS_UART_CR_TX_DIS 0x00000020 /* TX disabled. */
71#define CDNS_UART_CR_TX_EN 0x00000010 /* TX enabled */
72#define CDNS_UART_CR_RX_DIS 0x00000008 /* RX disabled. */
73#define CDNS_UART_CR_RX_EN 0x00000004 /* RX enabled */
74#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */
75#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */
76#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
Nava kishore Manne3816b2f82016-09-15 14:45:29 +053077#define CDNS_UART_RXBS_PARITY 0x00000001 /* Parity error status */
78#define CDNS_UART_RXBS_FRAMING 0x00000002 /* Framing error status */
79#define CDNS_UART_RXBS_BRK 0x00000004 /* Overrun error status */
John Linn61ec9012011-04-30 00:07:43 -040080
Soren Brinkmanne555a212014-04-04 17:23:39 -070081/*
82 * Mode Register:
John Linn61ec9012011-04-30 00:07:43 -040083 * The mode register (MR) defines the mode of transfer as well as the data
84 * format. If this register is modified during transmission or reception,
85 * data validity cannot be guaranteed.
John Linn61ec9012011-04-30 00:07:43 -040086 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070087#define CDNS_UART_MR_CLKSEL 0x00000001 /* Pre-scalar selection */
88#define CDNS_UART_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */
89#define CDNS_UART_MR_CHMODE_NORM 0x00000000 /* Normal mode */
Yasir-Khan5935a2b2017-01-23 13:26:08 +010090#define CDNS_UART_MR_CHMODE_MASK 0x00000300 /* Mask for mode bits */
John Linn61ec9012011-04-30 00:07:43 -040091
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070092#define CDNS_UART_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */
93#define CDNS_UART_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */
John Linn61ec9012011-04-30 00:07:43 -040094
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070095#define CDNS_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */
96#define CDNS_UART_MR_PARITY_MARK 0x00000018 /* Mark parity mode */
97#define CDNS_UART_MR_PARITY_SPACE 0x00000010 /* Space parity mode */
98#define CDNS_UART_MR_PARITY_ODD 0x00000008 /* Odd parity mode */
99#define CDNS_UART_MR_PARITY_EVEN 0x00000000 /* Even parity mode */
John Linn61ec9012011-04-30 00:07:43 -0400100
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700101#define CDNS_UART_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */
102#define CDNS_UART_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */
103#define CDNS_UART_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */
John Linn61ec9012011-04-30 00:07:43 -0400104
Soren Brinkmanne555a212014-04-04 17:23:39 -0700105/*
106 * Interrupt Registers:
John Linn61ec9012011-04-30 00:07:43 -0400107 * Interrupt control logic uses the interrupt enable register (IER) and the
108 * interrupt disable register (IDR) to set the value of the bits in the
109 * interrupt mask register (IMR). The IMR determines whether to pass an
110 * interrupt to the interrupt status register (ISR).
111 * Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an
112 * interrupt. IMR and ISR are read only, and IER and IDR are write only.
113 * Reading either IER or IDR returns 0x00.
John Linn61ec9012011-04-30 00:07:43 -0400114 * All four registers have the same bit definitions.
115 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700116#define CDNS_UART_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */
117#define CDNS_UART_IXR_PARITY 0x00000080 /* Parity error interrupt */
118#define CDNS_UART_IXR_FRAMING 0x00000040 /* Framing error interrupt */
119#define CDNS_UART_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */
120#define CDNS_UART_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */
121#define CDNS_UART_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */
122#define CDNS_UART_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */
123#define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
124#define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */
125#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
126#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
John Linn61ec9012011-04-30 00:07:43 -0400127
Anirudha Sarangia3081892016-09-21 15:01:18 +0100128 /*
129 * Do not enable parity error interrupt for the following
130 * reason: When parity error interrupt is enabled, each Rx
131 * parity error always results in 2 events. The first one
132 * being parity error interrupt and the second one with a
133 * proper Rx interrupt with the incoming data. Disabling
134 * parity error interrupt ensures better handling of parity
135 * error events. With this change, for a parity error case, we
136 * get a Rx interrupt with parity error set in ISR register
137 * and we still handle parity errors in the desired way.
138 */
139
140#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_FRAMING | \
141 CDNS_UART_IXR_OVERRUN | \
142 CDNS_UART_IXR_RXTRIG | \
Soren Brinkmann373e8822016-01-11 17:41:37 -0800143 CDNS_UART_IXR_TOUT)
144
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700145/* Goes in read_status_mask for break detection as the HW doesn't do it*/
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530146#define CDNS_UART_IXR_BRK 0x00002000
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700147
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530148#define CDNS_UART_RXBS_SUPPORT BIT(1)
Soren Brinkmanne555a212014-04-04 17:23:39 -0700149/*
Lars-Peter Clausen19038ad2014-11-05 13:35:16 +0100150 * Modem Control register:
151 * The read/write Modem Control register controls the interface with the modem
152 * or data set, or a peripheral device emulating a modem.
153 */
154#define CDNS_UART_MODEMCR_FCM 0x00000020 /* Automatic flow control mode */
155#define CDNS_UART_MODEMCR_RTS 0x00000002 /* Request to send output control */
156#define CDNS_UART_MODEMCR_DTR 0x00000001 /* Data Terminal Ready */
157
158/*
Soren Brinkmanne555a212014-04-04 17:23:39 -0700159 * Channel Status Register:
John Linn61ec9012011-04-30 00:07:43 -0400160 * The channel status register (CSR) is provided to enable the control logic
161 * to monitor the status of bits in the channel interrupt status register,
162 * even if these are masked out by the interrupt mask register.
163 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700164#define CDNS_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
165#define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
166#define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */
167#define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */
Helmut Grohnede4ed392018-06-04 12:22:11 +0200168#define CDNS_UART_SR_TACTIVE 0x00000800 /* TX state machine active */
John Linn61ec9012011-04-30 00:07:43 -0400169
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700170/* baud dividers min/max values */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700171#define CDNS_UART_BDIV_MIN 4
172#define CDNS_UART_BDIV_MAX 255
173#define CDNS_UART_CD_MAX 65535
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +0530174#define UART_AUTOSUSPEND_TIMEOUT 3000
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700175
John Linn61ec9012011-04-30 00:07:43 -0400176/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700177 * struct cdns_uart - device data
Michal Simek489810a12014-04-04 17:23:37 -0700178 * @port: Pointer to the UART port
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700179 * @uartclk: Reference clock
180 * @pclk: APB clock
Michal Simek46a460f2018-09-03 15:10:52 +0200181 * @cdns_uart_driver: Pointer to UART driver
Michal Simek489810a12014-04-04 17:23:37 -0700182 * @baud: Current baud rate
Michal Simekbed25ac2018-09-03 15:10:58 +0200183 * @id: Port ID
Michal Simek489810a12014-04-04 17:23:37 -0700184 * @clk_rate_change_nb: Notifier block for clock changes
Nava kishore Manne094094a2017-05-26 13:13:18 +0200185 * @quirks: Flags for RXBS support.
Soren Brinkmann30e1e282013-05-13 10:46:38 -0700186 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700187struct cdns_uart {
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700188 struct uart_port *port;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700189 struct clk *uartclk;
190 struct clk *pclk;
Michal Simek46a460f2018-09-03 15:10:52 +0200191 struct uart_driver *cdns_uart_driver;
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700192 unsigned int baud;
Michal Simekbed25ac2018-09-03 15:10:58 +0200193 int id;
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700194 struct notifier_block clk_rate_change_nb;
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530195 u32 quirks;
196};
197struct cdns_platform_data {
198 u32 quirks;
Soren Brinkmann30e1e282013-05-13 10:46:38 -0700199};
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700200#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
201 clk_rate_change_nb);
Soren Brinkmann30e1e282013-05-13 10:46:38 -0700202
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100203/**
204 * cdns_uart_handle_rx - Handle the received bytes along with Rx errors.
205 * @dev_id: Id of the UART port
206 * @isrstatus: The interrupt status register value as read
207 * Return: None
208 */
209static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
John Linn61ec9012011-04-30 00:07:43 -0400210{
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100211 struct uart_port *port = (struct uart_port *)dev_id;
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530212 struct cdns_uart *cdns_uart = port->private_data;
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100213 unsigned int data;
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530214 unsigned int rxbs_status = 0;
215 unsigned int status_mask;
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100216 unsigned int framerrprocessed = 0;
217 char status = TTY_NORMAL;
218 bool is_rxbs_support;
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530219
220 is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
221
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100222 while ((readl(port->membase + CDNS_UART_SR) &
223 CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530224 if (is_rxbs_support)
225 rxbs_status = readl(port->membase + CDNS_UART_RXBS);
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800226 data = readl(port->membase + CDNS_UART_FIFO);
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100227 port->icount.rx++;
228 /*
229 * There is no hardware break detection in Zynq, so we interpret
230 * framing error with all-zeros data as a break sequence.
231 * Most of the time, there's another non-zero byte at the
232 * end of the sequence.
233 */
234 if (!is_rxbs_support && (isrstatus & CDNS_UART_IXR_FRAMING)) {
235 if (!data) {
236 port->read_status_mask |= CDNS_UART_IXR_BRK;
237 framerrprocessed = 1;
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800238 continue;
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100239 }
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800240 }
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530241 if (is_rxbs_support && (rxbs_status & CDNS_UART_RXBS_BRK)) {
242 port->icount.brk++;
243 status = TTY_BREAK;
244 if (uart_handle_break(port))
245 continue;
246 }
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700247
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100248 isrstatus &= port->read_status_mask;
249 isrstatus &= ~port->ignore_status_mask;
250 status_mask = port->read_status_mask;
251 status_mask &= ~port->ignore_status_mask;
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700252
Nava kishore Manne212d2492016-09-22 16:58:15 +0100253 if (data &&
254 (port->read_status_mask & CDNS_UART_IXR_BRK)) {
255 port->read_status_mask &= ~CDNS_UART_IXR_BRK;
256 port->icount.brk++;
257 if (uart_handle_break(port))
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100258 continue;
John Linn61ec9012011-04-30 00:07:43 -0400259 }
Nava kishore Manne212d2492016-09-22 16:58:15 +0100260
261 if (uart_handle_sysrq_char(port, data))
262 continue;
263
264 if (is_rxbs_support) {
265 if ((rxbs_status & CDNS_UART_RXBS_PARITY)
266 && (status_mask & CDNS_UART_IXR_PARITY)) {
267 port->icount.parity++;
268 status = TTY_PARITY;
269 }
270 if ((rxbs_status & CDNS_UART_RXBS_FRAMING)
271 && (status_mask & CDNS_UART_IXR_PARITY)) {
272 port->icount.frame++;
273 status = TTY_FRAME;
274 }
275 } else {
276 if (isrstatus & CDNS_UART_IXR_PARITY) {
277 port->icount.parity++;
278 status = TTY_PARITY;
279 }
280 if ((isrstatus & CDNS_UART_IXR_FRAMING) &&
281 !framerrprocessed) {
282 port->icount.frame++;
283 status = TTY_FRAME;
284 }
285 }
286 if (isrstatus & CDNS_UART_IXR_OVERRUN) {
287 port->icount.overrun++;
288 tty_insert_flip_char(&port->state->port, 0,
289 TTY_OVERRUN);
290 }
291 tty_insert_flip_char(&port->state->port, data, status);
292 isrstatus = 0;
John Linn61ec9012011-04-30 00:07:43 -0400293 }
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100294 spin_unlock(&port->lock);
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800295 tty_flip_buffer_push(&port->state->port);
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100296 spin_lock(&port->lock);
Soren Brinkmann5ede4a52015-12-26 02:43:56 -0800297}
298
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100299/**
300 * cdns_uart_handle_tx - Handle the bytes to be Txed.
301 * @dev_id: Id of the UART port
302 * Return: None
303 */
304static void cdns_uart_handle_tx(void *dev_id)
Soren Brinkmann079865802016-01-11 17:41:41 -0800305{
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100306 struct uart_port *port = (struct uart_port *)dev_id;
Soren Brinkmann079865802016-01-11 17:41:41 -0800307 unsigned int numbytes;
308
309 if (uart_circ_empty(&port->state->xmit)) {
310 writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100311 } else {
312 numbytes = port->fifosize;
313 while (numbytes && !uart_circ_empty(&port->state->xmit) &&
314 !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
315 /*
316 * Get the data from the UART circular buffer
317 * and write it to the cdns_uart's TX_FIFO
318 * register.
319 */
320 writel(
321 port->state->xmit.buf[port->state->xmit.
322 tail], port->membase + CDNS_UART_FIFO);
323
324 port->icount.tx++;
325
326 /*
327 * Adjust the tail of the UART buffer and wrap
328 * the buffer if it reaches limit.
329 */
330 port->state->xmit.tail =
331 (port->state->xmit.tail + 1) &
332 (UART_XMIT_SIZE - 1);
333
334 numbytes--;
335 }
336
337 if (uart_circ_chars_pending(
338 &port->state->xmit) < WAKEUP_CHARS)
339 uart_write_wakeup(port);
Soren Brinkmann079865802016-01-11 17:41:41 -0800340 }
Soren Brinkmann079865802016-01-11 17:41:41 -0800341}
342
Soren Brinkmann5ede4a52015-12-26 02:43:56 -0800343/**
344 * cdns_uart_isr - Interrupt handler
345 * @irq: Irq number
346 * @dev_id: Id of the port
347 *
348 * Return: IRQHANDLED
349 */
350static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
351{
352 struct uart_port *port = (struct uart_port *)dev_id;
Soren Brinkmann079865802016-01-11 17:41:41 -0800353 unsigned int isrstatus;
Soren Brinkmann5ede4a52015-12-26 02:43:56 -0800354
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100355 spin_lock(&port->lock);
Soren Brinkmann5ede4a52015-12-26 02:43:56 -0800356
357 /* Read the interrupt status register to determine which
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100358 * interrupt(s) is/are active and clear them.
Soren Brinkmann5ede4a52015-12-26 02:43:56 -0800359 */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800360 isrstatus = readl(port->membase + CDNS_UART_ISR);
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800361 writel(isrstatus, port->membase + CDNS_UART_ISR);
John Linn61ec9012011-04-30 00:07:43 -0400362
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100363 if (isrstatus & CDNS_UART_IXR_TXEMPTY) {
364 cdns_uart_handle_tx(dev_id);
365 isrstatus &= ~CDNS_UART_IXR_TXEMPTY;
366 }
367 if (isrstatus & CDNS_UART_IXR_MASK)
368 cdns_uart_handle_rx(dev_id, isrstatus);
John Linn61ec9012011-04-30 00:07:43 -0400369
Anirudha Sarangic8dbdc82016-09-22 16:58:14 +0100370 spin_unlock(&port->lock);
John Linn61ec9012011-04-30 00:07:43 -0400371 return IRQ_HANDLED;
372}
373
374/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700375 * cdns_uart_calc_baud_divs - Calculate baud rate divisors
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700376 * @clk: UART module input clock
377 * @baud: Desired baud rate
378 * @rbdiv: BDIV value (return value)
379 * @rcd: CD value (return value)
380 * @div8: Value for clk_sel bit in mod (return value)
Michal Simek489810a12014-04-04 17:23:37 -0700381 * Return: baud rate, requested baud when possible, or actual baud when there
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700382 * was too much error, zero if no valid divisors are found.
383 *
384 * Formula to obtain baud rate is
385 * baud_tx/rx rate = clk/CD * (BDIV + 1)
386 * input_clk = (Uart User Defined Clock or Apb Clock)
387 * depends on UCLKEN in MR Reg
388 * clk = input_clk or input_clk/8;
389 * depends on CLKS in MR reg
390 * CD and BDIV depends on values in
391 * baud rate generate register
392 * baud rate clock divisor register
393 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700394static unsigned int cdns_uart_calc_baud_divs(unsigned int clk,
395 unsigned int baud, u32 *rbdiv, u32 *rcd, int *div8)
John Linn61ec9012011-04-30 00:07:43 -0400396{
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700397 u32 cd, bdiv;
398 unsigned int calc_baud;
399 unsigned int bestbaud = 0;
John Linn61ec9012011-04-30 00:07:43 -0400400 unsigned int bauderror;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700401 unsigned int besterror = ~0;
John Linn61ec9012011-04-30 00:07:43 -0400402
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700403 if (baud < clk / ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX)) {
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700404 *div8 = 1;
405 clk /= 8;
406 } else {
407 *div8 = 0;
408 }
John Linn61ec9012011-04-30 00:07:43 -0400409
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700410 for (bdiv = CDNS_UART_BDIV_MIN; bdiv <= CDNS_UART_BDIV_MAX; bdiv++) {
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700411 cd = DIV_ROUND_CLOSEST(clk, baud * (bdiv + 1));
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700412 if (cd < 1 || cd > CDNS_UART_CD_MAX)
John Linn61ec9012011-04-30 00:07:43 -0400413 continue;
414
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700415 calc_baud = clk / (cd * (bdiv + 1));
John Linn61ec9012011-04-30 00:07:43 -0400416
417 if (baud > calc_baud)
418 bauderror = baud - calc_baud;
419 else
420 bauderror = calc_baud - baud;
421
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700422 if (besterror > bauderror) {
423 *rbdiv = bdiv;
424 *rcd = cd;
425 bestbaud = calc_baud;
426 besterror = bauderror;
John Linn61ec9012011-04-30 00:07:43 -0400427 }
428 }
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700429 /* use the values when percent error is acceptable */
430 if (((besterror * 100) / baud) < 3)
431 bestbaud = baud;
John Linn61ec9012011-04-30 00:07:43 -0400432
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700433 return bestbaud;
434}
435
436/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700437 * cdns_uart_set_baud_rate - Calculate and set the baud rate
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700438 * @port: Handle to the uart port structure
439 * @baud: Baud rate to set
Michal Simek489810a12014-04-04 17:23:37 -0700440 * Return: baud rate, requested baud when possible, or actual baud when there
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700441 * was too much error, zero if no valid divisors are found.
442 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700443static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700444 unsigned int baud)
445{
446 unsigned int calc_baud;
Soren Brinkmannd54b1812013-10-21 16:40:59 -0700447 u32 cd = 0, bdiv = 0;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700448 u32 mreg;
449 int div8;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700450 struct cdns_uart *cdns_uart = port->private_data;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700451
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700452 calc_baud = cdns_uart_calc_baud_divs(port->uartclk, baud, &bdiv, &cd,
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700453 &div8);
454
455 /* Write new divisors to hardware */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800456 mreg = readl(port->membase + CDNS_UART_MR);
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700457 if (div8)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700458 mreg |= CDNS_UART_MR_CLKSEL;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700459 else
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700460 mreg &= ~CDNS_UART_MR_CLKSEL;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800461 writel(mreg, port->membase + CDNS_UART_MR);
462 writel(cd, port->membase + CDNS_UART_BAUDGEN);
463 writel(bdiv, port->membase + CDNS_UART_BAUDDIV);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700464 cdns_uart->baud = baud;
John Linn61ec9012011-04-30 00:07:43 -0400465
466 return calc_baud;
467}
468
Soren Brinkmann7ac57342013-10-21 16:41:01 -0700469#ifdef CONFIG_COMMON_CLK
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700470/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700471 * cdns_uart_clk_notitifer_cb - Clock notifier callback
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700472 * @nb: Notifier block
473 * @event: Notify event
474 * @data: Notifier data
Soren Brinkmanne555a212014-04-04 17:23:39 -0700475 * Return: NOTIFY_OK or NOTIFY_DONE on success, NOTIFY_BAD on error.
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700476 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700477static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700478 unsigned long event, void *data)
479{
480 u32 ctrl_reg;
481 struct uart_port *port;
482 int locked = 0;
483 struct clk_notifier_data *ndata = data;
484 unsigned long flags = 0;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700485 struct cdns_uart *cdns_uart = to_cdns_uart(nb);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700486
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700487 port = cdns_uart->port;
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700488 if (port->suspended)
489 return NOTIFY_OK;
490
491 switch (event) {
492 case PRE_RATE_CHANGE:
493 {
Soren Brinkmanne555a212014-04-04 17:23:39 -0700494 u32 bdiv, cd;
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700495 int div8;
496
497 /*
498 * Find out if current baud-rate can be achieved with new clock
499 * frequency.
500 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700501 if (!cdns_uart_calc_baud_divs(ndata->new_rate, cdns_uart->baud,
Soren Brinkmann5ce15d22014-04-04 17:23:40 -0700502 &bdiv, &cd, &div8)) {
503 dev_warn(port->dev, "clock rate change rejected\n");
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700504 return NOTIFY_BAD;
Soren Brinkmann5ce15d22014-04-04 17:23:40 -0700505 }
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700506
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700507 spin_lock_irqsave(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700508
509 /* Disable the TX and RX to set baud rate */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800510 ctrl_reg = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700511 ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800512 writel(ctrl_reg, port->membase + CDNS_UART_CR);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700513
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700514 spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700515
516 return NOTIFY_OK;
517 }
518 case POST_RATE_CHANGE:
519 /*
520 * Set clk dividers to generate correct baud with new clock
521 * frequency.
522 */
523
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700524 spin_lock_irqsave(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700525
526 locked = 1;
527 port->uartclk = ndata->new_rate;
528
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700529 cdns_uart->baud = cdns_uart_set_baud_rate(cdns_uart->port,
530 cdns_uart->baud);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700531 /* fall through */
532 case ABORT_RATE_CHANGE:
533 if (!locked)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700534 spin_lock_irqsave(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700535
536 /* Set TX/RX Reset */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800537 ctrl_reg = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700538 ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800539 writel(ctrl_reg, port->membase + CDNS_UART_CR);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700540
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800541 while (readl(port->membase + CDNS_UART_CR) &
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700542 (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700543 cpu_relax();
544
545 /*
546 * Clear the RX disable and TX disable bits and then set the TX
547 * enable bit and RX enable bit to enable the transmitter and
548 * receiver.
549 */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800550 writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
551 ctrl_reg = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700552 ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
553 ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800554 writel(ctrl_reg, port->membase + CDNS_UART_CR);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700555
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700556 spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700557
558 return NOTIFY_OK;
559 default:
560 return NOTIFY_DONE;
561 }
562}
Soren Brinkmann7ac57342013-10-21 16:41:01 -0700563#endif
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700564
John Linn61ec9012011-04-30 00:07:43 -0400565/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700566 * cdns_uart_start_tx - Start transmitting bytes
John Linn61ec9012011-04-30 00:07:43 -0400567 * @port: Handle to the uart port structure
Michal Simek489810a12014-04-04 17:23:37 -0700568 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700569static void cdns_uart_start_tx(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400570{
Soren Brinkmann079865802016-01-11 17:41:41 -0800571 unsigned int status;
John Linn61ec9012011-04-30 00:07:43 -0400572
Soren Brinkmannea8dd8e2015-12-26 02:43:51 -0800573 if (uart_tx_stopped(port))
John Linn61ec9012011-04-30 00:07:43 -0400574 return;
575
Soren Brinkmanne3538c32015-12-26 02:43:49 -0800576 /*
577 * Set the TX enable bit and clear the TX disable bit to enable the
John Linn61ec9012011-04-30 00:07:43 -0400578 * transmitter.
579 */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800580 status = readl(port->membase + CDNS_UART_CR);
Soren Brinkmanne3538c32015-12-26 02:43:49 -0800581 status &= ~CDNS_UART_CR_TX_DIS;
582 status |= CDNS_UART_CR_TX_EN;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800583 writel(status, port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400584
Soren Brinkmannea8dd8e2015-12-26 02:43:51 -0800585 if (uart_circ_empty(&port->state->xmit))
586 return;
587
Soren Brinkmann079865802016-01-11 17:41:41 -0800588 cdns_uart_handle_tx(port);
John Linn61ec9012011-04-30 00:07:43 -0400589
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800590 writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
John Linn61ec9012011-04-30 00:07:43 -0400591 /* Enable the TX Empty interrupt */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800592 writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
John Linn61ec9012011-04-30 00:07:43 -0400593}
594
595/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700596 * cdns_uart_stop_tx - Stop TX
John Linn61ec9012011-04-30 00:07:43 -0400597 * @port: Handle to the uart port structure
Michal Simek489810a12014-04-04 17:23:37 -0700598 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700599static void cdns_uart_stop_tx(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400600{
601 unsigned int regval;
602
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800603 regval = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700604 regval |= CDNS_UART_CR_TX_DIS;
John Linn61ec9012011-04-30 00:07:43 -0400605 /* Disable the transmitter */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800606 writel(regval, port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400607}
608
609/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700610 * cdns_uart_stop_rx - Stop RX
John Linn61ec9012011-04-30 00:07:43 -0400611 * @port: Handle to the uart port structure
Michal Simek489810a12014-04-04 17:23:37 -0700612 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700613static void cdns_uart_stop_rx(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400614{
615 unsigned int regval;
616
Soren Brinkmann373e8822016-01-11 17:41:37 -0800617 /* Disable RX IRQs */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800618 writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IDR);
Soren Brinkmann373e8822016-01-11 17:41:37 -0800619
620 /* Disable the receiver */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800621 regval = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700622 regval |= CDNS_UART_CR_RX_DIS;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800623 writel(regval, port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400624}
625
626/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700627 * cdns_uart_tx_empty - Check whether TX is empty
John Linn61ec9012011-04-30 00:07:43 -0400628 * @port: Handle to the uart port structure
629 *
Michal Simek489810a12014-04-04 17:23:37 -0700630 * Return: TIOCSER_TEMT on success, 0 otherwise
631 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700632static unsigned int cdns_uart_tx_empty(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400633{
634 unsigned int status;
635
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800636 status = readl(port->membase + CDNS_UART_SR) &
Thomas Betker19f22ef2015-03-12 22:11:59 +0100637 CDNS_UART_SR_TXEMPTY;
John Linn61ec9012011-04-30 00:07:43 -0400638 return status ? TIOCSER_TEMT : 0;
639}
640
641/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700642 * cdns_uart_break_ctl - Based on the input ctl we have to start or stop
John Linn61ec9012011-04-30 00:07:43 -0400643 * transmitting char breaks
644 * @port: Handle to the uart port structure
645 * @ctl: Value based on which start or stop decision is taken
Michal Simek489810a12014-04-04 17:23:37 -0700646 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700647static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
John Linn61ec9012011-04-30 00:07:43 -0400648{
649 unsigned int status;
650 unsigned long flags;
651
652 spin_lock_irqsave(&port->lock, flags);
653
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800654 status = readl(port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400655
656 if (ctl == -1)
Thomas Betker19f22ef2015-03-12 22:11:59 +0100657 writel(CDNS_UART_CR_STARTBRK | status,
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800658 port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400659 else {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700660 if ((status & CDNS_UART_CR_STOPBRK) == 0)
Thomas Betker19f22ef2015-03-12 22:11:59 +0100661 writel(CDNS_UART_CR_STOPBRK | status,
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800662 port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400663 }
664 spin_unlock_irqrestore(&port->lock, flags);
665}
666
667/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700668 * cdns_uart_set_termios - termios operations, handling data length, parity,
John Linn61ec9012011-04-30 00:07:43 -0400669 * stop bits, flow control, baud rate
670 * @port: Handle to the uart port structure
671 * @termios: Handle to the input termios structure
672 * @old: Values of the previously saved termios structure
Michal Simek489810a12014-04-04 17:23:37 -0700673 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700674static void cdns_uart_set_termios(struct uart_port *port,
John Linn61ec9012011-04-30 00:07:43 -0400675 struct ktermios *termios, struct ktermios *old)
676{
677 unsigned int cval = 0;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700678 unsigned int baud, minbaud, maxbaud;
John Linn61ec9012011-04-30 00:07:43 -0400679 unsigned long flags;
680 unsigned int ctrl_reg, mode_reg;
681
682 spin_lock_irqsave(&port->lock, flags);
683
Nathan Rossi6ecde472015-01-16 13:49:25 +0100684 /* Wait for the transmit FIFO to empty before making changes */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800685 if (!(readl(port->membase + CDNS_UART_CR) &
Thomas Betker19f22ef2015-03-12 22:11:59 +0100686 CDNS_UART_CR_TX_DIS)) {
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800687 while (!(readl(port->membase + CDNS_UART_SR) &
Nathan Rossi6ecde472015-01-16 13:49:25 +0100688 CDNS_UART_SR_TXEMPTY)) {
689 cpu_relax();
690 }
John Linn61ec9012011-04-30 00:07:43 -0400691 }
692
693 /* Disable the TX and RX to set baud rate */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800694 ctrl_reg = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700695 ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800696 writel(ctrl_reg, port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400697
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700698 /*
699 * Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk
700 * min and max baud should be calculated here based on port->uartclk.
701 * this way we get a valid baud and can safely call set_baud()
702 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700703 minbaud = port->uartclk /
704 ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX * 8);
705 maxbaud = port->uartclk / (CDNS_UART_BDIV_MIN + 1);
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700706 baud = uart_get_baud_rate(port, termios, old, minbaud, maxbaud);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700707 baud = cdns_uart_set_baud_rate(port, baud);
John Linn61ec9012011-04-30 00:07:43 -0400708 if (tty_termios_baud_rate(termios))
709 tty_termios_encode_baud_rate(termios, baud, baud);
710
Soren Brinkmanne555a212014-04-04 17:23:39 -0700711 /* Update the per-port timeout. */
John Linn61ec9012011-04-30 00:07:43 -0400712 uart_update_timeout(port, termios->c_cflag, baud);
713
714 /* Set TX/RX Reset */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800715 ctrl_reg = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700716 ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800717 writel(ctrl_reg, port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400718
Nava kishore Manne27b17ae2016-09-15 14:45:31 +0530719 while (readl(port->membase + CDNS_UART_CR) &
720 (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
721 cpu_relax();
722
Soren Brinkmanne555a212014-04-04 17:23:39 -0700723 /*
724 * Clear the RX disable and TX disable bits and then set the TX enable
John Linn61ec9012011-04-30 00:07:43 -0400725 * bit and RX enable bit to enable the transmitter and receiver.
726 */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800727 ctrl_reg = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700728 ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
729 ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800730 writel(ctrl_reg, port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400731
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800732 writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
John Linn61ec9012011-04-30 00:07:43 -0400733
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700734 port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
735 CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
John Linn61ec9012011-04-30 00:07:43 -0400736 port->ignore_status_mask = 0;
737
738 if (termios->c_iflag & INPCK)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700739 port->read_status_mask |= CDNS_UART_IXR_PARITY |
740 CDNS_UART_IXR_FRAMING;
John Linn61ec9012011-04-30 00:07:43 -0400741
742 if (termios->c_iflag & IGNPAR)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700743 port->ignore_status_mask |= CDNS_UART_IXR_PARITY |
744 CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
John Linn61ec9012011-04-30 00:07:43 -0400745
746 /* ignore all characters if CREAD is not set */
747 if ((termios->c_cflag & CREAD) == 0)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700748 port->ignore_status_mask |= CDNS_UART_IXR_RXTRIG |
749 CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY |
750 CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
John Linn61ec9012011-04-30 00:07:43 -0400751
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800752 mode_reg = readl(port->membase + CDNS_UART_MR);
John Linn61ec9012011-04-30 00:07:43 -0400753
754 /* Handling Data Size */
755 switch (termios->c_cflag & CSIZE) {
756 case CS6:
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700757 cval |= CDNS_UART_MR_CHARLEN_6_BIT;
John Linn61ec9012011-04-30 00:07:43 -0400758 break;
759 case CS7:
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700760 cval |= CDNS_UART_MR_CHARLEN_7_BIT;
John Linn61ec9012011-04-30 00:07:43 -0400761 break;
762 default:
763 case CS8:
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700764 cval |= CDNS_UART_MR_CHARLEN_8_BIT;
John Linn61ec9012011-04-30 00:07:43 -0400765 termios->c_cflag &= ~CSIZE;
766 termios->c_cflag |= CS8;
767 break;
768 }
769
770 /* Handling Parity and Stop Bits length */
771 if (termios->c_cflag & CSTOPB)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700772 cval |= CDNS_UART_MR_STOPMODE_2_BIT; /* 2 STOP bits */
John Linn61ec9012011-04-30 00:07:43 -0400773 else
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700774 cval |= CDNS_UART_MR_STOPMODE_1_BIT; /* 1 STOP bit */
John Linn61ec9012011-04-30 00:07:43 -0400775
776 if (termios->c_cflag & PARENB) {
777 /* Mark or Space parity */
778 if (termios->c_cflag & CMSPAR) {
779 if (termios->c_cflag & PARODD)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700780 cval |= CDNS_UART_MR_PARITY_MARK;
John Linn61ec9012011-04-30 00:07:43 -0400781 else
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700782 cval |= CDNS_UART_MR_PARITY_SPACE;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700783 } else {
784 if (termios->c_cflag & PARODD)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700785 cval |= CDNS_UART_MR_PARITY_ODD;
John Linn61ec9012011-04-30 00:07:43 -0400786 else
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700787 cval |= CDNS_UART_MR_PARITY_EVEN;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700788 }
789 } else {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700790 cval |= CDNS_UART_MR_PARITY_NONE;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700791 }
792 cval |= mode_reg & 1;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800793 writel(cval, port->membase + CDNS_UART_MR);
John Linn61ec9012011-04-30 00:07:43 -0400794
795 spin_unlock_irqrestore(&port->lock, flags);
796}
797
798/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700799 * cdns_uart_startup - Called when an application opens a cdns_uart port
John Linn61ec9012011-04-30 00:07:43 -0400800 * @port: Handle to the uart port structure
801 *
Soren Brinkmanne555a212014-04-04 17:23:39 -0700802 * Return: 0 on success, negative errno otherwise
Michal Simek489810a12014-04-04 17:23:37 -0700803 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700804static int cdns_uart_startup(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400805{
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530806 struct cdns_uart *cdns_uart = port->private_data;
807 bool is_brk_support;
Soren Brinkmann55861d12016-01-11 17:41:36 -0800808 int ret;
Soren Brinkmann6e14f7c2015-12-26 02:43:53 -0800809 unsigned long flags;
Soren Brinkmann55861d12016-01-11 17:41:36 -0800810 unsigned int status = 0;
John Linn61ec9012011-04-30 00:07:43 -0400811
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530812 is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
813
Soren Brinkmann6e14f7c2015-12-26 02:43:53 -0800814 spin_lock_irqsave(&port->lock, flags);
815
John Linn61ec9012011-04-30 00:07:43 -0400816 /* Disable the TX and RX */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100817 writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800818 port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400819
820 /* Set the Control Register with TX/RX Enable, TX/RX Reset,
821 * no break chars.
822 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100823 writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800824 port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400825
Nava kishore Manne27b17ae2016-09-15 14:45:31 +0530826 while (readl(port->membase + CDNS_UART_CR) &
827 (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
828 cpu_relax();
829
Soren Brinkmann6e14f7c2015-12-26 02:43:53 -0800830 /*
831 * Clear the RX disable bit and then set the RX enable bit to enable
832 * the receiver.
John Linn61ec9012011-04-30 00:07:43 -0400833 */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800834 status = readl(port->membase + CDNS_UART_CR);
Helmut Grohne68d12bb2018-06-04 12:22:05 +0200835 status &= ~CDNS_UART_CR_RX_DIS;
Soren Brinkmann6e14f7c2015-12-26 02:43:53 -0800836 status |= CDNS_UART_CR_RX_EN;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800837 writel(status, port->membase + CDNS_UART_CR);
John Linn61ec9012011-04-30 00:07:43 -0400838
839 /* Set the Mode Register with normal mode,8 data bits,1 stop bit,
840 * no parity.
841 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100842 writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700843 | CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT,
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800844 port->membase + CDNS_UART_MR);
John Linn61ec9012011-04-30 00:07:43 -0400845
Suneel85baf542013-10-17 14:08:08 -0700846 /*
847 * Set the RX FIFO Trigger level to use most of the FIFO, but it
848 * can be tuned with a module parameter
849 */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800850 writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
John Linn61ec9012011-04-30 00:07:43 -0400851
Suneel85baf542013-10-17 14:08:08 -0700852 /*
853 * Receive Timeout register is enabled but it
854 * can be tuned with a module parameter
855 */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800856 writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
John Linn61ec9012011-04-30 00:07:43 -0400857
John Linn855f6fd2013-03-22 18:49:27 +0100858 /* Clear out any pending interrupts before enabling them */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800859 writel(readl(port->membase + CDNS_UART_ISR),
860 port->membase + CDNS_UART_ISR);
John Linn61ec9012011-04-30 00:07:43 -0400861
Soren Brinkmann55861d12016-01-11 17:41:36 -0800862 spin_unlock_irqrestore(&port->lock, flags);
863
864 ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port);
865 if (ret) {
866 dev_err(port->dev, "request_irq '%d' failed with %d\n",
867 port->irq, ret);
868 return ret;
869 }
870
John Linn61ec9012011-04-30 00:07:43 -0400871 /* Set the Interrupt Registers with desired interrupts */
Nava kishore Manne3816b2f82016-09-15 14:45:29 +0530872 if (is_brk_support)
873 writel(CDNS_UART_RX_IRQS | CDNS_UART_IXR_BRK,
874 port->membase + CDNS_UART_IER);
875 else
876 writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
John Linn61ec9012011-04-30 00:07:43 -0400877
Soren Brinkmann55861d12016-01-11 17:41:36 -0800878 return 0;
John Linn61ec9012011-04-30 00:07:43 -0400879}
880
881/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700882 * cdns_uart_shutdown - Called when an application closes a cdns_uart port
John Linn61ec9012011-04-30 00:07:43 -0400883 * @port: Handle to the uart port structure
Michal Simek489810a12014-04-04 17:23:37 -0700884 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700885static void cdns_uart_shutdown(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400886{
887 int status;
Soren Brinkmanna19eda02015-12-26 02:43:55 -0800888 unsigned long flags;
889
890 spin_lock_irqsave(&port->lock, flags);
John Linn61ec9012011-04-30 00:07:43 -0400891
892 /* Disable interrupts */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800893 status = readl(port->membase + CDNS_UART_IMR);
894 writel(status, port->membase + CDNS_UART_IDR);
895 writel(0xffffffff, port->membase + CDNS_UART_ISR);
John Linn61ec9012011-04-30 00:07:43 -0400896
897 /* Disable the TX and RX */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100898 writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
Soren Brinkmanna8df6a52016-01-11 17:41:40 -0800899 port->membase + CDNS_UART_CR);
Soren Brinkmanna19eda02015-12-26 02:43:55 -0800900
901 spin_unlock_irqrestore(&port->lock, flags);
902
John Linn61ec9012011-04-30 00:07:43 -0400903 free_irq(port->irq, port);
904}
905
906/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700907 * cdns_uart_type - Set UART type to cdns_uart port
John Linn61ec9012011-04-30 00:07:43 -0400908 * @port: Handle to the uart port structure
909 *
Michal Simek489810a12014-04-04 17:23:37 -0700910 * Return: string on success, NULL otherwise
911 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700912static const char *cdns_uart_type(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400913{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700914 return port->type == PORT_XUARTPS ? CDNS_UART_NAME : NULL;
John Linn61ec9012011-04-30 00:07:43 -0400915}
916
917/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700918 * cdns_uart_verify_port - Verify the port params
John Linn61ec9012011-04-30 00:07:43 -0400919 * @port: Handle to the uart port structure
920 * @ser: Handle to the structure whose members are compared
921 *
Soren Brinkmanne555a212014-04-04 17:23:39 -0700922 * Return: 0 on success, negative errno otherwise.
Michal Simek489810a12014-04-04 17:23:37 -0700923 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700924static int cdns_uart_verify_port(struct uart_port *port,
John Linn61ec9012011-04-30 00:07:43 -0400925 struct serial_struct *ser)
926{
927 if (ser->type != PORT_UNKNOWN && ser->type != PORT_XUARTPS)
928 return -EINVAL;
929 if (port->irq != ser->irq)
930 return -EINVAL;
931 if (ser->io_type != UPIO_MEM)
932 return -EINVAL;
933 if (port->iobase != ser->port)
934 return -EINVAL;
935 if (ser->hub6 != 0)
936 return -EINVAL;
937 return 0;
938}
939
940/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700941 * cdns_uart_request_port - Claim the memory region attached to cdns_uart port,
942 * called when the driver adds a cdns_uart port via
John Linn61ec9012011-04-30 00:07:43 -0400943 * uart_add_one_port()
944 * @port: Handle to the uart port structure
945 *
Soren Brinkmanne555a212014-04-04 17:23:39 -0700946 * Return: 0 on success, negative errno otherwise.
Michal Simek489810a12014-04-04 17:23:37 -0700947 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700948static int cdns_uart_request_port(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400949{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700950 if (!request_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE,
951 CDNS_UART_NAME)) {
John Linn61ec9012011-04-30 00:07:43 -0400952 return -ENOMEM;
953 }
954
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700955 port->membase = ioremap(port->mapbase, CDNS_UART_REGISTER_SPACE);
John Linn61ec9012011-04-30 00:07:43 -0400956 if (!port->membase) {
957 dev_err(port->dev, "Unable to map registers\n");
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700958 release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE);
John Linn61ec9012011-04-30 00:07:43 -0400959 return -ENOMEM;
960 }
961 return 0;
962}
963
964/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700965 * cdns_uart_release_port - Release UART port
John Linn61ec9012011-04-30 00:07:43 -0400966 * @port: Handle to the uart port structure
Soren Brinkmanne555a212014-04-04 17:23:39 -0700967 *
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700968 * Release the memory region attached to a cdns_uart port. Called when the
969 * driver removes a cdns_uart port via uart_remove_one_port().
Michal Simek489810a12014-04-04 17:23:37 -0700970 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700971static void cdns_uart_release_port(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400972{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700973 release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE);
John Linn61ec9012011-04-30 00:07:43 -0400974 iounmap(port->membase);
975 port->membase = NULL;
976}
977
978/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700979 * cdns_uart_config_port - Configure UART port
John Linn61ec9012011-04-30 00:07:43 -0400980 * @port: Handle to the uart port structure
981 * @flags: If any
Michal Simek489810a12014-04-04 17:23:37 -0700982 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700983static void cdns_uart_config_port(struct uart_port *port, int flags)
John Linn61ec9012011-04-30 00:07:43 -0400984{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700985 if (flags & UART_CONFIG_TYPE && cdns_uart_request_port(port) == 0)
John Linn61ec9012011-04-30 00:07:43 -0400986 port->type = PORT_XUARTPS;
987}
988
989/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700990 * cdns_uart_get_mctrl - Get the modem control state
John Linn61ec9012011-04-30 00:07:43 -0400991 * @port: Handle to the uart port structure
992 *
Michal Simek489810a12014-04-04 17:23:37 -0700993 * Return: the modem control state
994 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700995static unsigned int cdns_uart_get_mctrl(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400996{
997 return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
998}
999
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001000static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
John Linn61ec9012011-04-30 00:07:43 -04001001{
Lars-Peter Clausen19038ad2014-11-05 13:35:16 +01001002 u32 val;
Yasir-Khan5935a2b2017-01-23 13:26:08 +01001003 u32 mode_reg;
Lars-Peter Clausen19038ad2014-11-05 13:35:16 +01001004
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001005 val = readl(port->membase + CDNS_UART_MODEMCR);
Yasir-Khan5935a2b2017-01-23 13:26:08 +01001006 mode_reg = readl(port->membase + CDNS_UART_MR);
Lars-Peter Clausen19038ad2014-11-05 13:35:16 +01001007
Michal Simek6ac1b912018-09-03 15:05:37 +02001008 val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR |
1009 CDNS_UART_MODEMCR_FCM);
Yasir-Khan5935a2b2017-01-23 13:26:08 +01001010 mode_reg &= ~CDNS_UART_MR_CHMODE_MASK;
Lars-Peter Clausen19038ad2014-11-05 13:35:16 +01001011
Michal Simek6ac1b912018-09-03 15:05:37 +02001012 if (mctrl & TIOCM_RTS || mctrl & TIOCM_DTR)
1013 val |= CDNS_UART_MODEMCR_FCM;
Yasir-Khan5935a2b2017-01-23 13:26:08 +01001014 if (mctrl & TIOCM_LOOP)
1015 mode_reg |= CDNS_UART_MR_CHMODE_L_LOOP;
1016 else
1017 mode_reg |= CDNS_UART_MR_CHMODE_NORM;
Lars-Peter Clausen19038ad2014-11-05 13:35:16 +01001018
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001019 writel(val, port->membase + CDNS_UART_MODEMCR);
Yasir-Khan5935a2b2017-01-23 13:26:08 +01001020 writel(mode_reg, port->membase + CDNS_UART_MR);
John Linn61ec9012011-04-30 00:07:43 -04001021}
1022
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001023#ifdef CONFIG_CONSOLE_POLL
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001024static int cdns_uart_poll_get_char(struct uart_port *port)
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001025{
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001026 int c;
Soren Brinkmannf0f54a82015-12-26 02:43:50 -08001027 unsigned long flags;
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001028
Soren Brinkmannf0f54a82015-12-26 02:43:50 -08001029 spin_lock_irqsave(&port->lock, flags);
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001030
1031 /* Check if FIFO is empty */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001032 if (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001033 c = NO_POLL_CHAR;
1034 else /* Read a character */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001035 c = (unsigned char) readl(port->membase + CDNS_UART_FIFO);
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001036
Soren Brinkmannf0f54a82015-12-26 02:43:50 -08001037 spin_unlock_irqrestore(&port->lock, flags);
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001038
1039 return c;
1040}
1041
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001042static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001043{
Soren Brinkmannf0f54a82015-12-26 02:43:50 -08001044 unsigned long flags;
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001045
Soren Brinkmannf0f54a82015-12-26 02:43:50 -08001046 spin_lock_irqsave(&port->lock, flags);
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001047
1048 /* Wait until FIFO is empty */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001049 while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001050 cpu_relax();
1051
1052 /* Write a character */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001053 writel(c, port->membase + CDNS_UART_FIFO);
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001054
1055 /* Wait until FIFO is empty */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001056 while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001057 cpu_relax();
1058
Soren Brinkmannf0f54a82015-12-26 02:43:50 -08001059 spin_unlock_irqrestore(&port->lock, flags);
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001060
1061 return;
1062}
1063#endif
1064
Shubhrajyoti Datta210417c2016-05-27 15:05:19 +05301065static void cdns_uart_pm(struct uart_port *port, unsigned int state,
1066 unsigned int oldstate)
1067{
Shubhrajyoti Datta210417c2016-05-27 15:05:19 +05301068 switch (state) {
1069 case UART_PM_STATE_OFF:
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301070 pm_runtime_mark_last_busy(port->dev);
1071 pm_runtime_put_autosuspend(port->dev);
Shubhrajyoti Datta210417c2016-05-27 15:05:19 +05301072 break;
1073 default:
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301074 pm_runtime_get_sync(port->dev);
Shubhrajyoti Datta210417c2016-05-27 15:05:19 +05301075 break;
1076 }
1077}
1078
Julia Lawallf098a0a2016-09-01 19:51:36 +02001079static const struct uart_ops cdns_uart_ops = {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001080 .set_mctrl = cdns_uart_set_mctrl,
1081 .get_mctrl = cdns_uart_get_mctrl,
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001082 .start_tx = cdns_uart_start_tx,
1083 .stop_tx = cdns_uart_stop_tx,
1084 .stop_rx = cdns_uart_stop_rx,
1085 .tx_empty = cdns_uart_tx_empty,
1086 .break_ctl = cdns_uart_break_ctl,
1087 .set_termios = cdns_uart_set_termios,
1088 .startup = cdns_uart_startup,
1089 .shutdown = cdns_uart_shutdown,
Shubhrajyoti Datta210417c2016-05-27 15:05:19 +05301090 .pm = cdns_uart_pm,
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001091 .type = cdns_uart_type,
1092 .verify_port = cdns_uart_verify_port,
1093 .request_port = cdns_uart_request_port,
1094 .release_port = cdns_uart_release_port,
1095 .config_port = cdns_uart_config_port,
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001096#ifdef CONFIG_CONSOLE_POLL
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001097 .poll_get_char = cdns_uart_poll_get_char,
1098 .poll_put_char = cdns_uart_poll_put_char,
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001099#endif
John Linn61ec9012011-04-30 00:07:43 -04001100};
1101
John Linn61ec9012011-04-30 00:07:43 -04001102#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
1103/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001104 * cdns_uart_console_putchar - write the character to the FIFO buffer
John Linn61ec9012011-04-30 00:07:43 -04001105 * @port: Handle to the uart port structure
1106 * @ch: Character to be written
Michal Simek489810a12014-04-04 17:23:37 -07001107 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001108static void cdns_uart_console_putchar(struct uart_port *port, int ch)
John Linn61ec9012011-04-30 00:07:43 -04001109{
Helmut Grohnede4ed392018-06-04 12:22:11 +02001110 while (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)
1111 cpu_relax();
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001112 writel(ch, port->membase + CDNS_UART_FIFO);
John Linn61ec9012011-04-30 00:07:43 -04001113}
1114
Jeffy Chen99d273162017-07-18 14:02:56 +08001115static void cdns_early_write(struct console *con, const char *s,
Masahiro Yamada54585ba2015-05-07 18:55:40 +09001116 unsigned n)
Michal Simek6fa62fc2014-09-10 12:43:02 +02001117{
1118 struct earlycon_device *dev = con->data;
1119
1120 uart_console_write(&dev->port, s, n, cdns_uart_console_putchar);
1121}
1122
1123static int __init cdns_early_console_setup(struct earlycon_device *device,
1124 const char *opt)
1125{
Scott Telfordc41251b2016-09-22 16:58:16 +01001126 struct uart_port *port = &device->port;
1127
1128 if (!port->membase)
Michal Simek6fa62fc2014-09-10 12:43:02 +02001129 return -ENODEV;
1130
Scott Telfordc41251b2016-09-22 16:58:16 +01001131 /* initialise control register */
1132 writel(CDNS_UART_CR_TX_EN|CDNS_UART_CR_TXRST|CDNS_UART_CR_RXRST,
1133 port->membase + CDNS_UART_CR);
1134
1135 /* only set baud if specified on command line - otherwise
1136 * assume it has been initialized by a boot loader.
1137 */
Michal Simek66dd99c2018-04-23 10:55:21 +02001138 if (port->uartclk && device->baud) {
Scott Telfordc41251b2016-09-22 16:58:16 +01001139 u32 cd = 0, bdiv = 0;
1140 u32 mr;
1141 int div8;
1142
1143 cdns_uart_calc_baud_divs(port->uartclk, device->baud,
1144 &bdiv, &cd, &div8);
1145 mr = CDNS_UART_MR_PARITY_NONE;
1146 if (div8)
1147 mr |= CDNS_UART_MR_CLKSEL;
1148
1149 writel(mr, port->membase + CDNS_UART_MR);
1150 writel(cd, port->membase + CDNS_UART_BAUDGEN);
1151 writel(bdiv, port->membase + CDNS_UART_BAUDDIV);
1152 }
1153
Michal Simek6fa62fc2014-09-10 12:43:02 +02001154 device->con->write = cdns_early_write;
1155
1156 return 0;
1157}
Michal Simek93d7bba2016-02-18 08:57:20 +01001158OF_EARLYCON_DECLARE(cdns, "xlnx,xuartps", cdns_early_console_setup);
1159OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p8", cdns_early_console_setup);
1160OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup);
Nava kishore Manne0267a4f2016-10-12 13:17:27 +05301161OF_EARLYCON_DECLARE(cdns, "xlnx,zynqmp-uart", cdns_early_console_setup);
Michal Simek6fa62fc2014-09-10 12:43:02 +02001162
Michal Simek0413fe02018-04-23 11:51:01 +02001163
1164/* Static pointer to console port */
1165static struct uart_port *console_port;
1166
John Linn61ec9012011-04-30 00:07:43 -04001167/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001168 * cdns_uart_console_write - perform write operation
Michal Simek489810a12014-04-04 17:23:37 -07001169 * @co: Console handle
John Linn61ec9012011-04-30 00:07:43 -04001170 * @s: Pointer to character array
1171 * @count: No of characters
Michal Simek489810a12014-04-04 17:23:37 -07001172 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001173static void cdns_uart_console_write(struct console *co, const char *s,
John Linn61ec9012011-04-30 00:07:43 -04001174 unsigned int count)
1175{
Michal Simek0413fe02018-04-23 11:51:01 +02001176 struct uart_port *port = console_port;
John Linn61ec9012011-04-30 00:07:43 -04001177 unsigned long flags;
Lars-Peter Clausend3755f52013-10-17 14:08:09 -07001178 unsigned int imr, ctrl;
John Linn61ec9012011-04-30 00:07:43 -04001179 int locked = 1;
1180
Soren Brinkmann74ea66d42016-01-11 17:41:39 -08001181 if (port->sysrq)
1182 locked = 0;
1183 else if (oops_in_progress)
John Linn61ec9012011-04-30 00:07:43 -04001184 locked = spin_trylock_irqsave(&port->lock, flags);
1185 else
1186 spin_lock_irqsave(&port->lock, flags);
1187
1188 /* save and disable interrupt */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001189 imr = readl(port->membase + CDNS_UART_IMR);
1190 writel(imr, port->membase + CDNS_UART_IDR);
John Linn61ec9012011-04-30 00:07:43 -04001191
Lars-Peter Clausend3755f52013-10-17 14:08:09 -07001192 /*
1193 * Make sure that the tx part is enabled. Set the TX enable bit and
1194 * clear the TX disable bit to enable the transmitter.
1195 */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001196 ctrl = readl(port->membase + CDNS_UART_CR);
Soren Brinkmanne3538c32015-12-26 02:43:49 -08001197 ctrl &= ~CDNS_UART_CR_TX_DIS;
1198 ctrl |= CDNS_UART_CR_TX_EN;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001199 writel(ctrl, port->membase + CDNS_UART_CR);
Lars-Peter Clausend3755f52013-10-17 14:08:09 -07001200
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001201 uart_console_write(port, s, count, cdns_uart_console_putchar);
Helmut Grohnede4ed392018-06-04 12:22:11 +02001202 while ((readl(port->membase + CDNS_UART_SR) &
1203 (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE)) !=
1204 CDNS_UART_SR_TXEMPTY)
1205 cpu_relax();
John Linn61ec9012011-04-30 00:07:43 -04001206
Soren Brinkmannb494a5f2014-04-04 17:23:42 -07001207 /* restore interrupt state */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001208 writel(imr, port->membase + CDNS_UART_IER);
John Linn61ec9012011-04-30 00:07:43 -04001209
1210 if (locked)
1211 spin_unlock_irqrestore(&port->lock, flags);
1212}
1213
1214/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001215 * cdns_uart_console_setup - Initialize the uart to default config
John Linn61ec9012011-04-30 00:07:43 -04001216 * @co: Console handle
1217 * @options: Initial settings of uart
1218 *
Soren Brinkmanne555a212014-04-04 17:23:39 -07001219 * Return: 0 on success, negative errno otherwise.
Michal Simek489810a12014-04-04 17:23:37 -07001220 */
Michal Simek4bb1ce22018-09-03 15:10:49 +02001221static int cdns_uart_console_setup(struct console *co, char *options)
John Linn61ec9012011-04-30 00:07:43 -04001222{
Michal Simek0413fe02018-04-23 11:51:01 +02001223 struct uart_port *port = console_port;
1224
John Linn61ec9012011-04-30 00:07:43 -04001225 int baud = 9600;
1226 int bits = 8;
1227 int parity = 'n';
1228 int flow = 'n';
1229
Thomas Betker136debf2015-03-11 22:39:28 +01001230 if (!port->membase) {
Peter Crosthwaitef6415492015-02-24 15:13:57 -08001231 pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n",
1232 co->index);
John Linn61ec9012011-04-30 00:07:43 -04001233 return -ENODEV;
1234 }
1235
1236 if (options)
1237 uart_parse_options(options, &baud, &parity, &bits, &flow);
1238
1239 return uart_set_options(port, co, baud, parity, bits, flow);
1240}
John Linn61ec9012011-04-30 00:07:43 -04001241#endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
1242
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001243#ifdef CONFIG_PM_SLEEP
1244/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001245 * cdns_uart_suspend - suspend event
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001246 * @device: Pointer to the device structure
1247 *
Michal Simek489810a12014-04-04 17:23:37 -07001248 * Return: 0
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001249 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001250static int cdns_uart_suspend(struct device *device)
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001251{
1252 struct uart_port *port = dev_get_drvdata(device);
Michal Simek46a460f2018-09-03 15:10:52 +02001253 struct cdns_uart *cdns_uart = port->private_data;
Nava kishore Manne4b9d33c2018-09-03 15:10:51 +02001254 int may_wake;
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001255
Nava kishore Manne4b9d33c2018-09-03 15:10:51 +02001256 may_wake = device_may_wakeup(device);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001257
Nava kishore Manne4b9d33c2018-09-03 15:10:51 +02001258 if (console_suspend_enabled && may_wake) {
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001259 unsigned long flags = 0;
1260
1261 spin_lock_irqsave(&port->lock, flags);
1262 /* Empty the receive FIFO 1st before making changes */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001263 while (!(readl(port->membase + CDNS_UART_SR) &
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001264 CDNS_UART_SR_RXEMPTY))
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001265 readl(port->membase + CDNS_UART_FIFO);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001266 /* set RX trigger level to 1 */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001267 writel(1, port->membase + CDNS_UART_RXWM);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001268 /* disable RX timeout interrups */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001269 writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IDR);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001270 spin_unlock_irqrestore(&port->lock, flags);
1271 }
1272
Nava kishore Manne4b9d33c2018-09-03 15:10:51 +02001273 /*
1274 * Call the API provided in serial_core.c file which handles
1275 * the suspend.
1276 */
Michal Simek46a460f2018-09-03 15:10:52 +02001277 return uart_suspend_port(cdns_uart->cdns_uart_driver, port);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001278}
1279
1280/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001281 * cdns_uart_resume - Resume after a previous suspend
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001282 * @device: Pointer to the device structure
1283 *
Michal Simek489810a12014-04-04 17:23:37 -07001284 * Return: 0
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001285 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001286static int cdns_uart_resume(struct device *device)
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001287{
1288 struct uart_port *port = dev_get_drvdata(device);
Michal Simek46a460f2018-09-03 15:10:52 +02001289 struct cdns_uart *cdns_uart = port->private_data;
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001290 unsigned long flags = 0;
1291 u32 ctrl_reg;
Nava kishore Manne4b9d33c2018-09-03 15:10:51 +02001292 int may_wake;
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001293
Nava kishore Manne4b9d33c2018-09-03 15:10:51 +02001294 may_wake = device_may_wakeup(device);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001295
1296 if (console_suspend_enabled && !may_wake) {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001297 clk_enable(cdns_uart->pclk);
1298 clk_enable(cdns_uart->uartclk);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001299
1300 spin_lock_irqsave(&port->lock, flags);
1301
1302 /* Set TX/RX Reset */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001303 ctrl_reg = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001304 ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001305 writel(ctrl_reg, port->membase + CDNS_UART_CR);
1306 while (readl(port->membase + CDNS_UART_CR) &
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001307 (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001308 cpu_relax();
1309
1310 /* restore rx timeout value */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001311 writel(rx_timeout, port->membase + CDNS_UART_RXTOUT);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001312 /* Enable Tx/Rx */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001313 ctrl_reg = readl(port->membase + CDNS_UART_CR);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001314 ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
1315 ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001316 writel(ctrl_reg, port->membase + CDNS_UART_CR);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001317
Shubhrajyoti Datta81e33b52017-03-15 08:38:56 -07001318 clk_disable(cdns_uart->uartclk);
1319 clk_disable(cdns_uart->pclk);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001320 spin_unlock_irqrestore(&port->lock, flags);
1321 } else {
1322 spin_lock_irqsave(&port->lock, flags);
1323 /* restore original rx trigger level */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001324 writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001325 /* enable RX timeout interrupt */
Soren Brinkmanna8df6a52016-01-11 17:41:40 -08001326 writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IER);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001327 spin_unlock_irqrestore(&port->lock, flags);
1328 }
1329
Michal Simek46a460f2018-09-03 15:10:52 +02001330 return uart_resume_port(cdns_uart->cdns_uart_driver, port);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001331}
1332#endif /* ! CONFIG_PM_SLEEP */
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301333static int __maybe_unused cdns_runtime_suspend(struct device *dev)
1334{
Wolfram Sanga406c4b2018-04-19 16:06:23 +02001335 struct uart_port *port = dev_get_drvdata(dev);
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301336 struct cdns_uart *cdns_uart = port->private_data;
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001337
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301338 clk_disable(cdns_uart->uartclk);
1339 clk_disable(cdns_uart->pclk);
1340 return 0;
1341};
1342
1343static int __maybe_unused cdns_runtime_resume(struct device *dev)
1344{
Wolfram Sanga406c4b2018-04-19 16:06:23 +02001345 struct uart_port *port = dev_get_drvdata(dev);
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301346 struct cdns_uart *cdns_uart = port->private_data;
1347
1348 clk_enable(cdns_uart->pclk);
1349 clk_enable(cdns_uart->uartclk);
1350 return 0;
1351};
1352
1353static const struct dev_pm_ops cdns_uart_dev_pm_ops = {
1354 SET_SYSTEM_SLEEP_PM_OPS(cdns_uart_suspend, cdns_uart_resume)
1355 SET_RUNTIME_PM_OPS(cdns_runtime_suspend,
1356 cdns_runtime_resume, NULL)
1357};
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001358
Nava kishore Manne3816b2f82016-09-15 14:45:29 +05301359static const struct cdns_platform_data zynqmp_uart_def = {
1360 .quirks = CDNS_UART_RXBS_SUPPORT, };
1361
1362/* Match table for of_platform binding */
1363static const struct of_device_id cdns_uart_of_match[] = {
1364 { .compatible = "xlnx,xuartps", },
1365 { .compatible = "cdns,uart-r1p8", },
1366 { .compatible = "cdns,uart-r1p12", .data = &zynqmp_uart_def },
Nava kishore Manne0267a4f2016-10-12 13:17:27 +05301367 { .compatible = "xlnx,zynqmp-uart", .data = &zynqmp_uart_def },
Nava kishore Manne3816b2f82016-09-15 14:45:29 +05301368 {}
1369};
1370MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
1371
Michal Simekae1cca32018-09-20 13:41:53 +02001372/*
1373 * Maximum number of instances without alias IDs but if there is alias
1374 * which target "< MAX_UART_INSTANCES" range this ID can't be used.
1375 */
1376#define MAX_UART_INSTANCES 32
1377
1378/* Stores static aliases list */
1379static DECLARE_BITMAP(alias_bitmap, MAX_UART_INSTANCES);
1380static int alias_bitmap_initialized;
1381
1382/* Stores actual bitmap of allocated IDs with alias IDs together */
1383static DECLARE_BITMAP(bitmap, MAX_UART_INSTANCES);
1384/* Protect bitmap operations to have unique IDs */
1385static DEFINE_MUTEX(bitmap_lock);
1386
1387static int cdns_get_id(struct platform_device *pdev)
1388{
1389 int id, ret;
1390
1391 mutex_lock(&bitmap_lock);
1392
1393 /* Alias list is stable that's why get alias bitmap only once */
1394 if (!alias_bitmap_initialized) {
1395 ret = of_alias_get_alias_list(cdns_uart_of_match, "serial",
1396 alias_bitmap, MAX_UART_INSTANCES);
Michal Simek59eaeba2018-10-12 07:43:11 +02001397 if (ret && ret != -EOVERFLOW) {
Wei Yongjun823f4e52018-09-25 14:23:21 +00001398 mutex_unlock(&bitmap_lock);
Michal Simekae1cca32018-09-20 13:41:53 +02001399 return ret;
Wei Yongjun823f4e52018-09-25 14:23:21 +00001400 }
Michal Simekae1cca32018-09-20 13:41:53 +02001401
1402 alias_bitmap_initialized++;
1403 }
1404
1405 /* Make sure that alias ID is not taken by instance without alias */
1406 bitmap_or(bitmap, bitmap, alias_bitmap, MAX_UART_INSTANCES);
1407
1408 dev_dbg(&pdev->dev, "Alias bitmap: %*pb\n",
1409 MAX_UART_INSTANCES, bitmap);
1410
1411 /* Look for a serialN alias */
1412 id = of_alias_get_id(pdev->dev.of_node, "serial");
1413 if (id < 0) {
1414 dev_warn(&pdev->dev,
1415 "No serial alias passed. Using the first free id\n");
1416
1417 /*
1418 * Start with id 0 and check if there is no serial0 alias
1419 * which points to device which is compatible with this driver.
1420 * If alias exists then try next free position.
1421 */
1422 id = 0;
1423
1424 for (;;) {
1425 dev_info(&pdev->dev, "Checking id %d\n", id);
1426 id = find_next_zero_bit(bitmap, MAX_UART_INSTANCES, id);
1427
1428 /* No free empty instance */
1429 if (id == MAX_UART_INSTANCES) {
1430 dev_err(&pdev->dev, "No free ID\n");
1431 mutex_unlock(&bitmap_lock);
1432 return -EINVAL;
1433 }
1434
1435 dev_dbg(&pdev->dev, "The empty id is %d\n", id);
1436 /* Check if ID is empty */
1437 if (!test_and_set_bit(id, bitmap)) {
1438 /* Break the loop if bit is taken */
1439 dev_dbg(&pdev->dev,
1440 "Selected ID %d allocation passed\n",
1441 id);
1442 break;
1443 }
1444 dev_dbg(&pdev->dev,
1445 "Selected ID %d allocation failed\n", id);
1446 /* if taking bit fails then try next one */
1447 id++;
1448 }
1449 }
1450
1451 mutex_unlock(&bitmap_lock);
1452
1453 return id;
1454}
1455
John Linn61ec9012011-04-30 00:07:43 -04001456/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001457 * cdns_uart_probe - Platform driver probe
John Linn61ec9012011-04-30 00:07:43 -04001458 * @pdev: Pointer to the platform device structure
1459 *
Soren Brinkmanne555a212014-04-04 17:23:39 -07001460 * Return: 0 on success, negative errno otherwise
Michal Simek489810a12014-04-04 17:23:37 -07001461 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001462static int cdns_uart_probe(struct platform_device *pdev)
John Linn61ec9012011-04-30 00:07:43 -04001463{
Michal Simekbed25ac2018-09-03 15:10:58 +02001464 int rc, irq;
John Linn61ec9012011-04-30 00:07:43 -04001465 struct uart_port *port;
Michal Simek5c90c072015-04-13 16:34:21 +02001466 struct resource *res;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001467 struct cdns_uart *cdns_uart_data;
Nava kishore Manne3816b2f82016-09-15 14:45:29 +05301468 const struct of_device_id *match;
Michal Simek024ca322018-09-03 15:10:57 +02001469 struct uart_driver *cdns_uart_uart_driver;
1470 char *driver_name;
1471#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
1472 struct console *cdns_uart_console;
1473#endif
John Linn61ec9012011-04-30 00:07:43 -04001474
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001475 cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
Soren Brinkmannc03cae12013-10-17 14:08:05 -07001476 GFP_KERNEL);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001477 if (!cdns_uart_data)
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001478 return -ENOMEM;
Michal Simek0a84bae2018-04-23 11:51:03 +02001479 port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
1480 if (!port)
1481 return -ENOMEM;
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001482
Michal Simek024ca322018-09-03 15:10:57 +02001483 cdns_uart_uart_driver = devm_kzalloc(&pdev->dev,
1484 sizeof(*cdns_uart_uart_driver),
1485 GFP_KERNEL);
1486 if (!cdns_uart_uart_driver)
1487 return -ENOMEM;
1488
Michal Simekae1cca32018-09-20 13:41:53 +02001489 cdns_uart_data->id = cdns_get_id(pdev);
Michal Simekbed25ac2018-09-03 15:10:58 +02001490 if (cdns_uart_data->id < 0)
Michal Simekae1cca32018-09-20 13:41:53 +02001491 return cdns_uart_data->id;
Michal Simek14090ad2018-09-03 15:10:53 +02001492
Michal Simek024ca322018-09-03 15:10:57 +02001493 /* There is a need to use unique driver name */
1494 driver_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%d",
Michal Simekbed25ac2018-09-03 15:10:58 +02001495 CDNS_UART_NAME, cdns_uart_data->id);
Michal Simekae1cca32018-09-20 13:41:53 +02001496 if (!driver_name) {
1497 rc = -ENOMEM;
1498 goto err_out_id;
1499 }
Michal Simek024ca322018-09-03 15:10:57 +02001500
1501 cdns_uart_uart_driver->owner = THIS_MODULE;
1502 cdns_uart_uart_driver->driver_name = driver_name;
1503 cdns_uart_uart_driver->dev_name = CDNS_UART_TTY_NAME;
1504 cdns_uart_uart_driver->major = CDNS_UART_MAJOR;
Michal Simekbed25ac2018-09-03 15:10:58 +02001505 cdns_uart_uart_driver->minor = cdns_uart_data->id;
Michal Simek024ca322018-09-03 15:10:57 +02001506 cdns_uart_uart_driver->nr = 1;
1507
Michal Simek10a53152018-09-03 15:10:55 +02001508#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
Michal Simek024ca322018-09-03 15:10:57 +02001509 cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console),
1510 GFP_KERNEL);
1511 if (!cdns_uart_console)
1512 return -ENOMEM;
1513
1514 strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME,
1515 sizeof(cdns_uart_console->name));
Michal Simekbed25ac2018-09-03 15:10:58 +02001516 cdns_uart_console->index = cdns_uart_data->id;
Michal Simek024ca322018-09-03 15:10:57 +02001517 cdns_uart_console->write = cdns_uart_console_write;
1518 cdns_uart_console->device = uart_console_device;
1519 cdns_uart_console->setup = cdns_uart_console_setup;
1520 cdns_uart_console->flags = CON_PRINTBUFFER;
1521 cdns_uart_console->data = cdns_uart_uart_driver;
1522 cdns_uart_uart_driver->cons = cdns_uart_console;
Michal Simek10a53152018-09-03 15:10:55 +02001523#endif
1524
Michal Simek024ca322018-09-03 15:10:57 +02001525 rc = uart_register_driver(cdns_uart_uart_driver);
1526 if (rc < 0) {
1527 dev_err(&pdev->dev, "Failed to register driver\n");
Michal Simekae1cca32018-09-20 13:41:53 +02001528 goto err_out_id;
Michal Simeke4bbb512018-09-03 15:10:54 +02001529 }
1530
Michal Simek024ca322018-09-03 15:10:57 +02001531 cdns_uart_data->cdns_uart_driver = cdns_uart_uart_driver;
1532
1533 /*
1534 * Setting up proper name_base needs to be done after uart
1535 * registration because tty_driver structure is not filled.
1536 * name_base is 0 by default.
1537 */
Michal Simekbed25ac2018-09-03 15:10:58 +02001538 cdns_uart_uart_driver->tty_driver->name_base = cdns_uart_data->id;
Michal Simek46a460f2018-09-03 15:10:52 +02001539
Nava kishore Manne3816b2f82016-09-15 14:45:29 +05301540 match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
1541 if (match && match->data) {
1542 const struct cdns_platform_data *data = match->data;
1543
1544 cdns_uart_data->quirks = data->quirks;
1545 }
1546
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001547 cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
1548 if (IS_ERR(cdns_uart_data->pclk)) {
1549 cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
1550 if (!IS_ERR(cdns_uart_data->pclk))
1551 dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n");
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001552 }
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001553 if (IS_ERR(cdns_uart_data->pclk)) {
1554 dev_err(&pdev->dev, "pclk clock not found.\n");
Michal Simeke4bbb512018-09-03 15:10:54 +02001555 rc = PTR_ERR(cdns_uart_data->pclk);
1556 goto err_out_unregister_driver;
Josh Cartwright2326669c2013-01-21 19:57:41 +01001557 }
1558
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001559 cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk");
1560 if (IS_ERR(cdns_uart_data->uartclk)) {
1561 cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "ref_clk");
1562 if (!IS_ERR(cdns_uart_data->uartclk))
1563 dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n");
1564 }
1565 if (IS_ERR(cdns_uart_data->uartclk)) {
1566 dev_err(&pdev->dev, "uart_clk clock not found.\n");
Michal Simeke4bbb512018-09-03 15:10:54 +02001567 rc = PTR_ERR(cdns_uart_data->uartclk);
1568 goto err_out_unregister_driver;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001569 }
1570
Shubhrajyoti Dattaecfc5772017-04-06 12:27:41 +05301571 rc = clk_prepare_enable(cdns_uart_data->pclk);
Josh Cartwright2326669c2013-01-21 19:57:41 +01001572 if (rc) {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001573 dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
Michal Simeke4bbb512018-09-03 15:10:54 +02001574 goto err_out_unregister_driver;
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001575 }
Shubhrajyoti Dattaecfc5772017-04-06 12:27:41 +05301576 rc = clk_prepare_enable(cdns_uart_data->uartclk);
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001577 if (rc) {
1578 dev_err(&pdev->dev, "Unable to enable device clock.\n");
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001579 goto err_out_clk_dis_pclk;
John Linn61ec9012011-04-30 00:07:43 -04001580 }
1581
1582 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001583 if (!res) {
1584 rc = -ENODEV;
1585 goto err_out_clk_disable;
1586 }
John Linn61ec9012011-04-30 00:07:43 -04001587
Michal Simek5c90c072015-04-13 16:34:21 +02001588 irq = platform_get_irq(pdev, 0);
1589 if (irq <= 0) {
1590 rc = -ENXIO;
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001591 goto err_out_clk_disable;
1592 }
John Linn61ec9012011-04-30 00:07:43 -04001593
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001594#ifdef CONFIG_COMMON_CLK
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001595 cdns_uart_data->clk_rate_change_nb.notifier_call =
1596 cdns_uart_clk_notifier_cb;
1597 if (clk_notifier_register(cdns_uart_data->uartclk,
1598 &cdns_uart_data->clk_rate_change_nb))
Soren Brinkmannc4b05102013-10-17 14:08:11 -07001599 dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001600#endif
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001601
Michal Simek1f210722018-04-23 11:51:02 +02001602 /* At this point, we've got an empty uart_port struct, initialize it */
1603 spin_lock_init(&port->lock);
Michal Simek1f210722018-04-23 11:51:02 +02001604 port->type = PORT_UNKNOWN;
1605 port->iotype = UPIO_MEM32;
1606 port->flags = UPF_BOOT_AUTOCONF;
1607 port->ops = &cdns_uart_ops;
1608 port->fifosize = CDNS_UART_FIFO_SIZE;
Michal Simek1f210722018-04-23 11:51:02 +02001609
Soren Brinkmann354fb1a2016-01-11 17:41:38 -08001610 /*
1611 * Register the port.
1612 * This function also registers this device with the tty layer
1613 * and triggers invocation of the config_port() entry point.
1614 */
1615 port->mapbase = res->start;
1616 port->irq = irq;
1617 port->dev = &pdev->dev;
1618 port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
1619 port->private_data = cdns_uart_data;
1620 cdns_uart_data->port = port;
1621 platform_set_drvdata(pdev, port);
1622
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301623 pm_runtime_use_autosuspend(&pdev->dev);
1624 pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301625 pm_runtime_set_active(&pdev->dev);
Shubhrajyoti Dattaecfc5772017-04-06 12:27:41 +05301626 pm_runtime_enable(&pdev->dev);
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301627
Michal Simek0413fe02018-04-23 11:51:01 +02001628#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
1629 /*
1630 * If console hasn't been found yet try to assign this port
1631 * because it is required to be assigned for console setup function.
1632 * If register_console() don't assign value, then console_port pointer
1633 * is cleanup.
1634 */
Michal Simek427c8ae2018-09-03 15:10:56 +02001635 if (!console_port)
Michal Simek0413fe02018-04-23 11:51:01 +02001636 console_port = port;
1637#endif
1638
Michal Simek024ca322018-09-03 15:10:57 +02001639 rc = uart_add_one_port(cdns_uart_uart_driver, port);
Soren Brinkmann354fb1a2016-01-11 17:41:38 -08001640 if (rc) {
1641 dev_err(&pdev->dev,
1642 "uart_add_one_port() failed; err=%i\n", rc);
Shubhrajyoti Dattad653c432017-05-09 11:50:32 +05301643 goto err_out_pm_disable;
Soren Brinkmann354fb1a2016-01-11 17:41:38 -08001644 }
1645
Michal Simek0413fe02018-04-23 11:51:01 +02001646#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
1647 /* This is not port which is used for console that's why clean it up */
Michal Simek427c8ae2018-09-03 15:10:56 +02001648 if (console_port == port &&
Michal Simek024ca322018-09-03 15:10:57 +02001649 !(cdns_uart_uart_driver->cons->flags & CON_ENABLED))
Michal Simek0413fe02018-04-23 11:51:01 +02001650 console_port = NULL;
1651#endif
1652
Soren Brinkmann354fb1a2016-01-11 17:41:38 -08001653 return 0;
1654
Shubhrajyoti Dattad653c432017-05-09 11:50:32 +05301655err_out_pm_disable:
1656 pm_runtime_disable(&pdev->dev);
1657 pm_runtime_set_suspended(&pdev->dev);
1658 pm_runtime_dont_use_autosuspend(&pdev->dev);
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001659#ifdef CONFIG_COMMON_CLK
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001660 clk_notifier_unregister(cdns_uart_data->uartclk,
1661 &cdns_uart_data->clk_rate_change_nb);
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001662#endif
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001663err_out_clk_disable:
Shubhrajyoti Dattaecfc5772017-04-06 12:27:41 +05301664 clk_disable_unprepare(cdns_uart_data->uartclk);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001665err_out_clk_dis_pclk:
Shubhrajyoti Dattaecfc5772017-04-06 12:27:41 +05301666 clk_disable_unprepare(cdns_uart_data->pclk);
Michal Simeke4bbb512018-09-03 15:10:54 +02001667err_out_unregister_driver:
Michal Simek024ca322018-09-03 15:10:57 +02001668 uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
Michal Simekae1cca32018-09-20 13:41:53 +02001669err_out_id:
1670 mutex_lock(&bitmap_lock);
Michal Simek2088cfd2018-10-08 14:17:19 +02001671 if (cdns_uart_data->id < MAX_UART_INSTANCES)
1672 clear_bit(cdns_uart_data->id, bitmap);
Michal Simekae1cca32018-09-20 13:41:53 +02001673 mutex_unlock(&bitmap_lock);
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001674 return rc;
John Linn61ec9012011-04-30 00:07:43 -04001675}
1676
1677/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001678 * cdns_uart_remove - called when the platform driver is unregistered
John Linn61ec9012011-04-30 00:07:43 -04001679 * @pdev: Pointer to the platform device structure
1680 *
Soren Brinkmanne555a212014-04-04 17:23:39 -07001681 * Return: 0 on success, negative errno otherwise
Michal Simek489810a12014-04-04 17:23:37 -07001682 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001683static int cdns_uart_remove(struct platform_device *pdev)
John Linn61ec9012011-04-30 00:07:43 -04001684{
Jingoo Han696faed2013-05-23 19:39:36 +09001685 struct uart_port *port = platform_get_drvdata(pdev);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001686 struct cdns_uart *cdns_uart_data = port->private_data;
Josh Cartwright2326669c2013-01-21 19:57:41 +01001687 int rc;
John Linn61ec9012011-04-30 00:07:43 -04001688
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001689 /* Remove the cdns_uart port from the serial core */
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001690#ifdef CONFIG_COMMON_CLK
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001691 clk_notifier_unregister(cdns_uart_data->uartclk,
1692 &cdns_uart_data->clk_rate_change_nb);
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001693#endif
Michal Simek46a460f2018-09-03 15:10:52 +02001694 rc = uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port);
Josh Cartwright2326669c2013-01-21 19:57:41 +01001695 port->mapbase = 0;
Michal Simekae1cca32018-09-20 13:41:53 +02001696 mutex_lock(&bitmap_lock);
Michal Simek2088cfd2018-10-08 14:17:19 +02001697 if (cdns_uart_data->id < MAX_UART_INSTANCES)
1698 clear_bit(cdns_uart_data->id, bitmap);
Michal Simekae1cca32018-09-20 13:41:53 +02001699 mutex_unlock(&bitmap_lock);
Shubhrajyoti Dattaecfc5772017-04-06 12:27:41 +05301700 clk_disable_unprepare(cdns_uart_data->uartclk);
1701 clk_disable_unprepare(cdns_uart_data->pclk);
Shubhrajyoti Dattad62100f2017-03-09 11:19:07 +05301702 pm_runtime_disable(&pdev->dev);
1703 pm_runtime_set_suspended(&pdev->dev);
1704 pm_runtime_dont_use_autosuspend(&pdev->dev);
Michal Simek427c8ae2018-09-03 15:10:56 +02001705
1706#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
1707 if (console_port == port)
1708 console_port = NULL;
1709#endif
1710
Michal Simek024ca322018-09-03 15:10:57 +02001711 uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
John Linn61ec9012011-04-30 00:07:43 -04001712 return rc;
1713}
1714
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001715static struct platform_driver cdns_uart_platform_driver = {
1716 .probe = cdns_uart_probe,
1717 .remove = cdns_uart_remove,
John Linn61ec9012011-04-30 00:07:43 -04001718 .driver = {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001719 .name = CDNS_UART_NAME,
1720 .of_match_table = cdns_uart_of_match,
1721 .pm = &cdns_uart_dev_pm_ops,
John Linn61ec9012011-04-30 00:07:43 -04001722 },
1723};
1724
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001725static int __init cdns_uart_init(void)
John Linn61ec9012011-04-30 00:07:43 -04001726{
John Linn61ec9012011-04-30 00:07:43 -04001727 /* Register the platform driver */
Michal Simeke4bbb512018-09-03 15:10:54 +02001728 return platform_driver_register(&cdns_uart_platform_driver);
John Linn61ec9012011-04-30 00:07:43 -04001729}
1730
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001731static void __exit cdns_uart_exit(void)
John Linn61ec9012011-04-30 00:07:43 -04001732{
John Linn61ec9012011-04-30 00:07:43 -04001733 /* Unregister the platform driver */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001734 platform_driver_unregister(&cdns_uart_platform_driver);
John Linn61ec9012011-04-30 00:07:43 -04001735}
1736
Shubhrajyoti Datta1d672432017-09-20 12:20:11 +05301737arch_initcall(cdns_uart_init);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001738module_exit(cdns_uart_exit);
John Linn61ec9012011-04-30 00:07:43 -04001739
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001740MODULE_DESCRIPTION("Driver for Cadence UART");
John Linn61ec9012011-04-30 00:07:43 -04001741MODULE_AUTHOR("Xilinx Inc.");
1742MODULE_LICENSE("GPL");