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