Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 *  Serial Port driver for a NWP uart device
  3 *
  4 *    Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.org>
  5 *
  6 *  This program is free software; you can redistribute it and/or
  7 *  modify it under the terms of the GNU General Public License
  8 *  as published by the Free Software Foundation; either version
  9 *  2 of the License, or (at your option) any later version.
 10 *
 11 */
 12#include <linux/init.h>
 13#include <linux/export.h>
 14#include <linux/console.h>
 15#include <linux/serial.h>
 16#include <linux/serial_reg.h>
 17#include <linux/serial_core.h>
 18#include <linux/tty.h>
 19#include <linux/tty_flip.h>
 20#include <linux/irqreturn.h>
 21#include <linux/mutex.h>
 22#include <linux/of_platform.h>
 23#include <linux/of_device.h>
 24#include <linux/nwpserial.h>
 25#include <asm/prom.h>
 26#include <asm/dcr.h>
 27
 28#define NWPSERIAL_NR               2
 29
 30#define NWPSERIAL_STATUS_RXVALID 0x1
 31#define NWPSERIAL_STATUS_TXFULL  0x2
 32
 33struct nwpserial_port {
 34	struct uart_port port;
 35	dcr_host_t dcr_host;
 36	unsigned int ier;
 37	unsigned int mcr;
 38};
 39
 40static DEFINE_MUTEX(nwpserial_mutex);
 41static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR];
 42
 43static void wait_for_bits(struct nwpserial_port *up, int bits)
 44{
 45	unsigned int status, tmout = 10000;
 46
 47	/* Wait up to 10ms for the character(s) to be sent. */
 48	do {
 49		status = dcr_read(up->dcr_host, UART_LSR);
 50
 51		if (--tmout == 0)
 52			break;
 53		udelay(1);
 54	} while ((status & bits) != bits);
 55}
 56
 57#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
 58static void nwpserial_console_putchar(struct uart_port *port, int c)
 59{
 60	struct nwpserial_port *up;
 61	up = container_of(port, struct nwpserial_port, port);
 62	/* check if tx buffer is full */
 63	wait_for_bits(up, UART_LSR_THRE);
 64	dcr_write(up->dcr_host, UART_TX, c);
 65	up->port.icount.tx++;
 66}
 67
 68static void
 69nwpserial_console_write(struct console *co, const char *s, unsigned int count)
 70{
 71	struct nwpserial_port *up = &nwpserial_ports[co->index];
 72	unsigned long flags;
 73	int locked = 1;
 74
 75	if (oops_in_progress)
 76		locked = spin_trylock_irqsave(&up->port.lock, flags);
 77	else
 78		spin_lock_irqsave(&up->port.lock, flags);
 79
 80	/* save and disable interrupt */
 81	up->ier = dcr_read(up->dcr_host, UART_IER);
 82	dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI);
 83
 84	uart_console_write(&up->port, s, count, nwpserial_console_putchar);
 85
 86	/* wait for transmitter to become empty */
 87	while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0)
 88		cpu_relax();
 89
 90	/* restore interrupt state */
 91	dcr_write(up->dcr_host, UART_IER, up->ier);
 92
 93	if (locked)
 94		spin_unlock_irqrestore(&up->port.lock, flags);
 95}
 96
 97static struct uart_driver nwpserial_reg;
 98static struct console nwpserial_console = {
 99	.name		= "ttySQ",
100	.write		= nwpserial_console_write,
101	.device		= uart_console_device,
102	.flags		= CON_PRINTBUFFER,
103	.index		= -1,
104	.data		= &nwpserial_reg,
105};
106#define NWPSERIAL_CONSOLE	(&nwpserial_console)
107#else
108#define NWPSERIAL_CONSOLE	NULL
109#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
110
111/**************************************************************************/
112
113static int nwpserial_request_port(struct uart_port *port)
114{
115	return 0;
116}
117
118static void nwpserial_release_port(struct uart_port *port)
119{
120	/* N/A */
121}
122
123static void nwpserial_config_port(struct uart_port *port, int flags)
124{
125	port->type = PORT_NWPSERIAL;
126}
127
128static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
129{
130	struct nwpserial_port *up = dev_id;
131	struct tty_port *port = &up->port.state->port;
132	irqreturn_t ret;
133	unsigned int iir;
134	unsigned char ch;
135
136	spin_lock(&up->port.lock);
137
138	/* check if the uart was the interrupt source. */
139	iir = dcr_read(up->dcr_host, UART_IIR);
140	if (!iir) {
141		ret = IRQ_NONE;
142		goto out;
143	}
144
145	do {
146		up->port.icount.rx++;
147		ch = dcr_read(up->dcr_host, UART_RX);
148		if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID)
149			tty_insert_flip_char(port, ch, TTY_NORMAL);
150	} while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
151
152	spin_unlock(&up->port.lock);
153	tty_flip_buffer_push(port);
154	spin_lock(&up->port.lock);
155
156	ret = IRQ_HANDLED;
157
158	/* clear interrupt */
159	dcr_write(up->dcr_host, UART_IIR, 1);
160out:
161	spin_unlock(&up->port.lock);
162	return ret;
163}
164
165static int nwpserial_startup(struct uart_port *port)
166{
167	struct nwpserial_port *up;
168	int err;
169
170	up = container_of(port, struct nwpserial_port, port);
171
172	/* disable flow control by default */
173	up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE;
174	dcr_write(up->dcr_host, UART_MCR, up->mcr);
175
176	/* register interrupt handler */
177	err = request_irq(up->port.irq, nwpserial_interrupt,
178			IRQF_SHARED, "nwpserial", up);
179	if (err)
180		return err;
181
182	/* enable interrupts */
183	up->ier = UART_IER_RDI;
184	dcr_write(up->dcr_host, UART_IER, up->ier);
185
186	/* enable receiving */
187	up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID;
188
189	return 0;
190}
191
192static void nwpserial_shutdown(struct uart_port *port)
193{
194	struct nwpserial_port *up;
195	up = container_of(port, struct nwpserial_port, port);
196
197	/* disable receiving */
198	up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
199
200	/* disable interrupts from this port */
201	up->ier = 0;
202	dcr_write(up->dcr_host, UART_IER, up->ier);
203
204	/* free irq */
205	free_irq(up->port.irq, up);
206}
207
208static int nwpserial_verify_port(struct uart_port *port,
209			struct serial_struct *ser)
210{
211	return -EINVAL;
212}
213
214static const char *nwpserial_type(struct uart_port *port)
215{
216	return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL;
217}
218
219static void nwpserial_set_termios(struct uart_port *port,
220			struct ktermios *termios, struct ktermios *old)
221{
222	struct nwpserial_port *up;
223	up = container_of(port, struct nwpserial_port, port);
224
225	up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID
226				| NWPSERIAL_STATUS_TXFULL;
227
228	up->port.ignore_status_mask = 0;
229	/* ignore all characters if CREAD is not set */
230	if ((termios->c_cflag & CREAD) == 0)
231		up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
232
233	/* Copy back the old hardware settings */
234	if (old)
235		tty_termios_copy_hw(termios, old);
236}
237
238static void nwpserial_break_ctl(struct uart_port *port, int ctl)
239{
240	/* N/A */
241}
242
243static void nwpserial_enable_ms(struct uart_port *port)
244{
245	/* N/A */
246}
247
248static void nwpserial_stop_rx(struct uart_port *port)
249{
250	struct nwpserial_port *up;
251	up = container_of(port, struct nwpserial_port, port);
252	/* don't forward any more data (like !CREAD) */
253	up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID;
254}
255
256static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c)
257{
258	/* check if tx buffer is full */
259	wait_for_bits(up, UART_LSR_THRE);
260	dcr_write(up->dcr_host, UART_TX, c);
261	up->port.icount.tx++;
262}
263
264static void nwpserial_start_tx(struct uart_port *port)
265{
266	struct nwpserial_port *up;
267	struct circ_buf *xmit;
268	up = container_of(port, struct nwpserial_port, port);
269	xmit  = &up->port.state->xmit;
270
271	if (port->x_char) {
272		nwpserial_putchar(up, up->port.x_char);
273		port->x_char = 0;
274	}
275
276	while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) {
277		nwpserial_putchar(up, xmit->buf[xmit->tail]);
278		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
279	}
280}
281
282static unsigned int nwpserial_get_mctrl(struct uart_port *port)
283{
284	return 0;
285}
286
287static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl)
288{
289	/* N/A */
290}
291
292static void nwpserial_stop_tx(struct uart_port *port)
293{
294	/* N/A */
295}
296
297static unsigned int nwpserial_tx_empty(struct uart_port *port)
298{
299	struct nwpserial_port *up;
300	unsigned long flags;
301	int ret;
302	up = container_of(port, struct nwpserial_port, port);
303
304	spin_lock_irqsave(&up->port.lock, flags);
305	ret = dcr_read(up->dcr_host, UART_LSR);
306	spin_unlock_irqrestore(&up->port.lock, flags);
307
308	return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
309}
310
311static struct uart_ops nwpserial_pops = {
312	.tx_empty     = nwpserial_tx_empty,
313	.set_mctrl    = nwpserial_set_mctrl,
314	.get_mctrl    = nwpserial_get_mctrl,
315	.stop_tx      = nwpserial_stop_tx,
316	.start_tx     = nwpserial_start_tx,
317	.stop_rx      = nwpserial_stop_rx,
318	.enable_ms    = nwpserial_enable_ms,
319	.break_ctl    = nwpserial_break_ctl,
320	.startup      = nwpserial_startup,
321	.shutdown     = nwpserial_shutdown,
322	.set_termios  = nwpserial_set_termios,
323	.type         = nwpserial_type,
324	.release_port = nwpserial_release_port,
325	.request_port = nwpserial_request_port,
326	.config_port  = nwpserial_config_port,
327	.verify_port  = nwpserial_verify_port,
328};
329
330static struct uart_driver nwpserial_reg = {
331	.owner       = THIS_MODULE,
332	.driver_name = "nwpserial",
333	.dev_name    = "ttySQ",
334	.major       = TTY_MAJOR,
335	.minor       = 68,
336	.nr          = NWPSERIAL_NR,
337	.cons        = NWPSERIAL_CONSOLE,
338};
339
340int nwpserial_register_port(struct uart_port *port)
341{
342	struct nwpserial_port *up = NULL;
343	int ret = -1;
344	int i;
345	static int first = 1;
346	int dcr_len;
347	int dcr_base;
348	struct device_node *dn;
349
350	mutex_lock(&nwpserial_mutex);
351
352	dn = port->dev->of_node;
353	if (dn == NULL)
354		goto out;
355
356	/* get dcr base. */
357	dcr_base = dcr_resource_start(dn, 0);
358
359	/* find matching entry */
360	for (i = 0; i < NWPSERIAL_NR; i++)
361		if (nwpserial_ports[i].port.iobase == dcr_base) {
362			up = &nwpserial_ports[i];
363			break;
364		}
365
366	/* we didn't find a mtching entry, search for a free port */
367	if (up == NULL)
368		for (i = 0; i < NWPSERIAL_NR; i++)
369			if (nwpserial_ports[i].port.type == PORT_UNKNOWN &&
370				nwpserial_ports[i].port.iobase == 0) {
371				up = &nwpserial_ports[i];
372				break;
373			}
374
375	if (up == NULL) {
376		ret = -EBUSY;
377		goto out;
378	}
379
380	if (first)
381		uart_register_driver(&nwpserial_reg);
382	first = 0;
383
384	up->port.membase      = port->membase;
385	up->port.irq          = port->irq;
386	up->port.uartclk      = port->uartclk;
387	up->port.fifosize     = port->fifosize;
388	up->port.regshift     = port->regshift;
389	up->port.iotype       = port->iotype;
390	up->port.flags        = port->flags;
391	up->port.mapbase      = port->mapbase;
392	up->port.private_data = port->private_data;
393
394	if (port->dev)
395		up->port.dev = port->dev;
396
397	if (up->port.iobase != dcr_base) {
398		up->port.ops          = &nwpserial_pops;
399		up->port.fifosize     = 16;
400
401		spin_lock_init(&up->port.lock);
402
403		up->port.iobase = dcr_base;
404		dcr_len = dcr_resource_len(dn, 0);
405
406		up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
407		if (!DCR_MAP_OK(up->dcr_host)) {
408			printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL");
409			goto out;
410		}
411	}
412
413	ret = uart_add_one_port(&nwpserial_reg, &up->port);
414	if (ret == 0)
415		ret = up->port.line;
416
417out:
418	mutex_unlock(&nwpserial_mutex);
419
420	return ret;
421}
422EXPORT_SYMBOL(nwpserial_register_port);
423
424void nwpserial_unregister_port(int line)
425{
426	struct nwpserial_port *up = &nwpserial_ports[line];
427	mutex_lock(&nwpserial_mutex);
428	uart_remove_one_port(&nwpserial_reg, &up->port);
429
430	up->port.type = PORT_UNKNOWN;
431
432	mutex_unlock(&nwpserial_mutex);
433}
434EXPORT_SYMBOL(nwpserial_unregister_port);
435
436#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
437static int __init nwpserial_console_init(void)
438{
439	struct nwpserial_port *up = NULL;
440	struct device_node *dn;
441	const char *name;
442	int dcr_base;
443	int dcr_len;
444	int i;
445
446	/* search for a free port */
447	for (i = 0; i < NWPSERIAL_NR; i++)
448		if (nwpserial_ports[i].port.type == PORT_UNKNOWN) {
449			up = &nwpserial_ports[i];
450			break;
451		}
452
453	if (up == NULL)
454		return -1;
455
456	name = of_get_property(of_chosen, "linux,stdout-path", NULL);
457	if (name == NULL)
458		return -1;
459
460	dn = of_find_node_by_path(name);
461	if (!dn)
462		return -1;
463
464	spin_lock_init(&up->port.lock);
465	up->port.ops = &nwpserial_pops;
466	up->port.type = PORT_NWPSERIAL;
467	up->port.fifosize = 16;
468
469	dcr_base = dcr_resource_start(dn, 0);
470	dcr_len = dcr_resource_len(dn, 0);
471	up->port.iobase = dcr_base;
472
473	up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
474	if (!DCR_MAP_OK(up->dcr_host)) {
475		printk("Cannot map DCR resources for SERIAL");
476		return -1;
477	}
478	register_console(&nwpserial_console);
479	return 0;
480}
481console_initcall(nwpserial_console_init);
482#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */