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