linux/drivers/tty/serial/altera_jtaguart.c
<<
>>
Prefs
   1/*
   2 * altera_jtaguart.c -- Altera JTAG UART driver
   3 *
   4 * Based on mcf.c -- Freescale ColdFire UART driver
   5 *
   6 * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
   7 * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
   8 * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or
  13 * (at your option) any later version.
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/init.h>
  18#include <linux/interrupt.h>
  19#include <linux/module.h>
  20#include <linux/console.h>
  21#include <linux/of.h>
  22#include <linux/tty.h>
  23#include <linux/tty_flip.h>
  24#include <linux/serial.h>
  25#include <linux/serial_core.h>
  26#include <linux/platform_device.h>
  27#include <linux/io.h>
  28#include <linux/altera_jtaguart.h>
  29
  30#define DRV_NAME "altera_jtaguart"
  31
  32/*
  33 * Altera JTAG UART register definitions according to the Altera JTAG UART
  34 * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
  35 */
  36
  37#define ALTERA_JTAGUART_SIZE                    8
  38
  39#define ALTERA_JTAGUART_DATA_REG                0
  40
  41#define ALTERA_JTAGUART_DATA_DATA_MSK           0x000000FF
  42#define ALTERA_JTAGUART_DATA_RVALID_MSK         0x00008000
  43#define ALTERA_JTAGUART_DATA_RAVAIL_MSK         0xFFFF0000
  44#define ALTERA_JTAGUART_DATA_RAVAIL_OFF         16
  45
  46#define ALTERA_JTAGUART_CONTROL_REG             4
  47
  48#define ALTERA_JTAGUART_CONTROL_RE_MSK          0x00000001
  49#define ALTERA_JTAGUART_CONTROL_WE_MSK          0x00000002
  50#define ALTERA_JTAGUART_CONTROL_RI_MSK          0x00000100
  51#define ALTERA_JTAGUART_CONTROL_RI_OFF          8
  52#define ALTERA_JTAGUART_CONTROL_WI_MSK          0x00000200
  53#define ALTERA_JTAGUART_CONTROL_AC_MSK          0x00000400
  54#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK      0xFFFF0000
  55#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF      16
  56
  57/*
  58 * Local per-uart structure.
  59 */
  60struct altera_jtaguart {
  61        struct uart_port port;
  62        unsigned int sigs;      /* Local copy of line sigs */
  63        unsigned long imr;      /* Local IMR mirror */
  64};
  65
  66static unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
  67{
  68        return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
  69                ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
  70}
  71
  72static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
  73{
  74        return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
  75}
  76
  77static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
  78{
  79}
  80
  81static void altera_jtaguart_start_tx(struct uart_port *port)
  82{
  83        struct altera_jtaguart *pp =
  84            container_of(port, struct altera_jtaguart, port);
  85
  86        pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
  87        writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
  88}
  89
  90static void altera_jtaguart_stop_tx(struct uart_port *port)
  91{
  92        struct altera_jtaguart *pp =
  93            container_of(port, struct altera_jtaguart, port);
  94
  95        pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
  96        writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
  97}
  98
  99static void altera_jtaguart_stop_rx(struct uart_port *port)
 100{
 101        struct altera_jtaguart *pp =
 102            container_of(port, struct altera_jtaguart, port);
 103
 104        pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
 105        writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
 106}
 107
 108static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
 109{
 110}
 111
 112static void altera_jtaguart_set_termios(struct uart_port *port,
 113                                        struct ktermios *termios,
 114                                        struct ktermios *old)
 115{
 116        /* Just copy the old termios settings back */
 117        if (old)
 118                tty_termios_copy_hw(termios, old);
 119}
 120
 121static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
 122{
 123        struct uart_port *port = &pp->port;
 124        unsigned char ch, flag;
 125        unsigned long status;
 126
 127        while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
 128               ALTERA_JTAGUART_DATA_RVALID_MSK) {
 129                ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
 130                flag = TTY_NORMAL;
 131                port->icount.rx++;
 132
 133                if (uart_handle_sysrq_char(port, ch))
 134                        continue;
 135                uart_insert_char(port, 0, 0, ch, flag);
 136        }
 137
 138        spin_unlock(&port->lock);
 139        tty_flip_buffer_push(&port->state->port);
 140        spin_lock(&port->lock);
 141}
 142
 143static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
 144{
 145        struct uart_port *port = &pp->port;
 146        struct circ_buf *xmit = &port->state->xmit;
 147        unsigned int pending, count;
 148
 149        if (port->x_char) {
 150                /* Send special char - probably flow control */
 151                writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
 152                port->x_char = 0;
 153                port->icount.tx++;
 154                return;
 155        }
 156
 157        pending = uart_circ_chars_pending(xmit);
 158        if (pending > 0) {
 159                count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
 160                                ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
 161                        ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
 162                if (count > pending)
 163                        count = pending;
 164                if (count > 0) {
 165                        pending -= count;
 166                        while (count--) {
 167                                writel(xmit->buf[xmit->tail],
 168                                       port->membase + ALTERA_JTAGUART_DATA_REG);
 169                                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 170                                port->icount.tx++;
 171                        }
 172                        if (pending < WAKEUP_CHARS)
 173                                uart_write_wakeup(port);
 174                }
 175        }
 176
 177        if (pending == 0) {
 178                pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
 179                writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
 180        }
 181}
 182
 183static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
 184{
 185        struct uart_port *port = data;
 186        struct altera_jtaguart *pp =
 187            container_of(port, struct altera_jtaguart, port);
 188        unsigned int isr;
 189
 190        isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
 191               ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
 192
 193        spin_lock(&port->lock);
 194
 195        if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
 196                altera_jtaguart_rx_chars(pp);
 197        if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
 198                altera_jtaguart_tx_chars(pp);
 199
 200        spin_unlock(&port->lock);
 201
 202        return IRQ_RETVAL(isr);
 203}
 204
 205static void altera_jtaguart_config_port(struct uart_port *port, int flags)
 206{
 207        port->type = PORT_ALTERA_JTAGUART;
 208
 209        /* Clear mask, so no surprise interrupts. */
 210        writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
 211}
 212
 213static int altera_jtaguart_startup(struct uart_port *port)
 214{
 215        struct altera_jtaguart *pp =
 216            container_of(port, struct altera_jtaguart, port);
 217        unsigned long flags;
 218        int ret;
 219
 220        ret = request_irq(port->irq, altera_jtaguart_interrupt, 0,
 221                        DRV_NAME, port);
 222        if (ret) {
 223                pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
 224                       "interrupt vector=%d\n", port->line, port->irq);
 225                return ret;
 226        }
 227
 228        spin_lock_irqsave(&port->lock, flags);
 229
 230        /* Enable RX interrupts now */
 231        pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
 232        writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
 233
 234        spin_unlock_irqrestore(&port->lock, flags);
 235
 236        return 0;
 237}
 238
 239static void altera_jtaguart_shutdown(struct uart_port *port)
 240{
 241        struct altera_jtaguart *pp =
 242            container_of(port, struct altera_jtaguart, port);
 243        unsigned long flags;
 244
 245        spin_lock_irqsave(&port->lock, flags);
 246
 247        /* Disable all interrupts now */
 248        pp->imr = 0;
 249        writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
 250
 251        spin_unlock_irqrestore(&port->lock, flags);
 252
 253        free_irq(port->irq, port);
 254}
 255
 256static const char *altera_jtaguart_type(struct uart_port *port)
 257{
 258        return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
 259}
 260
 261static int altera_jtaguart_request_port(struct uart_port *port)
 262{
 263        /* UARTs always present */
 264        return 0;
 265}
 266
 267static void altera_jtaguart_release_port(struct uart_port *port)
 268{
 269        /* Nothing to release... */
 270}
 271
 272static int altera_jtaguart_verify_port(struct uart_port *port,
 273                                       struct serial_struct *ser)
 274{
 275        if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
 276                return -EINVAL;
 277        return 0;
 278}
 279
 280/*
 281 *      Define the basic serial functions we support.
 282 */
 283static struct uart_ops altera_jtaguart_ops = {
 284        .tx_empty       = altera_jtaguart_tx_empty,
 285        .get_mctrl      = altera_jtaguart_get_mctrl,
 286        .set_mctrl      = altera_jtaguart_set_mctrl,
 287        .start_tx       = altera_jtaguart_start_tx,
 288        .stop_tx        = altera_jtaguart_stop_tx,
 289        .stop_rx        = altera_jtaguart_stop_rx,
 290        .break_ctl      = altera_jtaguart_break_ctl,
 291        .startup        = altera_jtaguart_startup,
 292        .shutdown       = altera_jtaguart_shutdown,
 293        .set_termios    = altera_jtaguart_set_termios,
 294        .type           = altera_jtaguart_type,
 295        .request_port   = altera_jtaguart_request_port,
 296        .release_port   = altera_jtaguart_release_port,
 297        .config_port    = altera_jtaguart_config_port,
 298        .verify_port    = altera_jtaguart_verify_port,
 299};
 300
 301#define ALTERA_JTAGUART_MAXPORTS 1
 302static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
 303
 304#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
 305
 306#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
 307static void altera_jtaguart_console_putc(struct uart_port *port, int c)
 308{
 309        unsigned long status;
 310        unsigned long flags;
 311
 312        spin_lock_irqsave(&port->lock, flags);
 313        while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
 314                ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
 315                if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
 316                        spin_unlock_irqrestore(&port->lock, flags);
 317                        return; /* no connection activity */
 318                }
 319                spin_unlock_irqrestore(&port->lock, flags);
 320                cpu_relax();
 321                spin_lock_irqsave(&port->lock, flags);
 322        }
 323        writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
 324        spin_unlock_irqrestore(&port->lock, flags);
 325}
 326#else
 327static void altera_jtaguart_console_putc(struct uart_port *port, int c)
 328{
 329        unsigned long flags;
 330
 331        spin_lock_irqsave(&port->lock, flags);
 332        while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
 333                ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
 334                spin_unlock_irqrestore(&port->lock, flags);
 335                cpu_relax();
 336                spin_lock_irqsave(&port->lock, flags);
 337        }
 338        writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
 339        spin_unlock_irqrestore(&port->lock, flags);
 340}
 341#endif
 342
 343static void altera_jtaguart_console_write(struct console *co, const char *s,
 344                                          unsigned int count)
 345{
 346        struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
 347
 348        uart_console_write(port, s, count, altera_jtaguart_console_putc);
 349}
 350
 351static int __init altera_jtaguart_console_setup(struct console *co,
 352                                                char *options)
 353{
 354        struct uart_port *port;
 355
 356        if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
 357                return -EINVAL;
 358        port = &altera_jtaguart_ports[co->index].port;
 359        if (port->membase == NULL)
 360                return -ENODEV;
 361        return 0;
 362}
 363
 364static struct uart_driver altera_jtaguart_driver;
 365
 366static struct console altera_jtaguart_console = {
 367        .name   = "ttyJ",
 368        .write  = altera_jtaguart_console_write,
 369        .device = uart_console_device,
 370        .setup  = altera_jtaguart_console_setup,
 371        .flags  = CON_PRINTBUFFER,
 372        .index  = -1,
 373        .data   = &altera_jtaguart_driver,
 374};
 375
 376static int __init altera_jtaguart_console_init(void)
 377{
 378        register_console(&altera_jtaguart_console);
 379        return 0;
 380}
 381
 382console_initcall(altera_jtaguart_console_init);
 383
 384#define ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console)
 385
 386#else
 387
 388#define ALTERA_JTAGUART_CONSOLE NULL
 389
 390#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
 391
 392static struct uart_driver altera_jtaguart_driver = {
 393        .owner          = THIS_MODULE,
 394        .driver_name    = "altera_jtaguart",
 395        .dev_name       = "ttyJ",
 396        .major          = ALTERA_JTAGUART_MAJOR,
 397        .minor          = ALTERA_JTAGUART_MINOR,
 398        .nr             = ALTERA_JTAGUART_MAXPORTS,
 399        .cons           = ALTERA_JTAGUART_CONSOLE,
 400};
 401
 402static int altera_jtaguart_probe(struct platform_device *pdev)
 403{
 404        struct altera_jtaguart_platform_uart *platp =
 405                        dev_get_platdata(&pdev->dev);
 406        struct uart_port *port;
 407        struct resource *res_irq, *res_mem;
 408        int i = pdev->id;
 409
 410        /* -1 emphasizes that the platform must have one port, no .N suffix */
 411        if (i == -1)
 412                i = 0;
 413
 414        if (i >= ALTERA_JTAGUART_MAXPORTS)
 415                return -EINVAL;
 416
 417        port = &altera_jtaguart_ports[i].port;
 418
 419        res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 420        if (res_mem)
 421                port->mapbase = res_mem->start;
 422        else if (platp)
 423                port->mapbase = platp->mapbase;
 424        else
 425                return -ENODEV;
 426
 427        res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 428        if (res_irq)
 429                port->irq = res_irq->start;
 430        else if (platp)
 431                port->irq = platp->irq;
 432        else
 433                return -ENODEV;
 434
 435        port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
 436        if (!port->membase)
 437                return -ENOMEM;
 438
 439        port->line = i;
 440        port->type = PORT_ALTERA_JTAGUART;
 441        port->iotype = SERIAL_IO_MEM;
 442        port->ops = &altera_jtaguart_ops;
 443        port->flags = UPF_BOOT_AUTOCONF;
 444
 445        uart_add_one_port(&altera_jtaguart_driver, port);
 446
 447        return 0;
 448}
 449
 450static int altera_jtaguart_remove(struct platform_device *pdev)
 451{
 452        struct uart_port *port;
 453        int i = pdev->id;
 454
 455        if (i == -1)
 456                i = 0;
 457
 458        port = &altera_jtaguart_ports[i].port;
 459        uart_remove_one_port(&altera_jtaguart_driver, port);
 460
 461        return 0;
 462}
 463
 464#ifdef CONFIG_OF
 465static const struct of_device_id altera_jtaguart_match[] = {
 466        { .compatible = "ALTR,juart-1.0", },
 467        { .compatible = "altr,juart-1.0", },
 468        {},
 469};
 470MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
 471#endif /* CONFIG_OF */
 472
 473static struct platform_driver altera_jtaguart_platform_driver = {
 474        .probe  = altera_jtaguart_probe,
 475        .remove = altera_jtaguart_remove,
 476        .driver = {
 477                .name           = DRV_NAME,
 478                .owner          = THIS_MODULE,
 479                .of_match_table = of_match_ptr(altera_jtaguart_match),
 480        },
 481};
 482
 483static int __init altera_jtaguart_init(void)
 484{
 485        int rc;
 486
 487        rc = uart_register_driver(&altera_jtaguart_driver);
 488        if (rc)
 489                return rc;
 490        rc = platform_driver_register(&altera_jtaguart_platform_driver);
 491        if (rc)
 492                uart_unregister_driver(&altera_jtaguart_driver);
 493        return rc;
 494}
 495
 496static void __exit altera_jtaguart_exit(void)
 497{
 498        platform_driver_unregister(&altera_jtaguart_platform_driver);
 499        uart_unregister_driver(&altera_jtaguart_driver);
 500}
 501
 502module_init(altera_jtaguart_init);
 503module_exit(altera_jtaguart_exit);
 504
 505MODULE_DESCRIPTION("Altera JTAG UART driver");
 506MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
 507MODULE_LICENSE("GPL");
 508MODULE_ALIAS("platform:" DRV_NAME);
 509