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