15bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser/*
25bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * altera_jtaguart.c -- Altera JTAG UART driver
35bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser *
45bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * Based on mcf.c -- Freescale ColdFire UART driver
55bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser *
65bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
75bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
85bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
95bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser *
105bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * This program is free software; you can redistribute it and/or modify
115bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * it under the terms of the GNU General Public License as published by
125bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * the Free Software Foundation; either version 2 of the License, or
135bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * (at your option) any later version.
145bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser */
155bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
165bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/kernel.h>
175bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/init.h>
185bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/interrupt.h>
195bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/module.h>
205bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/console.h>
216b3754d6183797263bc6b28884323cf7842a8961Grant Likely#include <linux/of.h>
225bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/tty.h>
235bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/tty_flip.h>
245bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/serial.h>
255bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/serial_core.h>
265bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/platform_device.h>
275bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/io.h>
285bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#include <linux/altera_jtaguart.h>
295bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
305bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define DRV_NAME "altera_jtaguart"
315bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
325bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser/*
335bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * Altera JTAG UART register definitions according to the Altera JTAG UART
345bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
355bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser */
365bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
375bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_SIZE			8
385bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
395bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_DATA_REG		0
405bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
415bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_DATA_DATA_MSK		0x000000FF
425bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_DATA_RVALID_MSK		0x00008000
435bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_DATA_RAVAIL_MSK		0xFFFF0000
445bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_DATA_RAVAIL_OFF		16
455bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
465bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_CONTROL_REG		4
475bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
485bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_CONTROL_RE_MSK		0x00000001
495bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_CONTROL_WE_MSK		0x00000002
505bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_CONTROL_RI_MSK		0x00000100
515bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_CONTROL_RI_OFF		8
525bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_CONTROL_WI_MSK		0x00000200
535bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_CONTROL_AC_MSK		0x00000400
545bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK	0xFFFF0000
555bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF	16
565bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
575bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser/*
585bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser * Local per-uart structure.
595bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser */
605bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstruct altera_jtaguart {
615bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct uart_port port;
625bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned int sigs;	/* Local copy of line sigs */
635bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned long imr;	/* Local IMR mirror */
645bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser};
655bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
665bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
675bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
685bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
695bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
705bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
715bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
725bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
735bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
745bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
755bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
765bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
775bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
785bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
795bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
805bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
815bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_start_tx(struct uart_port *port)
825bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
835bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct altera_jtaguart *pp =
845bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	    container_of(port, struct altera_jtaguart, port);
855bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
865bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
875bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
885bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
895bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
905bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_stop_tx(struct uart_port *port)
915bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
925bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct altera_jtaguart *pp =
935bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	    container_of(port, struct altera_jtaguart, port);
945bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
955bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
965bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
975bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
985bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
995bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_stop_rx(struct uart_port *port)
1005bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
1015bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct altera_jtaguart *pp =
1025bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	    container_of(port, struct altera_jtaguart, port);
1035bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1045bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
1055bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
1065bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
1075bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1085bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
1095bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
1105bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
1115bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1125bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_set_termios(struct uart_port *port,
1135bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser					struct ktermios *termios,
1145bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser					struct ktermios *old)
1155bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
1165bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	/* Just copy the old termios settings back */
1175bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (old)
1185bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		tty_termios_copy_hw(termios, old);
1195bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
1205bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1215bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
1225bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
1235bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct uart_port *port = &pp->port;
1245bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned char ch, flag;
1255bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned long status;
1265bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1275bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
1285bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	       ALTERA_JTAGUART_DATA_RVALID_MSK) {
1295bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
1305bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		flag = TTY_NORMAL;
1315bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		port->icount.rx++;
1325bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1335bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		if (uart_handle_sysrq_char(port, ch))
1345bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			continue;
1355bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		uart_insert_char(port, 0, 0, ch, flag);
1365bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	}
1375bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
13853dd0ba7a6f48ddc7ee044dcef838a0f8e7fec9bViresh Kumar	spin_unlock(&port->lock);
1392e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	tty_flip_buffer_push(&port->state->port);
14053dd0ba7a6f48ddc7ee044dcef838a0f8e7fec9bViresh Kumar	spin_lock(&port->lock);
1415bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
1425bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1435bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
1445bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
1455bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct uart_port *port = &pp->port;
1465bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct circ_buf *xmit = &port->state->xmit;
1475bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned int pending, count;
1485bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1495bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (port->x_char) {
1505bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		/* Send special char - probably flow control */
1515bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
1525bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		port->x_char = 0;
1535bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		port->icount.tx++;
1545bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		return;
1555bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	}
1565bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1575bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	pending = uart_circ_chars_pending(xmit);
1585bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (pending > 0) {
1595bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
1605bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser				ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
1615bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
1625bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		if (count > pending)
1635bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			count = pending;
1645bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		if (count > 0) {
1655bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			pending -= count;
1665bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			while (count--) {
1675bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser				writel(xmit->buf[xmit->tail],
1685bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser				       port->membase + ALTERA_JTAGUART_DATA_REG);
1695bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser				xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
1705bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser				port->icount.tx++;
1715bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			}
1725bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			if (pending < WAKEUP_CHARS)
1735bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser				uart_write_wakeup(port);
1745bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		}
1755bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	}
1765bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1775bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (pending == 0) {
1785bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
1795bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
1805bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	}
1815bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
1825bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1835bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
1845bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
1855bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct uart_port *port = data;
1865bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct altera_jtaguart *pp =
1875bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	    container_of(port, struct altera_jtaguart, port);
1885bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned int isr;
1895bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1905bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
1915bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	       ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
1925bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1935bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_lock(&port->lock);
1945bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
1955bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
1965bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		altera_jtaguart_rx_chars(pp);
1975bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
1985bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		altera_jtaguart_tx_chars(pp);
1995bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2005bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_unlock(&port->lock);
2015bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2025bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return IRQ_RETVAL(isr);
2035bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
2045bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2055bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_config_port(struct uart_port *port, int flags)
2065bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
2075bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	port->type = PORT_ALTERA_JTAGUART;
2085bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2095bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	/* Clear mask, so no surprise interrupts. */
2105bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
2115bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
2125bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2135bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic int altera_jtaguart_startup(struct uart_port *port)
2145bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
2155bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct altera_jtaguart *pp =
2165bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	    container_of(port, struct altera_jtaguart, port);
2175bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned long flags;
2185bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	int ret;
2195bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2209cfb5c05fee914cc65d4706801f6bc424082b5f5Yong Zhang	ret = request_irq(port->irq, altera_jtaguart_interrupt, 0,
2215bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			DRV_NAME, port);
2225bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (ret) {
2235bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
2245bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		       "interrupt vector=%d\n", port->line, port->irq);
2255bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		return ret;
2265bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	}
2275bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2285bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_lock_irqsave(&port->lock, flags);
2295bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2305bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	/* Enable RX interrupts now */
2315bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
2325bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
2335bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2345bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_unlock_irqrestore(&port->lock, flags);
2355bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2365bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return 0;
2375bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
2385bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2395bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_shutdown(struct uart_port *port)
2405bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
2415bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct altera_jtaguart *pp =
2425bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	    container_of(port, struct altera_jtaguart, port);
2435bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned long flags;
2445bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2455bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_lock_irqsave(&port->lock, flags);
2465bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2475bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	/* Disable all interrupts now */
2485bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	pp->imr = 0;
2495bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
2505bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2515bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_unlock_irqrestore(&port->lock, flags);
2525bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2535bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	free_irq(port->irq, port);
2545bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
2555bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2565bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic const char *altera_jtaguart_type(struct uart_port *port)
2575bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
2585bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
2595bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
2605bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2615bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic int altera_jtaguart_request_port(struct uart_port *port)
2625bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
2635bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	/* UARTs always present */
2645bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return 0;
2655bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
2665bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2675bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_release_port(struct uart_port *port)
2685bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
2695bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	/* Nothing to release... */
2705bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
2715bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2725bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic int altera_jtaguart_verify_port(struct uart_port *port,
2735bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser				       struct serial_struct *ser)
2745bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
2755bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
2765bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		return -EINVAL;
2775bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return 0;
2785bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
2795bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
2805bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser/*
2815bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser *	Define the basic serial functions we support.
2825bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser */
2835bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic struct uart_ops altera_jtaguart_ops = {
2845bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.tx_empty	= altera_jtaguart_tx_empty,
2855bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.get_mctrl	= altera_jtaguart_get_mctrl,
2865bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.set_mctrl	= altera_jtaguart_set_mctrl,
2875bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.start_tx	= altera_jtaguart_start_tx,
2885bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.stop_tx	= altera_jtaguart_stop_tx,
2895bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.stop_rx	= altera_jtaguart_stop_rx,
2905bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.break_ctl	= altera_jtaguart_break_ctl,
2915bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.startup	= altera_jtaguart_startup,
2925bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.shutdown	= altera_jtaguart_shutdown,
2935bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.set_termios	= altera_jtaguart_set_termios,
2945bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.type		= altera_jtaguart_type,
2955bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.request_port	= altera_jtaguart_request_port,
2965bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.release_port	= altera_jtaguart_release_port,
2975bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.config_port	= altera_jtaguart_config_port,
2985bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.verify_port	= altera_jtaguart_verify_port,
2995bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser};
3005bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3015bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define ALTERA_JTAGUART_MAXPORTS 1
3025bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
3035bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3045bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
3055bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3065bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
3072fbe6c5e3e7f8d698d97984a9dce4f05c3d940edTobias Klauserstatic void altera_jtaguart_console_putc(struct uart_port *port, int c)
3085bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
3095bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned long status;
3105bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned long flags;
3115bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3125bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_lock_irqsave(&port->lock, flags);
3135bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
3145bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
3155bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
3165bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			spin_unlock_irqrestore(&port->lock, flags);
3175bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser			return;	/* no connection activity */
3185bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		}
3195bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		spin_unlock_irqrestore(&port->lock, flags);
3205bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		cpu_relax();
3215bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		spin_lock_irqsave(&port->lock, flags);
3225bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	}
3235bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
3245bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_unlock_irqrestore(&port->lock, flags);
3255bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
3265bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#else
3272fbe6c5e3e7f8d698d97984a9dce4f05c3d940edTobias Klauserstatic void altera_jtaguart_console_putc(struct uart_port *port, int c)
3285bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
3295bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	unsigned long flags;
3305bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3315bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_lock_irqsave(&port->lock, flags);
3325bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
3335bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
3345bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		spin_unlock_irqrestore(&port->lock, flags);
3355bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		cpu_relax();
3365bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		spin_lock_irqsave(&port->lock, flags);
3375bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	}
3385bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
3395bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	spin_unlock_irqrestore(&port->lock, flags);
3405bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
3415bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#endif
3425bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3435bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void altera_jtaguart_console_write(struct console *co, const char *s,
3445bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser					  unsigned int count)
3455bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
3463d1c90d48cbe335a47a6a5a05ff731a86eacf6fbTobias Klauser	struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
3473d1c90d48cbe335a47a6a5a05ff731a86eacf6fbTobias Klauser
3483d1c90d48cbe335a47a6a5a05ff731a86eacf6fbTobias Klauser	uart_console_write(port, s, count, altera_jtaguart_console_putc);
3495bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
3505bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3515bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic int __init altera_jtaguart_console_setup(struct console *co,
3525bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser						char *options)
3535bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
3545bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct uart_port *port;
3555bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3565bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
3575bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		return -EINVAL;
3585bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	port = &altera_jtaguart_ports[co->index].port;
3592314a0f667352748a48753bf903f8c50fd2a756dTobias Klauser	if (port->membase == NULL)
3605bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		return -ENODEV;
3615bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return 0;
3625bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
3635bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3645bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic struct uart_driver altera_jtaguart_driver;
3655bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3665bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic struct console altera_jtaguart_console = {
3675bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.name	= "ttyJ",
3685bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.write	= altera_jtaguart_console_write,
3695bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.device	= uart_console_device,
3705bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.setup	= altera_jtaguart_console_setup,
3715bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.flags	= CON_PRINTBUFFER,
3725bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.index	= -1,
3735bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.data	= &altera_jtaguart_driver,
3745bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser};
3755bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3765bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic int __init altera_jtaguart_console_init(void)
3775bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
3785bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	register_console(&altera_jtaguart_console);
3795bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return 0;
3805bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
3815bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3825bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserconsole_initcall(altera_jtaguart_console_init);
3835bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3845bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define	ALTERA_JTAGUART_CONSOLE	(&altera_jtaguart_console)
3855bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3865bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#else
3875bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3885bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#define	ALTERA_JTAGUART_CONSOLE	NULL
3895bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3905bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
3915bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
3925bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic struct uart_driver altera_jtaguart_driver = {
3935bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.owner		= THIS_MODULE,
3945bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.driver_name	= "altera_jtaguart",
3955bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.dev_name	= "ttyJ",
3965bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.major		= ALTERA_JTAGUART_MAJOR,
3975bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.minor		= ALTERA_JTAGUART_MINOR,
3985bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.nr		= ALTERA_JTAGUART_MAXPORTS,
3995bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.cons		= ALTERA_JTAGUART_CONSOLE,
4005bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser};
4015bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
4029671f09921d93e722a28ae9610d478e092ac5466Bill Pembertonstatic int altera_jtaguart_probe(struct platform_device *pdev)
4035bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
404574de559c1797618fd8ed03576837eb3113c5d26Jingoo Han	struct altera_jtaguart_platform_uart *platp =
405574de559c1797618fd8ed03576837eb3113c5d26Jingoo Han			dev_get_platdata(&pdev->dev);
4065bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct uart_port *port;
40772af4762ee640b717a30761e27fc55126c686568Tobias Klauser	struct resource *res_irq, *res_mem;
40872af4762ee640b717a30761e27fc55126c686568Tobias Klauser	int i = pdev->id;
4095bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
41072af4762ee640b717a30761e27fc55126c686568Tobias Klauser	/* -1 emphasizes that the platform must have one port, no .N suffix */
41172af4762ee640b717a30761e27fc55126c686568Tobias Klauser	if (i == -1)
41272af4762ee640b717a30761e27fc55126c686568Tobias Klauser		i = 0;
4135bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
41472af4762ee640b717a30761e27fc55126c686568Tobias Klauser	if (i >= ALTERA_JTAGUART_MAXPORTS)
41572af4762ee640b717a30761e27fc55126c686568Tobias Klauser		return -EINVAL;
4165bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
41772af4762ee640b717a30761e27fc55126c686568Tobias Klauser	port = &altera_jtaguart_ports[i].port;
41872af4762ee640b717a30761e27fc55126c686568Tobias Klauser
41972af4762ee640b717a30761e27fc55126c686568Tobias Klauser	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
42072af4762ee640b717a30761e27fc55126c686568Tobias Klauser	if (res_mem)
42172af4762ee640b717a30761e27fc55126c686568Tobias Klauser		port->mapbase = res_mem->start;
42272af4762ee640b717a30761e27fc55126c686568Tobias Klauser	else if (platp)
42372af4762ee640b717a30761e27fc55126c686568Tobias Klauser		port->mapbase = platp->mapbase;
42472af4762ee640b717a30761e27fc55126c686568Tobias Klauser	else
42572af4762ee640b717a30761e27fc55126c686568Tobias Klauser		return -ENODEV;
42672af4762ee640b717a30761e27fc55126c686568Tobias Klauser
42772af4762ee640b717a30761e27fc55126c686568Tobias Klauser	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
42872af4762ee640b717a30761e27fc55126c686568Tobias Klauser	if (res_irq)
42972af4762ee640b717a30761e27fc55126c686568Tobias Klauser		port->irq = res_irq->start;
43072af4762ee640b717a30761e27fc55126c686568Tobias Klauser	else if (platp)
43172af4762ee640b717a30761e27fc55126c686568Tobias Klauser		port->irq = platp->irq;
43272af4762ee640b717a30761e27fc55126c686568Tobias Klauser	else
43372af4762ee640b717a30761e27fc55126c686568Tobias Klauser		return -ENODEV;
43472af4762ee640b717a30761e27fc55126c686568Tobias Klauser
43572af4762ee640b717a30761e27fc55126c686568Tobias Klauser	port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
43672af4762ee640b717a30761e27fc55126c686568Tobias Klauser	if (!port->membase)
43772af4762ee640b717a30761e27fc55126c686568Tobias Klauser		return -ENOMEM;
43872af4762ee640b717a30761e27fc55126c686568Tobias Klauser
43972af4762ee640b717a30761e27fc55126c686568Tobias Klauser	port->line = i;
44072af4762ee640b717a30761e27fc55126c686568Tobias Klauser	port->type = PORT_ALTERA_JTAGUART;
44172af4762ee640b717a30761e27fc55126c686568Tobias Klauser	port->iotype = SERIAL_IO_MEM;
44272af4762ee640b717a30761e27fc55126c686568Tobias Klauser	port->ops = &altera_jtaguart_ops;
44344ed76b78e158d852f640d533b7acc08b91f2132Tobias Klauser	port->flags = UPF_BOOT_AUTOCONF;
44472af4762ee640b717a30761e27fc55126c686568Tobias Klauser
44572af4762ee640b717a30761e27fc55126c686568Tobias Klauser	uart_add_one_port(&altera_jtaguart_driver, port);
4465bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
4475bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return 0;
4485bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
4495bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
450ae8d8a146725a966bd7c59c94f4d0016dcf7a04fBill Pembertonstatic int altera_jtaguart_remove(struct platform_device *pdev)
4515bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
4525bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	struct uart_port *port;
45372af4762ee640b717a30761e27fc55126c686568Tobias Klauser	int i = pdev->id;
4545bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
45572af4762ee640b717a30761e27fc55126c686568Tobias Klauser	if (i == -1)
45672af4762ee640b717a30761e27fc55126c686568Tobias Klauser		i = 0;
45772af4762ee640b717a30761e27fc55126c686568Tobias Klauser
45872af4762ee640b717a30761e27fc55126c686568Tobias Klauser	port = &altera_jtaguart_ports[i].port;
45972af4762ee640b717a30761e27fc55126c686568Tobias Klauser	uart_remove_one_port(&altera_jtaguart_driver, port);
4605bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
4615bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	return 0;
4625bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
4635bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
4649f15444fefdb33509132ff5c9be60cb315c44cb2Tobias Klauser#ifdef CONFIG_OF
4654d199a55c41b25f4255eaeea358f944e33e91a4bTobias Klauserstatic const struct of_device_id altera_jtaguart_match[] = {
4669f15444fefdb33509132ff5c9be60cb315c44cb2Tobias Klauser	{ .compatible = "ALTR,juart-1.0", },
46713960b47dc1df695f8537c32a0e0ce5ae5d4eee4Dinh Nguyen	{ .compatible = "altr,juart-1.0", },
4689f15444fefdb33509132ff5c9be60cb315c44cb2Tobias Klauser	{},
4699f15444fefdb33509132ff5c9be60cb315c44cb2Tobias Klauser};
4709f15444fefdb33509132ff5c9be60cb315c44cb2Tobias KlauserMODULE_DEVICE_TABLE(of, altera_jtaguart_match);
4719f15444fefdb33509132ff5c9be60cb315c44cb2Tobias Klauser#endif /* CONFIG_OF */
4729f15444fefdb33509132ff5c9be60cb315c44cb2Tobias Klauser
4735bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic struct platform_driver altera_jtaguart_platform_driver = {
4745bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.probe	= altera_jtaguart_probe,
4752d47b7160243b1422006b91debf438484a4fde58Bill Pemberton	.remove	= altera_jtaguart_remove,
4765bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	.driver	= {
4779f15444fefdb33509132ff5c9be60cb315c44cb2Tobias Klauser		.name		= DRV_NAME,
4789f15444fefdb33509132ff5c9be60cb315c44cb2Tobias Klauser		.owner		= THIS_MODULE,
47985888069cf5d0f21312e3ee730458a5e3a553509Ben Dooks		.of_match_table	= of_match_ptr(altera_jtaguart_match),
4805bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	},
4815bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser};
4825bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
4835bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic int __init altera_jtaguart_init(void)
4845bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
4855bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	int rc;
4865bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
4875bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	rc = uart_register_driver(&altera_jtaguart_driver);
4885bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	if (rc)
4895bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		return rc;
4905bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	rc = platform_driver_register(&altera_jtaguart_platform_driver);
491b16ea4b04c3b74524805a409ee2747b751b7a138Tobias Klauser	if (rc)
4925bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser		uart_unregister_driver(&altera_jtaguart_driver);
493b16ea4b04c3b74524805a409ee2747b751b7a138Tobias Klauser	return rc;
4945bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
4955bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
4965bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauserstatic void __exit altera_jtaguart_exit(void)
4975bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser{
4985bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	platform_driver_unregister(&altera_jtaguart_platform_driver);
4995bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser	uart_unregister_driver(&altera_jtaguart_driver);
5005bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser}
5015bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
5025bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klausermodule_init(altera_jtaguart_init);
5035bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klausermodule_exit(altera_jtaguart_exit);
5045bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias Klauser
5055bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias KlauserMODULE_DESCRIPTION("Altera JTAG UART driver");
5065bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias KlauserMODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
5075bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias KlauserMODULE_LICENSE("GPL");
5085bcd601049c6b2ad52733d4cd2794bfbaf1b9314Tobias KlauserMODULE_ALIAS("platform:" DRV_NAME);
509