apbuart.c revision c897dcf6311ea9c8d24e96cc7f7fe9de58a0a6a2
1d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo/*
2d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo *  Driver for GRLIB serial ports (APBUART)
3d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo *
4d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo *  Based on linux/drivers/serial/amba.c
5d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo *
6d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo *  Copyright (C) 2000 Deep Blue Solutions Ltd.
7d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo *  Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
8d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo *  Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
9d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo *  Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
10d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo *  Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
11d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo */
12d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
13d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
14d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#define SUPPORT_SYSRQ
15d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#endif
16d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
17d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/module.h>
18d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/tty.h>
19d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/ioport.h>
20d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/init.h>
21d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/serial.h>
22d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/console.h>
23d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/sysrq.h>
24d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/kthread.h>
25d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/device.h>
26d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/of.h>
27d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/of_device.h>
28ddaf1b27edf72372242d752730d526b79312a44eDavid S. Miller#include <linux/of_platform.h>
29f28f3313aa97dcb46954f90f596d75f8faf4626eDaniel Hellstrom#include <linux/of_irq.h>
30d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/platform_device.h>
31d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/io.h>
32d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <linux/serial_core.h>
33d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include <asm/irq.h>
34d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
35d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#include "apbuart.h"
36d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
37d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#define SERIAL_APBUART_MAJOR	TTY_MAJOR
38d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#define SERIAL_APBUART_MINOR	64
39d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#define UART_DUMMY_RSR_RX	0x8000	/* for ignore all read */
40d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
41d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_tx_chars(struct uart_port *port);
42d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
43d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_stop_tx(struct uart_port *port)
44d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
45d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int cr;
46d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
47d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr = UART_GET_CTRL(port);
48d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr &= ~UART_CTRL_TI;
49d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port, cr);
50d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
51d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
52d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_start_tx(struct uart_port *port)
53d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
54d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int cr;
55d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
56d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr = UART_GET_CTRL(port);
57d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr |= UART_CTRL_TI;
58d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port, cr);
59d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
60d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (UART_GET_STATUS(port) & UART_STATUS_THE)
61d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		apbuart_tx_chars(port);
62d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
63d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
64d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_stop_rx(struct uart_port *port)
65d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
66d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int cr;
67d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
68d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr = UART_GET_CTRL(port);
69d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr &= ~(UART_CTRL_RI);
70d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port, cr);
71d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
72d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
73d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_enable_ms(struct uart_port *port)
74d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
75d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* No modem status change interrupts for APBUART */
76d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
77d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
78d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_rx_chars(struct uart_port *port)
79d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
80d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	struct tty_struct *tty = port->state->port.tty;
81d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int status, ch, rsr, flag;
82d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int max_chars = port->fifosize;
83d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
84d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	status = UART_GET_STATUS(port);
85d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
86d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	while (UART_RX_DATA(status) && (max_chars--)) {
87d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
88d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		ch = UART_GET_CHAR(port);
89d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		flag = TTY_NORMAL;
90d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
91d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->icount.rx++;
92d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
93d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
94d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		UART_PUT_STATUS(port, 0);
95d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		if (rsr & UART_STATUS_ERR) {
96d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
97d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			if (rsr & UART_STATUS_BR) {
98d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
99d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				port->icount.brk++;
100d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				if (uart_handle_break(port))
101d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo					goto ignore_char;
102d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			} else if (rsr & UART_STATUS_PE) {
103d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				port->icount.parity++;
104d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			} else if (rsr & UART_STATUS_FE) {
105d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				port->icount.frame++;
106d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			}
107d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			if (rsr & UART_STATUS_OE)
108d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				port->icount.overrun++;
109d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
110d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			rsr &= port->read_status_mask;
111d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
112d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			if (rsr & UART_STATUS_PE)
113d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				flag = TTY_PARITY;
114d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			else if (rsr & UART_STATUS_FE)
115d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				flag = TTY_FRAME;
116d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		}
117d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
118d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		if (uart_handle_sysrq_char(port, ch))
119d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			goto ignore_char;
120d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
121d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
122d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
123d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
124d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	      ignore_char:
125d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		status = UART_GET_STATUS(port);
126d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
127d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
128d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	tty_flip_buffer_push(tty);
129d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
130d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
131d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_tx_chars(struct uart_port *port)
132d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
133d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	struct circ_buf *xmit = &port->state->xmit;
134d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int count;
135d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
136d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (port->x_char) {
137d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		UART_PUT_CHAR(port, port->x_char);
138d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->icount.tx++;
139d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->x_char = 0;
140d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		return;
141d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
142d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
143d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
144d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		apbuart_stop_tx(port);
145d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		return;
146d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
147d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
148d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* amba: fill FIFO */
149d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	count = port->fifosize >> 1;
150d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	do {
151d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
152d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
153d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->icount.tx++;
154d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		if (uart_circ_empty(xmit))
155d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			break;
156d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	} while (--count > 0);
157d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
158d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
159d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		uart_write_wakeup(port);
160d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
161d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (uart_circ_empty(xmit))
162d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		apbuart_stop_tx(port);
163d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
164d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
165d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic irqreturn_t apbuart_int(int irq, void *dev_id)
166d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
167d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	struct uart_port *port = dev_id;
168d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int status;
169d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
170d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	spin_lock(&port->lock);
171d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
172d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	status = UART_GET_STATUS(port);
173d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (status & UART_STATUS_DR)
174d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		apbuart_rx_chars(port);
175d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (status & UART_STATUS_THE)
176d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		apbuart_tx_chars(port);
177d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
178d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	spin_unlock(&port->lock);
179d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
180d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return IRQ_HANDLED;
181d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
182d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
183d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic unsigned int apbuart_tx_empty(struct uart_port *port)
184d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
185d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int status = UART_GET_STATUS(port);
186d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
187d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
188d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
189d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic unsigned int apbuart_get_mctrl(struct uart_port *port)
190d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
191d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* The GRLIB APBUART handles flow control in hardware */
192d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
193d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
194d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
195d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
196d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
197d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* The GRLIB APBUART handles flow control in hardware */
198d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
199d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
200d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_break_ctl(struct uart_port *port, int break_state)
201d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
202d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* We don't support sending break */
203d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
204d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
205d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic int apbuart_startup(struct uart_port *port)
206d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
207d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int retval;
208d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int cr;
209d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
210d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Allocate the IRQ */
211d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
212d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (retval)
213d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		return retval;
214d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
215d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Finally, enable interrupts */
216d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr = UART_GET_CTRL(port);
217d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port,
218d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		      cr | UART_CTRL_RE | UART_CTRL_TE |
219d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		      UART_CTRL_RI | UART_CTRL_TI);
220d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
221d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return 0;
222d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
223d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
224d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_shutdown(struct uart_port *port)
225d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
226d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int cr;
227d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
228d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* disable all interrupts, disable the port */
229d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr = UART_GET_CTRL(port);
230d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port,
231d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		      cr & ~(UART_CTRL_RE | UART_CTRL_TE |
232d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			     UART_CTRL_RI | UART_CTRL_TI));
233d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
234d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Free the interrupt */
235d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	free_irq(port->irq, port);
236d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
237d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
238d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_set_termios(struct uart_port *port,
239d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				struct ktermios *termios, struct ktermios *old)
240d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
241d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int cr;
242d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned long flags;
243d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int baud, quot;
244d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
245d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Ask the core to calculate the divisor for us. */
246d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
247d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (baud == 0)
248d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		panic("invalid baudrate %i\n", port->uartclk / 16);
249d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
250d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
251d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	quot = (uart_get_divisor(port, baud)) * 2;
252d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr = UART_GET_CTRL(port);
253d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
254d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
255d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (termios->c_cflag & PARENB) {
256d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		cr |= UART_CTRL_PE;
257d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		if ((termios->c_cflag & PARODD))
258d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			cr |= UART_CTRL_PS;
259d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
260d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
261d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Enable flow control. */
262d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (termios->c_cflag & CRTSCTS)
263d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		cr |= UART_CTRL_FL;
264d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
265d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	spin_lock_irqsave(&port->lock, flags);
266d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
267d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Update the per-port timeout. */
268d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	uart_update_timeout(port, termios->c_cflag, baud);
269d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
270d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	port->read_status_mask = UART_STATUS_OE;
271d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (termios->c_iflag & INPCK)
272d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
273d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
274d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Characters to ignore */
275d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	port->ignore_status_mask = 0;
276d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (termios->c_iflag & IGNPAR)
277d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
278d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
279d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Ignore all characters if CREAD is not set. */
280d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if ((termios->c_cflag & CREAD) == 0)
281d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->ignore_status_mask |= UART_DUMMY_RSR_RX;
282d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
283d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Set baud rate */
284d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	quot -= 1;
285d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_SCAL(port, quot);
286d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port, cr);
287d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
288d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	spin_unlock_irqrestore(&port->lock, flags);
289d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
290d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
291d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic const char *apbuart_type(struct uart_port *port)
292d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
293d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
294d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
295d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
296d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_release_port(struct uart_port *port)
297d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
298d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	release_mem_region(port->mapbase, 0x100);
299d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
300d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
301d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic int apbuart_request_port(struct uart_port *port)
302d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
303d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
304d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	    != NULL ? 0 : -EBUSY;
305d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return 0;
306d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
307d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
308d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo/* Configure/autoconfigure the port */
309d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_config_port(struct uart_port *port, int flags)
310d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
311d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (flags & UART_CONFIG_TYPE) {
312d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->type = PORT_APBUART;
313d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		apbuart_request_port(port);
314d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
315d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
316d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
317d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo/* Verify the new serial_struct (for TIOCSSERIAL) */
318d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic int apbuart_verify_port(struct uart_port *port,
319d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			       struct serial_struct *ser)
320d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
321d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int ret = 0;
322d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
323d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		ret = -EINVAL;
324d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (ser->irq < 0 || ser->irq >= NR_IRQS)
325d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		ret = -EINVAL;
326d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (ser->baud_base < 9600)
327d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		ret = -EINVAL;
328d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return ret;
329d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
330d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
331d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic struct uart_ops grlib_apbuart_ops = {
332d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.tx_empty = apbuart_tx_empty,
333d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.set_mctrl = apbuart_set_mctrl,
334d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.get_mctrl = apbuart_get_mctrl,
335d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.stop_tx = apbuart_stop_tx,
336d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.start_tx = apbuart_start_tx,
337d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.stop_rx = apbuart_stop_rx,
338d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.enable_ms = apbuart_enable_ms,
339d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.break_ctl = apbuart_break_ctl,
340d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.startup = apbuart_startup,
341d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.shutdown = apbuart_shutdown,
342d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.set_termios = apbuart_set_termios,
343d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.type = apbuart_type,
344d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.release_port = apbuart_release_port,
345d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.request_port = apbuart_request_port,
346d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.config_port = apbuart_config_port,
347d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.verify_port = apbuart_verify_port,
348d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo};
349d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
350d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic struct uart_port grlib_apbuart_ports[UART_NR];
351d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic struct device_node *grlib_apbuart_nodes[UART_NR];
352d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
353d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
354d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
355d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int ctrl, loop = 0;
356d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int status;
357d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int fifosize;
358d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned long flags;
359d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
360d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	ctrl = UART_GET_CTRL(port);
361d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
362d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/*
363d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * Enable the transceiver and wait for it to be ready to send data.
364d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * Clear interrupts so that this process will not be externally
365d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * interrupted in the middle (which can cause the transceiver to
366d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * drain prematurely).
367d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 */
368d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
369d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	local_irq_save(flags);
370d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
371d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
372d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
373d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	while (!UART_TX_READY(UART_GET_STATUS(port)))
374d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		loop++;
375d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
376d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/*
377d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * Disable the transceiver so data isn't actually sent during the
378d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * actual test.
379d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 */
380d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
381d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
382d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
383d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	fifosize = 1;
384d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CHAR(port, 0);
385d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
386d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/*
387d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * So long as transmitting a character increments the tranceivier FIFO
388d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * length the FIFO must be at least that big. These bytes will
389d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * automatically drain off of the FIFO.
390d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 */
391d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
392d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	status = UART_GET_STATUS(port);
393d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	while (((status >> 20) & 0x3F) == fifosize) {
394d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		fifosize++;
395d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		UART_PUT_CHAR(port, 0);
396d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		status = UART_GET_STATUS(port);
397d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
398d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
399d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	fifosize--;
400d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
401d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port, ctrl);
402d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	local_irq_restore(flags);
403d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
404d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (fifosize == 0)
405d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		fifosize = 1;
406d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
407d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return fifosize;
408d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
409d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
410d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_flush_fifo(struct uart_port *port)
411d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
412d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int i;
413d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
414d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	for (i = 0; i < port->fifosize; i++)
415d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		UART_GET_CHAR(port);
416d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
417d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
418d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
419d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo/* ======================================================================== */
420d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo/* Console driver, if enabled                                               */
421d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo/* ======================================================================== */
422d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
423d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
424d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
425d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void apbuart_console_putchar(struct uart_port *port, int ch)
426d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
427d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int status;
428d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	do {
429d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		status = UART_GET_STATUS(port);
430d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	} while (!UART_TX_READY(status));
431d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CHAR(port, ch);
432d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
433d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
434d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void
435d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glemboapbuart_console_write(struct console *co, const char *s, unsigned int count)
436d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
437d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	struct uart_port *port = &grlib_apbuart_ports[co->index];
438d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	unsigned int status, old_cr, new_cr;
439d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
440d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* First save the CR then disable the interrupts */
441d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	old_cr = UART_GET_CTRL(port);
442d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
443d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port, new_cr);
444d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
445d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	uart_console_write(port, s, count, apbuart_console_putchar);
446d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
447d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/*
448d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 *      Finally, wait for transmitter to become empty
449d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 *      and restore the TCR
450d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 */
451d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	do {
452d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		status = UART_GET_STATUS(port);
453d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	} while (!UART_TX_READY(status));
454d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	UART_PUT_CTRL(port, old_cr);
455d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
456d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
457d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void __init
458d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glemboapbuart_console_get_options(struct uart_port *port, int *baud,
459d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			    int *parity, int *bits)
460d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
461d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
462d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
463d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		unsigned int quot, status;
464d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		status = UART_GET_STATUS(port);
465d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
466d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		*parity = 'n';
467d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		if (status & UART_CTRL_PE) {
468d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			if ((status & UART_CTRL_PS) == 0)
469d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				*parity = 'e';
470d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			else
471d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				*parity = 'o';
472d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		}
473d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
474d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		*bits = 8;
475d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		quot = UART_GET_SCAL(port) / 8;
476d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		*baud = port->uartclk / (16 * (quot + 1));
477d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
478d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
479d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
480d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic int __init apbuart_console_setup(struct console *co, char *options)
481d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
482d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	struct uart_port *port;
483d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int baud = 38400;
484d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int bits = 8;
485d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int parity = 'n';
486d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int flow = 'n';
487d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
488d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
489d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		 co, co->index, options);
490d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
491d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/*
492d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * Check whether an invalid uart number has been specified, and
493d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * if so, search for the first available port that does have
494d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 * console support.
495d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 */
496d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (co->index >= grlib_apbuart_port_nr)
497d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		co->index = 0;
498d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
499d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	port = &grlib_apbuart_ports[co->index];
500d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
501d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	spin_lock_init(&port->lock);
502d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
503d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (options)
504d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		uart_parse_options(options, &baud, &parity, &bits, &flow);
505d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	else
506d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		apbuart_console_get_options(port, &baud, &parity, &bits);
507d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
508d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return uart_set_options(port, co, baud, parity, bits, flow);
509d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
510d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
511d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic struct uart_driver grlib_apbuart_driver;
512d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
513d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic struct console grlib_apbuart_console = {
514d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.name = "ttyS",
515d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.write = apbuart_console_write,
516d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.device = uart_console_device,
517d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.setup = apbuart_console_setup,
518d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.flags = CON_PRINTBUFFER,
519d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.index = -1,
520d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.data = &grlib_apbuart_driver,
521d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo};
522d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
523d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
524568389c257fa7d74ce36c2f78bad31965fded4cfThomas Gleixnerstatic int grlib_apbuart_configure(void);
525d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
526d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic int __init apbuart_console_init(void)
527d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
528568389c257fa7d74ce36c2f78bad31965fded4cfThomas Gleixner	if (grlib_apbuart_configure())
529568389c257fa7d74ce36c2f78bad31965fded4cfThomas Gleixner		return -ENODEV;
530d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	register_console(&grlib_apbuart_console);
531d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return 0;
532d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
533d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
534d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glemboconsole_initcall(apbuart_console_init);
535d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
536d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#define APBUART_CONSOLE	(&grlib_apbuart_console)
537d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#else
538d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#define APBUART_CONSOLE	NULL
539d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo#endif
540d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
541d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic struct uart_driver grlib_apbuart_driver = {
542d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.owner = THIS_MODULE,
543d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.driver_name = "serial",
544d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.dev_name = "ttyS",
545d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.major = SERIAL_APBUART_MAJOR,
546d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.minor = SERIAL_APBUART_MINOR,
547d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.nr = UART_NR,
548d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.cons = APBUART_CONSOLE,
549d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo};
550d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
551d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
552d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo/* ======================================================================== */
553d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo/* OF Platform Driver                                                       */
554d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo/* ======================================================================== */
555d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
556793218dfea146946a076f4fe51e574db61034a3eGrant Likelystatic int __devinit apbuart_probe(struct platform_device *op)
557d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
55810544f128c338aeb7f63c002ad7eee67aa0e6acfDaniel Hellstrom	int i;
559d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	struct uart_port *port = NULL;
560d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
561d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	for (i = 0; i < grlib_apbuart_port_nr; i++) {
56261c7a080a5a061c976988fd4b844dfb468dda255Grant Likely		if (op->dev.of_node == grlib_apbuart_nodes[i])
563d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			break;
564d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
565d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
566d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	port = &grlib_apbuart_ports[i];
567d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	port->dev = &op->dev;
56810544f128c338aeb7f63c002ad7eee67aa0e6acfDaniel Hellstrom	port->irq = op->archdata.irqs[0];
569d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
570d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
571d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
572d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	apbuart_flush_fifo((struct uart_port *) port);
573d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
574384a17b284b9dc92b480cf388310a25e255bac8aDavid S. Miller	printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
575384a17b284b9dc92b480cf388310a25e255bac8aDavid S. Miller	       (unsigned long long) port->mapbase, port->irq);
576d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return 0;
577d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
578d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
579d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic struct of_device_id __initdata apbuart_match[] = {
580d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	{
581d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 .name = "GAISLER_APBUART",
582d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	 },
583d89ddf0da8f0a140d4dc2e2dbc594fb278e33db5Daniel Hellstrom	{
584d89ddf0da8f0a140d4dc2e2dbc594fb278e33db5Daniel Hellstrom	 .name = "01_00c",
585d89ddf0da8f0a140d4dc2e2dbc594fb278e33db5Daniel Hellstrom	 },
586d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	{},
587d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo};
588d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
589793218dfea146946a076f4fe51e574db61034a3eGrant Likelystatic struct platform_driver grlib_apbuart_of_driver = {
590d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.probe = apbuart_probe,
591d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	.driver = {
5924018294b53d1dae026880e45f174c1cc63b5d435Grant Likely		.owner = THIS_MODULE,
5934018294b53d1dae026880e45f174c1cc63b5d435Grant Likely		.name = "grlib-apbuart",
5944018294b53d1dae026880e45f174c1cc63b5d435Grant Likely		.of_match_table = apbuart_match,
5954018294b53d1dae026880e45f174c1cc63b5d435Grant Likely	},
596d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo};
597d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
598d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
59935c64e5d13c3d7d8c4ad061ad5e20498b9160c24Thomas Gleixnerstatic int grlib_apbuart_configure(void)
600d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
601c897dcf6311ea9c8d24e96cc7f7fe9de58a0a6a2Daniel Hellstrom	struct device_node *np;
602c897dcf6311ea9c8d24e96cc7f7fe9de58a0a6a2Daniel Hellstrom	int line = 0;
603d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
604d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	for_each_matching_node(np, apbuart_match) {
60510544f128c338aeb7f63c002ad7eee67aa0e6acfDaniel Hellstrom		const int *ampopts;
606c897dcf6311ea9c8d24e96cc7f7fe9de58a0a6a2Daniel Hellstrom		const u32 *freq_hz;
60735c64e5d13c3d7d8c4ad061ad5e20498b9160c24Thomas Gleixner		const struct amba_prom_registers *regs;
60835c64e5d13c3d7d8c4ad061ad5e20498b9160c24Thomas Gleixner		struct uart_port *port;
60935c64e5d13c3d7d8c4ad061ad5e20498b9160c24Thomas Gleixner		unsigned long addr;
610d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
61156b85f32d530d09d6805488ad00775d4e0e3baabLinus Torvalds		ampopts = of_get_property(np, "ampopts", NULL);
612f28f3313aa97dcb46954f90f596d75f8faf4626eDaniel Hellstrom		if (ampopts && (*ampopts == 0))
613f28f3313aa97dcb46954f90f596d75f8faf4626eDaniel Hellstrom			continue; /* Ignore if used by another OS instance */
61435c64e5d13c3d7d8c4ad061ad5e20498b9160c24Thomas Gleixner		regs = of_get_property(np, "reg", NULL);
615c897dcf6311ea9c8d24e96cc7f7fe9de58a0a6a2Daniel Hellstrom		/* Frequency of APB Bus is frequency of UART */
616c897dcf6311ea9c8d24e96cc7f7fe9de58a0a6a2Daniel Hellstrom		freq_hz = of_get_property(np, "freq", NULL);
617d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
618c897dcf6311ea9c8d24e96cc7f7fe9de58a0a6a2Daniel Hellstrom		if (!regs || !freq_hz || (*freq_hz == 0))
61956b85f32d530d09d6805488ad00775d4e0e3baabLinus Torvalds			continue;
620d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
621d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		grlib_apbuart_nodes[line] = np;
622d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
623d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		addr = regs->phys_addr;
624d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
625d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port = &grlib_apbuart_ports[line];
626d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
627d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->mapbase = addr;
628d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
62910544f128c338aeb7f63c002ad7eee67aa0e6acfDaniel Hellstrom		port->irq = 0;
630d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->iotype = UPIO_MEM;
631d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->ops = &grlib_apbuart_ops;
632d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->flags = UPF_BOOT_AUTOCONF;
633d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->line = line;
634c897dcf6311ea9c8d24e96cc7f7fe9de58a0a6a2Daniel Hellstrom		port->uartclk = *freq_hz;
635d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
636d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		line++;
637d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
638d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		/* We support maximum UART_NR uarts ... */
639d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		if (line == UART_NR)
640d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo			break;
641d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
642d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
643d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
64435c64e5d13c3d7d8c4ad061ad5e20498b9160c24Thomas Gleixner	return line ? 0 : -ENODEV;
645d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
646d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
647d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic int __init grlib_apbuart_init(void)
648d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
649d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int ret;
650d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
651d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	/* Find all APBUARTS in device the tree and initialize their ports */
65235c64e5d13c3d7d8c4ad061ad5e20498b9160c24Thomas Gleixner	ret = grlib_apbuart_configure();
65335c64e5d13c3d7d8c4ad061ad5e20498b9160c24Thomas Gleixner	if (ret)
65435c64e5d13c3d7d8c4ad061ad5e20498b9160c24Thomas Gleixner		return ret;
655d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
656d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
657d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
658d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	ret = uart_register_driver(&grlib_apbuart_driver);
659d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
660d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (ret) {
661d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
662d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		       __FILE__, ret);
663d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		return ret;
664d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
665d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
666793218dfea146946a076f4fe51e574db61034a3eGrant Likely	ret = platform_driver_register(&grlib_apbuart_of_driver);
667d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	if (ret) {
668d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		printk(KERN_ERR
669793218dfea146946a076f4fe51e574db61034a3eGrant Likely		       "%s: platform_driver_register failed (%i)\n",
670d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		       __FILE__, ret);
671d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		uart_unregister_driver(&grlib_apbuart_driver);
672d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		return ret;
673d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	}
674d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
675d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	return ret;
676d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
677d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
678d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembostatic void __exit grlib_apbuart_exit(void)
679d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo{
680d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	int i;
681d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
682d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	for (i = 0; i < grlib_apbuart_port_nr; i++)
683d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo		uart_remove_one_port(&grlib_apbuart_driver,
684d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo				     &grlib_apbuart_ports[i]);
685d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
686d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo	uart_unregister_driver(&grlib_apbuart_driver);
687793218dfea146946a076f4fe51e574db61034a3eGrant Likely	platform_driver_unregister(&grlib_apbuart_of_driver);
688d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo}
689d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
690d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembomodule_init(grlib_apbuart_init);
691d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembomodule_exit(grlib_apbuart_exit);
692d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer Glembo
693d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer GlemboMODULE_AUTHOR("Aeroflex Gaisler AB");
694d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer GlemboMODULE_DESCRIPTION("GRLIB APBUART serial driver");
695d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer GlemboMODULE_VERSION("2.1");
696d4ac42a582e46d7f86f0acb4253a310423c72c4cKristoffer GlemboMODULE_LICENSE("GPL");
697