1*09864c1cSStefan-gabriel Mirea // SPDX-License-Identifier: GPL-2.0-or-later 2*09864c1cSStefan-gabriel Mirea /* 3*09864c1cSStefan-gabriel Mirea * Freescale linflexuart serial port driver 4*09864c1cSStefan-gabriel Mirea * 5*09864c1cSStefan-gabriel Mirea * Copyright 2012-2016 Freescale Semiconductor, Inc. 6*09864c1cSStefan-gabriel Mirea * Copyright 2017-2018 NXP 7*09864c1cSStefan-gabriel Mirea */ 8*09864c1cSStefan-gabriel Mirea 9*09864c1cSStefan-gabriel Mirea #if defined(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE) && \ 10*09864c1cSStefan-gabriel Mirea defined(CONFIG_MAGIC_SYSRQ) 11*09864c1cSStefan-gabriel Mirea #define SUPPORT_SYSRQ 12*09864c1cSStefan-gabriel Mirea #endif 13*09864c1cSStefan-gabriel Mirea 14*09864c1cSStefan-gabriel Mirea #include <linux/console.h> 15*09864c1cSStefan-gabriel Mirea #include <linux/io.h> 16*09864c1cSStefan-gabriel Mirea #include <linux/irq.h> 17*09864c1cSStefan-gabriel Mirea #include <linux/module.h> 18*09864c1cSStefan-gabriel Mirea #include <linux/of.h> 19*09864c1cSStefan-gabriel Mirea #include <linux/of_device.h> 20*09864c1cSStefan-gabriel Mirea #include <linux/serial_core.h> 21*09864c1cSStefan-gabriel Mirea #include <linux/slab.h> 22*09864c1cSStefan-gabriel Mirea #include <linux/tty_flip.h> 23*09864c1cSStefan-gabriel Mirea #include <linux/delay.h> 24*09864c1cSStefan-gabriel Mirea 25*09864c1cSStefan-gabriel Mirea /* All registers are 32-bit width */ 26*09864c1cSStefan-gabriel Mirea 27*09864c1cSStefan-gabriel Mirea #define LINCR1 0x0000 /* LIN control register */ 28*09864c1cSStefan-gabriel Mirea #define LINIER 0x0004 /* LIN interrupt enable register */ 29*09864c1cSStefan-gabriel Mirea #define LINSR 0x0008 /* LIN status register */ 30*09864c1cSStefan-gabriel Mirea #define LINESR 0x000C /* LIN error status register */ 31*09864c1cSStefan-gabriel Mirea #define UARTCR 0x0010 /* UART mode control register */ 32*09864c1cSStefan-gabriel Mirea #define UARTSR 0x0014 /* UART mode status register */ 33*09864c1cSStefan-gabriel Mirea #define LINTCSR 0x0018 /* LIN timeout control status register */ 34*09864c1cSStefan-gabriel Mirea #define LINOCR 0x001C /* LIN output compare register */ 35*09864c1cSStefan-gabriel Mirea #define LINTOCR 0x0020 /* LIN timeout control register */ 36*09864c1cSStefan-gabriel Mirea #define LINFBRR 0x0024 /* LIN fractional baud rate register */ 37*09864c1cSStefan-gabriel Mirea #define LINIBRR 0x0028 /* LIN integer baud rate register */ 38*09864c1cSStefan-gabriel Mirea #define LINCFR 0x002C /* LIN checksum field register */ 39*09864c1cSStefan-gabriel Mirea #define LINCR2 0x0030 /* LIN control register 2 */ 40*09864c1cSStefan-gabriel Mirea #define BIDR 0x0034 /* Buffer identifier register */ 41*09864c1cSStefan-gabriel Mirea #define BDRL 0x0038 /* Buffer data register least significant */ 42*09864c1cSStefan-gabriel Mirea #define BDRM 0x003C /* Buffer data register most significant */ 43*09864c1cSStefan-gabriel Mirea #define IFER 0x0040 /* Identifier filter enable register */ 44*09864c1cSStefan-gabriel Mirea #define IFMI 0x0044 /* Identifier filter match index */ 45*09864c1cSStefan-gabriel Mirea #define IFMR 0x0048 /* Identifier filter mode register */ 46*09864c1cSStefan-gabriel Mirea #define GCR 0x004C /* Global control register */ 47*09864c1cSStefan-gabriel Mirea #define UARTPTO 0x0050 /* UART preset timeout register */ 48*09864c1cSStefan-gabriel Mirea #define UARTCTO 0x0054 /* UART current timeout register */ 49*09864c1cSStefan-gabriel Mirea 50*09864c1cSStefan-gabriel Mirea /* 51*09864c1cSStefan-gabriel Mirea * Register field definitions 52*09864c1cSStefan-gabriel Mirea */ 53*09864c1cSStefan-gabriel Mirea 54*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINCR1_INIT BIT(0) 55*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINCR1_MME BIT(4) 56*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINCR1_BF BIT(7) 57*09864c1cSStefan-gabriel Mirea 58*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINSR_LINS_INITMODE BIT(12) 59*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINSR_LINS_MASK (0xF << 12) 60*09864c1cSStefan-gabriel Mirea 61*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_SZIE BIT(15) 62*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_OCIE BIT(14) 63*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_BEIE BIT(13) 64*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_CEIE BIT(12) 65*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_HEIE BIT(11) 66*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_FEIE BIT(8) 67*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_BOIE BIT(7) 68*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_LSIE BIT(6) 69*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_WUIE BIT(5) 70*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_DBFIE BIT(4) 71*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_DBEIETOIE BIT(3) 72*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_DRIE BIT(2) 73*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_DTIE BIT(1) 74*09864c1cSStefan-gabriel Mirea #define LINFLEXD_LINIER_HRIE BIT(0) 75*09864c1cSStefan-gabriel Mirea 76*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_OSR_MASK (0xF << 24) 77*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_OSR(uartcr) (((uartcr) \ 78*09864c1cSStefan-gabriel Mirea & LINFLEXD_UARTCR_OSR_MASK) >> 24) 79*09864c1cSStefan-gabriel Mirea 80*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_ROSE BIT(23) 81*09864c1cSStefan-gabriel Mirea 82*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_RFBM BIT(9) 83*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_TFBM BIT(8) 84*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_WL1 BIT(7) 85*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_PC1 BIT(6) 86*09864c1cSStefan-gabriel Mirea 87*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_RXEN BIT(5) 88*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_TXEN BIT(4) 89*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_PC0 BIT(3) 90*09864c1cSStefan-gabriel Mirea 91*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_PCE BIT(2) 92*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_WL0 BIT(1) 93*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTCR_UART BIT(0) 94*09864c1cSStefan-gabriel Mirea 95*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_SZF BIT(15) 96*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_OCF BIT(14) 97*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE3 BIT(13) 98*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE2 BIT(12) 99*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE1 BIT(11) 100*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE0 BIT(10) 101*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_RMB BIT(9) 102*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_FEF BIT(8) 103*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_BOF BIT(7) 104*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_RPS BIT(6) 105*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_WUF BIT(5) 106*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_4 BIT(4) 107*09864c1cSStefan-gabriel Mirea 108*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_TO BIT(3) 109*09864c1cSStefan-gabriel Mirea 110*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_DRFRFE BIT(2) 111*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_DTFTFF BIT(1) 112*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_NF BIT(0) 113*09864c1cSStefan-gabriel Mirea #define LINFLEXD_UARTSR_PE (LINFLEXD_UARTSR_PE0 |\ 114*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE1 |\ 115*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE2 |\ 116*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE3) 117*09864c1cSStefan-gabriel Mirea 118*09864c1cSStefan-gabriel Mirea #define LINFLEX_LDIV_MULTIPLIER (16) 119*09864c1cSStefan-gabriel Mirea 120*09864c1cSStefan-gabriel Mirea #define DRIVER_NAME "fsl-linflexuart" 121*09864c1cSStefan-gabriel Mirea #define DEV_NAME "ttyLF" 122*09864c1cSStefan-gabriel Mirea #define UART_NR 4 123*09864c1cSStefan-gabriel Mirea 124*09864c1cSStefan-gabriel Mirea #define EARLYCON_BUFFER_INITIAL_CAP 8 125*09864c1cSStefan-gabriel Mirea 126*09864c1cSStefan-gabriel Mirea #define PREINIT_DELAY 2000 /* us */ 127*09864c1cSStefan-gabriel Mirea 128*09864c1cSStefan-gabriel Mirea static const struct of_device_id linflex_dt_ids[] = { 129*09864c1cSStefan-gabriel Mirea { 130*09864c1cSStefan-gabriel Mirea .compatible = "fsl,s32-linflexuart", 131*09864c1cSStefan-gabriel Mirea }, 132*09864c1cSStefan-gabriel Mirea { /* sentinel */ } 133*09864c1cSStefan-gabriel Mirea }; 134*09864c1cSStefan-gabriel Mirea MODULE_DEVICE_TABLE(of, linflex_dt_ids); 135*09864c1cSStefan-gabriel Mirea 136*09864c1cSStefan-gabriel Mirea #ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE 137*09864c1cSStefan-gabriel Mirea static struct uart_port *earlycon_port; 138*09864c1cSStefan-gabriel Mirea static bool linflex_earlycon_same_instance; 139*09864c1cSStefan-gabriel Mirea static spinlock_t init_lock; 140*09864c1cSStefan-gabriel Mirea static bool during_init; 141*09864c1cSStefan-gabriel Mirea 142*09864c1cSStefan-gabriel Mirea static struct { 143*09864c1cSStefan-gabriel Mirea char *content; 144*09864c1cSStefan-gabriel Mirea unsigned int len, cap; 145*09864c1cSStefan-gabriel Mirea } earlycon_buf; 146*09864c1cSStefan-gabriel Mirea #endif 147*09864c1cSStefan-gabriel Mirea 148*09864c1cSStefan-gabriel Mirea static void linflex_stop_tx(struct uart_port *port) 149*09864c1cSStefan-gabriel Mirea { 150*09864c1cSStefan-gabriel Mirea unsigned long ier; 151*09864c1cSStefan-gabriel Mirea 152*09864c1cSStefan-gabriel Mirea ier = readl(port->membase + LINIER); 153*09864c1cSStefan-gabriel Mirea ier &= ~(LINFLEXD_LINIER_DTIE); 154*09864c1cSStefan-gabriel Mirea writel(ier, port->membase + LINIER); 155*09864c1cSStefan-gabriel Mirea } 156*09864c1cSStefan-gabriel Mirea 157*09864c1cSStefan-gabriel Mirea static void linflex_stop_rx(struct uart_port *port) 158*09864c1cSStefan-gabriel Mirea { 159*09864c1cSStefan-gabriel Mirea unsigned long ier; 160*09864c1cSStefan-gabriel Mirea 161*09864c1cSStefan-gabriel Mirea ier = readl(port->membase + LINIER); 162*09864c1cSStefan-gabriel Mirea writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER); 163*09864c1cSStefan-gabriel Mirea } 164*09864c1cSStefan-gabriel Mirea 165*09864c1cSStefan-gabriel Mirea static inline void linflex_transmit_buffer(struct uart_port *sport) 166*09864c1cSStefan-gabriel Mirea { 167*09864c1cSStefan-gabriel Mirea struct circ_buf *xmit = &sport->state->xmit; 168*09864c1cSStefan-gabriel Mirea unsigned char c; 169*09864c1cSStefan-gabriel Mirea unsigned long status; 170*09864c1cSStefan-gabriel Mirea 171*09864c1cSStefan-gabriel Mirea while (!uart_circ_empty(xmit)) { 172*09864c1cSStefan-gabriel Mirea c = xmit->buf[xmit->tail]; 173*09864c1cSStefan-gabriel Mirea writeb(c, sport->membase + BDRL); 174*09864c1cSStefan-gabriel Mirea 175*09864c1cSStefan-gabriel Mirea /* Waiting for data transmission completed. */ 176*09864c1cSStefan-gabriel Mirea while (((status = readl(sport->membase + UARTSR)) & 177*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) != 178*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) 179*09864c1cSStefan-gabriel Mirea ; 180*09864c1cSStefan-gabriel Mirea 181*09864c1cSStefan-gabriel Mirea xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 182*09864c1cSStefan-gabriel Mirea sport->icount.tx++; 183*09864c1cSStefan-gabriel Mirea 184*09864c1cSStefan-gabriel Mirea writel(status | LINFLEXD_UARTSR_DTFTFF, 185*09864c1cSStefan-gabriel Mirea sport->membase + UARTSR); 186*09864c1cSStefan-gabriel Mirea } 187*09864c1cSStefan-gabriel Mirea 188*09864c1cSStefan-gabriel Mirea if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 189*09864c1cSStefan-gabriel Mirea uart_write_wakeup(sport); 190*09864c1cSStefan-gabriel Mirea 191*09864c1cSStefan-gabriel Mirea if (uart_circ_empty(xmit)) 192*09864c1cSStefan-gabriel Mirea linflex_stop_tx(sport); 193*09864c1cSStefan-gabriel Mirea } 194*09864c1cSStefan-gabriel Mirea 195*09864c1cSStefan-gabriel Mirea static void linflex_start_tx(struct uart_port *port) 196*09864c1cSStefan-gabriel Mirea { 197*09864c1cSStefan-gabriel Mirea unsigned long ier; 198*09864c1cSStefan-gabriel Mirea 199*09864c1cSStefan-gabriel Mirea linflex_transmit_buffer(port); 200*09864c1cSStefan-gabriel Mirea ier = readl(port->membase + LINIER); 201*09864c1cSStefan-gabriel Mirea writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER); 202*09864c1cSStefan-gabriel Mirea } 203*09864c1cSStefan-gabriel Mirea 204*09864c1cSStefan-gabriel Mirea static irqreturn_t linflex_txint(int irq, void *dev_id) 205*09864c1cSStefan-gabriel Mirea { 206*09864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_id; 207*09864c1cSStefan-gabriel Mirea struct circ_buf *xmit = &sport->state->xmit; 208*09864c1cSStefan-gabriel Mirea unsigned long flags; 209*09864c1cSStefan-gabriel Mirea unsigned long status; 210*09864c1cSStefan-gabriel Mirea 211*09864c1cSStefan-gabriel Mirea spin_lock_irqsave(&sport->lock, flags); 212*09864c1cSStefan-gabriel Mirea 213*09864c1cSStefan-gabriel Mirea if (sport->x_char) { 214*09864c1cSStefan-gabriel Mirea writeb(sport->x_char, sport->membase + BDRL); 215*09864c1cSStefan-gabriel Mirea 216*09864c1cSStefan-gabriel Mirea /* waiting for data transmission completed */ 217*09864c1cSStefan-gabriel Mirea while (((status = readl(sport->membase + UARTSR)) & 218*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) != LINFLEXD_UARTSR_DTFTFF) 219*09864c1cSStefan-gabriel Mirea ; 220*09864c1cSStefan-gabriel Mirea 221*09864c1cSStefan-gabriel Mirea writel(status | LINFLEXD_UARTSR_DTFTFF, 222*09864c1cSStefan-gabriel Mirea sport->membase + UARTSR); 223*09864c1cSStefan-gabriel Mirea 224*09864c1cSStefan-gabriel Mirea goto out; 225*09864c1cSStefan-gabriel Mirea } 226*09864c1cSStefan-gabriel Mirea 227*09864c1cSStefan-gabriel Mirea if (uart_circ_empty(xmit) || uart_tx_stopped(sport)) { 228*09864c1cSStefan-gabriel Mirea linflex_stop_tx(sport); 229*09864c1cSStefan-gabriel Mirea goto out; 230*09864c1cSStefan-gabriel Mirea } 231*09864c1cSStefan-gabriel Mirea 232*09864c1cSStefan-gabriel Mirea linflex_transmit_buffer(sport); 233*09864c1cSStefan-gabriel Mirea 234*09864c1cSStefan-gabriel Mirea if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 235*09864c1cSStefan-gabriel Mirea uart_write_wakeup(sport); 236*09864c1cSStefan-gabriel Mirea 237*09864c1cSStefan-gabriel Mirea out: 238*09864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&sport->lock, flags); 239*09864c1cSStefan-gabriel Mirea return IRQ_HANDLED; 240*09864c1cSStefan-gabriel Mirea } 241*09864c1cSStefan-gabriel Mirea 242*09864c1cSStefan-gabriel Mirea static irqreturn_t linflex_rxint(int irq, void *dev_id) 243*09864c1cSStefan-gabriel Mirea { 244*09864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_id; 245*09864c1cSStefan-gabriel Mirea unsigned int flg; 246*09864c1cSStefan-gabriel Mirea struct tty_port *port = &sport->state->port; 247*09864c1cSStefan-gabriel Mirea unsigned long flags, status; 248*09864c1cSStefan-gabriel Mirea unsigned char rx; 249*09864c1cSStefan-gabriel Mirea 250*09864c1cSStefan-gabriel Mirea spin_lock_irqsave(&sport->lock, flags); 251*09864c1cSStefan-gabriel Mirea 252*09864c1cSStefan-gabriel Mirea status = readl(sport->membase + UARTSR); 253*09864c1cSStefan-gabriel Mirea while (status & LINFLEXD_UARTSR_RMB) { 254*09864c1cSStefan-gabriel Mirea rx = readb(sport->membase + BDRM); 255*09864c1cSStefan-gabriel Mirea flg = TTY_NORMAL; 256*09864c1cSStefan-gabriel Mirea sport->icount.rx++; 257*09864c1cSStefan-gabriel Mirea 258*09864c1cSStefan-gabriel Mirea if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_SZF | 259*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_FEF | LINFLEXD_UARTSR_PE)) { 260*09864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_SZF) 261*09864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_SZF; 262*09864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_BOF) 263*09864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_BOF; 264*09864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_FEF) 265*09864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_FEF; 266*09864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_PE) 267*09864c1cSStefan-gabriel Mirea status |= LINFLEXD_UARTSR_PE; 268*09864c1cSStefan-gabriel Mirea } 269*09864c1cSStefan-gabriel Mirea 270*09864c1cSStefan-gabriel Mirea writel(status | LINFLEXD_UARTSR_RMB | LINFLEXD_UARTSR_DRFRFE, 271*09864c1cSStefan-gabriel Mirea sport->membase + UARTSR); 272*09864c1cSStefan-gabriel Mirea status = readl(sport->membase + UARTSR); 273*09864c1cSStefan-gabriel Mirea 274*09864c1cSStefan-gabriel Mirea if (uart_handle_sysrq_char(sport, (unsigned char)rx)) 275*09864c1cSStefan-gabriel Mirea continue; 276*09864c1cSStefan-gabriel Mirea 277*09864c1cSStefan-gabriel Mirea #ifdef SUPPORT_SYSRQ 278*09864c1cSStefan-gabriel Mirea sport->sysrq = 0; 279*09864c1cSStefan-gabriel Mirea #endif 280*09864c1cSStefan-gabriel Mirea tty_insert_flip_char(port, rx, flg); 281*09864c1cSStefan-gabriel Mirea } 282*09864c1cSStefan-gabriel Mirea 283*09864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&sport->lock, flags); 284*09864c1cSStefan-gabriel Mirea 285*09864c1cSStefan-gabriel Mirea tty_flip_buffer_push(port); 286*09864c1cSStefan-gabriel Mirea 287*09864c1cSStefan-gabriel Mirea return IRQ_HANDLED; 288*09864c1cSStefan-gabriel Mirea } 289*09864c1cSStefan-gabriel Mirea 290*09864c1cSStefan-gabriel Mirea static irqreturn_t linflex_int(int irq, void *dev_id) 291*09864c1cSStefan-gabriel Mirea { 292*09864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_id; 293*09864c1cSStefan-gabriel Mirea unsigned long status; 294*09864c1cSStefan-gabriel Mirea 295*09864c1cSStefan-gabriel Mirea status = readl(sport->membase + UARTSR); 296*09864c1cSStefan-gabriel Mirea 297*09864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_DRFRFE) 298*09864c1cSStefan-gabriel Mirea linflex_rxint(irq, dev_id); 299*09864c1cSStefan-gabriel Mirea if (status & LINFLEXD_UARTSR_DTFTFF) 300*09864c1cSStefan-gabriel Mirea linflex_txint(irq, dev_id); 301*09864c1cSStefan-gabriel Mirea 302*09864c1cSStefan-gabriel Mirea return IRQ_HANDLED; 303*09864c1cSStefan-gabriel Mirea } 304*09864c1cSStefan-gabriel Mirea 305*09864c1cSStefan-gabriel Mirea /* return TIOCSER_TEMT when transmitter is not busy */ 306*09864c1cSStefan-gabriel Mirea static unsigned int linflex_tx_empty(struct uart_port *port) 307*09864c1cSStefan-gabriel Mirea { 308*09864c1cSStefan-gabriel Mirea unsigned long status; 309*09864c1cSStefan-gabriel Mirea 310*09864c1cSStefan-gabriel Mirea status = readl(port->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF; 311*09864c1cSStefan-gabriel Mirea 312*09864c1cSStefan-gabriel Mirea return status ? TIOCSER_TEMT : 0; 313*09864c1cSStefan-gabriel Mirea } 314*09864c1cSStefan-gabriel Mirea 315*09864c1cSStefan-gabriel Mirea static unsigned int linflex_get_mctrl(struct uart_port *port) 316*09864c1cSStefan-gabriel Mirea { 317*09864c1cSStefan-gabriel Mirea return 0; 318*09864c1cSStefan-gabriel Mirea } 319*09864c1cSStefan-gabriel Mirea 320*09864c1cSStefan-gabriel Mirea static void linflex_set_mctrl(struct uart_port *port, unsigned int mctrl) 321*09864c1cSStefan-gabriel Mirea { 322*09864c1cSStefan-gabriel Mirea } 323*09864c1cSStefan-gabriel Mirea 324*09864c1cSStefan-gabriel Mirea static void linflex_break_ctl(struct uart_port *port, int break_state) 325*09864c1cSStefan-gabriel Mirea { 326*09864c1cSStefan-gabriel Mirea } 327*09864c1cSStefan-gabriel Mirea 328*09864c1cSStefan-gabriel Mirea static void linflex_setup_watermark(struct uart_port *sport) 329*09864c1cSStefan-gabriel Mirea { 330*09864c1cSStefan-gabriel Mirea unsigned long cr, ier, cr1; 331*09864c1cSStefan-gabriel Mirea 332*09864c1cSStefan-gabriel Mirea /* Disable transmission/reception */ 333*09864c1cSStefan-gabriel Mirea ier = readl(sport->membase + LINIER); 334*09864c1cSStefan-gabriel Mirea ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); 335*09864c1cSStefan-gabriel Mirea writel(ier, sport->membase + LINIER); 336*09864c1cSStefan-gabriel Mirea 337*09864c1cSStefan-gabriel Mirea cr = readl(sport->membase + UARTCR); 338*09864c1cSStefan-gabriel Mirea cr &= ~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN); 339*09864c1cSStefan-gabriel Mirea writel(cr, sport->membase + UARTCR); 340*09864c1cSStefan-gabriel Mirea 341*09864c1cSStefan-gabriel Mirea /* Enter initialization mode by setting INIT bit */ 342*09864c1cSStefan-gabriel Mirea 343*09864c1cSStefan-gabriel Mirea /* set the Linflex in master mode and activate by-pass filter */ 344*09864c1cSStefan-gabriel Mirea cr1 = LINFLEXD_LINCR1_BF | LINFLEXD_LINCR1_MME 345*09864c1cSStefan-gabriel Mirea | LINFLEXD_LINCR1_INIT; 346*09864c1cSStefan-gabriel Mirea writel(cr1, sport->membase + LINCR1); 347*09864c1cSStefan-gabriel Mirea 348*09864c1cSStefan-gabriel Mirea /* wait for init mode entry */ 349*09864c1cSStefan-gabriel Mirea while ((readl(sport->membase + LINSR) 350*09864c1cSStefan-gabriel Mirea & LINFLEXD_LINSR_LINS_MASK) 351*09864c1cSStefan-gabriel Mirea != LINFLEXD_LINSR_LINS_INITMODE) 352*09864c1cSStefan-gabriel Mirea ; 353*09864c1cSStefan-gabriel Mirea 354*09864c1cSStefan-gabriel Mirea /* 355*09864c1cSStefan-gabriel Mirea * UART = 0x1; - Linflex working in UART mode 356*09864c1cSStefan-gabriel Mirea * TXEN = 0x1; - Enable transmission of data now 357*09864c1cSStefan-gabriel Mirea * RXEn = 0x1; - Receiver enabled 358*09864c1cSStefan-gabriel Mirea * WL0 = 0x1; - 8 bit data 359*09864c1cSStefan-gabriel Mirea * PCE = 0x0; - No parity 360*09864c1cSStefan-gabriel Mirea */ 361*09864c1cSStefan-gabriel Mirea 362*09864c1cSStefan-gabriel Mirea /* set UART bit to allow writing other bits */ 363*09864c1cSStefan-gabriel Mirea writel(LINFLEXD_UARTCR_UART, sport->membase + UARTCR); 364*09864c1cSStefan-gabriel Mirea 365*09864c1cSStefan-gabriel Mirea cr = (LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN | 366*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART); 367*09864c1cSStefan-gabriel Mirea 368*09864c1cSStefan-gabriel Mirea writel(cr, sport->membase + UARTCR); 369*09864c1cSStefan-gabriel Mirea 370*09864c1cSStefan-gabriel Mirea cr1 &= ~(LINFLEXD_LINCR1_INIT); 371*09864c1cSStefan-gabriel Mirea 372*09864c1cSStefan-gabriel Mirea writel(cr1, sport->membase + LINCR1); 373*09864c1cSStefan-gabriel Mirea 374*09864c1cSStefan-gabriel Mirea ier = readl(sport->membase + LINIER); 375*09864c1cSStefan-gabriel Mirea ier |= LINFLEXD_LINIER_DRIE; 376*09864c1cSStefan-gabriel Mirea ier |= LINFLEXD_LINIER_DTIE; 377*09864c1cSStefan-gabriel Mirea 378*09864c1cSStefan-gabriel Mirea writel(ier, sport->membase + LINIER); 379*09864c1cSStefan-gabriel Mirea } 380*09864c1cSStefan-gabriel Mirea 381*09864c1cSStefan-gabriel Mirea static int linflex_startup(struct uart_port *port) 382*09864c1cSStefan-gabriel Mirea { 383*09864c1cSStefan-gabriel Mirea int ret = 0; 384*09864c1cSStefan-gabriel Mirea unsigned long flags; 385*09864c1cSStefan-gabriel Mirea 386*09864c1cSStefan-gabriel Mirea spin_lock_irqsave(&port->lock, flags); 387*09864c1cSStefan-gabriel Mirea 388*09864c1cSStefan-gabriel Mirea linflex_setup_watermark(port); 389*09864c1cSStefan-gabriel Mirea 390*09864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&port->lock, flags); 391*09864c1cSStefan-gabriel Mirea 392*09864c1cSStefan-gabriel Mirea ret = devm_request_irq(port->dev, port->irq, linflex_int, 0, 393*09864c1cSStefan-gabriel Mirea DRIVER_NAME, port); 394*09864c1cSStefan-gabriel Mirea 395*09864c1cSStefan-gabriel Mirea return ret; 396*09864c1cSStefan-gabriel Mirea } 397*09864c1cSStefan-gabriel Mirea 398*09864c1cSStefan-gabriel Mirea static void linflex_shutdown(struct uart_port *port) 399*09864c1cSStefan-gabriel Mirea { 400*09864c1cSStefan-gabriel Mirea unsigned long ier; 401*09864c1cSStefan-gabriel Mirea unsigned long flags; 402*09864c1cSStefan-gabriel Mirea 403*09864c1cSStefan-gabriel Mirea spin_lock_irqsave(&port->lock, flags); 404*09864c1cSStefan-gabriel Mirea 405*09864c1cSStefan-gabriel Mirea /* disable interrupts */ 406*09864c1cSStefan-gabriel Mirea ier = readl(port->membase + LINIER); 407*09864c1cSStefan-gabriel Mirea ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); 408*09864c1cSStefan-gabriel Mirea writel(ier, port->membase + LINIER); 409*09864c1cSStefan-gabriel Mirea 410*09864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&port->lock, flags); 411*09864c1cSStefan-gabriel Mirea 412*09864c1cSStefan-gabriel Mirea devm_free_irq(port->dev, port->irq, port); 413*09864c1cSStefan-gabriel Mirea } 414*09864c1cSStefan-gabriel Mirea 415*09864c1cSStefan-gabriel Mirea static void 416*09864c1cSStefan-gabriel Mirea linflex_set_termios(struct uart_port *port, struct ktermios *termios, 417*09864c1cSStefan-gabriel Mirea struct ktermios *old) 418*09864c1cSStefan-gabriel Mirea { 419*09864c1cSStefan-gabriel Mirea unsigned long flags; 420*09864c1cSStefan-gabriel Mirea unsigned long cr, old_cr, cr1; 421*09864c1cSStefan-gabriel Mirea unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; 422*09864c1cSStefan-gabriel Mirea 423*09864c1cSStefan-gabriel Mirea cr = readl(port->membase + UARTCR); 424*09864c1cSStefan-gabriel Mirea old_cr = cr; 425*09864c1cSStefan-gabriel Mirea 426*09864c1cSStefan-gabriel Mirea /* Enter initialization mode by setting INIT bit */ 427*09864c1cSStefan-gabriel Mirea cr1 = readl(port->membase + LINCR1); 428*09864c1cSStefan-gabriel Mirea cr1 |= LINFLEXD_LINCR1_INIT; 429*09864c1cSStefan-gabriel Mirea writel(cr1, port->membase + LINCR1); 430*09864c1cSStefan-gabriel Mirea 431*09864c1cSStefan-gabriel Mirea /* wait for init mode entry */ 432*09864c1cSStefan-gabriel Mirea while ((readl(port->membase + LINSR) 433*09864c1cSStefan-gabriel Mirea & LINFLEXD_LINSR_LINS_MASK) 434*09864c1cSStefan-gabriel Mirea != LINFLEXD_LINSR_LINS_INITMODE) 435*09864c1cSStefan-gabriel Mirea ; 436*09864c1cSStefan-gabriel Mirea 437*09864c1cSStefan-gabriel Mirea /* 438*09864c1cSStefan-gabriel Mirea * only support CS8 and CS7, and for CS7 must enable PE. 439*09864c1cSStefan-gabriel Mirea * supported mode: 440*09864c1cSStefan-gabriel Mirea * - (7,e/o,1) 441*09864c1cSStefan-gabriel Mirea * - (8,n,1) 442*09864c1cSStefan-gabriel Mirea * - (8,e/o,1) 443*09864c1cSStefan-gabriel Mirea */ 444*09864c1cSStefan-gabriel Mirea /* enter the UART into configuration mode */ 445*09864c1cSStefan-gabriel Mirea 446*09864c1cSStefan-gabriel Mirea while ((termios->c_cflag & CSIZE) != CS8 && 447*09864c1cSStefan-gabriel Mirea (termios->c_cflag & CSIZE) != CS7) { 448*09864c1cSStefan-gabriel Mirea termios->c_cflag &= ~CSIZE; 449*09864c1cSStefan-gabriel Mirea termios->c_cflag |= old_csize; 450*09864c1cSStefan-gabriel Mirea old_csize = CS8; 451*09864c1cSStefan-gabriel Mirea } 452*09864c1cSStefan-gabriel Mirea 453*09864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) == CS7) { 454*09864c1cSStefan-gabriel Mirea /* Word length: WL1WL0:00 */ 455*09864c1cSStefan-gabriel Mirea cr = old_cr & ~LINFLEXD_UARTCR_WL1 & ~LINFLEXD_UARTCR_WL0; 456*09864c1cSStefan-gabriel Mirea } 457*09864c1cSStefan-gabriel Mirea 458*09864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) == CS8) { 459*09864c1cSStefan-gabriel Mirea /* Word length: WL1WL0:01 */ 460*09864c1cSStefan-gabriel Mirea cr = (old_cr | LINFLEXD_UARTCR_WL0) & ~LINFLEXD_UARTCR_WL1; 461*09864c1cSStefan-gabriel Mirea } 462*09864c1cSStefan-gabriel Mirea 463*09864c1cSStefan-gabriel Mirea if (termios->c_cflag & CMSPAR) { 464*09864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) != CS8) { 465*09864c1cSStefan-gabriel Mirea termios->c_cflag &= ~CSIZE; 466*09864c1cSStefan-gabriel Mirea termios->c_cflag |= CS8; 467*09864c1cSStefan-gabriel Mirea } 468*09864c1cSStefan-gabriel Mirea /* has a space/sticky bit */ 469*09864c1cSStefan-gabriel Mirea cr |= LINFLEXD_UARTCR_WL0; 470*09864c1cSStefan-gabriel Mirea } 471*09864c1cSStefan-gabriel Mirea 472*09864c1cSStefan-gabriel Mirea if (termios->c_cflag & CSTOPB) 473*09864c1cSStefan-gabriel Mirea termios->c_cflag &= ~CSTOPB; 474*09864c1cSStefan-gabriel Mirea 475*09864c1cSStefan-gabriel Mirea /* parity must be enabled when CS7 to match 8-bits format */ 476*09864c1cSStefan-gabriel Mirea if ((termios->c_cflag & CSIZE) == CS7) 477*09864c1cSStefan-gabriel Mirea termios->c_cflag |= PARENB; 478*09864c1cSStefan-gabriel Mirea 479*09864c1cSStefan-gabriel Mirea if ((termios->c_cflag & PARENB)) { 480*09864c1cSStefan-gabriel Mirea cr |= LINFLEXD_UARTCR_PCE; 481*09864c1cSStefan-gabriel Mirea if (termios->c_cflag & PARODD) 482*09864c1cSStefan-gabriel Mirea cr = (cr | LINFLEXD_UARTCR_PC0) & 483*09864c1cSStefan-gabriel Mirea (~LINFLEXD_UARTCR_PC1); 484*09864c1cSStefan-gabriel Mirea else 485*09864c1cSStefan-gabriel Mirea cr = cr & (~LINFLEXD_UARTCR_PC1 & 486*09864c1cSStefan-gabriel Mirea ~LINFLEXD_UARTCR_PC0); 487*09864c1cSStefan-gabriel Mirea } else { 488*09864c1cSStefan-gabriel Mirea cr &= ~LINFLEXD_UARTCR_PCE; 489*09864c1cSStefan-gabriel Mirea } 490*09864c1cSStefan-gabriel Mirea 491*09864c1cSStefan-gabriel Mirea spin_lock_irqsave(&port->lock, flags); 492*09864c1cSStefan-gabriel Mirea 493*09864c1cSStefan-gabriel Mirea port->read_status_mask = 0; 494*09864c1cSStefan-gabriel Mirea 495*09864c1cSStefan-gabriel Mirea if (termios->c_iflag & INPCK) 496*09864c1cSStefan-gabriel Mirea port->read_status_mask |= (LINFLEXD_UARTSR_FEF | 497*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE0 | 498*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE1 | 499*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE2 | 500*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_PE3); 501*09864c1cSStefan-gabriel Mirea if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 502*09864c1cSStefan-gabriel Mirea port->read_status_mask |= LINFLEXD_UARTSR_FEF; 503*09864c1cSStefan-gabriel Mirea 504*09864c1cSStefan-gabriel Mirea /* characters to ignore */ 505*09864c1cSStefan-gabriel Mirea port->ignore_status_mask = 0; 506*09864c1cSStefan-gabriel Mirea if (termios->c_iflag & IGNPAR) 507*09864c1cSStefan-gabriel Mirea port->ignore_status_mask |= LINFLEXD_UARTSR_PE; 508*09864c1cSStefan-gabriel Mirea if (termios->c_iflag & IGNBRK) { 509*09864c1cSStefan-gabriel Mirea port->ignore_status_mask |= LINFLEXD_UARTSR_PE; 510*09864c1cSStefan-gabriel Mirea /* 511*09864c1cSStefan-gabriel Mirea * if we're ignoring parity and break indicators, 512*09864c1cSStefan-gabriel Mirea * ignore overruns too (for real raw support). 513*09864c1cSStefan-gabriel Mirea */ 514*09864c1cSStefan-gabriel Mirea if (termios->c_iflag & IGNPAR) 515*09864c1cSStefan-gabriel Mirea port->ignore_status_mask |= LINFLEXD_UARTSR_BOF; 516*09864c1cSStefan-gabriel Mirea } 517*09864c1cSStefan-gabriel Mirea 518*09864c1cSStefan-gabriel Mirea writel(cr, port->membase + UARTCR); 519*09864c1cSStefan-gabriel Mirea 520*09864c1cSStefan-gabriel Mirea cr1 &= ~(LINFLEXD_LINCR1_INIT); 521*09864c1cSStefan-gabriel Mirea 522*09864c1cSStefan-gabriel Mirea writel(cr1, port->membase + LINCR1); 523*09864c1cSStefan-gabriel Mirea 524*09864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&port->lock, flags); 525*09864c1cSStefan-gabriel Mirea } 526*09864c1cSStefan-gabriel Mirea 527*09864c1cSStefan-gabriel Mirea static const char *linflex_type(struct uart_port *port) 528*09864c1cSStefan-gabriel Mirea { 529*09864c1cSStefan-gabriel Mirea return "FSL_LINFLEX"; 530*09864c1cSStefan-gabriel Mirea } 531*09864c1cSStefan-gabriel Mirea 532*09864c1cSStefan-gabriel Mirea static void linflex_release_port(struct uart_port *port) 533*09864c1cSStefan-gabriel Mirea { 534*09864c1cSStefan-gabriel Mirea /* nothing to do */ 535*09864c1cSStefan-gabriel Mirea } 536*09864c1cSStefan-gabriel Mirea 537*09864c1cSStefan-gabriel Mirea static int linflex_request_port(struct uart_port *port) 538*09864c1cSStefan-gabriel Mirea { 539*09864c1cSStefan-gabriel Mirea return 0; 540*09864c1cSStefan-gabriel Mirea } 541*09864c1cSStefan-gabriel Mirea 542*09864c1cSStefan-gabriel Mirea /* configure/auto-configure the port */ 543*09864c1cSStefan-gabriel Mirea static void linflex_config_port(struct uart_port *port, int flags) 544*09864c1cSStefan-gabriel Mirea { 545*09864c1cSStefan-gabriel Mirea if (flags & UART_CONFIG_TYPE) 546*09864c1cSStefan-gabriel Mirea port->type = PORT_LINFLEXUART; 547*09864c1cSStefan-gabriel Mirea } 548*09864c1cSStefan-gabriel Mirea 549*09864c1cSStefan-gabriel Mirea static const struct uart_ops linflex_pops = { 550*09864c1cSStefan-gabriel Mirea .tx_empty = linflex_tx_empty, 551*09864c1cSStefan-gabriel Mirea .set_mctrl = linflex_set_mctrl, 552*09864c1cSStefan-gabriel Mirea .get_mctrl = linflex_get_mctrl, 553*09864c1cSStefan-gabriel Mirea .stop_tx = linflex_stop_tx, 554*09864c1cSStefan-gabriel Mirea .start_tx = linflex_start_tx, 555*09864c1cSStefan-gabriel Mirea .stop_rx = linflex_stop_rx, 556*09864c1cSStefan-gabriel Mirea .break_ctl = linflex_break_ctl, 557*09864c1cSStefan-gabriel Mirea .startup = linflex_startup, 558*09864c1cSStefan-gabriel Mirea .shutdown = linflex_shutdown, 559*09864c1cSStefan-gabriel Mirea .set_termios = linflex_set_termios, 560*09864c1cSStefan-gabriel Mirea .type = linflex_type, 561*09864c1cSStefan-gabriel Mirea .request_port = linflex_request_port, 562*09864c1cSStefan-gabriel Mirea .release_port = linflex_release_port, 563*09864c1cSStefan-gabriel Mirea .config_port = linflex_config_port, 564*09864c1cSStefan-gabriel Mirea }; 565*09864c1cSStefan-gabriel Mirea 566*09864c1cSStefan-gabriel Mirea static struct uart_port *linflex_ports[UART_NR]; 567*09864c1cSStefan-gabriel Mirea 568*09864c1cSStefan-gabriel Mirea #ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE 569*09864c1cSStefan-gabriel Mirea static void linflex_console_putchar(struct uart_port *port, int ch) 570*09864c1cSStefan-gabriel Mirea { 571*09864c1cSStefan-gabriel Mirea unsigned long cr; 572*09864c1cSStefan-gabriel Mirea 573*09864c1cSStefan-gabriel Mirea cr = readl(port->membase + UARTCR); 574*09864c1cSStefan-gabriel Mirea 575*09864c1cSStefan-gabriel Mirea writeb(ch, port->membase + BDRL); 576*09864c1cSStefan-gabriel Mirea 577*09864c1cSStefan-gabriel Mirea if (!(cr & LINFLEXD_UARTCR_TFBM)) 578*09864c1cSStefan-gabriel Mirea while ((readl(port->membase + UARTSR) & 579*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) 580*09864c1cSStefan-gabriel Mirea != LINFLEXD_UARTSR_DTFTFF) 581*09864c1cSStefan-gabriel Mirea ; 582*09864c1cSStefan-gabriel Mirea else 583*09864c1cSStefan-gabriel Mirea while (readl(port->membase + UARTSR) & 584*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF) 585*09864c1cSStefan-gabriel Mirea ; 586*09864c1cSStefan-gabriel Mirea 587*09864c1cSStefan-gabriel Mirea if (!(cr & LINFLEXD_UARTCR_TFBM)) { 588*09864c1cSStefan-gabriel Mirea writel((readl(port->membase + UARTSR) | 589*09864c1cSStefan-gabriel Mirea LINFLEXD_UARTSR_DTFTFF), 590*09864c1cSStefan-gabriel Mirea port->membase + UARTSR); 591*09864c1cSStefan-gabriel Mirea } 592*09864c1cSStefan-gabriel Mirea } 593*09864c1cSStefan-gabriel Mirea 594*09864c1cSStefan-gabriel Mirea static void linflex_earlycon_putchar(struct uart_port *port, int ch) 595*09864c1cSStefan-gabriel Mirea { 596*09864c1cSStefan-gabriel Mirea unsigned long flags; 597*09864c1cSStefan-gabriel Mirea char *ret; 598*09864c1cSStefan-gabriel Mirea 599*09864c1cSStefan-gabriel Mirea if (!linflex_earlycon_same_instance) { 600*09864c1cSStefan-gabriel Mirea linflex_console_putchar(port, ch); 601*09864c1cSStefan-gabriel Mirea return; 602*09864c1cSStefan-gabriel Mirea } 603*09864c1cSStefan-gabriel Mirea 604*09864c1cSStefan-gabriel Mirea spin_lock_irqsave(&init_lock, flags); 605*09864c1cSStefan-gabriel Mirea if (!during_init) 606*09864c1cSStefan-gabriel Mirea goto outside_init; 607*09864c1cSStefan-gabriel Mirea 608*09864c1cSStefan-gabriel Mirea if (earlycon_buf.len >= 1 << CONFIG_LOG_BUF_SHIFT) 609*09864c1cSStefan-gabriel Mirea goto init_release; 610*09864c1cSStefan-gabriel Mirea 611*09864c1cSStefan-gabriel Mirea if (!earlycon_buf.cap) { 612*09864c1cSStefan-gabriel Mirea earlycon_buf.content = kmalloc(EARLYCON_BUFFER_INITIAL_CAP, 613*09864c1cSStefan-gabriel Mirea GFP_ATOMIC); 614*09864c1cSStefan-gabriel Mirea earlycon_buf.cap = earlycon_buf.content ? 615*09864c1cSStefan-gabriel Mirea EARLYCON_BUFFER_INITIAL_CAP : 0; 616*09864c1cSStefan-gabriel Mirea } else if (earlycon_buf.len == earlycon_buf.cap) { 617*09864c1cSStefan-gabriel Mirea ret = krealloc(earlycon_buf.content, earlycon_buf.cap << 1, 618*09864c1cSStefan-gabriel Mirea GFP_ATOMIC); 619*09864c1cSStefan-gabriel Mirea if (ret) { 620*09864c1cSStefan-gabriel Mirea earlycon_buf.content = ret; 621*09864c1cSStefan-gabriel Mirea earlycon_buf.cap <<= 1; 622*09864c1cSStefan-gabriel Mirea } 623*09864c1cSStefan-gabriel Mirea } 624*09864c1cSStefan-gabriel Mirea 625*09864c1cSStefan-gabriel Mirea if (earlycon_buf.len < earlycon_buf.cap) 626*09864c1cSStefan-gabriel Mirea earlycon_buf.content[earlycon_buf.len++] = ch; 627*09864c1cSStefan-gabriel Mirea 628*09864c1cSStefan-gabriel Mirea goto init_release; 629*09864c1cSStefan-gabriel Mirea 630*09864c1cSStefan-gabriel Mirea outside_init: 631*09864c1cSStefan-gabriel Mirea linflex_console_putchar(port, ch); 632*09864c1cSStefan-gabriel Mirea init_release: 633*09864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&init_lock, flags); 634*09864c1cSStefan-gabriel Mirea } 635*09864c1cSStefan-gabriel Mirea 636*09864c1cSStefan-gabriel Mirea static void linflex_string_write(struct uart_port *sport, const char *s, 637*09864c1cSStefan-gabriel Mirea unsigned int count) 638*09864c1cSStefan-gabriel Mirea { 639*09864c1cSStefan-gabriel Mirea unsigned long cr, ier = 0; 640*09864c1cSStefan-gabriel Mirea 641*09864c1cSStefan-gabriel Mirea ier = readl(sport->membase + LINIER); 642*09864c1cSStefan-gabriel Mirea linflex_stop_tx(sport); 643*09864c1cSStefan-gabriel Mirea 644*09864c1cSStefan-gabriel Mirea cr = readl(sport->membase + UARTCR); 645*09864c1cSStefan-gabriel Mirea cr |= (LINFLEXD_UARTCR_TXEN); 646*09864c1cSStefan-gabriel Mirea writel(cr, sport->membase + UARTCR); 647*09864c1cSStefan-gabriel Mirea 648*09864c1cSStefan-gabriel Mirea uart_console_write(sport, s, count, linflex_console_putchar); 649*09864c1cSStefan-gabriel Mirea 650*09864c1cSStefan-gabriel Mirea writel(ier, sport->membase + LINIER); 651*09864c1cSStefan-gabriel Mirea } 652*09864c1cSStefan-gabriel Mirea 653*09864c1cSStefan-gabriel Mirea static void 654*09864c1cSStefan-gabriel Mirea linflex_console_write(struct console *co, const char *s, unsigned int count) 655*09864c1cSStefan-gabriel Mirea { 656*09864c1cSStefan-gabriel Mirea struct uart_port *sport = linflex_ports[co->index]; 657*09864c1cSStefan-gabriel Mirea unsigned long flags; 658*09864c1cSStefan-gabriel Mirea int locked = 1; 659*09864c1cSStefan-gabriel Mirea 660*09864c1cSStefan-gabriel Mirea if (sport->sysrq) 661*09864c1cSStefan-gabriel Mirea locked = 0; 662*09864c1cSStefan-gabriel Mirea else if (oops_in_progress) 663*09864c1cSStefan-gabriel Mirea locked = spin_trylock_irqsave(&sport->lock, flags); 664*09864c1cSStefan-gabriel Mirea else 665*09864c1cSStefan-gabriel Mirea spin_lock_irqsave(&sport->lock, flags); 666*09864c1cSStefan-gabriel Mirea 667*09864c1cSStefan-gabriel Mirea linflex_string_write(sport, s, count); 668*09864c1cSStefan-gabriel Mirea 669*09864c1cSStefan-gabriel Mirea if (locked) 670*09864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&sport->lock, flags); 671*09864c1cSStefan-gabriel Mirea } 672*09864c1cSStefan-gabriel Mirea 673*09864c1cSStefan-gabriel Mirea /* 674*09864c1cSStefan-gabriel Mirea * if the port was already initialised (eg, by a boot loader), 675*09864c1cSStefan-gabriel Mirea * try to determine the current setup. 676*09864c1cSStefan-gabriel Mirea */ 677*09864c1cSStefan-gabriel Mirea static void __init 678*09864c1cSStefan-gabriel Mirea linflex_console_get_options(struct uart_port *sport, int *parity, int *bits) 679*09864c1cSStefan-gabriel Mirea { 680*09864c1cSStefan-gabriel Mirea unsigned long cr; 681*09864c1cSStefan-gabriel Mirea 682*09864c1cSStefan-gabriel Mirea cr = readl(sport->membase + UARTCR); 683*09864c1cSStefan-gabriel Mirea cr &= LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN; 684*09864c1cSStefan-gabriel Mirea 685*09864c1cSStefan-gabriel Mirea if (!cr) 686*09864c1cSStefan-gabriel Mirea return; 687*09864c1cSStefan-gabriel Mirea 688*09864c1cSStefan-gabriel Mirea /* ok, the port was enabled */ 689*09864c1cSStefan-gabriel Mirea 690*09864c1cSStefan-gabriel Mirea *parity = 'n'; 691*09864c1cSStefan-gabriel Mirea if (cr & LINFLEXD_UARTCR_PCE) { 692*09864c1cSStefan-gabriel Mirea if (cr & LINFLEXD_UARTCR_PC0) 693*09864c1cSStefan-gabriel Mirea *parity = 'o'; 694*09864c1cSStefan-gabriel Mirea else 695*09864c1cSStefan-gabriel Mirea *parity = 'e'; 696*09864c1cSStefan-gabriel Mirea } 697*09864c1cSStefan-gabriel Mirea 698*09864c1cSStefan-gabriel Mirea if ((cr & LINFLEXD_UARTCR_WL0) && ((cr & LINFLEXD_UARTCR_WL1) == 0)) { 699*09864c1cSStefan-gabriel Mirea if (cr & LINFLEXD_UARTCR_PCE) 700*09864c1cSStefan-gabriel Mirea *bits = 9; 701*09864c1cSStefan-gabriel Mirea else 702*09864c1cSStefan-gabriel Mirea *bits = 8; 703*09864c1cSStefan-gabriel Mirea } 704*09864c1cSStefan-gabriel Mirea } 705*09864c1cSStefan-gabriel Mirea 706*09864c1cSStefan-gabriel Mirea static int __init linflex_console_setup(struct console *co, char *options) 707*09864c1cSStefan-gabriel Mirea { 708*09864c1cSStefan-gabriel Mirea struct uart_port *sport; 709*09864c1cSStefan-gabriel Mirea int baud = 115200; 710*09864c1cSStefan-gabriel Mirea int bits = 8; 711*09864c1cSStefan-gabriel Mirea int parity = 'n'; 712*09864c1cSStefan-gabriel Mirea int flow = 'n'; 713*09864c1cSStefan-gabriel Mirea int ret; 714*09864c1cSStefan-gabriel Mirea int i; 715*09864c1cSStefan-gabriel Mirea unsigned long flags; 716*09864c1cSStefan-gabriel Mirea /* 717*09864c1cSStefan-gabriel Mirea * check whether an invalid uart number has been specified, and 718*09864c1cSStefan-gabriel Mirea * if so, search for the first available port that does have 719*09864c1cSStefan-gabriel Mirea * console support. 720*09864c1cSStefan-gabriel Mirea */ 721*09864c1cSStefan-gabriel Mirea if (co->index == -1 || co->index >= ARRAY_SIZE(linflex_ports)) 722*09864c1cSStefan-gabriel Mirea co->index = 0; 723*09864c1cSStefan-gabriel Mirea 724*09864c1cSStefan-gabriel Mirea sport = linflex_ports[co->index]; 725*09864c1cSStefan-gabriel Mirea if (!sport) 726*09864c1cSStefan-gabriel Mirea return -ENODEV; 727*09864c1cSStefan-gabriel Mirea 728*09864c1cSStefan-gabriel Mirea if (options) 729*09864c1cSStefan-gabriel Mirea uart_parse_options(options, &baud, &parity, &bits, &flow); 730*09864c1cSStefan-gabriel Mirea else 731*09864c1cSStefan-gabriel Mirea linflex_console_get_options(sport, &parity, &bits); 732*09864c1cSStefan-gabriel Mirea 733*09864c1cSStefan-gabriel Mirea if (earlycon_port && sport->mapbase == earlycon_port->mapbase) { 734*09864c1cSStefan-gabriel Mirea linflex_earlycon_same_instance = true; 735*09864c1cSStefan-gabriel Mirea 736*09864c1cSStefan-gabriel Mirea spin_lock_irqsave(&init_lock, flags); 737*09864c1cSStefan-gabriel Mirea during_init = true; 738*09864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&init_lock, flags); 739*09864c1cSStefan-gabriel Mirea 740*09864c1cSStefan-gabriel Mirea /* Workaround for character loss or output of many invalid 741*09864c1cSStefan-gabriel Mirea * characters, when INIT mode is entered shortly after a 742*09864c1cSStefan-gabriel Mirea * character has just been printed. 743*09864c1cSStefan-gabriel Mirea */ 744*09864c1cSStefan-gabriel Mirea udelay(PREINIT_DELAY); 745*09864c1cSStefan-gabriel Mirea } 746*09864c1cSStefan-gabriel Mirea 747*09864c1cSStefan-gabriel Mirea linflex_setup_watermark(sport); 748*09864c1cSStefan-gabriel Mirea 749*09864c1cSStefan-gabriel Mirea ret = uart_set_options(sport, co, baud, parity, bits, flow); 750*09864c1cSStefan-gabriel Mirea 751*09864c1cSStefan-gabriel Mirea if (!linflex_earlycon_same_instance) 752*09864c1cSStefan-gabriel Mirea goto done; 753*09864c1cSStefan-gabriel Mirea 754*09864c1cSStefan-gabriel Mirea spin_lock_irqsave(&init_lock, flags); 755*09864c1cSStefan-gabriel Mirea 756*09864c1cSStefan-gabriel Mirea /* Emptying buffer */ 757*09864c1cSStefan-gabriel Mirea if (earlycon_buf.len) { 758*09864c1cSStefan-gabriel Mirea for (i = 0; i < earlycon_buf.len; i++) 759*09864c1cSStefan-gabriel Mirea linflex_console_putchar(earlycon_port, 760*09864c1cSStefan-gabriel Mirea earlycon_buf.content[i]); 761*09864c1cSStefan-gabriel Mirea 762*09864c1cSStefan-gabriel Mirea kfree(earlycon_buf.content); 763*09864c1cSStefan-gabriel Mirea earlycon_buf.len = 0; 764*09864c1cSStefan-gabriel Mirea } 765*09864c1cSStefan-gabriel Mirea 766*09864c1cSStefan-gabriel Mirea during_init = false; 767*09864c1cSStefan-gabriel Mirea spin_unlock_irqrestore(&init_lock, flags); 768*09864c1cSStefan-gabriel Mirea 769*09864c1cSStefan-gabriel Mirea done: 770*09864c1cSStefan-gabriel Mirea return ret; 771*09864c1cSStefan-gabriel Mirea } 772*09864c1cSStefan-gabriel Mirea 773*09864c1cSStefan-gabriel Mirea static struct uart_driver linflex_reg; 774*09864c1cSStefan-gabriel Mirea static struct console linflex_console = { 775*09864c1cSStefan-gabriel Mirea .name = DEV_NAME, 776*09864c1cSStefan-gabriel Mirea .write = linflex_console_write, 777*09864c1cSStefan-gabriel Mirea .device = uart_console_device, 778*09864c1cSStefan-gabriel Mirea .setup = linflex_console_setup, 779*09864c1cSStefan-gabriel Mirea .flags = CON_PRINTBUFFER, 780*09864c1cSStefan-gabriel Mirea .index = -1, 781*09864c1cSStefan-gabriel Mirea .data = &linflex_reg, 782*09864c1cSStefan-gabriel Mirea }; 783*09864c1cSStefan-gabriel Mirea 784*09864c1cSStefan-gabriel Mirea static void linflex_earlycon_write(struct console *con, const char *s, 785*09864c1cSStefan-gabriel Mirea unsigned int n) 786*09864c1cSStefan-gabriel Mirea { 787*09864c1cSStefan-gabriel Mirea struct earlycon_device *dev = con->data; 788*09864c1cSStefan-gabriel Mirea 789*09864c1cSStefan-gabriel Mirea uart_console_write(&dev->port, s, n, linflex_earlycon_putchar); 790*09864c1cSStefan-gabriel Mirea } 791*09864c1cSStefan-gabriel Mirea 792*09864c1cSStefan-gabriel Mirea static int __init linflex_early_console_setup(struct earlycon_device *device, 793*09864c1cSStefan-gabriel Mirea const char *options) 794*09864c1cSStefan-gabriel Mirea { 795*09864c1cSStefan-gabriel Mirea if (!device->port.membase) 796*09864c1cSStefan-gabriel Mirea return -ENODEV; 797*09864c1cSStefan-gabriel Mirea 798*09864c1cSStefan-gabriel Mirea device->con->write = linflex_earlycon_write; 799*09864c1cSStefan-gabriel Mirea earlycon_port = &device->port; 800*09864c1cSStefan-gabriel Mirea 801*09864c1cSStefan-gabriel Mirea return 0; 802*09864c1cSStefan-gabriel Mirea } 803*09864c1cSStefan-gabriel Mirea 804*09864c1cSStefan-gabriel Mirea OF_EARLYCON_DECLARE(linflex, "fsl,s32-linflexuart", 805*09864c1cSStefan-gabriel Mirea linflex_early_console_setup); 806*09864c1cSStefan-gabriel Mirea 807*09864c1cSStefan-gabriel Mirea #define LINFLEX_CONSOLE (&linflex_console) 808*09864c1cSStefan-gabriel Mirea #else 809*09864c1cSStefan-gabriel Mirea #define LINFLEX_CONSOLE NULL 810*09864c1cSStefan-gabriel Mirea #endif 811*09864c1cSStefan-gabriel Mirea 812*09864c1cSStefan-gabriel Mirea static struct uart_driver linflex_reg = { 813*09864c1cSStefan-gabriel Mirea .owner = THIS_MODULE, 814*09864c1cSStefan-gabriel Mirea .driver_name = DRIVER_NAME, 815*09864c1cSStefan-gabriel Mirea .dev_name = DEV_NAME, 816*09864c1cSStefan-gabriel Mirea .nr = ARRAY_SIZE(linflex_ports), 817*09864c1cSStefan-gabriel Mirea .cons = LINFLEX_CONSOLE, 818*09864c1cSStefan-gabriel Mirea }; 819*09864c1cSStefan-gabriel Mirea 820*09864c1cSStefan-gabriel Mirea static int linflex_probe(struct platform_device *pdev) 821*09864c1cSStefan-gabriel Mirea { 822*09864c1cSStefan-gabriel Mirea struct device_node *np = pdev->dev.of_node; 823*09864c1cSStefan-gabriel Mirea struct uart_port *sport; 824*09864c1cSStefan-gabriel Mirea struct resource *res; 825*09864c1cSStefan-gabriel Mirea int ret; 826*09864c1cSStefan-gabriel Mirea 827*09864c1cSStefan-gabriel Mirea sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); 828*09864c1cSStefan-gabriel Mirea if (!sport) 829*09864c1cSStefan-gabriel Mirea return -ENOMEM; 830*09864c1cSStefan-gabriel Mirea 831*09864c1cSStefan-gabriel Mirea ret = of_alias_get_id(np, "serial"); 832*09864c1cSStefan-gabriel Mirea if (ret < 0) { 833*09864c1cSStefan-gabriel Mirea dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); 834*09864c1cSStefan-gabriel Mirea return ret; 835*09864c1cSStefan-gabriel Mirea } 836*09864c1cSStefan-gabriel Mirea if (ret >= UART_NR) { 837*09864c1cSStefan-gabriel Mirea dev_err(&pdev->dev, "driver limited to %d serial ports\n", 838*09864c1cSStefan-gabriel Mirea UART_NR); 839*09864c1cSStefan-gabriel Mirea return -ENOMEM; 840*09864c1cSStefan-gabriel Mirea } 841*09864c1cSStefan-gabriel Mirea 842*09864c1cSStefan-gabriel Mirea sport->line = ret; 843*09864c1cSStefan-gabriel Mirea 844*09864c1cSStefan-gabriel Mirea res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 845*09864c1cSStefan-gabriel Mirea if (!res) 846*09864c1cSStefan-gabriel Mirea return -ENODEV; 847*09864c1cSStefan-gabriel Mirea 848*09864c1cSStefan-gabriel Mirea sport->mapbase = res->start; 849*09864c1cSStefan-gabriel Mirea sport->membase = devm_ioremap_resource(&pdev->dev, res); 850*09864c1cSStefan-gabriel Mirea if (IS_ERR(sport->membase)) 851*09864c1cSStefan-gabriel Mirea return PTR_ERR(sport->membase); 852*09864c1cSStefan-gabriel Mirea 853*09864c1cSStefan-gabriel Mirea sport->dev = &pdev->dev; 854*09864c1cSStefan-gabriel Mirea sport->type = PORT_LINFLEXUART; 855*09864c1cSStefan-gabriel Mirea sport->iotype = UPIO_MEM; 856*09864c1cSStefan-gabriel Mirea sport->irq = platform_get_irq(pdev, 0); 857*09864c1cSStefan-gabriel Mirea sport->ops = &linflex_pops; 858*09864c1cSStefan-gabriel Mirea sport->flags = UPF_BOOT_AUTOCONF; 859*09864c1cSStefan-gabriel Mirea 860*09864c1cSStefan-gabriel Mirea linflex_ports[sport->line] = sport; 861*09864c1cSStefan-gabriel Mirea 862*09864c1cSStefan-gabriel Mirea platform_set_drvdata(pdev, sport); 863*09864c1cSStefan-gabriel Mirea 864*09864c1cSStefan-gabriel Mirea ret = uart_add_one_port(&linflex_reg, sport); 865*09864c1cSStefan-gabriel Mirea if (ret) 866*09864c1cSStefan-gabriel Mirea return ret; 867*09864c1cSStefan-gabriel Mirea 868*09864c1cSStefan-gabriel Mirea return 0; 869*09864c1cSStefan-gabriel Mirea } 870*09864c1cSStefan-gabriel Mirea 871*09864c1cSStefan-gabriel Mirea static int linflex_remove(struct platform_device *pdev) 872*09864c1cSStefan-gabriel Mirea { 873*09864c1cSStefan-gabriel Mirea struct uart_port *sport = platform_get_drvdata(pdev); 874*09864c1cSStefan-gabriel Mirea 875*09864c1cSStefan-gabriel Mirea uart_remove_one_port(&linflex_reg, sport); 876*09864c1cSStefan-gabriel Mirea 877*09864c1cSStefan-gabriel Mirea return 0; 878*09864c1cSStefan-gabriel Mirea } 879*09864c1cSStefan-gabriel Mirea 880*09864c1cSStefan-gabriel Mirea #ifdef CONFIG_PM_SLEEP 881*09864c1cSStefan-gabriel Mirea static int linflex_suspend(struct device *dev) 882*09864c1cSStefan-gabriel Mirea { 883*09864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_get_drvdata(dev); 884*09864c1cSStefan-gabriel Mirea 885*09864c1cSStefan-gabriel Mirea uart_suspend_port(&linflex_reg, sport); 886*09864c1cSStefan-gabriel Mirea 887*09864c1cSStefan-gabriel Mirea return 0; 888*09864c1cSStefan-gabriel Mirea } 889*09864c1cSStefan-gabriel Mirea 890*09864c1cSStefan-gabriel Mirea static int linflex_resume(struct device *dev) 891*09864c1cSStefan-gabriel Mirea { 892*09864c1cSStefan-gabriel Mirea struct uart_port *sport = dev_get_drvdata(dev); 893*09864c1cSStefan-gabriel Mirea 894*09864c1cSStefan-gabriel Mirea uart_resume_port(&linflex_reg, sport); 895*09864c1cSStefan-gabriel Mirea 896*09864c1cSStefan-gabriel Mirea return 0; 897*09864c1cSStefan-gabriel Mirea } 898*09864c1cSStefan-gabriel Mirea #endif 899*09864c1cSStefan-gabriel Mirea 900*09864c1cSStefan-gabriel Mirea static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume); 901*09864c1cSStefan-gabriel Mirea 902*09864c1cSStefan-gabriel Mirea static struct platform_driver linflex_driver = { 903*09864c1cSStefan-gabriel Mirea .probe = linflex_probe, 904*09864c1cSStefan-gabriel Mirea .remove = linflex_remove, 905*09864c1cSStefan-gabriel Mirea .driver = { 906*09864c1cSStefan-gabriel Mirea .name = DRIVER_NAME, 907*09864c1cSStefan-gabriel Mirea .owner = THIS_MODULE, 908*09864c1cSStefan-gabriel Mirea .of_match_table = linflex_dt_ids, 909*09864c1cSStefan-gabriel Mirea .pm = &linflex_pm_ops, 910*09864c1cSStefan-gabriel Mirea }, 911*09864c1cSStefan-gabriel Mirea }; 912*09864c1cSStefan-gabriel Mirea 913*09864c1cSStefan-gabriel Mirea static int __init linflex_serial_init(void) 914*09864c1cSStefan-gabriel Mirea { 915*09864c1cSStefan-gabriel Mirea int ret; 916*09864c1cSStefan-gabriel Mirea 917*09864c1cSStefan-gabriel Mirea ret = uart_register_driver(&linflex_reg); 918*09864c1cSStefan-gabriel Mirea if (ret) 919*09864c1cSStefan-gabriel Mirea return ret; 920*09864c1cSStefan-gabriel Mirea 921*09864c1cSStefan-gabriel Mirea ret = platform_driver_register(&linflex_driver); 922*09864c1cSStefan-gabriel Mirea if (ret) 923*09864c1cSStefan-gabriel Mirea uart_unregister_driver(&linflex_reg); 924*09864c1cSStefan-gabriel Mirea 925*09864c1cSStefan-gabriel Mirea #ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE 926*09864c1cSStefan-gabriel Mirea spin_lock_init(&init_lock); 927*09864c1cSStefan-gabriel Mirea #endif 928*09864c1cSStefan-gabriel Mirea 929*09864c1cSStefan-gabriel Mirea return ret; 930*09864c1cSStefan-gabriel Mirea } 931*09864c1cSStefan-gabriel Mirea 932*09864c1cSStefan-gabriel Mirea static void __exit linflex_serial_exit(void) 933*09864c1cSStefan-gabriel Mirea { 934*09864c1cSStefan-gabriel Mirea platform_driver_unregister(&linflex_driver); 935*09864c1cSStefan-gabriel Mirea uart_unregister_driver(&linflex_reg); 936*09864c1cSStefan-gabriel Mirea } 937*09864c1cSStefan-gabriel Mirea 938*09864c1cSStefan-gabriel Mirea module_init(linflex_serial_init); 939*09864c1cSStefan-gabriel Mirea module_exit(linflex_serial_exit); 940*09864c1cSStefan-gabriel Mirea 941*09864c1cSStefan-gabriel Mirea MODULE_DESCRIPTION("Freescale linflex serial port driver"); 942*09864c1cSStefan-gabriel Mirea MODULE_LICENSE("GPL v2"); 943