root/drivers/tty/serial/clps711x.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. uart_clps711x_stop_tx
  2. uart_clps711x_start_tx
  3. uart_clps711x_int_rx
  4. uart_clps711x_int_tx
  5. uart_clps711x_tx_empty
  6. uart_clps711x_get_mctrl
  7. uart_clps711x_set_mctrl
  8. uart_clps711x_break_ctl
  9. uart_clps711x_set_ldisc
  10. uart_clps711x_startup
  11. uart_clps711x_shutdown
  12. uart_clps711x_set_termios
  13. uart_clps711x_type
  14. uart_clps711x_config_port
  15. uart_clps711x_nop_void
  16. uart_clps711x_nop_int
  17. uart_clps711x_console_putchar
  18. uart_clps711x_console_write
  19. uart_clps711x_console_setup
  20. uart_clps711x_probe
  21. uart_clps711x_remove
  22. uart_clps711x_init
  23. uart_clps711x_exit

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  *  Driver for CLPS711x serial ports
   4  *
   5  *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
   6  *
   7  *  Copyright 1999 ARM Limited
   8  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
   9  */
  10 
  11 #if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
  12 #define SUPPORT_SYSRQ
  13 #endif
  14 
  15 #include <linux/module.h>
  16 #include <linux/device.h>
  17 #include <linux/console.h>
  18 #include <linux/serial_core.h>
  19 #include <linux/serial.h>
  20 #include <linux/clk.h>
  21 #include <linux/io.h>
  22 #include <linux/tty.h>
  23 #include <linux/tty_flip.h>
  24 #include <linux/ioport.h>
  25 #include <linux/of.h>
  26 #include <linux/platform_device.h>
  27 #include <linux/regmap.h>
  28 
  29 #include <linux/mfd/syscon.h>
  30 #include <linux/mfd/syscon/clps711x.h>
  31 
  32 #include "serial_mctrl_gpio.h"
  33 
  34 #define UART_CLPS711X_DEVNAME   "ttyCL"
  35 #define UART_CLPS711X_NR        2
  36 #define UART_CLPS711X_MAJOR     204
  37 #define UART_CLPS711X_MINOR     40
  38 
  39 #define UARTDR_OFFSET           (0x00)
  40 #define UBRLCR_OFFSET           (0x40)
  41 
  42 #define UARTDR_FRMERR           (1 << 8)
  43 #define UARTDR_PARERR           (1 << 9)
  44 #define UARTDR_OVERR            (1 << 10)
  45 
  46 #define UBRLCR_BAUD_MASK        ((1 << 12) - 1)
  47 #define UBRLCR_BREAK            (1 << 12)
  48 #define UBRLCR_PRTEN            (1 << 13)
  49 #define UBRLCR_EVENPRT          (1 << 14)
  50 #define UBRLCR_XSTOP            (1 << 15)
  51 #define UBRLCR_FIFOEN           (1 << 16)
  52 #define UBRLCR_WRDLEN5          (0 << 17)
  53 #define UBRLCR_WRDLEN6          (1 << 17)
  54 #define UBRLCR_WRDLEN7          (2 << 17)
  55 #define UBRLCR_WRDLEN8          (3 << 17)
  56 #define UBRLCR_WRDLEN_MASK      (3 << 17)
  57 
  58 struct clps711x_port {
  59         struct uart_port        port;
  60         unsigned int            tx_enabled;
  61         int                     rx_irq;
  62         struct regmap           *syscon;
  63         struct mctrl_gpios      *gpios;
  64 };
  65 
  66 static struct uart_driver clps711x_uart = {
  67         .owner          = THIS_MODULE,
  68         .driver_name    = UART_CLPS711X_DEVNAME,
  69         .dev_name       = UART_CLPS711X_DEVNAME,
  70         .major          = UART_CLPS711X_MAJOR,
  71         .minor          = UART_CLPS711X_MINOR,
  72         .nr             = UART_CLPS711X_NR,
  73 };
  74 
  75 static void uart_clps711x_stop_tx(struct uart_port *port)
  76 {
  77         struct clps711x_port *s = dev_get_drvdata(port->dev);
  78 
  79         if (s->tx_enabled) {
  80                 disable_irq(port->irq);
  81                 s->tx_enabled = 0;
  82         }
  83 }
  84 
  85 static void uart_clps711x_start_tx(struct uart_port *port)
  86 {
  87         struct clps711x_port *s = dev_get_drvdata(port->dev);
  88 
  89         if (!s->tx_enabled) {
  90                 s->tx_enabled = 1;
  91                 enable_irq(port->irq);
  92         }
  93 }
  94 
  95 static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)
  96 {
  97         struct uart_port *port = dev_id;
  98         struct clps711x_port *s = dev_get_drvdata(port->dev);
  99         unsigned int status, flg;
 100         u16 ch;
 101 
 102         for (;;) {
 103                 u32 sysflg = 0;
 104 
 105                 regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
 106                 if (sysflg & SYSFLG_URXFE)
 107                         break;
 108 
 109                 ch = readw(port->membase + UARTDR_OFFSET);
 110                 status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR);
 111                 ch &= 0xff;
 112 
 113                 port->icount.rx++;
 114                 flg = TTY_NORMAL;
 115 
 116                 if (unlikely(status)) {
 117                         if (status & UARTDR_PARERR)
 118                                 port->icount.parity++;
 119                         else if (status & UARTDR_FRMERR)
 120                                 port->icount.frame++;
 121                         else if (status & UARTDR_OVERR)
 122                                 port->icount.overrun++;
 123 
 124                         status &= port->read_status_mask;
 125 
 126                         if (status & UARTDR_PARERR)
 127                                 flg = TTY_PARITY;
 128                         else if (status & UARTDR_FRMERR)
 129                                 flg = TTY_FRAME;
 130                         else if (status & UARTDR_OVERR)
 131                                 flg = TTY_OVERRUN;
 132                 }
 133 
 134                 if (uart_handle_sysrq_char(port, ch))
 135                         continue;
 136 
 137                 if (status & port->ignore_status_mask)
 138                         continue;
 139 
 140                 uart_insert_char(port, status, UARTDR_OVERR, ch, flg);
 141         }
 142 
 143         tty_flip_buffer_push(&port->state->port);
 144 
 145         return IRQ_HANDLED;
 146 }
 147 
 148 static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
 149 {
 150         struct uart_port *port = dev_id;
 151         struct clps711x_port *s = dev_get_drvdata(port->dev);
 152         struct circ_buf *xmit = &port->state->xmit;
 153 
 154         if (port->x_char) {
 155                 writew(port->x_char, port->membase + UARTDR_OFFSET);
 156                 port->icount.tx++;
 157                 port->x_char = 0;
 158                 return IRQ_HANDLED;
 159         }
 160 
 161         if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
 162                 if (s->tx_enabled) {
 163                         disable_irq_nosync(port->irq);
 164                         s->tx_enabled = 0;
 165                 }
 166                 return IRQ_HANDLED;
 167         }
 168 
 169         while (!uart_circ_empty(xmit)) {
 170                 u32 sysflg = 0;
 171 
 172                 writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET);
 173                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 174                 port->icount.tx++;
 175 
 176                 regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
 177                 if (sysflg & SYSFLG_UTXFF)
 178                         break;
 179         }
 180 
 181         if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 182                 uart_write_wakeup(port);
 183 
 184         return IRQ_HANDLED;
 185 }
 186 
 187 static unsigned int uart_clps711x_tx_empty(struct uart_port *port)
 188 {
 189         struct clps711x_port *s = dev_get_drvdata(port->dev);
 190         u32 sysflg = 0;
 191 
 192         regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
 193 
 194         return (sysflg & SYSFLG_UBUSY) ? 0 : TIOCSER_TEMT;
 195 }
 196 
 197 static unsigned int uart_clps711x_get_mctrl(struct uart_port *port)
 198 {
 199         unsigned int result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
 200         struct clps711x_port *s = dev_get_drvdata(port->dev);
 201 
 202         return mctrl_gpio_get(s->gpios, &result);
 203 }
 204 
 205 static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl)
 206 {
 207         struct clps711x_port *s = dev_get_drvdata(port->dev);
 208 
 209         mctrl_gpio_set(s->gpios, mctrl);
 210 }
 211 
 212 static void uart_clps711x_break_ctl(struct uart_port *port, int break_state)
 213 {
 214         unsigned int ubrlcr;
 215 
 216         ubrlcr = readl(port->membase + UBRLCR_OFFSET);
 217         if (break_state)
 218                 ubrlcr |= UBRLCR_BREAK;
 219         else
 220                 ubrlcr &= ~UBRLCR_BREAK;
 221         writel(ubrlcr, port->membase + UBRLCR_OFFSET);
 222 }
 223 
 224 static void uart_clps711x_set_ldisc(struct uart_port *port,
 225                                     struct ktermios *termios)
 226 {
 227         if (!port->line) {
 228                 struct clps711x_port *s = dev_get_drvdata(port->dev);
 229 
 230                 regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON1_SIREN,
 231                                    (termios->c_line == N_IRDA) ? SYSCON1_SIREN : 0);
 232         }
 233 }
 234 
 235 static int uart_clps711x_startup(struct uart_port *port)
 236 {
 237         struct clps711x_port *s = dev_get_drvdata(port->dev);
 238 
 239         /* Disable break */
 240         writel(readl(port->membase + UBRLCR_OFFSET) & ~UBRLCR_BREAK,
 241                port->membase + UBRLCR_OFFSET);
 242 
 243         /* Enable the port */
 244         return regmap_update_bits(s->syscon, SYSCON_OFFSET,
 245                                   SYSCON_UARTEN, SYSCON_UARTEN);
 246 }
 247 
 248 static void uart_clps711x_shutdown(struct uart_port *port)
 249 {
 250         struct clps711x_port *s = dev_get_drvdata(port->dev);
 251 
 252         /* Disable the port */
 253         regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0);
 254 }
 255 
 256 static void uart_clps711x_set_termios(struct uart_port *port,
 257                                       struct ktermios *termios,
 258                                       struct ktermios *old)
 259 {
 260         u32 ubrlcr;
 261         unsigned int baud, quot;
 262 
 263         /* Mask termios capabilities we don't support */
 264         termios->c_cflag &= ~CMSPAR;
 265         termios->c_iflag &= ~(BRKINT | IGNBRK);
 266 
 267         /* Ask the core to calculate the divisor for us */
 268         baud = uart_get_baud_rate(port, termios, old, port->uartclk / 4096,
 269                                                       port->uartclk / 16);
 270         quot = uart_get_divisor(port, baud);
 271 
 272         switch (termios->c_cflag & CSIZE) {
 273         case CS5:
 274                 ubrlcr = UBRLCR_WRDLEN5;
 275                 break;
 276         case CS6:
 277                 ubrlcr = UBRLCR_WRDLEN6;
 278                 break;
 279         case CS7:
 280                 ubrlcr = UBRLCR_WRDLEN7;
 281                 break;
 282         case CS8:
 283         default:
 284                 ubrlcr = UBRLCR_WRDLEN8;
 285                 break;
 286         }
 287 
 288         if (termios->c_cflag & CSTOPB)
 289                 ubrlcr |= UBRLCR_XSTOP;
 290 
 291         if (termios->c_cflag & PARENB) {
 292                 ubrlcr |= UBRLCR_PRTEN;
 293                 if (!(termios->c_cflag & PARODD))
 294                         ubrlcr |= UBRLCR_EVENPRT;
 295         }
 296 
 297         /* Enable FIFO */
 298         ubrlcr |= UBRLCR_FIFOEN;
 299 
 300         /* Set read status mask */
 301         port->read_status_mask = UARTDR_OVERR;
 302         if (termios->c_iflag & INPCK)
 303                 port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
 304 
 305         /* Set status ignore mask */
 306         port->ignore_status_mask = 0;
 307         if (!(termios->c_cflag & CREAD))
 308                 port->ignore_status_mask |= UARTDR_OVERR | UARTDR_PARERR |
 309                                             UARTDR_FRMERR;
 310 
 311         uart_update_timeout(port, termios->c_cflag, baud);
 312 
 313         writel(ubrlcr | (quot - 1), port->membase + UBRLCR_OFFSET);
 314 }
 315 
 316 static const char *uart_clps711x_type(struct uart_port *port)
 317 {
 318         return (port->type == PORT_CLPS711X) ? "CLPS711X" : NULL;
 319 }
 320 
 321 static void uart_clps711x_config_port(struct uart_port *port, int flags)
 322 {
 323         if (flags & UART_CONFIG_TYPE)
 324                 port->type = PORT_CLPS711X;
 325 }
 326 
 327 static void uart_clps711x_nop_void(struct uart_port *port)
 328 {
 329 }
 330 
 331 static int uart_clps711x_nop_int(struct uart_port *port)
 332 {
 333         return 0;
 334 }
 335 
 336 static const struct uart_ops uart_clps711x_ops = {
 337         .tx_empty       = uart_clps711x_tx_empty,
 338         .set_mctrl      = uart_clps711x_set_mctrl,
 339         .get_mctrl      = uart_clps711x_get_mctrl,
 340         .stop_tx        = uart_clps711x_stop_tx,
 341         .start_tx       = uart_clps711x_start_tx,
 342         .stop_rx        = uart_clps711x_nop_void,
 343         .break_ctl      = uart_clps711x_break_ctl,
 344         .set_ldisc      = uart_clps711x_set_ldisc,
 345         .startup        = uart_clps711x_startup,
 346         .shutdown       = uart_clps711x_shutdown,
 347         .set_termios    = uart_clps711x_set_termios,
 348         .type           = uart_clps711x_type,
 349         .config_port    = uart_clps711x_config_port,
 350         .release_port   = uart_clps711x_nop_void,
 351         .request_port   = uart_clps711x_nop_int,
 352 };
 353 
 354 #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
 355 static void uart_clps711x_console_putchar(struct uart_port *port, int ch)
 356 {
 357         struct clps711x_port *s = dev_get_drvdata(port->dev);
 358         u32 sysflg = 0;
 359 
 360         /* Wait for FIFO is not full */
 361         do {
 362                 regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
 363         } while (sysflg & SYSFLG_UTXFF);
 364 
 365         writew(ch, port->membase + UARTDR_OFFSET);
 366 }
 367 
 368 static void uart_clps711x_console_write(struct console *co, const char *c,
 369                                         unsigned n)
 370 {
 371         struct uart_port *port = clps711x_uart.state[co->index].uart_port;
 372         struct clps711x_port *s = dev_get_drvdata(port->dev);
 373         u32 sysflg = 0;
 374 
 375         uart_console_write(port, c, n, uart_clps711x_console_putchar);
 376 
 377         /* Wait for transmitter to become empty */
 378         do {
 379                 regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
 380         } while (sysflg & SYSFLG_UBUSY);
 381 }
 382 
 383 static int uart_clps711x_console_setup(struct console *co, char *options)
 384 {
 385         int baud = 38400, bits = 8, parity = 'n', flow = 'n';
 386         int ret, index = co->index;
 387         struct clps711x_port *s;
 388         struct uart_port *port;
 389         unsigned int quot;
 390         u32 ubrlcr;
 391 
 392         if (index < 0 || index >= UART_CLPS711X_NR)
 393                 return -EINVAL;
 394 
 395         port = clps711x_uart.state[index].uart_port;
 396         if (!port)
 397                 return -ENODEV;
 398 
 399         s = dev_get_drvdata(port->dev);
 400 
 401         if (!options) {
 402                 u32 syscon = 0;
 403 
 404                 regmap_read(s->syscon, SYSCON_OFFSET, &syscon);
 405                 if (syscon & SYSCON_UARTEN) {
 406                         ubrlcr = readl(port->membase + UBRLCR_OFFSET);
 407 
 408                         if (ubrlcr & UBRLCR_PRTEN) {
 409                                 if (ubrlcr & UBRLCR_EVENPRT)
 410                                         parity = 'e';
 411                                 else
 412                                         parity = 'o';
 413                         }
 414 
 415                         if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
 416                                 bits = 7;
 417 
 418                         quot = ubrlcr & UBRLCR_BAUD_MASK;
 419                         baud = port->uartclk / (16 * (quot + 1));
 420                 }
 421         } else
 422                 uart_parse_options(options, &baud, &parity, &bits, &flow);
 423 
 424         ret = uart_set_options(port, co, baud, parity, bits, flow);
 425         if (ret)
 426                 return ret;
 427 
 428         return regmap_update_bits(s->syscon, SYSCON_OFFSET,
 429                                   SYSCON_UARTEN, SYSCON_UARTEN);
 430 }
 431 
 432 static struct console clps711x_console = {
 433         .name   = UART_CLPS711X_DEVNAME,
 434         .device = uart_console_device,
 435         .write  = uart_clps711x_console_write,
 436         .setup  = uart_clps711x_console_setup,
 437         .flags  = CON_PRINTBUFFER,
 438         .index  = -1,
 439 };
 440 #endif
 441 
 442 static int uart_clps711x_probe(struct platform_device *pdev)
 443 {
 444         struct device_node *np = pdev->dev.of_node;
 445         struct clps711x_port *s;
 446         struct resource *res;
 447         struct clk *uart_clk;
 448         int irq, ret;
 449 
 450         s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
 451         if (!s)
 452                 return -ENOMEM;
 453 
 454         uart_clk = devm_clk_get(&pdev->dev, NULL);
 455         if (IS_ERR(uart_clk))
 456                 return PTR_ERR(uart_clk);
 457 
 458         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 459         s->port.membase = devm_ioremap_resource(&pdev->dev, res);
 460         if (IS_ERR(s->port.membase))
 461                 return PTR_ERR(s->port.membase);
 462 
 463         irq = platform_get_irq(pdev, 0);
 464         if (irq < 0)
 465                 return irq;
 466         s->port.irq = irq;
 467 
 468         s->rx_irq = platform_get_irq(pdev, 1);
 469         if (s->rx_irq < 0)
 470                 return s->rx_irq;
 471 
 472         s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
 473         if (IS_ERR(s->syscon))
 474                 return PTR_ERR(s->syscon);
 475 
 476         s->port.line            = of_alias_get_id(np, "serial");
 477         s->port.dev             = &pdev->dev;
 478         s->port.iotype          = UPIO_MEM32;
 479         s->port.mapbase         = res->start;
 480         s->port.type            = PORT_CLPS711X;
 481         s->port.fifosize        = 16;
 482         s->port.flags           = UPF_SKIP_TEST | UPF_FIXED_TYPE;
 483         s->port.uartclk         = clk_get_rate(uart_clk);
 484         s->port.ops             = &uart_clps711x_ops;
 485 
 486         platform_set_drvdata(pdev, s);
 487 
 488         s->gpios = mctrl_gpio_init_noauto(&pdev->dev, 0);
 489         if (IS_ERR(s->gpios))
 490             return PTR_ERR(s->gpios);
 491 
 492         ret = uart_add_one_port(&clps711x_uart, &s->port);
 493         if (ret)
 494                 return ret;
 495 
 496         /* Disable port */
 497         if (!uart_console(&s->port))
 498                 regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0);
 499 
 500         s->tx_enabled = 1;
 501 
 502         ret = devm_request_irq(&pdev->dev, s->port.irq, uart_clps711x_int_tx, 0,
 503                                dev_name(&pdev->dev), &s->port);
 504         if (ret) {
 505                 uart_remove_one_port(&clps711x_uart, &s->port);
 506                 return ret;
 507         }
 508 
 509         ret = devm_request_irq(&pdev->dev, s->rx_irq, uart_clps711x_int_rx, 0,
 510                                dev_name(&pdev->dev), &s->port);
 511         if (ret)
 512                 uart_remove_one_port(&clps711x_uart, &s->port);
 513 
 514         return ret;
 515 }
 516 
 517 static int uart_clps711x_remove(struct platform_device *pdev)
 518 {
 519         struct clps711x_port *s = platform_get_drvdata(pdev);
 520 
 521         return uart_remove_one_port(&clps711x_uart, &s->port);
 522 }
 523 
 524 static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = {
 525         { .compatible = "cirrus,ep7209-uart", },
 526         { }
 527 };
 528 MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids);
 529 
 530 static struct platform_driver clps711x_uart_platform = {
 531         .driver = {
 532                 .name           = "clps711x-uart",
 533                 .of_match_table = of_match_ptr(clps711x_uart_dt_ids),
 534         },
 535         .probe  = uart_clps711x_probe,
 536         .remove = uart_clps711x_remove,
 537 };
 538 
 539 static int __init uart_clps711x_init(void)
 540 {
 541         int ret;
 542 
 543 #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
 544         clps711x_uart.cons = &clps711x_console;
 545         clps711x_console.data = &clps711x_uart;
 546 #endif
 547 
 548         ret = uart_register_driver(&clps711x_uart);
 549         if (ret)
 550                 return ret;
 551 
 552         return platform_driver_register(&clps711x_uart_platform);
 553 }
 554 module_init(uart_clps711x_init);
 555 
 556 static void __exit uart_clps711x_exit(void)
 557 {
 558         platform_driver_unregister(&clps711x_uart_platform);
 559         uart_unregister_driver(&clps711x_uart);
 560 }
 561 module_exit(uart_clps711x_exit);
 562 
 563 MODULE_AUTHOR("Deep Blue Solutions Ltd");
 564 MODULE_DESCRIPTION("CLPS711X serial driver");
 565 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */