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