1/*
2 * linux/drivers/serial/21285.c
3 *
4 * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
5 *
6 * Based on drivers/char/serial.c
7 *
8 *  $Id: 21285.c,v 1.1.1.1 2007/08/03 18:53:00 Exp $
9 */
10#include <linux/module.h>
11#include <linux/tty.h>
12#include <linux/ioport.h>
13#include <linux/init.h>
14#include <linux/console.h>
15#include <linux/device.h>
16#include <linux/tty_flip.h>
17#include <linux/serial_core.h>
18#include <linux/serial.h>
19
20#include <asm/io.h>
21#include <asm/irq.h>
22#include <asm/mach-types.h>
23#include <asm/hardware/dec21285.h>
24#include <asm/hardware.h>
25
26#define BAUD_BASE		(mem_fclk_21285/64)
27
28#define SERIAL_21285_NAME	"ttyFB"
29#define SERIAL_21285_MAJOR	204
30#define SERIAL_21285_MINOR	4
31
32#define RXSTAT_DUMMY_READ	0x80000000
33#define RXSTAT_FRAME		(1 << 0)
34#define RXSTAT_PARITY		(1 << 1)
35#define RXSTAT_OVERRUN		(1 << 2)
36#define RXSTAT_ANYERR		(RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN)
37
38#define H_UBRLCR_BREAK		(1 << 0)
39#define H_UBRLCR_PARENB		(1 << 1)
40#define H_UBRLCR_PAREVN		(1 << 2)
41#define H_UBRLCR_STOPB		(1 << 3)
42#define H_UBRLCR_FIFO		(1 << 4)
43
44static const char serial21285_name[] = "Footbridge UART";
45
46#define tx_enabled(port)	((port)->unused[0])
47#define rx_enabled(port)	((port)->unused[1])
48
49/*
50 * The documented expression for selecting the divisor is:
51 *  BAUD_BASE / baud - 1
52 * However, typically BAUD_BASE is not divisible by baud, so
53 * we want to select the divisor that gives us the minimum
54 * error.  Therefore, we want:
55 *  int(BAUD_BASE / baud - 0.5) ->
56 *  int(BAUD_BASE / baud - (baud >> 1) / baud) ->
57 *  int((BAUD_BASE - (baud >> 1)) / baud)
58 */
59
60static void serial21285_stop_tx(struct uart_port *port)
61{
62	if (tx_enabled(port)) {
63		disable_irq(IRQ_CONTX);
64		tx_enabled(port) = 0;
65	}
66}
67
68static void serial21285_start_tx(struct uart_port *port)
69{
70	if (!tx_enabled(port)) {
71		enable_irq(IRQ_CONTX);
72		tx_enabled(port) = 1;
73	}
74}
75
76static void serial21285_stop_rx(struct uart_port *port)
77{
78	if (rx_enabled(port)) {
79		disable_irq(IRQ_CONRX);
80		rx_enabled(port) = 0;
81	}
82}
83
84static void serial21285_enable_ms(struct uart_port *port)
85{
86}
87
88static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
89{
90	struct uart_port *port = dev_id;
91	struct tty_struct *tty = port->info->tty;
92	unsigned int status, ch, flag, rxs, max_count = 256;
93
94	status = *CSR_UARTFLG;
95	while (!(status & 0x10) && max_count--) {
96		ch = *CSR_UARTDR;
97		flag = TTY_NORMAL;
98		port->icount.rx++;
99
100		rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
101		if (unlikely(rxs & RXSTAT_ANYERR)) {
102			if (rxs & RXSTAT_PARITY)
103				port->icount.parity++;
104			else if (rxs & RXSTAT_FRAME)
105				port->icount.frame++;
106			if (rxs & RXSTAT_OVERRUN)
107				port->icount.overrun++;
108
109			rxs &= port->read_status_mask;
110
111			if (rxs & RXSTAT_PARITY)
112				flag = TTY_PARITY;
113			else if (rxs & RXSTAT_FRAME)
114				flag = TTY_FRAME;
115		}
116
117		uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
118
119		status = *CSR_UARTFLG;
120	}
121	tty_flip_buffer_push(tty);
122
123	return IRQ_HANDLED;
124}
125
126static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
127{
128	struct uart_port *port = dev_id;
129	struct circ_buf *xmit = &port->info->xmit;
130	int count = 256;
131
132	if (port->x_char) {
133		*CSR_UARTDR = port->x_char;
134		port->icount.tx++;
135		port->x_char = 0;
136		goto out;
137	}
138	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
139		serial21285_stop_tx(port);
140		goto out;
141	}
142
143	do {
144		*CSR_UARTDR = xmit->buf[xmit->tail];
145		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
146		port->icount.tx++;
147		if (uart_circ_empty(xmit))
148			break;
149	} while (--count > 0 && !(*CSR_UARTFLG & 0x20));
150
151	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
152		uart_write_wakeup(port);
153
154	if (uart_circ_empty(xmit))
155		serial21285_stop_tx(port);
156
157 out:
158	return IRQ_HANDLED;
159}
160
161static unsigned int serial21285_tx_empty(struct uart_port *port)
162{
163	return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT;
164}
165
166/* no modem control lines */
167static unsigned int serial21285_get_mctrl(struct uart_port *port)
168{
169	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
170}
171
172static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl)
173{
174}
175
176static void serial21285_break_ctl(struct uart_port *port, int break_state)
177{
178	unsigned long flags;
179	unsigned int h_lcr;
180
181	spin_lock_irqsave(&port->lock, flags);
182	h_lcr = *CSR_H_UBRLCR;
183	if (break_state)
184		h_lcr |= H_UBRLCR_BREAK;
185	else
186		h_lcr &= ~H_UBRLCR_BREAK;
187	*CSR_H_UBRLCR = h_lcr;
188	spin_unlock_irqrestore(&port->lock, flags);
189}
190
191static int serial21285_startup(struct uart_port *port)
192{
193	int ret;
194
195	tx_enabled(port) = 1;
196	rx_enabled(port) = 1;
197
198	ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0,
199			  serial21285_name, port);
200	if (ret == 0) {
201		ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0,
202				  serial21285_name, port);
203		if (ret)
204			free_irq(IRQ_CONRX, port);
205	}
206
207	return ret;
208}
209
210static void serial21285_shutdown(struct uart_port *port)
211{
212	free_irq(IRQ_CONTX, port);
213	free_irq(IRQ_CONRX, port);
214}
215
216static void
217serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
218			struct ktermios *old)
219{
220	unsigned long flags;
221	unsigned int baud, quot, h_lcr;
222
223	/*
224	 * We don't support modem control lines.
225	 */
226	termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
227	termios->c_cflag |= CLOCAL;
228
229	/*
230	 * We don't support BREAK character recognition.
231	 */
232	termios->c_iflag &= ~(IGNBRK | BRKINT);
233
234	/*
235	 * Ask the core to calculate the divisor for us.
236	 */
237	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
238	quot = uart_get_divisor(port, baud);
239
240	switch (termios->c_cflag & CSIZE) {
241	case CS5:
242		h_lcr = 0x00;
243		break;
244	case CS6:
245		h_lcr = 0x20;
246		break;
247	case CS7:
248		h_lcr = 0x40;
249		break;
250	default: /* CS8 */
251		h_lcr = 0x60;
252		break;
253	}
254
255	if (termios->c_cflag & CSTOPB)
256		h_lcr |= H_UBRLCR_STOPB;
257	if (termios->c_cflag & PARENB) {
258		h_lcr |= H_UBRLCR_PARENB;
259		if (!(termios->c_cflag & PARODD))
260			h_lcr |= H_UBRLCR_PAREVN;
261	}
262
263	if (port->fifosize)
264		h_lcr |= H_UBRLCR_FIFO;
265
266	spin_lock_irqsave(&port->lock, flags);
267
268	/*
269	 * Update the per-port timeout.
270	 */
271	uart_update_timeout(port, termios->c_cflag, baud);
272
273	/*
274	 * Which character status flags are we interested in?
275	 */
276	port->read_status_mask = RXSTAT_OVERRUN;
277	if (termios->c_iflag & INPCK)
278		port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
279
280	/*
281	 * Which character status flags should we ignore?
282	 */
283	port->ignore_status_mask = 0;
284	if (termios->c_iflag & IGNPAR)
285		port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
286	if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
287		port->ignore_status_mask |= RXSTAT_OVERRUN;
288
289	/*
290	 * Ignore all characters if CREAD is not set.
291	 */
292	if ((termios->c_cflag & CREAD) == 0)
293		port->ignore_status_mask |= RXSTAT_DUMMY_READ;
294
295	quot -= 1;
296
297	*CSR_UARTCON = 0;
298	*CSR_L_UBRLCR = quot & 0xff;
299	*CSR_M_UBRLCR = (quot >> 8) & 0x0f;
300	*CSR_H_UBRLCR = h_lcr;
301	*CSR_UARTCON = 1;
302
303	spin_unlock_irqrestore(&port->lock, flags);
304}
305
306static const char *serial21285_type(struct uart_port *port)
307{
308	return port->type == PORT_21285 ? "DC21285" : NULL;
309}
310
311static void serial21285_release_port(struct uart_port *port)
312{
313	release_mem_region(port->mapbase, 32);
314}
315
316static int serial21285_request_port(struct uart_port *port)
317{
318	return request_mem_region(port->mapbase, 32, serial21285_name)
319			 != NULL ? 0 : -EBUSY;
320}
321
322static void serial21285_config_port(struct uart_port *port, int flags)
323{
324	if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0)
325		port->type = PORT_21285;
326}
327
328/*
329 * verify the new serial_struct (for TIOCSSERIAL).
330 */
331static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser)
332{
333	int ret = 0;
334	if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
335		ret = -EINVAL;
336	if (ser->irq != NO_IRQ)
337		ret = -EINVAL;
338	if (ser->baud_base != port->uartclk / 16)
339		ret = -EINVAL;
340	return ret;
341}
342
343static struct uart_ops serial21285_ops = {
344	.tx_empty	= serial21285_tx_empty,
345	.get_mctrl	= serial21285_get_mctrl,
346	.set_mctrl	= serial21285_set_mctrl,
347	.stop_tx	= serial21285_stop_tx,
348	.start_tx	= serial21285_start_tx,
349	.stop_rx	= serial21285_stop_rx,
350	.enable_ms	= serial21285_enable_ms,
351	.break_ctl	= serial21285_break_ctl,
352	.startup	= serial21285_startup,
353	.shutdown	= serial21285_shutdown,
354	.set_termios	= serial21285_set_termios,
355	.type		= serial21285_type,
356	.release_port	= serial21285_release_port,
357	.request_port	= serial21285_request_port,
358	.config_port	= serial21285_config_port,
359	.verify_port	= serial21285_verify_port,
360};
361
362static struct uart_port serial21285_port = {
363	.mapbase	= 0x42000160,
364	.iotype		= UPIO_MEM,
365	.irq		= NO_IRQ,
366	.fifosize	= 16,
367	.ops		= &serial21285_ops,
368	.flags		= UPF_BOOT_AUTOCONF,
369};
370
371static void serial21285_setup_ports(void)
372{
373	serial21285_port.uartclk = mem_fclk_21285 / 4;
374}
375
376#ifdef CONFIG_SERIAL_21285_CONSOLE
377static void serial21285_console_putchar(struct uart_port *port, int ch)
378{
379	while (*CSR_UARTFLG & 0x20)
380		barrier();
381	*CSR_UARTDR = ch;
382}
383
384static void
385serial21285_console_write(struct console *co, const char *s,
386			  unsigned int count)
387{
388	uart_console_write(&serial21285_port, s, count, serial21285_console_putchar);
389}
390
391static void __init
392serial21285_get_options(struct uart_port *port, int *baud,
393			int *parity, int *bits)
394{
395	if (*CSR_UARTCON == 1) {
396		unsigned int tmp;
397
398		tmp = *CSR_H_UBRLCR;
399		switch (tmp & 0x60) {
400		case 0x00:
401			*bits = 5;
402			break;
403		case 0x20:
404			*bits = 6;
405			break;
406		case 0x40:
407			*bits = 7;
408			break;
409		default:
410		case 0x60:
411			*bits = 8;
412			break;
413		}
414
415		if (tmp & H_UBRLCR_PARENB) {
416			*parity = 'o';
417			if (tmp & H_UBRLCR_PAREVN)
418				*parity = 'e';
419		}
420
421		tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8);
422
423		*baud = port->uartclk / (16 * (tmp + 1));
424	}
425}
426
427static int __init serial21285_console_setup(struct console *co, char *options)
428{
429	struct uart_port *port = &serial21285_port;
430	int baud = 9600;
431	int bits = 8;
432	int parity = 'n';
433	int flow = 'n';
434
435	if (machine_is_personal_server())
436		baud = 57600;
437
438	/*
439	 * Check whether an invalid uart number has been specified, and
440	 * if so, search for the first available port that does have
441	 * console support.
442	 */
443	if (options)
444		uart_parse_options(options, &baud, &parity, &bits, &flow);
445	else
446		serial21285_get_options(port, &baud, &parity, &bits);
447
448	return uart_set_options(port, co, baud, parity, bits, flow);
449}
450
451static struct uart_driver serial21285_reg;
452
453static struct console serial21285_console =
454{
455	.name		= SERIAL_21285_NAME,
456	.write		= serial21285_console_write,
457	.device		= uart_console_device,
458	.setup		= serial21285_console_setup,
459	.flags		= CON_PRINTBUFFER,
460	.index		= -1,
461	.data		= &serial21285_reg,
462};
463
464static int __init rs285_console_init(void)
465{
466	serial21285_setup_ports();
467	register_console(&serial21285_console);
468	return 0;
469}
470console_initcall(rs285_console_init);
471
472#define SERIAL_21285_CONSOLE	&serial21285_console
473#else
474#define SERIAL_21285_CONSOLE	NULL
475#endif
476
477static struct uart_driver serial21285_reg = {
478	.owner			= THIS_MODULE,
479	.driver_name		= "ttyFB",
480	.dev_name		= "ttyFB",
481	.major			= SERIAL_21285_MAJOR,
482	.minor			= SERIAL_21285_MINOR,
483	.nr			= 1,
484	.cons			= SERIAL_21285_CONSOLE,
485};
486
487static int __init serial21285_init(void)
488{
489	int ret;
490
491	printk(KERN_INFO "Serial: 21285 driver $Revision: 1.1.1.1 $\n");
492
493	serial21285_setup_ports();
494
495	ret = uart_register_driver(&serial21285_reg);
496	if (ret == 0)
497		uart_add_one_port(&serial21285_reg, &serial21285_port);
498
499	return ret;
500}
501
502static void __exit serial21285_exit(void)
503{
504	uart_remove_one_port(&serial21285_reg, &serial21285_port);
505	uart_unregister_driver(&serial21285_reg);
506}
507
508module_init(serial21285_init);
509module_exit(serial21285_exit);
510
511MODULE_LICENSE("GPL");
512MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.1.1.1 $");
513MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
514