blob: 8014dd3c6d55360b0c2b6c20da6cbe4f9944f4df [file] [log] [blame]
John Linn61ec9012011-04-30 00:07:43 -04001/*
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07002 * Cadence UART driver (found in Xilinx Zynq)
John Linn61ec9012011-04-30 00:07:43 -04003 *
Soren Brinkmanne555a212014-04-04 17:23:39 -07004 * 2011 - 2014 (C) Xilinx Inc.
John Linn61ec9012011-04-30 00:07:43 -04005 *
6 * This program is free software; you can redistribute it
7 * and/or modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation;
9 * either version 2 of the License, or (at your option) any
10 * later version.
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070011 *
12 * This driver has originally been pushed by Xilinx using a Zynq-branding. This
13 * still shows in the naming of this file, the kconfig symbols and some symbols
14 * in the code.
John Linn61ec9012011-04-30 00:07:43 -040015 */
16
Vlad Lungu0c0c47b2013-10-17 14:08:06 -070017#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
18#define SUPPORT_SYSRQ
19#endif
20
John Linn61ec9012011-04-30 00:07:43 -040021#include <linux/platform_device.h>
John Linn61ec9012011-04-30 00:07:43 -040022#include <linux/serial.h>
Vlad Lungu0c0c47b2013-10-17 14:08:06 -070023#include <linux/console.h>
Jiri Slabyee160a32011-09-01 16:20:57 +020024#include <linux/serial_core.h>
Soren Brinkmann30e1e282013-05-13 10:46:38 -070025#include <linux/slab.h>
Jiri Slabyee160a32011-09-01 16:20:57 +020026#include <linux/tty.h>
27#include <linux/tty_flip.h>
Josh Cartwright2326669c2013-01-21 19:57:41 +010028#include <linux/clk.h>
John Linn61ec9012011-04-30 00:07:43 -040029#include <linux/irq.h>
30#include <linux/io.h>
31#include <linux/of.h>
Paul Gortmaker578b9ce2011-05-27 16:14:23 -040032#include <linux/module.h>
John Linn61ec9012011-04-30 00:07:43 -040033
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070034#define CDNS_UART_TTY_NAME "ttyPS"
35#define CDNS_UART_NAME "xuartps"
36#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */
37#define CDNS_UART_MINOR 0 /* works best with devtmpfs */
38#define CDNS_UART_NR_PORTS 2
39#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */
Thomas Betker9646e4f2015-03-11 22:39:25 +010040#define CDNS_UART_REGISTER_SPACE 0x1000
John Linn61ec9012011-04-30 00:07:43 -040041
Suneel85baf542013-10-17 14:08:08 -070042/* Rx Trigger level */
43static int rx_trigger_level = 56;
44module_param(rx_trigger_level, uint, S_IRUGO);
45MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes");
46
47/* Rx Timeout */
48static int rx_timeout = 10;
49module_param(rx_timeout, uint, S_IRUGO);
50MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
51
Soren Brinkmanne555a212014-04-04 17:23:39 -070052/* Register offsets for the UART. */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070053#define CDNS_UART_CR_OFFSET 0x00 /* Control Register */
54#define CDNS_UART_MR_OFFSET 0x04 /* Mode Register */
55#define CDNS_UART_IER_OFFSET 0x08 /* Interrupt Enable */
56#define CDNS_UART_IDR_OFFSET 0x0C /* Interrupt Disable */
57#define CDNS_UART_IMR_OFFSET 0x10 /* Interrupt Mask */
58#define CDNS_UART_ISR_OFFSET 0x14 /* Interrupt Status */
59#define CDNS_UART_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator */
60#define CDNS_UART_RXTOUT_OFFSET 0x1C /* RX Timeout */
61#define CDNS_UART_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level */
62#define CDNS_UART_MODEMCR_OFFSET 0x24 /* Modem Control */
63#define CDNS_UART_MODEMSR_OFFSET 0x28 /* Modem Status */
64#define CDNS_UART_SR_OFFSET 0x2C /* Channel Status */
65#define CDNS_UART_FIFO_OFFSET 0x30 /* FIFO */
66#define CDNS_UART_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider */
67#define CDNS_UART_FLOWDEL_OFFSET 0x38 /* Flow Delay */
68#define CDNS_UART_IRRX_PWIDTH_OFFSET 0x3C /* IR Min Received Pulse Width */
69#define CDNS_UART_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse Width */
70#define CDNS_UART_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level */
John Linn61ec9012011-04-30 00:07:43 -040071
Soren Brinkmanne555a212014-04-04 17:23:39 -070072/* Control Register Bit Definitions */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070073#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
74#define CDNS_UART_CR_STARTBRK 0x00000080 /* Set TX break */
75#define CDNS_UART_CR_TX_DIS 0x00000020 /* TX disabled. */
76#define CDNS_UART_CR_TX_EN 0x00000010 /* TX enabled */
77#define CDNS_UART_CR_RX_DIS 0x00000008 /* RX disabled. */
78#define CDNS_UART_CR_RX_EN 0x00000004 /* RX enabled */
79#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */
80#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */
81#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
John Linn61ec9012011-04-30 00:07:43 -040082
Soren Brinkmanne555a212014-04-04 17:23:39 -070083/*
84 * Mode Register:
John Linn61ec9012011-04-30 00:07:43 -040085 * The mode register (MR) defines the mode of transfer as well as the data
86 * format. If this register is modified during transmission or reception,
87 * data validity cannot be guaranteed.
John Linn61ec9012011-04-30 00:07:43 -040088 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070089#define CDNS_UART_MR_CLKSEL 0x00000001 /* Pre-scalar selection */
90#define CDNS_UART_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */
91#define CDNS_UART_MR_CHMODE_NORM 0x00000000 /* Normal mode */
John Linn61ec9012011-04-30 00:07:43 -040092
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070093#define CDNS_UART_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */
94#define CDNS_UART_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */
John Linn61ec9012011-04-30 00:07:43 -040095
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -070096#define CDNS_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */
97#define CDNS_UART_MR_PARITY_MARK 0x00000018 /* Mark parity mode */
98#define CDNS_UART_MR_PARITY_SPACE 0x00000010 /* Space parity mode */
99#define CDNS_UART_MR_PARITY_ODD 0x00000008 /* Odd parity mode */
100#define CDNS_UART_MR_PARITY_EVEN 0x00000000 /* Even parity mode */
John Linn61ec9012011-04-30 00:07:43 -0400101
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700102#define CDNS_UART_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */
103#define CDNS_UART_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */
104#define CDNS_UART_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */
John Linn61ec9012011-04-30 00:07:43 -0400105
Soren Brinkmanne555a212014-04-04 17:23:39 -0700106/*
107 * Interrupt Registers:
John Linn61ec9012011-04-30 00:07:43 -0400108 * Interrupt control logic uses the interrupt enable register (IER) and the
109 * interrupt disable register (IDR) to set the value of the bits in the
110 * interrupt mask register (IMR). The IMR determines whether to pass an
111 * interrupt to the interrupt status register (ISR).
112 * Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an
113 * interrupt. IMR and ISR are read only, and IER and IDR are write only.
114 * Reading either IER or IDR returns 0x00.
John Linn61ec9012011-04-30 00:07:43 -0400115 * All four registers have the same bit definitions.
116 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700117#define CDNS_UART_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */
118#define CDNS_UART_IXR_PARITY 0x00000080 /* Parity error interrupt */
119#define CDNS_UART_IXR_FRAMING 0x00000040 /* Framing error interrupt */
120#define CDNS_UART_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */
121#define CDNS_UART_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */
122#define CDNS_UART_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */
123#define CDNS_UART_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */
124#define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
125#define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */
126#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
127#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
John Linn61ec9012011-04-30 00:07:43 -0400128
Soren Brinkmann373e8822016-01-11 17:41:37 -0800129#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | \
130 CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | \
131 CDNS_UART_IXR_TOUT)
132
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700133/* Goes in read_status_mask for break detection as the HW doesn't do it*/
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700134#define CDNS_UART_IXR_BRK 0x80000000
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700135
Soren Brinkmanne555a212014-04-04 17:23:39 -0700136/*
Lars-Peter Clausen19038ad2014-11-05 13:35:16 +0100137 * Modem Control register:
138 * The read/write Modem Control register controls the interface with the modem
139 * or data set, or a peripheral device emulating a modem.
140 */
141#define CDNS_UART_MODEMCR_FCM 0x00000020 /* Automatic flow control mode */
142#define CDNS_UART_MODEMCR_RTS 0x00000002 /* Request to send output control */
143#define CDNS_UART_MODEMCR_DTR 0x00000001 /* Data Terminal Ready */
144
145/*
Soren Brinkmanne555a212014-04-04 17:23:39 -0700146 * Channel Status Register:
John Linn61ec9012011-04-30 00:07:43 -0400147 * The channel status register (CSR) is provided to enable the control logic
148 * to monitor the status of bits in the channel interrupt status register,
149 * even if these are masked out by the interrupt mask register.
150 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700151#define CDNS_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
152#define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
153#define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */
154#define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */
John Linn61ec9012011-04-30 00:07:43 -0400155
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700156/* baud dividers min/max values */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700157#define CDNS_UART_BDIV_MIN 4
158#define CDNS_UART_BDIV_MAX 255
159#define CDNS_UART_CD_MAX 65535
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700160
John Linn61ec9012011-04-30 00:07:43 -0400161/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700162 * struct cdns_uart - device data
Michal Simek489810a12014-04-04 17:23:37 -0700163 * @port: Pointer to the UART port
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700164 * @uartclk: Reference clock
165 * @pclk: APB clock
Michal Simek489810a12014-04-04 17:23:37 -0700166 * @baud: Current baud rate
167 * @clk_rate_change_nb: Notifier block for clock changes
Soren Brinkmann30e1e282013-05-13 10:46:38 -0700168 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700169struct cdns_uart {
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700170 struct uart_port *port;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700171 struct clk *uartclk;
172 struct clk *pclk;
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700173 unsigned int baud;
174 struct notifier_block clk_rate_change_nb;
Soren Brinkmann30e1e282013-05-13 10:46:38 -0700175};
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700176#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
177 clk_rate_change_nb);
Soren Brinkmann30e1e282013-05-13 10:46:38 -0700178
Soren Brinkmann5ede4a52015-12-26 02:43:56 -0800179static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
John Linn61ec9012011-04-30 00:07:43 -0400180{
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700181 /*
182 * There is no hardware break detection, so we interpret framing
183 * error with all-zeros data as a break sequence. Most of the time,
184 * there's another non-zero byte at the end of the sequence.
185 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700186 if (isrstatus & CDNS_UART_IXR_FRAMING) {
Thomas Betker19f22ef2015-03-12 22:11:59 +0100187 while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700188 CDNS_UART_SR_RXEMPTY)) {
Thomas Betker19f22ef2015-03-12 22:11:59 +0100189 if (!readl(port->membase + CDNS_UART_FIFO_OFFSET)) {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700190 port->read_status_mask |= CDNS_UART_IXR_BRK;
191 isrstatus &= ~CDNS_UART_IXR_FRAMING;
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700192 }
193 }
Thomas Betker19f22ef2015-03-12 22:11:59 +0100194 writel(CDNS_UART_IXR_FRAMING,
195 port->membase + CDNS_UART_ISR_OFFSET);
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700196 }
197
John Linn61ec9012011-04-30 00:07:43 -0400198 /* drop byte with parity error if IGNPAR specified */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700199 if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY)
200 isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT);
John Linn61ec9012011-04-30 00:07:43 -0400201
202 isrstatus &= port->read_status_mask;
203 isrstatus &= ~port->ignore_status_mask;
204
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800205 if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG)))
206 return;
Soren Brinkmann5ede4a52015-12-26 02:43:56 -0800207
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800208 while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
209 CDNS_UART_SR_RXEMPTY)) {
210 u32 data;
211 char status = TTY_NORMAL;
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700212
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800213 data = readl(port->membase + CDNS_UART_FIFO_OFFSET);
214
215 /* Non-NULL byte after BREAK is garbage (99%) */
216 if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) {
217 port->read_status_mask &= ~CDNS_UART_IXR_BRK;
218 port->icount.brk++;
219 if (uart_handle_break(port))
220 continue;
221 }
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700222
Soren Brinkmannc2db11e2013-12-02 11:38:38 -0800223#ifdef SUPPORT_SYSRQ
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800224 /*
225 * uart_handle_sysrq_char() doesn't work if
226 * spinlocked, for some reason
227 */
228 if (port->sysrq) {
229 spin_unlock(&port->lock);
230 if (uart_handle_sysrq_char(port, data)) {
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700231 spin_lock(&port->lock);
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800232 continue;
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700233 }
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800234 spin_lock(&port->lock);
235 }
Soren Brinkmannc2db11e2013-12-02 11:38:38 -0800236#endif
Vlad Lungu0c0c47b2013-10-17 14:08:06 -0700237
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800238 port->icount.rx++;
John Linn61ec9012011-04-30 00:07:43 -0400239
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800240 if (isrstatus & CDNS_UART_IXR_PARITY) {
241 port->icount.parity++;
242 status = TTY_PARITY;
243 } else if (isrstatus & CDNS_UART_IXR_FRAMING) {
244 port->icount.frame++;
245 status = TTY_FRAME;
246 } else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
247 port->icount.overrun++;
John Linn61ec9012011-04-30 00:07:43 -0400248 }
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800249
250 uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
251 data, status);
John Linn61ec9012011-04-30 00:07:43 -0400252 }
Soren Brinkmann354fb1a2016-01-11 17:41:38 -0800253 tty_flip_buffer_push(&port->state->port);
Soren Brinkmann5ede4a52015-12-26 02:43:56 -0800254}
255
256/**
257 * cdns_uart_isr - Interrupt handler
258 * @irq: Irq number
259 * @dev_id: Id of the port
260 *
261 * Return: IRQHANDLED
262 */
263static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
264{
265 struct uart_port *port = (struct uart_port *)dev_id;
266 unsigned long flags;
267 unsigned int isrstatus, numbytes;
268
269 spin_lock_irqsave(&port->lock, flags);
270
271 /* Read the interrupt status register to determine which
272 * interrupt(s) is/are active.
273 */
274 isrstatus = readl(port->membase + CDNS_UART_ISR_OFFSET);
275
Soren Brinkmann373e8822016-01-11 17:41:37 -0800276 if (isrstatus & CDNS_UART_RX_IRQS)
277 cdns_uart_handle_rx(port, isrstatus);
John Linn61ec9012011-04-30 00:07:43 -0400278
279 /* Dispatch an appropriate handler */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700280 if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) {
John Linn61ec9012011-04-30 00:07:43 -0400281 if (uart_circ_empty(&port->state->xmit)) {
Thomas Betker19f22ef2015-03-12 22:11:59 +0100282 writel(CDNS_UART_IXR_TXEMPTY,
283 port->membase + CDNS_UART_IDR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400284 } else {
285 numbytes = port->fifosize;
286 /* Break if no more data available in the UART buffer */
287 while (numbytes--) {
288 if (uart_circ_empty(&port->state->xmit))
289 break;
290 /* Get the data from the UART circular buffer
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700291 * and write it to the cdns_uart's TX_FIFO
John Linn61ec9012011-04-30 00:07:43 -0400292 * register.
293 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100294 writel(port->state->xmit.buf[
295 port->state->xmit.tail],
296 port->membase + CDNS_UART_FIFO_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400297
298 port->icount.tx++;
299
300 /* Adjust the tail of the UART buffer and wrap
301 * the buffer if it reaches limit.
302 */
303 port->state->xmit.tail =
Soren Brinkmanne555a212014-04-04 17:23:39 -0700304 (port->state->xmit.tail + 1) &
John Linn61ec9012011-04-30 00:07:43 -0400305 (UART_XMIT_SIZE - 1);
306 }
307
308 if (uart_circ_chars_pending(
309 &port->state->xmit) < WAKEUP_CHARS)
310 uart_write_wakeup(port);
311 }
312 }
313
Thomas Betker19f22ef2015-03-12 22:11:59 +0100314 writel(isrstatus, port->membase + CDNS_UART_ISR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400315
316 /* be sure to release the lock and tty before leaving */
317 spin_unlock_irqrestore(&port->lock, flags);
John Linn61ec9012011-04-30 00:07:43 -0400318
319 return IRQ_HANDLED;
320}
321
322/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700323 * cdns_uart_calc_baud_divs - Calculate baud rate divisors
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700324 * @clk: UART module input clock
325 * @baud: Desired baud rate
326 * @rbdiv: BDIV value (return value)
327 * @rcd: CD value (return value)
328 * @div8: Value for clk_sel bit in mod (return value)
Michal Simek489810a12014-04-04 17:23:37 -0700329 * Return: baud rate, requested baud when possible, or actual baud when there
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700330 * was too much error, zero if no valid divisors are found.
331 *
332 * Formula to obtain baud rate is
333 * baud_tx/rx rate = clk/CD * (BDIV + 1)
334 * input_clk = (Uart User Defined Clock or Apb Clock)
335 * depends on UCLKEN in MR Reg
336 * clk = input_clk or input_clk/8;
337 * depends on CLKS in MR reg
338 * CD and BDIV depends on values in
339 * baud rate generate register
340 * baud rate clock divisor register
341 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700342static unsigned int cdns_uart_calc_baud_divs(unsigned int clk,
343 unsigned int baud, u32 *rbdiv, u32 *rcd, int *div8)
John Linn61ec9012011-04-30 00:07:43 -0400344{
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700345 u32 cd, bdiv;
346 unsigned int calc_baud;
347 unsigned int bestbaud = 0;
John Linn61ec9012011-04-30 00:07:43 -0400348 unsigned int bauderror;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700349 unsigned int besterror = ~0;
John Linn61ec9012011-04-30 00:07:43 -0400350
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700351 if (baud < clk / ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX)) {
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700352 *div8 = 1;
353 clk /= 8;
354 } else {
355 *div8 = 0;
356 }
John Linn61ec9012011-04-30 00:07:43 -0400357
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700358 for (bdiv = CDNS_UART_BDIV_MIN; bdiv <= CDNS_UART_BDIV_MAX; bdiv++) {
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700359 cd = DIV_ROUND_CLOSEST(clk, baud * (bdiv + 1));
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700360 if (cd < 1 || cd > CDNS_UART_CD_MAX)
John Linn61ec9012011-04-30 00:07:43 -0400361 continue;
362
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700363 calc_baud = clk / (cd * (bdiv + 1));
John Linn61ec9012011-04-30 00:07:43 -0400364
365 if (baud > calc_baud)
366 bauderror = baud - calc_baud;
367 else
368 bauderror = calc_baud - baud;
369
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700370 if (besterror > bauderror) {
371 *rbdiv = bdiv;
372 *rcd = cd;
373 bestbaud = calc_baud;
374 besterror = bauderror;
John Linn61ec9012011-04-30 00:07:43 -0400375 }
376 }
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700377 /* use the values when percent error is acceptable */
378 if (((besterror * 100) / baud) < 3)
379 bestbaud = baud;
John Linn61ec9012011-04-30 00:07:43 -0400380
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700381 return bestbaud;
382}
383
384/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700385 * cdns_uart_set_baud_rate - Calculate and set the baud rate
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700386 * @port: Handle to the uart port structure
387 * @baud: Baud rate to set
Michal Simek489810a12014-04-04 17:23:37 -0700388 * Return: baud rate, requested baud when possible, or actual baud when there
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700389 * was too much error, zero if no valid divisors are found.
390 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700391static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700392 unsigned int baud)
393{
394 unsigned int calc_baud;
Soren Brinkmannd54b1812013-10-21 16:40:59 -0700395 u32 cd = 0, bdiv = 0;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700396 u32 mreg;
397 int div8;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700398 struct cdns_uart *cdns_uart = port->private_data;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700399
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700400 calc_baud = cdns_uart_calc_baud_divs(port->uartclk, baud, &bdiv, &cd,
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700401 &div8);
402
403 /* Write new divisors to hardware */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100404 mreg = readl(port->membase + CDNS_UART_MR_OFFSET);
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700405 if (div8)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700406 mreg |= CDNS_UART_MR_CLKSEL;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700407 else
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700408 mreg &= ~CDNS_UART_MR_CLKSEL;
Thomas Betker19f22ef2015-03-12 22:11:59 +0100409 writel(mreg, port->membase + CDNS_UART_MR_OFFSET);
410 writel(cd, port->membase + CDNS_UART_BAUDGEN_OFFSET);
411 writel(bdiv, port->membase + CDNS_UART_BAUDDIV_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700412 cdns_uart->baud = baud;
John Linn61ec9012011-04-30 00:07:43 -0400413
414 return calc_baud;
415}
416
Soren Brinkmann7ac57342013-10-21 16:41:01 -0700417#ifdef CONFIG_COMMON_CLK
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700418/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700419 * cdns_uart_clk_notitifer_cb - Clock notifier callback
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700420 * @nb: Notifier block
421 * @event: Notify event
422 * @data: Notifier data
Soren Brinkmanne555a212014-04-04 17:23:39 -0700423 * Return: NOTIFY_OK or NOTIFY_DONE on success, NOTIFY_BAD on error.
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700424 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700425static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700426 unsigned long event, void *data)
427{
428 u32 ctrl_reg;
429 struct uart_port *port;
430 int locked = 0;
431 struct clk_notifier_data *ndata = data;
432 unsigned long flags = 0;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700433 struct cdns_uart *cdns_uart = to_cdns_uart(nb);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700434
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700435 port = cdns_uart->port;
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700436 if (port->suspended)
437 return NOTIFY_OK;
438
439 switch (event) {
440 case PRE_RATE_CHANGE:
441 {
Soren Brinkmanne555a212014-04-04 17:23:39 -0700442 u32 bdiv, cd;
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700443 int div8;
444
445 /*
446 * Find out if current baud-rate can be achieved with new clock
447 * frequency.
448 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700449 if (!cdns_uart_calc_baud_divs(ndata->new_rate, cdns_uart->baud,
Soren Brinkmann5ce15d22014-04-04 17:23:40 -0700450 &bdiv, &cd, &div8)) {
451 dev_warn(port->dev, "clock rate change rejected\n");
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700452 return NOTIFY_BAD;
Soren Brinkmann5ce15d22014-04-04 17:23:40 -0700453 }
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700454
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700455 spin_lock_irqsave(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700456
457 /* Disable the TX and RX to set baud rate */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100458 ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700459 ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
Thomas Betker19f22ef2015-03-12 22:11:59 +0100460 writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700461
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700462 spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700463
464 return NOTIFY_OK;
465 }
466 case POST_RATE_CHANGE:
467 /*
468 * Set clk dividers to generate correct baud with new clock
469 * frequency.
470 */
471
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700472 spin_lock_irqsave(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700473
474 locked = 1;
475 port->uartclk = ndata->new_rate;
476
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700477 cdns_uart->baud = cdns_uart_set_baud_rate(cdns_uart->port,
478 cdns_uart->baud);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700479 /* fall through */
480 case ABORT_RATE_CHANGE:
481 if (!locked)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700482 spin_lock_irqsave(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700483
484 /* Set TX/RX Reset */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100485 ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700486 ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
Thomas Betker19f22ef2015-03-12 22:11:59 +0100487 writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700488
Thomas Betker19f22ef2015-03-12 22:11:59 +0100489 while (readl(port->membase + CDNS_UART_CR_OFFSET) &
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700490 (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700491 cpu_relax();
492
493 /*
494 * Clear the RX disable and TX disable bits and then set the TX
495 * enable bit and RX enable bit to enable the transmitter and
496 * receiver.
497 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100498 writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
499 ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700500 ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
501 ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
Thomas Betker19f22ef2015-03-12 22:11:59 +0100502 writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700503
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700504 spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700505
506 return NOTIFY_OK;
507 default:
508 return NOTIFY_DONE;
509 }
510}
Soren Brinkmann7ac57342013-10-21 16:41:01 -0700511#endif
Soren Brinkmannc4b05102013-10-17 14:08:11 -0700512
John Linn61ec9012011-04-30 00:07:43 -0400513/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700514 * cdns_uart_start_tx - Start transmitting bytes
John Linn61ec9012011-04-30 00:07:43 -0400515 * @port: Handle to the uart port structure
Michal Simek489810a12014-04-04 17:23:37 -0700516 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700517static void cdns_uart_start_tx(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400518{
519 unsigned int status, numbytes = port->fifosize;
520
Soren Brinkmannea8dd8e2015-12-26 02:43:51 -0800521 if (uart_tx_stopped(port))
John Linn61ec9012011-04-30 00:07:43 -0400522 return;
523
Soren Brinkmanne3538c32015-12-26 02:43:49 -0800524 /*
525 * Set the TX enable bit and clear the TX disable bit to enable the
John Linn61ec9012011-04-30 00:07:43 -0400526 * transmitter.
527 */
Soren Brinkmanne3538c32015-12-26 02:43:49 -0800528 status = readl(port->membase + CDNS_UART_CR_OFFSET);
529 status &= ~CDNS_UART_CR_TX_DIS;
530 status |= CDNS_UART_CR_TX_EN;
531 writel(status, port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400532
Soren Brinkmannea8dd8e2015-12-26 02:43:51 -0800533 if (uart_circ_empty(&port->state->xmit))
534 return;
535
Thomas Betker19f22ef2015-03-12 22:11:59 +0100536 while (numbytes-- && ((readl(port->membase + CDNS_UART_SR_OFFSET) &
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700537 CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) {
John Linn61ec9012011-04-30 00:07:43 -0400538 /* Break if no more data available in the UART buffer */
539 if (uart_circ_empty(&port->state->xmit))
540 break;
541
542 /* Get the data from the UART circular buffer and
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700543 * write it to the cdns_uart's TX_FIFO register.
John Linn61ec9012011-04-30 00:07:43 -0400544 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100545 writel(port->state->xmit.buf[port->state->xmit.tail],
546 port->membase + CDNS_UART_FIFO_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400547 port->icount.tx++;
548
549 /* Adjust the tail of the UART buffer and wrap
550 * the buffer if it reaches limit.
551 */
552 port->state->xmit.tail = (port->state->xmit.tail + 1) &
553 (UART_XMIT_SIZE - 1);
554 }
Thomas Betker19f22ef2015-03-12 22:11:59 +0100555 writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400556 /* Enable the TX Empty interrupt */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100557 writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400558
559 if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)
560 uart_write_wakeup(port);
561}
562
563/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700564 * cdns_uart_stop_tx - Stop TX
John Linn61ec9012011-04-30 00:07:43 -0400565 * @port: Handle to the uart port structure
Michal Simek489810a12014-04-04 17:23:37 -0700566 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700567static void cdns_uart_stop_tx(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400568{
569 unsigned int regval;
570
Thomas Betker19f22ef2015-03-12 22:11:59 +0100571 regval = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700572 regval |= CDNS_UART_CR_TX_DIS;
John Linn61ec9012011-04-30 00:07:43 -0400573 /* Disable the transmitter */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100574 writel(regval, port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400575}
576
577/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700578 * cdns_uart_stop_rx - Stop RX
John Linn61ec9012011-04-30 00:07:43 -0400579 * @port: Handle to the uart port structure
Michal Simek489810a12014-04-04 17:23:37 -0700580 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700581static void cdns_uart_stop_rx(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400582{
583 unsigned int regval;
584
Soren Brinkmann373e8822016-01-11 17:41:37 -0800585 /* Disable RX IRQs */
586 writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IDR_OFFSET);
587
588 /* Disable the receiver */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100589 regval = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700590 regval |= CDNS_UART_CR_RX_DIS;
Thomas Betker19f22ef2015-03-12 22:11:59 +0100591 writel(regval, port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400592}
593
594/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700595 * cdns_uart_tx_empty - Check whether TX is empty
John Linn61ec9012011-04-30 00:07:43 -0400596 * @port: Handle to the uart port structure
597 *
Michal Simek489810a12014-04-04 17:23:37 -0700598 * Return: TIOCSER_TEMT on success, 0 otherwise
599 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700600static unsigned int cdns_uart_tx_empty(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400601{
602 unsigned int status;
603
Thomas Betker19f22ef2015-03-12 22:11:59 +0100604 status = readl(port->membase + CDNS_UART_SR_OFFSET) &
605 CDNS_UART_SR_TXEMPTY;
John Linn61ec9012011-04-30 00:07:43 -0400606 return status ? TIOCSER_TEMT : 0;
607}
608
609/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700610 * cdns_uart_break_ctl - Based on the input ctl we have to start or stop
John Linn61ec9012011-04-30 00:07:43 -0400611 * transmitting char breaks
612 * @port: Handle to the uart port structure
613 * @ctl: Value based on which start or stop decision is taken
Michal Simek489810a12014-04-04 17:23:37 -0700614 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700615static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
John Linn61ec9012011-04-30 00:07:43 -0400616{
617 unsigned int status;
618 unsigned long flags;
619
620 spin_lock_irqsave(&port->lock, flags);
621
Thomas Betker19f22ef2015-03-12 22:11:59 +0100622 status = readl(port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400623
624 if (ctl == -1)
Thomas Betker19f22ef2015-03-12 22:11:59 +0100625 writel(CDNS_UART_CR_STARTBRK | status,
626 port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400627 else {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700628 if ((status & CDNS_UART_CR_STOPBRK) == 0)
Thomas Betker19f22ef2015-03-12 22:11:59 +0100629 writel(CDNS_UART_CR_STOPBRK | status,
630 port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400631 }
632 spin_unlock_irqrestore(&port->lock, flags);
633}
634
635/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700636 * cdns_uart_set_termios - termios operations, handling data length, parity,
John Linn61ec9012011-04-30 00:07:43 -0400637 * stop bits, flow control, baud rate
638 * @port: Handle to the uart port structure
639 * @termios: Handle to the input termios structure
640 * @old: Values of the previously saved termios structure
Michal Simek489810a12014-04-04 17:23:37 -0700641 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700642static void cdns_uart_set_termios(struct uart_port *port,
John Linn61ec9012011-04-30 00:07:43 -0400643 struct ktermios *termios, struct ktermios *old)
644{
645 unsigned int cval = 0;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700646 unsigned int baud, minbaud, maxbaud;
John Linn61ec9012011-04-30 00:07:43 -0400647 unsigned long flags;
648 unsigned int ctrl_reg, mode_reg;
649
650 spin_lock_irqsave(&port->lock, flags);
651
Nathan Rossi6ecde472015-01-16 13:49:25 +0100652 /* Wait for the transmit FIFO to empty before making changes */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100653 if (!(readl(port->membase + CDNS_UART_CR_OFFSET) &
654 CDNS_UART_CR_TX_DIS)) {
655 while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
Nathan Rossi6ecde472015-01-16 13:49:25 +0100656 CDNS_UART_SR_TXEMPTY)) {
657 cpu_relax();
658 }
John Linn61ec9012011-04-30 00:07:43 -0400659 }
660
661 /* Disable the TX and RX to set baud rate */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100662 ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700663 ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
Thomas Betker19f22ef2015-03-12 22:11:59 +0100664 writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400665
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700666 /*
667 * Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk
668 * min and max baud should be calculated here based on port->uartclk.
669 * this way we get a valid baud and can safely call set_baud()
670 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700671 minbaud = port->uartclk /
672 ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX * 8);
673 maxbaud = port->uartclk / (CDNS_UART_BDIV_MIN + 1);
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700674 baud = uart_get_baud_rate(port, termios, old, minbaud, maxbaud);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700675 baud = cdns_uart_set_baud_rate(port, baud);
John Linn61ec9012011-04-30 00:07:43 -0400676 if (tty_termios_baud_rate(termios))
677 tty_termios_encode_baud_rate(termios, baud, baud);
678
Soren Brinkmanne555a212014-04-04 17:23:39 -0700679 /* Update the per-port timeout. */
John Linn61ec9012011-04-30 00:07:43 -0400680 uart_update_timeout(port, termios->c_cflag, baud);
681
682 /* Set TX/RX Reset */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100683 ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700684 ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
Thomas Betker19f22ef2015-03-12 22:11:59 +0100685 writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400686
Soren Brinkmanne555a212014-04-04 17:23:39 -0700687 /*
688 * Clear the RX disable and TX disable bits and then set the TX enable
John Linn61ec9012011-04-30 00:07:43 -0400689 * bit and RX enable bit to enable the transmitter and receiver.
690 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100691 ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700692 ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
693 ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
Thomas Betker19f22ef2015-03-12 22:11:59 +0100694 writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400695
Thomas Betker19f22ef2015-03-12 22:11:59 +0100696 writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400697
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700698 port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
699 CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
John Linn61ec9012011-04-30 00:07:43 -0400700 port->ignore_status_mask = 0;
701
702 if (termios->c_iflag & INPCK)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700703 port->read_status_mask |= CDNS_UART_IXR_PARITY |
704 CDNS_UART_IXR_FRAMING;
John Linn61ec9012011-04-30 00:07:43 -0400705
706 if (termios->c_iflag & IGNPAR)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700707 port->ignore_status_mask |= CDNS_UART_IXR_PARITY |
708 CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
John Linn61ec9012011-04-30 00:07:43 -0400709
710 /* ignore all characters if CREAD is not set */
711 if ((termios->c_cflag & CREAD) == 0)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700712 port->ignore_status_mask |= CDNS_UART_IXR_RXTRIG |
713 CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY |
714 CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;
John Linn61ec9012011-04-30 00:07:43 -0400715
Thomas Betker19f22ef2015-03-12 22:11:59 +0100716 mode_reg = readl(port->membase + CDNS_UART_MR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400717
718 /* Handling Data Size */
719 switch (termios->c_cflag & CSIZE) {
720 case CS6:
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700721 cval |= CDNS_UART_MR_CHARLEN_6_BIT;
John Linn61ec9012011-04-30 00:07:43 -0400722 break;
723 case CS7:
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700724 cval |= CDNS_UART_MR_CHARLEN_7_BIT;
John Linn61ec9012011-04-30 00:07:43 -0400725 break;
726 default:
727 case CS8:
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700728 cval |= CDNS_UART_MR_CHARLEN_8_BIT;
John Linn61ec9012011-04-30 00:07:43 -0400729 termios->c_cflag &= ~CSIZE;
730 termios->c_cflag |= CS8;
731 break;
732 }
733
734 /* Handling Parity and Stop Bits length */
735 if (termios->c_cflag & CSTOPB)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700736 cval |= CDNS_UART_MR_STOPMODE_2_BIT; /* 2 STOP bits */
John Linn61ec9012011-04-30 00:07:43 -0400737 else
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700738 cval |= CDNS_UART_MR_STOPMODE_1_BIT; /* 1 STOP bit */
John Linn61ec9012011-04-30 00:07:43 -0400739
740 if (termios->c_cflag & PARENB) {
741 /* Mark or Space parity */
742 if (termios->c_cflag & CMSPAR) {
743 if (termios->c_cflag & PARODD)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700744 cval |= CDNS_UART_MR_PARITY_MARK;
John Linn61ec9012011-04-30 00:07:43 -0400745 else
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700746 cval |= CDNS_UART_MR_PARITY_SPACE;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700747 } else {
748 if (termios->c_cflag & PARODD)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700749 cval |= CDNS_UART_MR_PARITY_ODD;
John Linn61ec9012011-04-30 00:07:43 -0400750 else
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700751 cval |= CDNS_UART_MR_PARITY_EVEN;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700752 }
753 } else {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700754 cval |= CDNS_UART_MR_PARITY_NONE;
Soren Brinkmanne6b39bf2013-10-17 14:08:10 -0700755 }
756 cval |= mode_reg & 1;
Thomas Betker19f22ef2015-03-12 22:11:59 +0100757 writel(cval, port->membase + CDNS_UART_MR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400758
759 spin_unlock_irqrestore(&port->lock, flags);
760}
761
762/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700763 * cdns_uart_startup - Called when an application opens a cdns_uart port
John Linn61ec9012011-04-30 00:07:43 -0400764 * @port: Handle to the uart port structure
765 *
Soren Brinkmanne555a212014-04-04 17:23:39 -0700766 * Return: 0 on success, negative errno otherwise
Michal Simek489810a12014-04-04 17:23:37 -0700767 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700768static int cdns_uart_startup(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400769{
Soren Brinkmann55861d12016-01-11 17:41:36 -0800770 int ret;
Soren Brinkmann6e14f7c2015-12-26 02:43:53 -0800771 unsigned long flags;
Soren Brinkmann55861d12016-01-11 17:41:36 -0800772 unsigned int status = 0;
John Linn61ec9012011-04-30 00:07:43 -0400773
Soren Brinkmann6e14f7c2015-12-26 02:43:53 -0800774 spin_lock_irqsave(&port->lock, flags);
775
John Linn61ec9012011-04-30 00:07:43 -0400776 /* Disable the TX and RX */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100777 writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
778 port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400779
780 /* Set the Control Register with TX/RX Enable, TX/RX Reset,
781 * no break chars.
782 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100783 writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
784 port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400785
Soren Brinkmann6e14f7c2015-12-26 02:43:53 -0800786 /*
787 * Clear the RX disable bit and then set the RX enable bit to enable
788 * the receiver.
John Linn61ec9012011-04-30 00:07:43 -0400789 */
Soren Brinkmann6e14f7c2015-12-26 02:43:53 -0800790 status = readl(port->membase + CDNS_UART_CR_OFFSET);
791 status &= CDNS_UART_CR_RX_DIS;
792 status |= CDNS_UART_CR_RX_EN;
793 writel(status, port->membase + CDNS_UART_CR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400794
795 /* Set the Mode Register with normal mode,8 data bits,1 stop bit,
796 * no parity.
797 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100798 writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700799 | CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT,
Thomas Betker19f22ef2015-03-12 22:11:59 +0100800 port->membase + CDNS_UART_MR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400801
Suneel85baf542013-10-17 14:08:08 -0700802 /*
803 * Set the RX FIFO Trigger level to use most of the FIFO, but it
804 * can be tuned with a module parameter
805 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100806 writel(rx_trigger_level, port->membase + CDNS_UART_RXWM_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400807
Suneel85baf542013-10-17 14:08:08 -0700808 /*
809 * Receive Timeout register is enabled but it
810 * can be tuned with a module parameter
811 */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100812 writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400813
John Linn855f6fd2013-03-22 18:49:27 +0100814 /* Clear out any pending interrupts before enabling them */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100815 writel(readl(port->membase + CDNS_UART_ISR_OFFSET),
816 port->membase + CDNS_UART_ISR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400817
Soren Brinkmann55861d12016-01-11 17:41:36 -0800818 spin_unlock_irqrestore(&port->lock, flags);
819
820 ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port);
821 if (ret) {
822 dev_err(port->dev, "request_irq '%d' failed with %d\n",
823 port->irq, ret);
824 return ret;
825 }
826
John Linn61ec9012011-04-30 00:07:43 -0400827 /* Set the Interrupt Registers with desired interrupts */
Soren Brinkmann373e8822016-01-11 17:41:37 -0800828 writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400829
Soren Brinkmann55861d12016-01-11 17:41:36 -0800830 return 0;
John Linn61ec9012011-04-30 00:07:43 -0400831}
832
833/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700834 * cdns_uart_shutdown - Called when an application closes a cdns_uart port
John Linn61ec9012011-04-30 00:07:43 -0400835 * @port: Handle to the uart port structure
Michal Simek489810a12014-04-04 17:23:37 -0700836 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700837static void cdns_uart_shutdown(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400838{
839 int status;
Soren Brinkmanna19eda02015-12-26 02:43:55 -0800840 unsigned long flags;
841
842 spin_lock_irqsave(&port->lock, flags);
John Linn61ec9012011-04-30 00:07:43 -0400843
844 /* Disable interrupts */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100845 status = readl(port->membase + CDNS_UART_IMR_OFFSET);
846 writel(status, port->membase + CDNS_UART_IDR_OFFSET);
Soren Brinkmannaea8f3d2015-12-26 02:43:52 -0800847 writel(0xffffffff, port->membase + CDNS_UART_ISR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400848
849 /* Disable the TX and RX */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100850 writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
851 port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmanna19eda02015-12-26 02:43:55 -0800852
853 spin_unlock_irqrestore(&port->lock, flags);
854
John Linn61ec9012011-04-30 00:07:43 -0400855 free_irq(port->irq, port);
856}
857
858/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700859 * cdns_uart_type - Set UART type to cdns_uart port
John Linn61ec9012011-04-30 00:07:43 -0400860 * @port: Handle to the uart port structure
861 *
Michal Simek489810a12014-04-04 17:23:37 -0700862 * Return: string on success, NULL otherwise
863 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700864static const char *cdns_uart_type(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400865{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700866 return port->type == PORT_XUARTPS ? CDNS_UART_NAME : NULL;
John Linn61ec9012011-04-30 00:07:43 -0400867}
868
869/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700870 * cdns_uart_verify_port - Verify the port params
John Linn61ec9012011-04-30 00:07:43 -0400871 * @port: Handle to the uart port structure
872 * @ser: Handle to the structure whose members are compared
873 *
Soren Brinkmanne555a212014-04-04 17:23:39 -0700874 * Return: 0 on success, negative errno otherwise.
Michal Simek489810a12014-04-04 17:23:37 -0700875 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700876static int cdns_uart_verify_port(struct uart_port *port,
John Linn61ec9012011-04-30 00:07:43 -0400877 struct serial_struct *ser)
878{
879 if (ser->type != PORT_UNKNOWN && ser->type != PORT_XUARTPS)
880 return -EINVAL;
881 if (port->irq != ser->irq)
882 return -EINVAL;
883 if (ser->io_type != UPIO_MEM)
884 return -EINVAL;
885 if (port->iobase != ser->port)
886 return -EINVAL;
887 if (ser->hub6 != 0)
888 return -EINVAL;
889 return 0;
890}
891
892/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700893 * cdns_uart_request_port - Claim the memory region attached to cdns_uart port,
894 * called when the driver adds a cdns_uart port via
John Linn61ec9012011-04-30 00:07:43 -0400895 * uart_add_one_port()
896 * @port: Handle to the uart port structure
897 *
Soren Brinkmanne555a212014-04-04 17:23:39 -0700898 * Return: 0 on success, negative errno otherwise.
Michal Simek489810a12014-04-04 17:23:37 -0700899 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700900static int cdns_uart_request_port(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400901{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700902 if (!request_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE,
903 CDNS_UART_NAME)) {
John Linn61ec9012011-04-30 00:07:43 -0400904 return -ENOMEM;
905 }
906
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700907 port->membase = ioremap(port->mapbase, CDNS_UART_REGISTER_SPACE);
John Linn61ec9012011-04-30 00:07:43 -0400908 if (!port->membase) {
909 dev_err(port->dev, "Unable to map registers\n");
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700910 release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE);
John Linn61ec9012011-04-30 00:07:43 -0400911 return -ENOMEM;
912 }
913 return 0;
914}
915
916/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700917 * cdns_uart_release_port - Release UART port
John Linn61ec9012011-04-30 00:07:43 -0400918 * @port: Handle to the uart port structure
Soren Brinkmanne555a212014-04-04 17:23:39 -0700919 *
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700920 * Release the memory region attached to a cdns_uart port. Called when the
921 * driver removes a cdns_uart port via uart_remove_one_port().
Michal Simek489810a12014-04-04 17:23:37 -0700922 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700923static void cdns_uart_release_port(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400924{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700925 release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE);
John Linn61ec9012011-04-30 00:07:43 -0400926 iounmap(port->membase);
927 port->membase = NULL;
928}
929
930/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700931 * cdns_uart_config_port - Configure UART port
John Linn61ec9012011-04-30 00:07:43 -0400932 * @port: Handle to the uart port structure
933 * @flags: If any
Michal Simek489810a12014-04-04 17:23:37 -0700934 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700935static void cdns_uart_config_port(struct uart_port *port, int flags)
John Linn61ec9012011-04-30 00:07:43 -0400936{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700937 if (flags & UART_CONFIG_TYPE && cdns_uart_request_port(port) == 0)
John Linn61ec9012011-04-30 00:07:43 -0400938 port->type = PORT_XUARTPS;
939}
940
941/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700942 * cdns_uart_get_mctrl - Get the modem control state
John Linn61ec9012011-04-30 00:07:43 -0400943 * @port: Handle to the uart port structure
944 *
Michal Simek489810a12014-04-04 17:23:37 -0700945 * Return: the modem control state
946 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700947static unsigned int cdns_uart_get_mctrl(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -0400948{
949 return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
950}
951
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700952static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
John Linn61ec9012011-04-30 00:07:43 -0400953{
Lars-Peter Clausen19038ad2014-11-05 13:35:16 +0100954 u32 val;
955
Thomas Betker19f22ef2015-03-12 22:11:59 +0100956 val = readl(port->membase + CDNS_UART_MODEMCR_OFFSET);
Lars-Peter Clausen19038ad2014-11-05 13:35:16 +0100957
958 val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
959
960 if (mctrl & TIOCM_RTS)
961 val |= CDNS_UART_MODEMCR_RTS;
962 if (mctrl & TIOCM_DTR)
963 val |= CDNS_UART_MODEMCR_DTR;
964
Thomas Betker19f22ef2015-03-12 22:11:59 +0100965 writel(val, port->membase + CDNS_UART_MODEMCR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -0400966}
967
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700968#ifdef CONFIG_CONSOLE_POLL
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700969static int cdns_uart_poll_get_char(struct uart_port *port)
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700970{
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700971 int c;
Soren Brinkmannf0f54a82015-12-26 02:43:50 -0800972 unsigned long flags;
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700973
Soren Brinkmannf0f54a82015-12-26 02:43:50 -0800974 spin_lock_irqsave(&port->lock, flags);
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700975
976 /* Check if FIFO is empty */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100977 if (readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700978 c = NO_POLL_CHAR;
979 else /* Read a character */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100980 c = (unsigned char) readl(
981 port->membase + CDNS_UART_FIFO_OFFSET);
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700982
Soren Brinkmannf0f54a82015-12-26 02:43:50 -0800983 spin_unlock_irqrestore(&port->lock, flags);
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700984
985 return c;
986}
987
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -0700988static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700989{
Soren Brinkmannf0f54a82015-12-26 02:43:50 -0800990 unsigned long flags;
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700991
Soren Brinkmannf0f54a82015-12-26 02:43:50 -0800992 spin_lock_irqsave(&port->lock, flags);
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700993
994 /* Wait until FIFO is empty */
Thomas Betker19f22ef2015-03-12 22:11:59 +0100995 while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
996 CDNS_UART_SR_TXEMPTY))
Vlad Lungu6ee04c62013-10-17 14:08:07 -0700997 cpu_relax();
998
999 /* Write a character */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001000 writel(c, port->membase + CDNS_UART_FIFO_OFFSET);
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001001
1002 /* Wait until FIFO is empty */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001003 while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
1004 CDNS_UART_SR_TXEMPTY))
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001005 cpu_relax();
1006
Soren Brinkmannf0f54a82015-12-26 02:43:50 -08001007 spin_unlock_irqrestore(&port->lock, flags);
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001008
1009 return;
1010}
1011#endif
1012
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001013static struct uart_ops cdns_uart_ops = {
1014 .set_mctrl = cdns_uart_set_mctrl,
1015 .get_mctrl = cdns_uart_get_mctrl,
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001016 .start_tx = cdns_uart_start_tx,
1017 .stop_tx = cdns_uart_stop_tx,
1018 .stop_rx = cdns_uart_stop_rx,
1019 .tx_empty = cdns_uart_tx_empty,
1020 .break_ctl = cdns_uart_break_ctl,
1021 .set_termios = cdns_uart_set_termios,
1022 .startup = cdns_uart_startup,
1023 .shutdown = cdns_uart_shutdown,
1024 .type = cdns_uart_type,
1025 .verify_port = cdns_uart_verify_port,
1026 .request_port = cdns_uart_request_port,
1027 .release_port = cdns_uart_release_port,
1028 .config_port = cdns_uart_config_port,
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001029#ifdef CONFIG_CONSOLE_POLL
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001030 .poll_get_char = cdns_uart_poll_get_char,
1031 .poll_put_char = cdns_uart_poll_put_char,
Vlad Lungu6ee04c62013-10-17 14:08:07 -07001032#endif
John Linn61ec9012011-04-30 00:07:43 -04001033};
1034
Thomas Betker6db6df02015-03-11 22:39:26 +01001035static struct uart_port cdns_uart_port[CDNS_UART_NR_PORTS];
John Linn61ec9012011-04-30 00:07:43 -04001036
1037/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001038 * cdns_uart_get_port - Configure the port from platform device resource info
Michal Simek928e9262014-04-04 17:23:38 -07001039 * @id: Port id
1040 *
Michal Simek489810a12014-04-04 17:23:37 -07001041 * Return: a pointer to a uart_port or NULL for failure
1042 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001043static struct uart_port *cdns_uart_get_port(int id)
John Linn61ec9012011-04-30 00:07:43 -04001044{
1045 struct uart_port *port;
John Linn61ec9012011-04-30 00:07:43 -04001046
Michal Simek928e9262014-04-04 17:23:38 -07001047 /* Try the given port id if failed use default method */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001048 if (cdns_uart_port[id].mapbase != 0) {
Michal Simek928e9262014-04-04 17:23:38 -07001049 /* Find the next unused port */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001050 for (id = 0; id < CDNS_UART_NR_PORTS; id++)
1051 if (cdns_uart_port[id].mapbase == 0)
Michal Simek928e9262014-04-04 17:23:38 -07001052 break;
1053 }
John Linn61ec9012011-04-30 00:07:43 -04001054
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001055 if (id >= CDNS_UART_NR_PORTS)
John Linn61ec9012011-04-30 00:07:43 -04001056 return NULL;
1057
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001058 port = &cdns_uart_port[id];
John Linn61ec9012011-04-30 00:07:43 -04001059
1060 /* At this point, we've got an empty uart_port struct, initialize it */
1061 spin_lock_init(&port->lock);
1062 port->membase = NULL;
John Linn61ec9012011-04-30 00:07:43 -04001063 port->irq = 0;
1064 port->type = PORT_UNKNOWN;
1065 port->iotype = UPIO_MEM32;
1066 port->flags = UPF_BOOT_AUTOCONF;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001067 port->ops = &cdns_uart_ops;
1068 port->fifosize = CDNS_UART_FIFO_SIZE;
John Linn61ec9012011-04-30 00:07:43 -04001069 port->line = id;
1070 port->dev = NULL;
1071 return port;
1072}
1073
John Linn61ec9012011-04-30 00:07:43 -04001074#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
1075/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001076 * cdns_uart_console_wait_tx - Wait for the TX to be full
John Linn61ec9012011-04-30 00:07:43 -04001077 * @port: Handle to the uart port structure
Michal Simek489810a12014-04-04 17:23:37 -07001078 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001079static void cdns_uart_console_wait_tx(struct uart_port *port)
John Linn61ec9012011-04-30 00:07:43 -04001080{
Thomas Betker19f22ef2015-03-12 22:11:59 +01001081 while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
1082 CDNS_UART_SR_TXEMPTY))
John Linn61ec9012011-04-30 00:07:43 -04001083 barrier();
1084}
1085
1086/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001087 * cdns_uart_console_putchar - write the character to the FIFO buffer
John Linn61ec9012011-04-30 00:07:43 -04001088 * @port: Handle to the uart port structure
1089 * @ch: Character to be written
Michal Simek489810a12014-04-04 17:23:37 -07001090 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001091static void cdns_uart_console_putchar(struct uart_port *port, int ch)
John Linn61ec9012011-04-30 00:07:43 -04001092{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001093 cdns_uart_console_wait_tx(port);
Thomas Betker19f22ef2015-03-12 22:11:59 +01001094 writel(ch, port->membase + CDNS_UART_FIFO_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -04001095}
1096
Masahiro Yamada54585ba2015-05-07 18:55:40 +09001097static void __init cdns_early_write(struct console *con, const char *s,
1098 unsigned n)
Michal Simek6fa62fc2014-09-10 12:43:02 +02001099{
1100 struct earlycon_device *dev = con->data;
1101
1102 uart_console_write(&dev->port, s, n, cdns_uart_console_putchar);
1103}
1104
1105static int __init cdns_early_console_setup(struct earlycon_device *device,
1106 const char *opt)
1107{
1108 if (!device->port.membase)
1109 return -ENODEV;
1110
1111 device->con->write = cdns_early_write;
1112
1113 return 0;
1114}
1115EARLYCON_DECLARE(cdns, cdns_early_console_setup);
1116
John Linn61ec9012011-04-30 00:07:43 -04001117/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001118 * cdns_uart_console_write - perform write operation
Michal Simek489810a12014-04-04 17:23:37 -07001119 * @co: Console handle
John Linn61ec9012011-04-30 00:07:43 -04001120 * @s: Pointer to character array
1121 * @count: No of characters
Michal Simek489810a12014-04-04 17:23:37 -07001122 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001123static void cdns_uart_console_write(struct console *co, const char *s,
John Linn61ec9012011-04-30 00:07:43 -04001124 unsigned int count)
1125{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001126 struct uart_port *port = &cdns_uart_port[co->index];
John Linn61ec9012011-04-30 00:07:43 -04001127 unsigned long flags;
Lars-Peter Clausend3755f52013-10-17 14:08:09 -07001128 unsigned int imr, ctrl;
John Linn61ec9012011-04-30 00:07:43 -04001129 int locked = 1;
1130
1131 if (oops_in_progress)
1132 locked = spin_trylock_irqsave(&port->lock, flags);
1133 else
1134 spin_lock_irqsave(&port->lock, flags);
1135
1136 /* save and disable interrupt */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001137 imr = readl(port->membase + CDNS_UART_IMR_OFFSET);
1138 writel(imr, port->membase + CDNS_UART_IDR_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -04001139
Lars-Peter Clausend3755f52013-10-17 14:08:09 -07001140 /*
1141 * Make sure that the tx part is enabled. Set the TX enable bit and
1142 * clear the TX disable bit to enable the transmitter.
1143 */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001144 ctrl = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmanne3538c32015-12-26 02:43:49 -08001145 ctrl &= ~CDNS_UART_CR_TX_DIS;
1146 ctrl |= CDNS_UART_CR_TX_EN;
1147 writel(ctrl, port->membase + CDNS_UART_CR_OFFSET);
Lars-Peter Clausend3755f52013-10-17 14:08:09 -07001148
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001149 uart_console_write(port, s, count, cdns_uart_console_putchar);
1150 cdns_uart_console_wait_tx(port);
John Linn61ec9012011-04-30 00:07:43 -04001151
Thomas Betker19f22ef2015-03-12 22:11:59 +01001152 writel(ctrl, port->membase + CDNS_UART_CR_OFFSET);
Lars-Peter Clausend3755f52013-10-17 14:08:09 -07001153
Soren Brinkmannb494a5f2014-04-04 17:23:42 -07001154 /* restore interrupt state */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001155 writel(imr, port->membase + CDNS_UART_IER_OFFSET);
John Linn61ec9012011-04-30 00:07:43 -04001156
1157 if (locked)
1158 spin_unlock_irqrestore(&port->lock, flags);
1159}
1160
1161/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001162 * cdns_uart_console_setup - Initialize the uart to default config
John Linn61ec9012011-04-30 00:07:43 -04001163 * @co: Console handle
1164 * @options: Initial settings of uart
1165 *
Soren Brinkmanne555a212014-04-04 17:23:39 -07001166 * Return: 0 on success, negative errno otherwise.
Michal Simek489810a12014-04-04 17:23:37 -07001167 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001168static int __init cdns_uart_console_setup(struct console *co, char *options)
John Linn61ec9012011-04-30 00:07:43 -04001169{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001170 struct uart_port *port = &cdns_uart_port[co->index];
John Linn61ec9012011-04-30 00:07:43 -04001171 int baud = 9600;
1172 int bits = 8;
1173 int parity = 'n';
1174 int flow = 'n';
1175
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001176 if (co->index < 0 || co->index >= CDNS_UART_NR_PORTS)
John Linn61ec9012011-04-30 00:07:43 -04001177 return -EINVAL;
1178
Thomas Betker136debf2015-03-11 22:39:28 +01001179 if (!port->membase) {
Peter Crosthwaitef6415492015-02-24 15:13:57 -08001180 pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n",
1181 co->index);
John Linn61ec9012011-04-30 00:07:43 -04001182 return -ENODEV;
1183 }
1184
1185 if (options)
1186 uart_parse_options(options, &baud, &parity, &bits, &flow);
1187
1188 return uart_set_options(port, co, baud, parity, bits, flow);
1189}
1190
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001191static struct uart_driver cdns_uart_uart_driver;
John Linn61ec9012011-04-30 00:07:43 -04001192
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001193static struct console cdns_uart_console = {
1194 .name = CDNS_UART_TTY_NAME,
1195 .write = cdns_uart_console_write,
John Linn61ec9012011-04-30 00:07:43 -04001196 .device = uart_console_device,
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001197 .setup = cdns_uart_console_setup,
John Linn61ec9012011-04-30 00:07:43 -04001198 .flags = CON_PRINTBUFFER,
1199 .index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001200 .data = &cdns_uart_uart_driver,
John Linn61ec9012011-04-30 00:07:43 -04001201};
1202
1203/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001204 * cdns_uart_console_init - Initialization call
John Linn61ec9012011-04-30 00:07:43 -04001205 *
Soren Brinkmanne555a212014-04-04 17:23:39 -07001206 * Return: 0 on success, negative errno otherwise
Michal Simek489810a12014-04-04 17:23:37 -07001207 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001208static int __init cdns_uart_console_init(void)
John Linn61ec9012011-04-30 00:07:43 -04001209{
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001210 register_console(&cdns_uart_console);
John Linn61ec9012011-04-30 00:07:43 -04001211 return 0;
1212}
1213
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001214console_initcall(cdns_uart_console_init);
John Linn61ec9012011-04-30 00:07:43 -04001215
1216#endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
1217
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001218static struct uart_driver cdns_uart_uart_driver = {
Soren Brinkmanne555a212014-04-04 17:23:39 -07001219 .owner = THIS_MODULE,
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001220 .driver_name = CDNS_UART_NAME,
1221 .dev_name = CDNS_UART_TTY_NAME,
1222 .major = CDNS_UART_MAJOR,
1223 .minor = CDNS_UART_MINOR,
1224 .nr = CDNS_UART_NR_PORTS,
Soren Brinkmannd3641f62013-10-21 16:41:00 -07001225#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001226 .cons = &cdns_uart_console,
Soren Brinkmannd3641f62013-10-21 16:41:00 -07001227#endif
1228};
1229
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001230#ifdef CONFIG_PM_SLEEP
1231/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001232 * cdns_uart_suspend - suspend event
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001233 * @device: Pointer to the device structure
1234 *
Michal Simek489810a12014-04-04 17:23:37 -07001235 * Return: 0
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001236 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001237static int cdns_uart_suspend(struct device *device)
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001238{
1239 struct uart_port *port = dev_get_drvdata(device);
1240 struct tty_struct *tty;
1241 struct device *tty_dev;
1242 int may_wake = 0;
1243
1244 /* Get the tty which could be NULL so don't assume it's valid */
1245 tty = tty_port_tty_get(&port->state->port);
1246 if (tty) {
1247 tty_dev = tty->dev;
1248 may_wake = device_may_wakeup(tty_dev);
1249 tty_kref_put(tty);
1250 }
1251
1252 /*
1253 * Call the API provided in serial_core.c file which handles
1254 * the suspend.
1255 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001256 uart_suspend_port(&cdns_uart_uart_driver, port);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001257 if (console_suspend_enabled && !may_wake) {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001258 struct cdns_uart *cdns_uart = port->private_data;
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001259
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001260 clk_disable(cdns_uart->uartclk);
1261 clk_disable(cdns_uart->pclk);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001262 } else {
1263 unsigned long flags = 0;
1264
1265 spin_lock_irqsave(&port->lock, flags);
1266 /* Empty the receive FIFO 1st before making changes */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001267 while (!(readl(port->membase + CDNS_UART_SR_OFFSET) &
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001268 CDNS_UART_SR_RXEMPTY))
Thomas Betker19f22ef2015-03-12 22:11:59 +01001269 readl(port->membase + CDNS_UART_FIFO_OFFSET);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001270 /* set RX trigger level to 1 */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001271 writel(1, port->membase + CDNS_UART_RXWM_OFFSET);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001272 /* disable RX timeout interrups */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001273 writel(CDNS_UART_IXR_TOUT,
1274 port->membase + CDNS_UART_IDR_OFFSET);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001275 spin_unlock_irqrestore(&port->lock, flags);
1276 }
1277
1278 return 0;
1279}
1280
1281/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001282 * cdns_uart_resume - Resume after a previous suspend
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001283 * @device: Pointer to the device structure
1284 *
Michal Simek489810a12014-04-04 17:23:37 -07001285 * Return: 0
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001286 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001287static int cdns_uart_resume(struct device *device)
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001288{
1289 struct uart_port *port = dev_get_drvdata(device);
1290 unsigned long flags = 0;
1291 u32 ctrl_reg;
1292 struct tty_struct *tty;
1293 struct device *tty_dev;
1294 int may_wake = 0;
1295
1296 /* Get the tty which could be NULL so don't assume it's valid */
1297 tty = tty_port_tty_get(&port->state->port);
1298 if (tty) {
1299 tty_dev = tty->dev;
1300 may_wake = device_may_wakeup(tty_dev);
1301 tty_kref_put(tty);
1302 }
1303
1304 if (console_suspend_enabled && !may_wake) {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001305 struct cdns_uart *cdns_uart = port->private_data;
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001306
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001307 clk_enable(cdns_uart->pclk);
1308 clk_enable(cdns_uart->uartclk);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001309
1310 spin_lock_irqsave(&port->lock, flags);
1311
1312 /* Set TX/RX Reset */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001313 ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001314 ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
Thomas Betker19f22ef2015-03-12 22:11:59 +01001315 writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
1316 while (readl(port->membase + CDNS_UART_CR_OFFSET) &
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001317 (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001318 cpu_relax();
1319
1320 /* restore rx timeout value */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001321 writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001322 /* Enable Tx/Rx */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001323 ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001324 ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS);
1325 ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
Thomas Betker19f22ef2015-03-12 22:11:59 +01001326 writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001327
1328 spin_unlock_irqrestore(&port->lock, flags);
1329 } else {
1330 spin_lock_irqsave(&port->lock, flags);
1331 /* restore original rx trigger level */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001332 writel(rx_trigger_level,
1333 port->membase + CDNS_UART_RXWM_OFFSET);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001334 /* enable RX timeout interrupt */
Thomas Betker19f22ef2015-03-12 22:11:59 +01001335 writel(CDNS_UART_IXR_TOUT,
1336 port->membase + CDNS_UART_IER_OFFSET);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001337 spin_unlock_irqrestore(&port->lock, flags);
1338 }
1339
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001340 return uart_resume_port(&cdns_uart_uart_driver, port);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001341}
1342#endif /* ! CONFIG_PM_SLEEP */
1343
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001344static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend,
1345 cdns_uart_resume);
Soren Brinkmann4b47d9a2013-10-17 14:08:12 -07001346
John Linn61ec9012011-04-30 00:07:43 -04001347/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001348 * cdns_uart_probe - Platform driver probe
John Linn61ec9012011-04-30 00:07:43 -04001349 * @pdev: Pointer to the platform device structure
1350 *
Soren Brinkmanne555a212014-04-04 17:23:39 -07001351 * Return: 0 on success, negative errno otherwise
Michal Simek489810a12014-04-04 17:23:37 -07001352 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001353static int cdns_uart_probe(struct platform_device *pdev)
John Linn61ec9012011-04-30 00:07:43 -04001354{
Michal Simek5c90c072015-04-13 16:34:21 +02001355 int rc, id, irq;
John Linn61ec9012011-04-30 00:07:43 -04001356 struct uart_port *port;
Michal Simek5c90c072015-04-13 16:34:21 +02001357 struct resource *res;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001358 struct cdns_uart *cdns_uart_data;
John Linn61ec9012011-04-30 00:07:43 -04001359
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001360 cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
Soren Brinkmannc03cae12013-10-17 14:08:05 -07001361 GFP_KERNEL);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001362 if (!cdns_uart_data)
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001363 return -ENOMEM;
1364
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001365 cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
1366 if (IS_ERR(cdns_uart_data->pclk)) {
1367 cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
1368 if (!IS_ERR(cdns_uart_data->pclk))
1369 dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n");
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001370 }
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001371 if (IS_ERR(cdns_uart_data->pclk)) {
1372 dev_err(&pdev->dev, "pclk clock not found.\n");
1373 return PTR_ERR(cdns_uart_data->pclk);
Josh Cartwright2326669c2013-01-21 19:57:41 +01001374 }
1375
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001376 cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk");
1377 if (IS_ERR(cdns_uart_data->uartclk)) {
1378 cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "ref_clk");
1379 if (!IS_ERR(cdns_uart_data->uartclk))
1380 dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n");
1381 }
1382 if (IS_ERR(cdns_uart_data->uartclk)) {
1383 dev_err(&pdev->dev, "uart_clk clock not found.\n");
1384 return PTR_ERR(cdns_uart_data->uartclk);
1385 }
1386
1387 rc = clk_prepare_enable(cdns_uart_data->pclk);
Josh Cartwright2326669c2013-01-21 19:57:41 +01001388 if (rc) {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001389 dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
Soren Brinkmannc03cae12013-10-17 14:08:05 -07001390 return rc;
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001391 }
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001392 rc = clk_prepare_enable(cdns_uart_data->uartclk);
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001393 if (rc) {
1394 dev_err(&pdev->dev, "Unable to enable device clock.\n");
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001395 goto err_out_clk_dis_pclk;
John Linn61ec9012011-04-30 00:07:43 -04001396 }
1397
1398 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001399 if (!res) {
1400 rc = -ENODEV;
1401 goto err_out_clk_disable;
1402 }
John Linn61ec9012011-04-30 00:07:43 -04001403
Michal Simek5c90c072015-04-13 16:34:21 +02001404 irq = platform_get_irq(pdev, 0);
1405 if (irq <= 0) {
1406 rc = -ENXIO;
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001407 goto err_out_clk_disable;
1408 }
John Linn61ec9012011-04-30 00:07:43 -04001409
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001410#ifdef CONFIG_COMMON_CLK
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001411 cdns_uart_data->clk_rate_change_nb.notifier_call =
1412 cdns_uart_clk_notifier_cb;
1413 if (clk_notifier_register(cdns_uart_data->uartclk,
1414 &cdns_uart_data->clk_rate_change_nb))
Soren Brinkmannc4b05102013-10-17 14:08:11 -07001415 dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001416#endif
Michal Simek928e9262014-04-04 17:23:38 -07001417 /* Look for a serialN alias */
1418 id = of_alias_get_id(pdev->dev.of_node, "serial");
1419 if (id < 0)
1420 id = 0;
Soren Brinkmannc4b05102013-10-17 14:08:11 -07001421
John Linn61ec9012011-04-30 00:07:43 -04001422 /* Initialize the port structure */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001423 port = cdns_uart_get_port(id);
John Linn61ec9012011-04-30 00:07:43 -04001424
1425 if (!port) {
1426 dev_err(&pdev->dev, "Cannot get uart_port structure\n");
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001427 rc = -ENODEV;
Soren Brinkmannc4b05102013-10-17 14:08:11 -07001428 goto err_out_notif_unreg;
John Linn61ec9012011-04-30 00:07:43 -04001429 }
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001430
Soren Brinkmann354fb1a2016-01-11 17:41:38 -08001431 /*
1432 * Register the port.
1433 * This function also registers this device with the tty layer
1434 * and triggers invocation of the config_port() entry point.
1435 */
1436 port->mapbase = res->start;
1437 port->irq = irq;
1438 port->dev = &pdev->dev;
1439 port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
1440 port->private_data = cdns_uart_data;
1441 cdns_uart_data->port = port;
1442 platform_set_drvdata(pdev, port);
1443
1444 rc = uart_add_one_port(&cdns_uart_uart_driver, port);
1445 if (rc) {
1446 dev_err(&pdev->dev,
1447 "uart_add_one_port() failed; err=%i\n", rc);
1448 goto err_out_notif_unreg;
1449 }
1450
1451 return 0;
1452
Soren Brinkmannc4b05102013-10-17 14:08:11 -07001453err_out_notif_unreg:
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001454#ifdef CONFIG_COMMON_CLK
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001455 clk_notifier_unregister(cdns_uart_data->uartclk,
1456 &cdns_uart_data->clk_rate_change_nb);
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001457#endif
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001458err_out_clk_disable:
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001459 clk_disable_unprepare(cdns_uart_data->uartclk);
1460err_out_clk_dis_pclk:
1461 clk_disable_unprepare(cdns_uart_data->pclk);
Soren Brinkmann30e1e282013-05-13 10:46:38 -07001462
1463 return rc;
John Linn61ec9012011-04-30 00:07:43 -04001464}
1465
1466/**
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001467 * cdns_uart_remove - called when the platform driver is unregistered
John Linn61ec9012011-04-30 00:07:43 -04001468 * @pdev: Pointer to the platform device structure
1469 *
Soren Brinkmanne555a212014-04-04 17:23:39 -07001470 * Return: 0 on success, negative errno otherwise
Michal Simek489810a12014-04-04 17:23:37 -07001471 */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001472static int cdns_uart_remove(struct platform_device *pdev)
John Linn61ec9012011-04-30 00:07:43 -04001473{
Jingoo Han696faed2013-05-23 19:39:36 +09001474 struct uart_port *port = platform_get_drvdata(pdev);
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001475 struct cdns_uart *cdns_uart_data = port->private_data;
Josh Cartwright2326669c2013-01-21 19:57:41 +01001476 int rc;
John Linn61ec9012011-04-30 00:07:43 -04001477
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001478 /* Remove the cdns_uart port from the serial core */
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001479#ifdef CONFIG_COMMON_CLK
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001480 clk_notifier_unregister(cdns_uart_data->uartclk,
1481 &cdns_uart_data->clk_rate_change_nb);
Soren Brinkmann7ac57342013-10-21 16:41:01 -07001482#endif
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001483 rc = uart_remove_one_port(&cdns_uart_uart_driver, port);
Josh Cartwright2326669c2013-01-21 19:57:41 +01001484 port->mapbase = 0;
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001485 clk_disable_unprepare(cdns_uart_data->uartclk);
1486 clk_disable_unprepare(cdns_uart_data->pclk);
John Linn61ec9012011-04-30 00:07:43 -04001487 return rc;
1488}
1489
John Linn61ec9012011-04-30 00:07:43 -04001490/* Match table for of_platform binding */
Fabian Fredericked0bb232015-03-16 20:17:11 +01001491static const struct of_device_id cdns_uart_of_match[] = {
John Linn61ec9012011-04-30 00:07:43 -04001492 { .compatible = "xlnx,xuartps", },
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001493 { .compatible = "cdns,uart-r1p8", },
John Linn61ec9012011-04-30 00:07:43 -04001494 {}
1495};
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001496MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
John Linn61ec9012011-04-30 00:07:43 -04001497
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001498static struct platform_driver cdns_uart_platform_driver = {
1499 .probe = cdns_uart_probe,
1500 .remove = cdns_uart_remove,
John Linn61ec9012011-04-30 00:07:43 -04001501 .driver = {
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001502 .name = CDNS_UART_NAME,
1503 .of_match_table = cdns_uart_of_match,
1504 .pm = &cdns_uart_dev_pm_ops,
John Linn61ec9012011-04-30 00:07:43 -04001505 },
1506};
1507
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001508static int __init cdns_uart_init(void)
John Linn61ec9012011-04-30 00:07:43 -04001509{
1510 int retval = 0;
1511
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001512 /* Register the cdns_uart driver with the serial core */
1513 retval = uart_register_driver(&cdns_uart_uart_driver);
John Linn61ec9012011-04-30 00:07:43 -04001514 if (retval)
1515 return retval;
1516
1517 /* Register the platform driver */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001518 retval = platform_driver_register(&cdns_uart_platform_driver);
John Linn61ec9012011-04-30 00:07:43 -04001519 if (retval)
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001520 uart_unregister_driver(&cdns_uart_uart_driver);
John Linn61ec9012011-04-30 00:07:43 -04001521
1522 return retval;
1523}
1524
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001525static void __exit cdns_uart_exit(void)
John Linn61ec9012011-04-30 00:07:43 -04001526{
John Linn61ec9012011-04-30 00:07:43 -04001527 /* Unregister the platform driver */
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001528 platform_driver_unregister(&cdns_uart_platform_driver);
John Linn61ec9012011-04-30 00:07:43 -04001529
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001530 /* Unregister the cdns_uart driver */
1531 uart_unregister_driver(&cdns_uart_uart_driver);
John Linn61ec9012011-04-30 00:07:43 -04001532}
1533
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001534module_init(cdns_uart_init);
1535module_exit(cdns_uart_exit);
John Linn61ec9012011-04-30 00:07:43 -04001536
Soren Brinkmannd9bb3fb2014-04-04 17:23:43 -07001537MODULE_DESCRIPTION("Driver for Cadence UART");
John Linn61ec9012011-04-30 00:07:43 -04001538MODULE_AUTHOR("Xilinx Inc.");
1539MODULE_LICENSE("GPL");