1*9e8d5470SHammer Hsieh // SPDX-License-Identifier: GPL-2.0 2*9e8d5470SHammer Hsieh /* 3*9e8d5470SHammer Hsieh * Sunplus SoC UART driver 4*9e8d5470SHammer Hsieh * 5*9e8d5470SHammer Hsieh * Author: Hammer Hsieh <[email protected]> 6*9e8d5470SHammer Hsieh * 7*9e8d5470SHammer Hsieh * Note1: This driver is 8250-like uart, but are not register compatible. 8*9e8d5470SHammer Hsieh * 9*9e8d5470SHammer Hsieh * Note2: On some buses, for preventing data incoherence, must do a read 10*9e8d5470SHammer Hsieh * for ensure write made it to hardware. In this driver, function startup 11*9e8d5470SHammer Hsieh * and shutdown did not do a read but only do a write directly. For what? 12*9e8d5470SHammer Hsieh * In Sunplus bus communication between memory bus and peripheral bus with 13*9e8d5470SHammer Hsieh * posted write, it will send a specific command after last write command 14*9e8d5470SHammer Hsieh * to make sure write done. Then memory bus identify the specific command 15*9e8d5470SHammer Hsieh * and send done signal back to master device. After master device received 16*9e8d5470SHammer Hsieh * done signal, then proceed next write command. It is no need to do a read 17*9e8d5470SHammer Hsieh * before write. 18*9e8d5470SHammer Hsieh */ 19*9e8d5470SHammer Hsieh #include <linux/clk.h> 20*9e8d5470SHammer Hsieh #include <linux/console.h> 21*9e8d5470SHammer Hsieh #include <linux/interrupt.h> 22*9e8d5470SHammer Hsieh #include <linux/io.h> 23*9e8d5470SHammer Hsieh #include <linux/iopoll.h> 24*9e8d5470SHammer Hsieh #include <linux/module.h> 25*9e8d5470SHammer Hsieh #include <linux/of.h> 26*9e8d5470SHammer Hsieh #include <linux/of_platform.h> 27*9e8d5470SHammer Hsieh #include <linux/platform_device.h> 28*9e8d5470SHammer Hsieh #include <linux/reset.h> 29*9e8d5470SHammer Hsieh #include <linux/serial_core.h> 30*9e8d5470SHammer Hsieh #include <linux/serial_reg.h> 31*9e8d5470SHammer Hsieh #include <linux/sysrq.h> 32*9e8d5470SHammer Hsieh #include <linux/tty.h> 33*9e8d5470SHammer Hsieh #include <linux/tty_flip.h> 34*9e8d5470SHammer Hsieh #include <asm/irq.h> 35*9e8d5470SHammer Hsieh 36*9e8d5470SHammer Hsieh /* Register offsets */ 37*9e8d5470SHammer Hsieh #define SUP_UART_DATA 0x00 38*9e8d5470SHammer Hsieh #define SUP_UART_LSR 0x04 39*9e8d5470SHammer Hsieh #define SUP_UART_MSR 0x08 40*9e8d5470SHammer Hsieh #define SUP_UART_LCR 0x0C 41*9e8d5470SHammer Hsieh #define SUP_UART_MCR 0x10 42*9e8d5470SHammer Hsieh #define SUP_UART_DIV_L 0x14 43*9e8d5470SHammer Hsieh #define SUP_UART_DIV_H 0x18 44*9e8d5470SHammer Hsieh #define SUP_UART_ISC 0x1C 45*9e8d5470SHammer Hsieh #define SUP_UART_TX_RESIDUE 0x20 46*9e8d5470SHammer Hsieh #define SUP_UART_RX_RESIDUE 0x24 47*9e8d5470SHammer Hsieh 48*9e8d5470SHammer Hsieh /* Line Status Register bits */ 49*9e8d5470SHammer Hsieh #define SUP_UART_LSR_BC BIT(5) /* break condition status */ 50*9e8d5470SHammer Hsieh #define SUP_UART_LSR_FE BIT(4) /* frame error status */ 51*9e8d5470SHammer Hsieh #define SUP_UART_LSR_OE BIT(3) /* overrun error status */ 52*9e8d5470SHammer Hsieh #define SUP_UART_LSR_PE BIT(2) /* parity error status */ 53*9e8d5470SHammer Hsieh #define SUP_UART_LSR_RX BIT(1) /* 1: receive fifo not empty */ 54*9e8d5470SHammer Hsieh #define SUP_UART_LSR_TX BIT(0) /* 1: transmit fifo is not full */ 55*9e8d5470SHammer Hsieh #define SUP_UART_LSR_TX_NOT_FULL 1 56*9e8d5470SHammer Hsieh #define SUP_UART_LSR_BRK_ERROR_BITS GENMASK(5, 2) 57*9e8d5470SHammer Hsieh 58*9e8d5470SHammer Hsieh /* Line Control Register bits */ 59*9e8d5470SHammer Hsieh #define SUP_UART_LCR_SBC BIT(5) /* select break condition */ 60*9e8d5470SHammer Hsieh 61*9e8d5470SHammer Hsieh /* Modem Control Register bits */ 62*9e8d5470SHammer Hsieh #define SUP_UART_MCR_RI BIT(3) /* ring indicator */ 63*9e8d5470SHammer Hsieh #define SUP_UART_MCR_DCD BIT(2) /* data carrier detect */ 64*9e8d5470SHammer Hsieh 65*9e8d5470SHammer Hsieh /* Interrupt Status/Control Register bits */ 66*9e8d5470SHammer Hsieh #define SUP_UART_ISC_RXM BIT(5) /* RX interrupt enable */ 67*9e8d5470SHammer Hsieh #define SUP_UART_ISC_TXM BIT(4) /* TX interrupt enable */ 68*9e8d5470SHammer Hsieh #define SUP_UART_ISC_RX BIT(1) /* RX interrupt status */ 69*9e8d5470SHammer Hsieh #define SUP_UART_ISC_TX BIT(0) /* TX interrupt status */ 70*9e8d5470SHammer Hsieh 71*9e8d5470SHammer Hsieh #define SUP_DUMMY_READ BIT(16) /* drop bytes received on a !CREAD port */ 72*9e8d5470SHammer Hsieh #define SUP_UART_NR 5 73*9e8d5470SHammer Hsieh 74*9e8d5470SHammer Hsieh struct sunplus_uart_port { 75*9e8d5470SHammer Hsieh struct uart_port port; 76*9e8d5470SHammer Hsieh struct clk *clk; 77*9e8d5470SHammer Hsieh struct reset_control *rstc; 78*9e8d5470SHammer Hsieh }; 79*9e8d5470SHammer Hsieh 80*9e8d5470SHammer Hsieh static void sp_uart_put_char(struct uart_port *port, unsigned int ch) 81*9e8d5470SHammer Hsieh { 82*9e8d5470SHammer Hsieh writel(ch, port->membase + SUP_UART_DATA); 83*9e8d5470SHammer Hsieh } 84*9e8d5470SHammer Hsieh 85*9e8d5470SHammer Hsieh static u32 sunplus_tx_buf_not_full(struct uart_port *port) 86*9e8d5470SHammer Hsieh { 87*9e8d5470SHammer Hsieh unsigned int lsr = readl(port->membase + SUP_UART_LSR); 88*9e8d5470SHammer Hsieh 89*9e8d5470SHammer Hsieh return (lsr & SUP_UART_LSR_TX) ? SUP_UART_LSR_TX_NOT_FULL : 0; 90*9e8d5470SHammer Hsieh } 91*9e8d5470SHammer Hsieh 92*9e8d5470SHammer Hsieh static unsigned int sunplus_tx_empty(struct uart_port *port) 93*9e8d5470SHammer Hsieh { 94*9e8d5470SHammer Hsieh unsigned int lsr = readl(port->membase + SUP_UART_LSR); 95*9e8d5470SHammer Hsieh 96*9e8d5470SHammer Hsieh return (lsr & UART_LSR_TEMT) ? TIOCSER_TEMT : 0; 97*9e8d5470SHammer Hsieh } 98*9e8d5470SHammer Hsieh 99*9e8d5470SHammer Hsieh static void sunplus_set_mctrl(struct uart_port *port, unsigned int mctrl) 100*9e8d5470SHammer Hsieh { 101*9e8d5470SHammer Hsieh unsigned int mcr = readl(port->membase + SUP_UART_MCR); 102*9e8d5470SHammer Hsieh 103*9e8d5470SHammer Hsieh if (mctrl & TIOCM_DTR) 104*9e8d5470SHammer Hsieh mcr |= UART_MCR_DTR; 105*9e8d5470SHammer Hsieh else 106*9e8d5470SHammer Hsieh mcr &= ~UART_MCR_DTR; 107*9e8d5470SHammer Hsieh 108*9e8d5470SHammer Hsieh if (mctrl & TIOCM_RTS) 109*9e8d5470SHammer Hsieh mcr |= UART_MCR_RTS; 110*9e8d5470SHammer Hsieh else 111*9e8d5470SHammer Hsieh mcr &= ~UART_MCR_RTS; 112*9e8d5470SHammer Hsieh 113*9e8d5470SHammer Hsieh if (mctrl & TIOCM_CAR) 114*9e8d5470SHammer Hsieh mcr |= SUP_UART_MCR_DCD; 115*9e8d5470SHammer Hsieh else 116*9e8d5470SHammer Hsieh mcr &= ~SUP_UART_MCR_DCD; 117*9e8d5470SHammer Hsieh 118*9e8d5470SHammer Hsieh if (mctrl & TIOCM_RI) 119*9e8d5470SHammer Hsieh mcr |= SUP_UART_MCR_RI; 120*9e8d5470SHammer Hsieh else 121*9e8d5470SHammer Hsieh mcr &= ~SUP_UART_MCR_RI; 122*9e8d5470SHammer Hsieh 123*9e8d5470SHammer Hsieh if (mctrl & TIOCM_LOOP) 124*9e8d5470SHammer Hsieh mcr |= UART_MCR_LOOP; 125*9e8d5470SHammer Hsieh else 126*9e8d5470SHammer Hsieh mcr &= ~UART_MCR_LOOP; 127*9e8d5470SHammer Hsieh 128*9e8d5470SHammer Hsieh writel(mcr, port->membase + SUP_UART_MCR); 129*9e8d5470SHammer Hsieh } 130*9e8d5470SHammer Hsieh 131*9e8d5470SHammer Hsieh static unsigned int sunplus_get_mctrl(struct uart_port *port) 132*9e8d5470SHammer Hsieh { 133*9e8d5470SHammer Hsieh unsigned int mcr, ret = 0; 134*9e8d5470SHammer Hsieh 135*9e8d5470SHammer Hsieh mcr = readl(port->membase + SUP_UART_MCR); 136*9e8d5470SHammer Hsieh 137*9e8d5470SHammer Hsieh if (mcr & UART_MCR_DTR) 138*9e8d5470SHammer Hsieh ret |= TIOCM_DTR; 139*9e8d5470SHammer Hsieh 140*9e8d5470SHammer Hsieh if (mcr & UART_MCR_RTS) 141*9e8d5470SHammer Hsieh ret |= TIOCM_RTS; 142*9e8d5470SHammer Hsieh 143*9e8d5470SHammer Hsieh if (mcr & SUP_UART_MCR_DCD) 144*9e8d5470SHammer Hsieh ret |= TIOCM_CAR; 145*9e8d5470SHammer Hsieh 146*9e8d5470SHammer Hsieh if (mcr & SUP_UART_MCR_RI) 147*9e8d5470SHammer Hsieh ret |= TIOCM_RI; 148*9e8d5470SHammer Hsieh 149*9e8d5470SHammer Hsieh if (mcr & UART_MCR_LOOP) 150*9e8d5470SHammer Hsieh ret |= TIOCM_LOOP; 151*9e8d5470SHammer Hsieh 152*9e8d5470SHammer Hsieh return ret; 153*9e8d5470SHammer Hsieh } 154*9e8d5470SHammer Hsieh 155*9e8d5470SHammer Hsieh static void sunplus_stop_tx(struct uart_port *port) 156*9e8d5470SHammer Hsieh { 157*9e8d5470SHammer Hsieh unsigned int isc; 158*9e8d5470SHammer Hsieh 159*9e8d5470SHammer Hsieh isc = readl(port->membase + SUP_UART_ISC); 160*9e8d5470SHammer Hsieh isc &= ~SUP_UART_ISC_TXM; 161*9e8d5470SHammer Hsieh writel(isc, port->membase + SUP_UART_ISC); 162*9e8d5470SHammer Hsieh } 163*9e8d5470SHammer Hsieh 164*9e8d5470SHammer Hsieh static void sunplus_start_tx(struct uart_port *port) 165*9e8d5470SHammer Hsieh { 166*9e8d5470SHammer Hsieh unsigned int isc; 167*9e8d5470SHammer Hsieh 168*9e8d5470SHammer Hsieh isc = readl(port->membase + SUP_UART_ISC); 169*9e8d5470SHammer Hsieh isc |= SUP_UART_ISC_TXM; 170*9e8d5470SHammer Hsieh writel(isc, port->membase + SUP_UART_ISC); 171*9e8d5470SHammer Hsieh } 172*9e8d5470SHammer Hsieh 173*9e8d5470SHammer Hsieh static void sunplus_stop_rx(struct uart_port *port) 174*9e8d5470SHammer Hsieh { 175*9e8d5470SHammer Hsieh unsigned int isc; 176*9e8d5470SHammer Hsieh 177*9e8d5470SHammer Hsieh isc = readl(port->membase + SUP_UART_ISC); 178*9e8d5470SHammer Hsieh isc &= ~SUP_UART_ISC_RXM; 179*9e8d5470SHammer Hsieh writel(isc, port->membase + SUP_UART_ISC); 180*9e8d5470SHammer Hsieh } 181*9e8d5470SHammer Hsieh 182*9e8d5470SHammer Hsieh static void sunplus_break_ctl(struct uart_port *port, int ctl) 183*9e8d5470SHammer Hsieh { 184*9e8d5470SHammer Hsieh unsigned long flags; 185*9e8d5470SHammer Hsieh unsigned int lcr; 186*9e8d5470SHammer Hsieh 187*9e8d5470SHammer Hsieh spin_lock_irqsave(&port->lock, flags); 188*9e8d5470SHammer Hsieh 189*9e8d5470SHammer Hsieh lcr = readl(port->membase + SUP_UART_LCR); 190*9e8d5470SHammer Hsieh 191*9e8d5470SHammer Hsieh if (ctl) 192*9e8d5470SHammer Hsieh lcr |= SUP_UART_LCR_SBC; /* start break */ 193*9e8d5470SHammer Hsieh else 194*9e8d5470SHammer Hsieh lcr &= ~SUP_UART_LCR_SBC; /* stop break */ 195*9e8d5470SHammer Hsieh 196*9e8d5470SHammer Hsieh writel(lcr, port->membase + SUP_UART_LCR); 197*9e8d5470SHammer Hsieh 198*9e8d5470SHammer Hsieh spin_unlock_irqrestore(&port->lock, flags); 199*9e8d5470SHammer Hsieh } 200*9e8d5470SHammer Hsieh 201*9e8d5470SHammer Hsieh static void transmit_chars(struct uart_port *port) 202*9e8d5470SHammer Hsieh { 203*9e8d5470SHammer Hsieh struct circ_buf *xmit = &port->state->xmit; 204*9e8d5470SHammer Hsieh 205*9e8d5470SHammer Hsieh if (port->x_char) { 206*9e8d5470SHammer Hsieh sp_uart_put_char(port, port->x_char); 207*9e8d5470SHammer Hsieh port->icount.tx++; 208*9e8d5470SHammer Hsieh port->x_char = 0; 209*9e8d5470SHammer Hsieh return; 210*9e8d5470SHammer Hsieh } 211*9e8d5470SHammer Hsieh 212*9e8d5470SHammer Hsieh if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { 213*9e8d5470SHammer Hsieh sunplus_stop_tx(port); 214*9e8d5470SHammer Hsieh return; 215*9e8d5470SHammer Hsieh } 216*9e8d5470SHammer Hsieh 217*9e8d5470SHammer Hsieh do { 218*9e8d5470SHammer Hsieh sp_uart_put_char(port, xmit->buf[xmit->tail]); 219*9e8d5470SHammer Hsieh xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE; 220*9e8d5470SHammer Hsieh port->icount.tx++; 221*9e8d5470SHammer Hsieh 222*9e8d5470SHammer Hsieh if (uart_circ_empty(xmit)) 223*9e8d5470SHammer Hsieh break; 224*9e8d5470SHammer Hsieh } while (sunplus_tx_buf_not_full(port)); 225*9e8d5470SHammer Hsieh 226*9e8d5470SHammer Hsieh if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 227*9e8d5470SHammer Hsieh uart_write_wakeup(port); 228*9e8d5470SHammer Hsieh 229*9e8d5470SHammer Hsieh if (uart_circ_empty(xmit)) 230*9e8d5470SHammer Hsieh sunplus_stop_tx(port); 231*9e8d5470SHammer Hsieh } 232*9e8d5470SHammer Hsieh 233*9e8d5470SHammer Hsieh static void receive_chars(struct uart_port *port) 234*9e8d5470SHammer Hsieh { 235*9e8d5470SHammer Hsieh unsigned int lsr = readl(port->membase + SUP_UART_LSR); 236*9e8d5470SHammer Hsieh unsigned int ch, flag; 237*9e8d5470SHammer Hsieh 238*9e8d5470SHammer Hsieh do { 239*9e8d5470SHammer Hsieh ch = readl(port->membase + SUP_UART_DATA); 240*9e8d5470SHammer Hsieh flag = TTY_NORMAL; 241*9e8d5470SHammer Hsieh port->icount.rx++; 242*9e8d5470SHammer Hsieh 243*9e8d5470SHammer Hsieh if (unlikely(lsr & SUP_UART_LSR_BRK_ERROR_BITS)) { 244*9e8d5470SHammer Hsieh if (lsr & SUP_UART_LSR_BC) { 245*9e8d5470SHammer Hsieh lsr &= ~(SUP_UART_LSR_FE | SUP_UART_LSR_PE); 246*9e8d5470SHammer Hsieh port->icount.brk++; 247*9e8d5470SHammer Hsieh flag = TTY_BREAK; 248*9e8d5470SHammer Hsieh if (uart_handle_break(port)) 249*9e8d5470SHammer Hsieh goto ignore_char; 250*9e8d5470SHammer Hsieh } else if (lsr & SUP_UART_LSR_PE) { 251*9e8d5470SHammer Hsieh port->icount.parity++; 252*9e8d5470SHammer Hsieh flag = TTY_PARITY; 253*9e8d5470SHammer Hsieh } else if (lsr & SUP_UART_LSR_FE) { 254*9e8d5470SHammer Hsieh port->icount.frame++; 255*9e8d5470SHammer Hsieh flag = TTY_FRAME; 256*9e8d5470SHammer Hsieh } 257*9e8d5470SHammer Hsieh 258*9e8d5470SHammer Hsieh if (lsr & SUP_UART_LSR_OE) 259*9e8d5470SHammer Hsieh port->icount.overrun++; 260*9e8d5470SHammer Hsieh } 261*9e8d5470SHammer Hsieh 262*9e8d5470SHammer Hsieh if (port->ignore_status_mask & SUP_DUMMY_READ) 263*9e8d5470SHammer Hsieh goto ignore_char; 264*9e8d5470SHammer Hsieh 265*9e8d5470SHammer Hsieh if (uart_handle_sysrq_char(port, ch)) 266*9e8d5470SHammer Hsieh goto ignore_char; 267*9e8d5470SHammer Hsieh 268*9e8d5470SHammer Hsieh uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag); 269*9e8d5470SHammer Hsieh 270*9e8d5470SHammer Hsieh ignore_char: 271*9e8d5470SHammer Hsieh lsr = readl(port->membase + SUP_UART_LSR); 272*9e8d5470SHammer Hsieh } while (lsr & SUP_UART_LSR_RX); 273*9e8d5470SHammer Hsieh 274*9e8d5470SHammer Hsieh tty_flip_buffer_push(&port->state->port); 275*9e8d5470SHammer Hsieh } 276*9e8d5470SHammer Hsieh 277*9e8d5470SHammer Hsieh static irqreturn_t sunplus_uart_irq(int irq, void *args) 278*9e8d5470SHammer Hsieh { 279*9e8d5470SHammer Hsieh struct uart_port *port = args; 280*9e8d5470SHammer Hsieh unsigned int isc; 281*9e8d5470SHammer Hsieh 282*9e8d5470SHammer Hsieh spin_lock(&port->lock); 283*9e8d5470SHammer Hsieh 284*9e8d5470SHammer Hsieh isc = readl(port->membase + SUP_UART_ISC); 285*9e8d5470SHammer Hsieh 286*9e8d5470SHammer Hsieh if (isc & SUP_UART_ISC_RX) 287*9e8d5470SHammer Hsieh receive_chars(port); 288*9e8d5470SHammer Hsieh 289*9e8d5470SHammer Hsieh if (isc & SUP_UART_ISC_TX) 290*9e8d5470SHammer Hsieh transmit_chars(port); 291*9e8d5470SHammer Hsieh 292*9e8d5470SHammer Hsieh spin_unlock(&port->lock); 293*9e8d5470SHammer Hsieh 294*9e8d5470SHammer Hsieh return IRQ_HANDLED; 295*9e8d5470SHammer Hsieh } 296*9e8d5470SHammer Hsieh 297*9e8d5470SHammer Hsieh static int sunplus_startup(struct uart_port *port) 298*9e8d5470SHammer Hsieh { 299*9e8d5470SHammer Hsieh unsigned long flags; 300*9e8d5470SHammer Hsieh unsigned int isc = 0; 301*9e8d5470SHammer Hsieh int ret; 302*9e8d5470SHammer Hsieh 303*9e8d5470SHammer Hsieh ret = request_irq(port->irq, sunplus_uart_irq, 0, "sunplus_uart", port); 304*9e8d5470SHammer Hsieh if (ret) 305*9e8d5470SHammer Hsieh return ret; 306*9e8d5470SHammer Hsieh 307*9e8d5470SHammer Hsieh spin_lock_irqsave(&port->lock, flags); 308*9e8d5470SHammer Hsieh /* isc define Bit[7:4] int setting, Bit[3:0] int status 309*9e8d5470SHammer Hsieh * isc register will clean Bit[3:0] int status after read 310*9e8d5470SHammer Hsieh * only do a write to Bit[7:4] int setting 311*9e8d5470SHammer Hsieh */ 312*9e8d5470SHammer Hsieh isc |= SUP_UART_ISC_RXM; 313*9e8d5470SHammer Hsieh writel(isc, port->membase + SUP_UART_ISC); 314*9e8d5470SHammer Hsieh spin_unlock_irqrestore(&port->lock, flags); 315*9e8d5470SHammer Hsieh 316*9e8d5470SHammer Hsieh return 0; 317*9e8d5470SHammer Hsieh } 318*9e8d5470SHammer Hsieh 319*9e8d5470SHammer Hsieh static void sunplus_shutdown(struct uart_port *port) 320*9e8d5470SHammer Hsieh { 321*9e8d5470SHammer Hsieh unsigned long flags; 322*9e8d5470SHammer Hsieh 323*9e8d5470SHammer Hsieh spin_lock_irqsave(&port->lock, flags); 324*9e8d5470SHammer Hsieh /* isc define Bit[7:4] int setting, Bit[3:0] int status 325*9e8d5470SHammer Hsieh * isc register will clean Bit[3:0] int status after read 326*9e8d5470SHammer Hsieh * only do a write to Bit[7:4] int setting 327*9e8d5470SHammer Hsieh */ 328*9e8d5470SHammer Hsieh writel(0, port->membase + SUP_UART_ISC); /* disable all interrupt */ 329*9e8d5470SHammer Hsieh spin_unlock_irqrestore(&port->lock, flags); 330*9e8d5470SHammer Hsieh 331*9e8d5470SHammer Hsieh free_irq(port->irq, port); 332*9e8d5470SHammer Hsieh } 333*9e8d5470SHammer Hsieh 334*9e8d5470SHammer Hsieh static void sunplus_set_termios(struct uart_port *port, 335*9e8d5470SHammer Hsieh struct ktermios *termios, 336*9e8d5470SHammer Hsieh struct ktermios *oldtermios) 337*9e8d5470SHammer Hsieh { 338*9e8d5470SHammer Hsieh u32 ext, div, div_l, div_h, baud, lcr; 339*9e8d5470SHammer Hsieh u32 clk = port->uartclk; 340*9e8d5470SHammer Hsieh unsigned long flags; 341*9e8d5470SHammer Hsieh 342*9e8d5470SHammer Hsieh baud = uart_get_baud_rate(port, termios, oldtermios, 0, port->uartclk / 16); 343*9e8d5470SHammer Hsieh 344*9e8d5470SHammer Hsieh /* baud rate = uartclk / ((16 * divisor + 1) + divisor_ext) */ 345*9e8d5470SHammer Hsieh clk += baud >> 1; 346*9e8d5470SHammer Hsieh div = clk / baud; 347*9e8d5470SHammer Hsieh ext = div & 0x0F; 348*9e8d5470SHammer Hsieh div = (div >> 4) - 1; 349*9e8d5470SHammer Hsieh div_l = (div & 0xFF) | (ext << 12); 350*9e8d5470SHammer Hsieh div_h = div >> 8; 351*9e8d5470SHammer Hsieh 352*9e8d5470SHammer Hsieh switch (termios->c_cflag & CSIZE) { 353*9e8d5470SHammer Hsieh case CS5: 354*9e8d5470SHammer Hsieh lcr = UART_LCR_WLEN5; 355*9e8d5470SHammer Hsieh break; 356*9e8d5470SHammer Hsieh case CS6: 357*9e8d5470SHammer Hsieh lcr = UART_LCR_WLEN6; 358*9e8d5470SHammer Hsieh break; 359*9e8d5470SHammer Hsieh case CS7: 360*9e8d5470SHammer Hsieh lcr = UART_LCR_WLEN7; 361*9e8d5470SHammer Hsieh break; 362*9e8d5470SHammer Hsieh default: 363*9e8d5470SHammer Hsieh lcr = UART_LCR_WLEN8; 364*9e8d5470SHammer Hsieh break; 365*9e8d5470SHammer Hsieh } 366*9e8d5470SHammer Hsieh 367*9e8d5470SHammer Hsieh if (termios->c_cflag & CSTOPB) 368*9e8d5470SHammer Hsieh lcr |= UART_LCR_STOP; 369*9e8d5470SHammer Hsieh 370*9e8d5470SHammer Hsieh if (termios->c_cflag & PARENB) { 371*9e8d5470SHammer Hsieh lcr |= UART_LCR_PARITY; 372*9e8d5470SHammer Hsieh 373*9e8d5470SHammer Hsieh if (!(termios->c_cflag & PARODD)) 374*9e8d5470SHammer Hsieh lcr |= UART_LCR_EPAR; 375*9e8d5470SHammer Hsieh } 376*9e8d5470SHammer Hsieh 377*9e8d5470SHammer Hsieh spin_lock_irqsave(&port->lock, flags); 378*9e8d5470SHammer Hsieh 379*9e8d5470SHammer Hsieh uart_update_timeout(port, termios->c_cflag, baud); 380*9e8d5470SHammer Hsieh 381*9e8d5470SHammer Hsieh port->read_status_mask = 0; 382*9e8d5470SHammer Hsieh if (termios->c_iflag & INPCK) 383*9e8d5470SHammer Hsieh port->read_status_mask |= SUP_UART_LSR_PE | SUP_UART_LSR_FE; 384*9e8d5470SHammer Hsieh 385*9e8d5470SHammer Hsieh if (termios->c_iflag & (BRKINT | PARMRK)) 386*9e8d5470SHammer Hsieh port->read_status_mask |= SUP_UART_LSR_BC; 387*9e8d5470SHammer Hsieh 388*9e8d5470SHammer Hsieh /* Characters to ignore */ 389*9e8d5470SHammer Hsieh port->ignore_status_mask = 0; 390*9e8d5470SHammer Hsieh if (termios->c_iflag & IGNPAR) 391*9e8d5470SHammer Hsieh port->ignore_status_mask |= SUP_UART_LSR_FE | SUP_UART_LSR_PE; 392*9e8d5470SHammer Hsieh 393*9e8d5470SHammer Hsieh if (termios->c_iflag & IGNBRK) { 394*9e8d5470SHammer Hsieh port->ignore_status_mask |= SUP_UART_LSR_BC; 395*9e8d5470SHammer Hsieh 396*9e8d5470SHammer Hsieh if (termios->c_iflag & IGNPAR) 397*9e8d5470SHammer Hsieh port->ignore_status_mask |= SUP_UART_LSR_OE; 398*9e8d5470SHammer Hsieh } 399*9e8d5470SHammer Hsieh 400*9e8d5470SHammer Hsieh /* Ignore all characters if CREAD is not set */ 401*9e8d5470SHammer Hsieh if ((termios->c_cflag & CREAD) == 0) { 402*9e8d5470SHammer Hsieh port->ignore_status_mask |= SUP_DUMMY_READ; 403*9e8d5470SHammer Hsieh /* flush rx data FIFO */ 404*9e8d5470SHammer Hsieh writel(0, port->membase + SUP_UART_RX_RESIDUE); 405*9e8d5470SHammer Hsieh } 406*9e8d5470SHammer Hsieh 407*9e8d5470SHammer Hsieh /* Settings for baud rate divisor and lcr */ 408*9e8d5470SHammer Hsieh writel(div_h, port->membase + SUP_UART_DIV_H); 409*9e8d5470SHammer Hsieh writel(div_l, port->membase + SUP_UART_DIV_L); 410*9e8d5470SHammer Hsieh writel(lcr, port->membase + SUP_UART_LCR); 411*9e8d5470SHammer Hsieh 412*9e8d5470SHammer Hsieh spin_unlock_irqrestore(&port->lock, flags); 413*9e8d5470SHammer Hsieh } 414*9e8d5470SHammer Hsieh 415*9e8d5470SHammer Hsieh static void sunplus_set_ldisc(struct uart_port *port, struct ktermios *termios) 416*9e8d5470SHammer Hsieh { 417*9e8d5470SHammer Hsieh int new = termios->c_line; 418*9e8d5470SHammer Hsieh 419*9e8d5470SHammer Hsieh if (new == N_PPS) 420*9e8d5470SHammer Hsieh port->flags |= UPF_HARDPPS_CD; 421*9e8d5470SHammer Hsieh else 422*9e8d5470SHammer Hsieh port->flags &= ~UPF_HARDPPS_CD; 423*9e8d5470SHammer Hsieh } 424*9e8d5470SHammer Hsieh 425*9e8d5470SHammer Hsieh static const char *sunplus_type(struct uart_port *port) 426*9e8d5470SHammer Hsieh { 427*9e8d5470SHammer Hsieh return port->type == PORT_SUNPLUS ? "sunplus_uart" : NULL; 428*9e8d5470SHammer Hsieh } 429*9e8d5470SHammer Hsieh 430*9e8d5470SHammer Hsieh static void sunplus_config_port(struct uart_port *port, int type) 431*9e8d5470SHammer Hsieh { 432*9e8d5470SHammer Hsieh if (type & UART_CONFIG_TYPE) 433*9e8d5470SHammer Hsieh port->type = PORT_SUNPLUS; 434*9e8d5470SHammer Hsieh } 435*9e8d5470SHammer Hsieh 436*9e8d5470SHammer Hsieh static int sunplus_verify_port(struct uart_port *port, struct serial_struct *ser) 437*9e8d5470SHammer Hsieh { 438*9e8d5470SHammer Hsieh if (ser->type != PORT_UNKNOWN && ser->type != PORT_SUNPLUS) 439*9e8d5470SHammer Hsieh return -EINVAL; 440*9e8d5470SHammer Hsieh 441*9e8d5470SHammer Hsieh return 0; 442*9e8d5470SHammer Hsieh } 443*9e8d5470SHammer Hsieh 444*9e8d5470SHammer Hsieh #ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE 445*9e8d5470SHammer Hsieh static void wait_for_xmitr(struct uart_port *port) 446*9e8d5470SHammer Hsieh { 447*9e8d5470SHammer Hsieh unsigned int val; 448*9e8d5470SHammer Hsieh int ret; 449*9e8d5470SHammer Hsieh 450*9e8d5470SHammer Hsieh /* Wait while FIFO is full or timeout */ 451*9e8d5470SHammer Hsieh ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val, 452*9e8d5470SHammer Hsieh (val & SUP_UART_LSR_TX), 1, 10000); 453*9e8d5470SHammer Hsieh 454*9e8d5470SHammer Hsieh if (ret == -ETIMEDOUT) { 455*9e8d5470SHammer Hsieh dev_err(port->dev, "Timeout waiting while UART TX FULL\n"); 456*9e8d5470SHammer Hsieh return; 457*9e8d5470SHammer Hsieh } 458*9e8d5470SHammer Hsieh } 459*9e8d5470SHammer Hsieh #endif 460*9e8d5470SHammer Hsieh 461*9e8d5470SHammer Hsieh #ifdef CONFIG_CONSOLE_POLL 462*9e8d5470SHammer Hsieh static void sunplus_poll_put_char(struct uart_port *port, unsigned char data) 463*9e8d5470SHammer Hsieh { 464*9e8d5470SHammer Hsieh wait_for_xmitr(port); 465*9e8d5470SHammer Hsieh sp_uart_put_char(port, data); 466*9e8d5470SHammer Hsieh } 467*9e8d5470SHammer Hsieh 468*9e8d5470SHammer Hsieh static int sunplus_poll_get_char(struct uart_port *port) 469*9e8d5470SHammer Hsieh { 470*9e8d5470SHammer Hsieh unsigned int lsr = readl(port->membase + SUP_UART_LSR); 471*9e8d5470SHammer Hsieh 472*9e8d5470SHammer Hsieh if (!(lsr & SUP_UART_LSR_RX)) 473*9e8d5470SHammer Hsieh return NO_POLL_CHAR; 474*9e8d5470SHammer Hsieh 475*9e8d5470SHammer Hsieh return readl(port->membase + SUP_UART_DATA); 476*9e8d5470SHammer Hsieh } 477*9e8d5470SHammer Hsieh #endif 478*9e8d5470SHammer Hsieh 479*9e8d5470SHammer Hsieh static const struct uart_ops sunplus_uart_ops = { 480*9e8d5470SHammer Hsieh .tx_empty = sunplus_tx_empty, 481*9e8d5470SHammer Hsieh .set_mctrl = sunplus_set_mctrl, 482*9e8d5470SHammer Hsieh .get_mctrl = sunplus_get_mctrl, 483*9e8d5470SHammer Hsieh .stop_tx = sunplus_stop_tx, 484*9e8d5470SHammer Hsieh .start_tx = sunplus_start_tx, 485*9e8d5470SHammer Hsieh .stop_rx = sunplus_stop_rx, 486*9e8d5470SHammer Hsieh .break_ctl = sunplus_break_ctl, 487*9e8d5470SHammer Hsieh .startup = sunplus_startup, 488*9e8d5470SHammer Hsieh .shutdown = sunplus_shutdown, 489*9e8d5470SHammer Hsieh .set_termios = sunplus_set_termios, 490*9e8d5470SHammer Hsieh .set_ldisc = sunplus_set_ldisc, 491*9e8d5470SHammer Hsieh .type = sunplus_type, 492*9e8d5470SHammer Hsieh .config_port = sunplus_config_port, 493*9e8d5470SHammer Hsieh .verify_port = sunplus_verify_port, 494*9e8d5470SHammer Hsieh #ifdef CONFIG_CONSOLE_POLL 495*9e8d5470SHammer Hsieh .poll_put_char = sunplus_poll_put_char, 496*9e8d5470SHammer Hsieh .poll_get_char = sunplus_poll_get_char, 497*9e8d5470SHammer Hsieh #endif 498*9e8d5470SHammer Hsieh }; 499*9e8d5470SHammer Hsieh 500*9e8d5470SHammer Hsieh #ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE 501*9e8d5470SHammer Hsieh struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR]; 502*9e8d5470SHammer Hsieh 503*9e8d5470SHammer Hsieh static void sunplus_uart_console_putchar(struct uart_port *port, int ch) 504*9e8d5470SHammer Hsieh { 505*9e8d5470SHammer Hsieh wait_for_xmitr(port); 506*9e8d5470SHammer Hsieh sp_uart_put_char(port, ch); 507*9e8d5470SHammer Hsieh } 508*9e8d5470SHammer Hsieh 509*9e8d5470SHammer Hsieh static void sunplus_console_write(struct console *co, 510*9e8d5470SHammer Hsieh const char *s, 511*9e8d5470SHammer Hsieh unsigned int count) 512*9e8d5470SHammer Hsieh { 513*9e8d5470SHammer Hsieh unsigned long flags; 514*9e8d5470SHammer Hsieh int locked = 1; 515*9e8d5470SHammer Hsieh 516*9e8d5470SHammer Hsieh local_irq_save(flags); 517*9e8d5470SHammer Hsieh 518*9e8d5470SHammer Hsieh if (sunplus_console_ports[co->index]->port.sysrq) 519*9e8d5470SHammer Hsieh locked = 0; 520*9e8d5470SHammer Hsieh else if (oops_in_progress) 521*9e8d5470SHammer Hsieh locked = spin_trylock(&sunplus_console_ports[co->index]->port.lock); 522*9e8d5470SHammer Hsieh else 523*9e8d5470SHammer Hsieh spin_lock(&sunplus_console_ports[co->index]->port.lock); 524*9e8d5470SHammer Hsieh 525*9e8d5470SHammer Hsieh uart_console_write(&sunplus_console_ports[co->index]->port, s, count, 526*9e8d5470SHammer Hsieh sunplus_uart_console_putchar); 527*9e8d5470SHammer Hsieh 528*9e8d5470SHammer Hsieh if (locked) 529*9e8d5470SHammer Hsieh spin_unlock(&sunplus_console_ports[co->index]->port.lock); 530*9e8d5470SHammer Hsieh 531*9e8d5470SHammer Hsieh local_irq_restore(flags); 532*9e8d5470SHammer Hsieh } 533*9e8d5470SHammer Hsieh 534*9e8d5470SHammer Hsieh static int __init sunplus_console_setup(struct console *co, char *options) 535*9e8d5470SHammer Hsieh { 536*9e8d5470SHammer Hsieh struct sunplus_uart_port *sup; 537*9e8d5470SHammer Hsieh int baud = 115200; 538*9e8d5470SHammer Hsieh int bits = 8; 539*9e8d5470SHammer Hsieh int parity = 'n'; 540*9e8d5470SHammer Hsieh int flow = 'n'; 541*9e8d5470SHammer Hsieh 542*9e8d5470SHammer Hsieh if (co->index < 0 || co->index >= SUP_UART_NR) 543*9e8d5470SHammer Hsieh return -EINVAL; 544*9e8d5470SHammer Hsieh 545*9e8d5470SHammer Hsieh sup = sunplus_console_ports[co->index]; 546*9e8d5470SHammer Hsieh if (!sup) 547*9e8d5470SHammer Hsieh return -ENODEV; 548*9e8d5470SHammer Hsieh 549*9e8d5470SHammer Hsieh if (options) 550*9e8d5470SHammer Hsieh uart_parse_options(options, &baud, &parity, &bits, &flow); 551*9e8d5470SHammer Hsieh 552*9e8d5470SHammer Hsieh return uart_set_options(&sup->port, co, baud, parity, bits, flow); 553*9e8d5470SHammer Hsieh } 554*9e8d5470SHammer Hsieh 555*9e8d5470SHammer Hsieh static struct uart_driver sunplus_uart_driver; 556*9e8d5470SHammer Hsieh static struct console sunplus_uart_console = { 557*9e8d5470SHammer Hsieh .name = "ttySUP", 558*9e8d5470SHammer Hsieh .write = sunplus_console_write, 559*9e8d5470SHammer Hsieh .device = uart_console_device, 560*9e8d5470SHammer Hsieh .setup = sunplus_console_setup, 561*9e8d5470SHammer Hsieh .flags = CON_PRINTBUFFER, 562*9e8d5470SHammer Hsieh .index = -1, 563*9e8d5470SHammer Hsieh .data = &sunplus_uart_driver 564*9e8d5470SHammer Hsieh }; 565*9e8d5470SHammer Hsieh #endif 566*9e8d5470SHammer Hsieh 567*9e8d5470SHammer Hsieh static struct uart_driver sunplus_uart_driver = { 568*9e8d5470SHammer Hsieh .owner = THIS_MODULE, 569*9e8d5470SHammer Hsieh .driver_name = "sunplus_uart", 570*9e8d5470SHammer Hsieh .dev_name = "ttySUP", 571*9e8d5470SHammer Hsieh .major = TTY_MAJOR, 572*9e8d5470SHammer Hsieh .minor = 64, 573*9e8d5470SHammer Hsieh .nr = SUP_UART_NR, 574*9e8d5470SHammer Hsieh .cons = &sunplus_uart_console, 575*9e8d5470SHammer Hsieh }; 576*9e8d5470SHammer Hsieh 577*9e8d5470SHammer Hsieh static void sunplus_uart_disable_unprepare(void *data) 578*9e8d5470SHammer Hsieh { 579*9e8d5470SHammer Hsieh clk_disable_unprepare(data); 580*9e8d5470SHammer Hsieh } 581*9e8d5470SHammer Hsieh 582*9e8d5470SHammer Hsieh static void sunplus_uart_reset_control_assert(void *data) 583*9e8d5470SHammer Hsieh { 584*9e8d5470SHammer Hsieh reset_control_assert(data); 585*9e8d5470SHammer Hsieh } 586*9e8d5470SHammer Hsieh 587*9e8d5470SHammer Hsieh static int sunplus_uart_probe(struct platform_device *pdev) 588*9e8d5470SHammer Hsieh { 589*9e8d5470SHammer Hsieh struct sunplus_uart_port *sup; 590*9e8d5470SHammer Hsieh struct uart_port *port; 591*9e8d5470SHammer Hsieh struct resource *res; 592*9e8d5470SHammer Hsieh int ret, irq; 593*9e8d5470SHammer Hsieh 594*9e8d5470SHammer Hsieh pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); 595*9e8d5470SHammer Hsieh 596*9e8d5470SHammer Hsieh if (pdev->id < 0 || pdev->id >= SUP_UART_NR) 597*9e8d5470SHammer Hsieh return -EINVAL; 598*9e8d5470SHammer Hsieh 599*9e8d5470SHammer Hsieh sup = devm_kzalloc(&pdev->dev, sizeof(*sup), GFP_KERNEL); 600*9e8d5470SHammer Hsieh if (!sup) 601*9e8d5470SHammer Hsieh return -ENOMEM; 602*9e8d5470SHammer Hsieh 603*9e8d5470SHammer Hsieh sup->clk = devm_clk_get_optional(&pdev->dev, NULL); 604*9e8d5470SHammer Hsieh if (IS_ERR(sup->clk)) 605*9e8d5470SHammer Hsieh return dev_err_probe(&pdev->dev, PTR_ERR(sup->clk), "clk not found\n"); 606*9e8d5470SHammer Hsieh 607*9e8d5470SHammer Hsieh ret = clk_prepare_enable(sup->clk); 608*9e8d5470SHammer Hsieh if (ret) 609*9e8d5470SHammer Hsieh return ret; 610*9e8d5470SHammer Hsieh 611*9e8d5470SHammer Hsieh ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_disable_unprepare, sup->clk); 612*9e8d5470SHammer Hsieh if (ret) 613*9e8d5470SHammer Hsieh return ret; 614*9e8d5470SHammer Hsieh 615*9e8d5470SHammer Hsieh sup->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); 616*9e8d5470SHammer Hsieh if (IS_ERR(sup->rstc)) 617*9e8d5470SHammer Hsieh return dev_err_probe(&pdev->dev, PTR_ERR(sup->rstc), "rstc not found\n"); 618*9e8d5470SHammer Hsieh 619*9e8d5470SHammer Hsieh port = &sup->port; 620*9e8d5470SHammer Hsieh 621*9e8d5470SHammer Hsieh port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 622*9e8d5470SHammer Hsieh if (IS_ERR(port->membase)) 623*9e8d5470SHammer Hsieh return dev_err_probe(&pdev->dev, PTR_ERR(port->membase), "membase not found\n"); 624*9e8d5470SHammer Hsieh 625*9e8d5470SHammer Hsieh irq = platform_get_irq(pdev, 0); 626*9e8d5470SHammer Hsieh if (irq < 0) 627*9e8d5470SHammer Hsieh return irq; 628*9e8d5470SHammer Hsieh 629*9e8d5470SHammer Hsieh port->mapbase = res->start; 630*9e8d5470SHammer Hsieh port->uartclk = clk_get_rate(sup->clk); 631*9e8d5470SHammer Hsieh port->line = pdev->id; 632*9e8d5470SHammer Hsieh port->irq = irq; 633*9e8d5470SHammer Hsieh port->dev = &pdev->dev; 634*9e8d5470SHammer Hsieh port->iotype = UPIO_MEM; 635*9e8d5470SHammer Hsieh port->ops = &sunplus_uart_ops; 636*9e8d5470SHammer Hsieh port->flags = UPF_BOOT_AUTOCONF; 637*9e8d5470SHammer Hsieh port->fifosize = 128; 638*9e8d5470SHammer Hsieh 639*9e8d5470SHammer Hsieh ret = reset_control_deassert(sup->rstc); 640*9e8d5470SHammer Hsieh if (ret) 641*9e8d5470SHammer Hsieh return ret; 642*9e8d5470SHammer Hsieh 643*9e8d5470SHammer Hsieh ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_reset_control_assert, sup->rstc); 644*9e8d5470SHammer Hsieh if (ret) 645*9e8d5470SHammer Hsieh return ret; 646*9e8d5470SHammer Hsieh 647*9e8d5470SHammer Hsieh #ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE 648*9e8d5470SHammer Hsieh sunplus_console_ports[sup->port.line] = sup; 649*9e8d5470SHammer Hsieh #endif 650*9e8d5470SHammer Hsieh 651*9e8d5470SHammer Hsieh platform_set_drvdata(pdev, &sup->port); 652*9e8d5470SHammer Hsieh 653*9e8d5470SHammer Hsieh ret = uart_add_one_port(&sunplus_uart_driver, &sup->port); 654*9e8d5470SHammer Hsieh #ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE 655*9e8d5470SHammer Hsieh if (ret) 656*9e8d5470SHammer Hsieh sunplus_console_ports[sup->port.line] = NULL; 657*9e8d5470SHammer Hsieh #endif 658*9e8d5470SHammer Hsieh 659*9e8d5470SHammer Hsieh return ret; 660*9e8d5470SHammer Hsieh } 661*9e8d5470SHammer Hsieh 662*9e8d5470SHammer Hsieh static int sunplus_uart_remove(struct platform_device *pdev) 663*9e8d5470SHammer Hsieh { 664*9e8d5470SHammer Hsieh struct sunplus_uart_port *sup = platform_get_drvdata(pdev); 665*9e8d5470SHammer Hsieh 666*9e8d5470SHammer Hsieh uart_remove_one_port(&sunplus_uart_driver, &sup->port); 667*9e8d5470SHammer Hsieh 668*9e8d5470SHammer Hsieh return 0; 669*9e8d5470SHammer Hsieh } 670*9e8d5470SHammer Hsieh 671*9e8d5470SHammer Hsieh static int __maybe_unused sunplus_uart_suspend(struct device *dev) 672*9e8d5470SHammer Hsieh { 673*9e8d5470SHammer Hsieh struct sunplus_uart_port *sup = dev_get_drvdata(dev); 674*9e8d5470SHammer Hsieh 675*9e8d5470SHammer Hsieh if (!uart_console(&sup->port)) 676*9e8d5470SHammer Hsieh uart_suspend_port(&sunplus_uart_driver, &sup->port); 677*9e8d5470SHammer Hsieh 678*9e8d5470SHammer Hsieh return 0; 679*9e8d5470SHammer Hsieh } 680*9e8d5470SHammer Hsieh 681*9e8d5470SHammer Hsieh static int __maybe_unused sunplus_uart_resume(struct device *dev) 682*9e8d5470SHammer Hsieh { 683*9e8d5470SHammer Hsieh struct sunplus_uart_port *sup = dev_get_drvdata(dev); 684*9e8d5470SHammer Hsieh 685*9e8d5470SHammer Hsieh if (!uart_console(&sup->port)) 686*9e8d5470SHammer Hsieh uart_resume_port(&sunplus_uart_driver, &sup->port); 687*9e8d5470SHammer Hsieh 688*9e8d5470SHammer Hsieh return 0; 689*9e8d5470SHammer Hsieh } 690*9e8d5470SHammer Hsieh 691*9e8d5470SHammer Hsieh static const struct dev_pm_ops sunplus_uart_pm_ops = { 692*9e8d5470SHammer Hsieh SET_SYSTEM_SLEEP_PM_OPS(sunplus_uart_suspend, sunplus_uart_resume) 693*9e8d5470SHammer Hsieh }; 694*9e8d5470SHammer Hsieh 695*9e8d5470SHammer Hsieh static const struct of_device_id sp_uart_of_match[] = { 696*9e8d5470SHammer Hsieh { .compatible = "sunplus,sp7021-uart" }, 697*9e8d5470SHammer Hsieh {} 698*9e8d5470SHammer Hsieh }; 699*9e8d5470SHammer Hsieh MODULE_DEVICE_TABLE(of, sp_uart_of_match); 700*9e8d5470SHammer Hsieh 701*9e8d5470SHammer Hsieh static struct platform_driver sunplus_uart_platform_driver = { 702*9e8d5470SHammer Hsieh .probe = sunplus_uart_probe, 703*9e8d5470SHammer Hsieh .remove = sunplus_uart_remove, 704*9e8d5470SHammer Hsieh .driver = { 705*9e8d5470SHammer Hsieh .name = "sunplus_uart", 706*9e8d5470SHammer Hsieh .of_match_table = sp_uart_of_match, 707*9e8d5470SHammer Hsieh .pm = &sunplus_uart_pm_ops, 708*9e8d5470SHammer Hsieh } 709*9e8d5470SHammer Hsieh }; 710*9e8d5470SHammer Hsieh 711*9e8d5470SHammer Hsieh static int __init sunplus_uart_init(void) 712*9e8d5470SHammer Hsieh { 713*9e8d5470SHammer Hsieh int ret; 714*9e8d5470SHammer Hsieh 715*9e8d5470SHammer Hsieh ret = uart_register_driver(&sunplus_uart_driver); 716*9e8d5470SHammer Hsieh if (ret) 717*9e8d5470SHammer Hsieh return ret; 718*9e8d5470SHammer Hsieh 719*9e8d5470SHammer Hsieh ret = platform_driver_register(&sunplus_uart_platform_driver); 720*9e8d5470SHammer Hsieh if (ret) 721*9e8d5470SHammer Hsieh uart_unregister_driver(&sunplus_uart_driver); 722*9e8d5470SHammer Hsieh 723*9e8d5470SHammer Hsieh return ret; 724*9e8d5470SHammer Hsieh } 725*9e8d5470SHammer Hsieh module_init(sunplus_uart_init); 726*9e8d5470SHammer Hsieh 727*9e8d5470SHammer Hsieh static void __exit sunplus_uart_exit(void) 728*9e8d5470SHammer Hsieh { 729*9e8d5470SHammer Hsieh platform_driver_unregister(&sunplus_uart_platform_driver); 730*9e8d5470SHammer Hsieh uart_unregister_driver(&sunplus_uart_driver); 731*9e8d5470SHammer Hsieh } 732*9e8d5470SHammer Hsieh module_exit(sunplus_uart_exit); 733*9e8d5470SHammer Hsieh 734*9e8d5470SHammer Hsieh #ifdef CONFIG_SERIAL_EARLYCON 735*9e8d5470SHammer Hsieh static void sunplus_uart_putc(struct uart_port *port, int c) 736*9e8d5470SHammer Hsieh { 737*9e8d5470SHammer Hsieh unsigned int val; 738*9e8d5470SHammer Hsieh int ret; 739*9e8d5470SHammer Hsieh 740*9e8d5470SHammer Hsieh ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val, 741*9e8d5470SHammer Hsieh (val & UART_LSR_TEMT), 1, 10000); 742*9e8d5470SHammer Hsieh if (ret) 743*9e8d5470SHammer Hsieh return; 744*9e8d5470SHammer Hsieh 745*9e8d5470SHammer Hsieh writel(c, port->membase + SUP_UART_DATA); 746*9e8d5470SHammer Hsieh } 747*9e8d5470SHammer Hsieh 748*9e8d5470SHammer Hsieh static void sunplus_uart_early_write(struct console *con, const char *s, unsigned int n) 749*9e8d5470SHammer Hsieh { 750*9e8d5470SHammer Hsieh struct earlycon_device *dev = con->data; 751*9e8d5470SHammer Hsieh 752*9e8d5470SHammer Hsieh uart_console_write(&dev->port, s, n, sunplus_uart_putc); 753*9e8d5470SHammer Hsieh } 754*9e8d5470SHammer Hsieh 755*9e8d5470SHammer Hsieh static int __init 756*9e8d5470SHammer Hsieh sunplus_uart_early_setup(struct earlycon_device *dev, const char *opt) 757*9e8d5470SHammer Hsieh { 758*9e8d5470SHammer Hsieh if (!(dev->port.membase || dev->port.iobase)) 759*9e8d5470SHammer Hsieh return -ENODEV; 760*9e8d5470SHammer Hsieh 761*9e8d5470SHammer Hsieh dev->con->write = sunplus_uart_early_write; 762*9e8d5470SHammer Hsieh 763*9e8d5470SHammer Hsieh return 0; 764*9e8d5470SHammer Hsieh } 765*9e8d5470SHammer Hsieh OF_EARLYCON_DECLARE(sunplus_uart, "sunplus,sp7021-uart", sunplus_uart_early_setup); 766*9e8d5470SHammer Hsieh #endif 767*9e8d5470SHammer Hsieh 768*9e8d5470SHammer Hsieh MODULE_DESCRIPTION("Sunplus UART driver"); 769*9e8d5470SHammer Hsieh MODULE_AUTHOR("Hammer Hsieh <[email protected]>"); 770*9e8d5470SHammer Hsieh MODULE_LICENSE("GPL v2"); 771