Root/drivers/tty/serial/pnx8xxx_uart.c

1/*
2 * UART driver for PNX8XXX SoCs
3 *
4 * Author: Per Hallsmark per.hallsmark@mvista.com
5 * Ported to 2.6 kernel by EmbeddedAlley
6 * Reworked by Vitaly Wool <vitalywool@gmail.com>
7 *
8 * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
9 * Copyright (C) 2000 Deep Blue Solutions Ltd.
10 *
11 * This file is licensed under the terms of the GNU General Public License
12 * version 2. This program is licensed "as is" without any warranty of
13 * any kind, whether express or implied.
14 *
15 */
16
17#if defined(CONFIG_SERIAL_PNX8XXX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
18#define SUPPORT_SYSRQ
19#endif
20
21#include <linux/module.h>
22#include <linux/ioport.h>
23#include <linux/init.h>
24#include <linux/console.h>
25#include <linux/sysrq.h>
26#include <linux/device.h>
27#include <linux/platform_device.h>
28#include <linux/tty.h>
29#include <linux/tty_flip.h>
30#include <linux/serial_core.h>
31#include <linux/serial.h>
32#include <linux/serial_pnx8xxx.h>
33
34#include <asm/io.h>
35#include <asm/irq.h>
36
37/* We'll be using StrongARM sa1100 serial port major/minor */
38#define SERIAL_PNX8XXX_MAJOR 204
39#define MINOR_START 5
40
41#define NR_PORTS 2
42
43#define PNX8XXX_ISR_PASS_LIMIT 256
44
45/*
46 * Convert from ignore_status_mask or read_status_mask to FIFO
47 * and interrupt status bits
48 */
49#define SM_TO_FIFO(x) ((x) >> 10)
50#define SM_TO_ISTAT(x) ((x) & 0x000001ff)
51#define FIFO_TO_SM(x) ((x) << 10)
52#define ISTAT_TO_SM(x) ((x) & 0x000001ff)
53
54/*
55 * This is the size of our serial port register set.
56 */
57#define UART_PORT_SIZE 0x1000
58
59/*
60 * This determines how often we check the modem status signals
61 * for any change. They generally aren't connected to an IRQ
62 * so we have to poll them. We also check immediately before
63 * filling the TX fifo incase CTS has been dropped.
64 */
65#define MCTRL_TIMEOUT (250*HZ/1000)
66
67extern struct pnx8xxx_port pnx8xxx_ports[];
68
69static inline int serial_in(struct pnx8xxx_port *sport, int offset)
70{
71    return (__raw_readl(sport->port.membase + offset));
72}
73
74static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value)
75{
76    __raw_writel(value, sport->port.membase + offset);
77}
78
79/*
80 * Handle any change of modem status signal since we were last called.
81 */
82static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport)
83{
84    unsigned int status, changed;
85
86    status = sport->port.ops->get_mctrl(&sport->port);
87    changed = status ^ sport->old_status;
88
89    if (changed == 0)
90        return;
91
92    sport->old_status = status;
93
94    if (changed & TIOCM_RI)
95        sport->port.icount.rng++;
96    if (changed & TIOCM_DSR)
97        sport->port.icount.dsr++;
98    if (changed & TIOCM_CAR)
99        uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
100    if (changed & TIOCM_CTS)
101        uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
102
103    wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
104}
105
106/*
107 * This is our per-port timeout handler, for checking the
108 * modem status signals.
109 */
110static void pnx8xxx_timeout(unsigned long data)
111{
112    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data;
113    unsigned long flags;
114
115    if (sport->port.state) {
116        spin_lock_irqsave(&sport->port.lock, flags);
117        pnx8xxx_mctrl_check(sport);
118        spin_unlock_irqrestore(&sport->port.lock, flags);
119
120        mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
121    }
122}
123
124/*
125 * interrupts disabled on entry
126 */
127static void pnx8xxx_stop_tx(struct uart_port *port)
128{
129    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
130    u32 ien;
131
132    /* Disable TX intr */
133    ien = serial_in(sport, PNX8XXX_IEN);
134    serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX);
135
136    /* Clear all pending TX intr */
137    serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
138}
139
140/*
141 * interrupts may not be disabled on entry
142 */
143static void pnx8xxx_start_tx(struct uart_port *port)
144{
145    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
146    u32 ien;
147
148    /* Clear all pending TX intr */
149    serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
150
151    /* Enable TX intr */
152    ien = serial_in(sport, PNX8XXX_IEN);
153    serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX);
154}
155
156/*
157 * Interrupts enabled
158 */
159static void pnx8xxx_stop_rx(struct uart_port *port)
160{
161    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
162    u32 ien;
163
164    /* Disable RX intr */
165    ien = serial_in(sport, PNX8XXX_IEN);
166    serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX);
167
168    /* Clear all pending RX intr */
169    serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX);
170}
171
172/*
173 * Set the modem control timer to fire immediately.
174 */
175static void pnx8xxx_enable_ms(struct uart_port *port)
176{
177    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
178
179    mod_timer(&sport->timer, jiffies);
180}
181
182static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
183{
184    unsigned int status, ch, flg;
185
186    status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
187         ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
188    while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) {
189        ch = serial_in(sport, PNX8XXX_FIFO) & 0xff;
190
191        sport->port.icount.rx++;
192
193        flg = TTY_NORMAL;
194
195        /*
196         * note that the error handling code is
197         * out of the main execution path
198         */
199        if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE |
200                    PNX8XXX_UART_FIFO_RXPAR |
201                    PNX8XXX_UART_FIFO_RXBRK) |
202                  ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) {
203            if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) {
204                status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
205                    FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR));
206                sport->port.icount.brk++;
207                if (uart_handle_break(&sport->port))
208                    goto ignore_char;
209            } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
210                sport->port.icount.parity++;
211            else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
212                sport->port.icount.frame++;
213            if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))
214                sport->port.icount.overrun++;
215
216            status &= sport->port.read_status_mask;
217
218            if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
219                flg = TTY_PARITY;
220            else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
221                flg = TTY_FRAME;
222
223#ifdef SUPPORT_SYSRQ
224            sport->port.sysrq = 0;
225#endif
226        }
227
228        if (uart_handle_sysrq_char(&sport->port, ch))
229            goto ignore_char;
230
231        uart_insert_char(&sport->port, status,
232                ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg);
233
234    ignore_char:
235        serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) |
236                PNX8XXX_UART_LCR_RX_NEXT);
237        status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
238             ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
239    }
240    tty_flip_buffer_push(&sport->port.state->port);
241}
242
243static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
244{
245    struct circ_buf *xmit = &sport->port.state->xmit;
246
247    if (sport->port.x_char) {
248        serial_out(sport, PNX8XXX_FIFO, sport->port.x_char);
249        sport->port.icount.tx++;
250        sport->port.x_char = 0;
251        return;
252    }
253
254    /*
255     * Check the modem control lines before
256     * transmitting anything.
257     */
258    pnx8xxx_mctrl_check(sport);
259
260    if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
261        pnx8xxx_stop_tx(&sport->port);
262        return;
263    }
264
265    /*
266     * TX while bytes available
267     */
268    while (((serial_in(sport, PNX8XXX_FIFO) &
269                    PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) {
270        serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]);
271        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
272        sport->port.icount.tx++;
273        if (uart_circ_empty(xmit))
274            break;
275    }
276
277    if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
278        uart_write_wakeup(&sport->port);
279
280    if (uart_circ_empty(xmit))
281        pnx8xxx_stop_tx(&sport->port);
282}
283
284static irqreturn_t pnx8xxx_int(int irq, void *dev_id)
285{
286    struct pnx8xxx_port *sport = dev_id;
287    unsigned int status;
288
289    spin_lock(&sport->port.lock);
290    /* Get the interrupts */
291    status = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN);
292
293    /* Byte or break signal received */
294    if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK))
295        pnx8xxx_rx_chars(sport);
296
297    /* TX holding register empty - transmit a byte */
298    if (status & PNX8XXX_UART_INT_TX)
299        pnx8xxx_tx_chars(sport);
300
301    /* Clear the ISTAT register */
302    serial_out(sport, PNX8XXX_ICLR, status);
303
304    spin_unlock(&sport->port.lock);
305    return IRQ_HANDLED;
306}
307
308/*
309 * Return TIOCSER_TEMT when transmitter is not busy.
310 */
311static unsigned int pnx8xxx_tx_empty(struct uart_port *port)
312{
313    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
314
315    return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT;
316}
317
318static unsigned int pnx8xxx_get_mctrl(struct uart_port *port)
319{
320    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
321    unsigned int mctrl = TIOCM_DSR;
322    unsigned int msr;
323
324    /* REVISIT */
325
326    msr = serial_in(sport, PNX8XXX_MCR);
327
328    mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0;
329    mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0;
330
331    return mctrl;
332}
333
334static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl)
335{
336#if 0 /* FIXME */
337    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
338    unsigned int msr;
339#endif
340}
341
342/*
343 * Interrupts always disabled.
344 */
345static void pnx8xxx_break_ctl(struct uart_port *port, int break_state)
346{
347    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
348    unsigned long flags;
349    unsigned int lcr;
350
351    spin_lock_irqsave(&sport->port.lock, flags);
352    lcr = serial_in(sport, PNX8XXX_LCR);
353    if (break_state == -1)
354        lcr |= PNX8XXX_UART_LCR_TXBREAK;
355    else
356        lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
357    serial_out(sport, PNX8XXX_LCR, lcr);
358    spin_unlock_irqrestore(&sport->port.lock, flags);
359}
360
361static int pnx8xxx_startup(struct uart_port *port)
362{
363    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
364    int retval;
365
366    /*
367     * Allocate the IRQ
368     */
369    retval = request_irq(sport->port.irq, pnx8xxx_int, 0,
370                 "pnx8xxx-uart", sport);
371    if (retval)
372        return retval;
373
374    /*
375     * Finally, clear and enable interrupts
376     */
377
378    serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
379                 PNX8XXX_UART_INT_ALLTX);
380
381    serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) |
382                PNX8XXX_UART_INT_ALLRX |
383                PNX8XXX_UART_INT_ALLTX);
384
385    /*
386     * Enable modem status interrupts
387     */
388    spin_lock_irq(&sport->port.lock);
389    pnx8xxx_enable_ms(&sport->port);
390    spin_unlock_irq(&sport->port.lock);
391
392    return 0;
393}
394
395static void pnx8xxx_shutdown(struct uart_port *port)
396{
397    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
398    int lcr;
399
400    /*
401     * Stop our timer.
402     */
403    del_timer_sync(&sport->timer);
404
405    /*
406     * Disable all interrupts
407     */
408    serial_out(sport, PNX8XXX_IEN, 0);
409
410    /*
411     * Reset the Tx and Rx FIFOS, disable the break condition
412     */
413    lcr = serial_in(sport, PNX8XXX_LCR);
414    lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
415    lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST;
416    serial_out(sport, PNX8XXX_LCR, lcr);
417
418    /*
419     * Clear all interrupts
420     */
421    serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
422                 PNX8XXX_UART_INT_ALLTX);
423
424    /*
425     * Free the interrupt
426     */
427    free_irq(sport->port.irq, sport);
428}
429
430static void
431pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
432           struct ktermios *old)
433{
434    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
435    unsigned long flags;
436    unsigned int lcr_fcr, old_ien, baud, quot;
437    unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
438
439    /*
440     * We only support CS7 and CS8.
441     */
442    while ((termios->c_cflag & CSIZE) != CS7 &&
443           (termios->c_cflag & CSIZE) != CS8) {
444        termios->c_cflag &= ~CSIZE;
445        termios->c_cflag |= old_csize;
446        old_csize = CS8;
447    }
448
449    if ((termios->c_cflag & CSIZE) == CS8)
450        lcr_fcr = PNX8XXX_UART_LCR_8BIT;
451    else
452        lcr_fcr = 0;
453
454    if (termios->c_cflag & CSTOPB)
455        lcr_fcr |= PNX8XXX_UART_LCR_2STOPB;
456    if (termios->c_cflag & PARENB) {
457        lcr_fcr |= PNX8XXX_UART_LCR_PAREN;
458        if (!(termios->c_cflag & PARODD))
459            lcr_fcr |= PNX8XXX_UART_LCR_PAREVN;
460    }
461
462    /*
463     * Ask the core to calculate the divisor for us.
464     */
465    baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
466    quot = uart_get_divisor(port, baud);
467
468    spin_lock_irqsave(&sport->port.lock, flags);
469
470    sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) |
471                ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) |
472                ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
473    if (termios->c_iflag & INPCK)
474        sport->port.read_status_mask |=
475            FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
476            FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
477    if (termios->c_iflag & (BRKINT | PARMRK))
478        sport->port.read_status_mask |=
479            ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
480
481    /*
482     * Characters to ignore
483     */
484    sport->port.ignore_status_mask = 0;
485    if (termios->c_iflag & IGNPAR)
486        sport->port.ignore_status_mask |=
487            FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
488            FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
489    if (termios->c_iflag & IGNBRK) {
490        sport->port.ignore_status_mask |=
491            ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
492        /*
493         * If we're ignoring parity and break indicators,
494         * ignore overruns too (for real raw support).
495         */
496        if (termios->c_iflag & IGNPAR)
497            sport->port.ignore_status_mask |=
498                ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN);
499    }
500
501    /*
502     * ignore all characters if CREAD is not set
503     */
504    if ((termios->c_cflag & CREAD) == 0)
505        sport->port.ignore_status_mask |=
506            ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
507
508    del_timer_sync(&sport->timer);
509
510    /*
511     * Update the per-port timeout.
512     */
513    uart_update_timeout(port, termios->c_cflag, baud);
514
515    /*
516     * disable interrupts and drain transmitter
517     */
518    old_ien = serial_in(sport, PNX8XXX_IEN);
519    serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
520                    PNX8XXX_UART_INT_ALLRX));
521
522    while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA)
523        barrier();
524
525    /* then, disable everything */
526    serial_out(sport, PNX8XXX_IEN, 0);
527
528    /* Reset the Rx and Tx FIFOs too */
529    lcr_fcr |= PNX8XXX_UART_LCR_TX_RST;
530    lcr_fcr |= PNX8XXX_UART_LCR_RX_RST;
531
532    /* set the parity, stop bits and data size */
533    serial_out(sport, PNX8XXX_LCR, lcr_fcr);
534
535    /* set the baud rate */
536    quot -= 1;
537    serial_out(sport, PNX8XXX_BAUD, quot);
538
539    serial_out(sport, PNX8XXX_ICLR, -1);
540
541    serial_out(sport, PNX8XXX_IEN, old_ien);
542
543    if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
544        pnx8xxx_enable_ms(&sport->port);
545
546    spin_unlock_irqrestore(&sport->port.lock, flags);
547}
548
549static const char *pnx8xxx_type(struct uart_port *port)
550{
551    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
552
553    return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL;
554}
555
556/*
557 * Release the memory region(s) being used by 'port'.
558 */
559static void pnx8xxx_release_port(struct uart_port *port)
560{
561    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
562
563    release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
564}
565
566/*
567 * Request the memory region(s) being used by 'port'.
568 */
569static int pnx8xxx_request_port(struct uart_port *port)
570{
571    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
572    return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
573            "pnx8xxx-uart") != NULL ? 0 : -EBUSY;
574}
575
576/*
577 * Configure/autoconfigure the port.
578 */
579static void pnx8xxx_config_port(struct uart_port *port, int flags)
580{
581    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
582
583    if (flags & UART_CONFIG_TYPE &&
584        pnx8xxx_request_port(&sport->port) == 0)
585        sport->port.type = PORT_PNX8XXX;
586}
587
588/*
589 * Verify the new serial_struct (for TIOCSSERIAL).
590 * The only change we allow are to the flags and type, and
591 * even then only between PORT_PNX8XXX and PORT_UNKNOWN
592 */
593static int
594pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser)
595{
596    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
597    int ret = 0;
598
599    if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX)
600        ret = -EINVAL;
601    if (sport->port.irq != ser->irq)
602        ret = -EINVAL;
603    if (ser->io_type != SERIAL_IO_MEM)
604        ret = -EINVAL;
605    if (sport->port.uartclk / 16 != ser->baud_base)
606        ret = -EINVAL;
607    if ((void *)sport->port.mapbase != ser->iomem_base)
608        ret = -EINVAL;
609    if (sport->port.iobase != ser->port)
610        ret = -EINVAL;
611    if (ser->hub6 != 0)
612        ret = -EINVAL;
613    return ret;
614}
615
616static struct uart_ops pnx8xxx_pops = {
617    .tx_empty = pnx8xxx_tx_empty,
618    .set_mctrl = pnx8xxx_set_mctrl,
619    .get_mctrl = pnx8xxx_get_mctrl,
620    .stop_tx = pnx8xxx_stop_tx,
621    .start_tx = pnx8xxx_start_tx,
622    .stop_rx = pnx8xxx_stop_rx,
623    .enable_ms = pnx8xxx_enable_ms,
624    .break_ctl = pnx8xxx_break_ctl,
625    .startup = pnx8xxx_startup,
626    .shutdown = pnx8xxx_shutdown,
627    .set_termios = pnx8xxx_set_termios,
628    .type = pnx8xxx_type,
629    .release_port = pnx8xxx_release_port,
630    .request_port = pnx8xxx_request_port,
631    .config_port = pnx8xxx_config_port,
632    .verify_port = pnx8xxx_verify_port,
633};
634
635
636/*
637 * Setup the PNX8XXX serial ports.
638 *
639 * Note also that we support "console=ttySx" where "x" is either 0 or 1.
640 */
641static void __init pnx8xxx_init_ports(void)
642{
643    static int first = 1;
644    int i;
645
646    if (!first)
647        return;
648    first = 0;
649
650    for (i = 0; i < NR_PORTS; i++) {
651        init_timer(&pnx8xxx_ports[i].timer);
652        pnx8xxx_ports[i].timer.function = pnx8xxx_timeout;
653        pnx8xxx_ports[i].timer.data = (unsigned long)&pnx8xxx_ports[i];
654        pnx8xxx_ports[i].port.ops = &pnx8xxx_pops;
655    }
656}
657
658#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE
659
660static void pnx8xxx_console_putchar(struct uart_port *port, int ch)
661{
662    struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
663    int status;
664
665    do {
666        /* Wait for UART_TX register to empty */
667        status = serial_in(sport, PNX8XXX_FIFO);
668    } while (status & PNX8XXX_UART_FIFO_TXFIFO);
669    serial_out(sport, PNX8XXX_FIFO, ch);
670}
671
672/*
673 * Interrupts are disabled on entering
674 */static void
675pnx8xxx_console_write(struct console *co, const char *s, unsigned int count)
676{
677    struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index];
678    unsigned int old_ien, status;
679
680    /*
681     * First, save IEN and then disable interrupts
682     */
683    old_ien = serial_in(sport, PNX8XXX_IEN);
684    serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
685                    PNX8XXX_UART_INT_ALLRX));
686
687    uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar);
688
689    /*
690     * Finally, wait for transmitter to become empty
691     * and restore IEN
692     */
693    do {
694        /* Wait for UART_TX register to empty */
695        status = serial_in(sport, PNX8XXX_FIFO);
696    } while (status & PNX8XXX_UART_FIFO_TXFIFO);
697
698    /* Clear TX and EMPTY interrupt */
699    serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX |
700                 PNX8XXX_UART_INT_EMPTY);
701
702    serial_out(sport, PNX8XXX_IEN, old_ien);
703}
704
705static int __init
706pnx8xxx_console_setup(struct console *co, char *options)
707{
708    struct pnx8xxx_port *sport;
709    int baud = 38400;
710    int bits = 8;
711    int parity = 'n';
712    int flow = 'n';
713
714    /*
715     * Check whether an invalid uart number has been specified, and
716     * if so, search for the first available port that does have
717     * console support.
718     */
719    if (co->index == -1 || co->index >= NR_PORTS)
720        co->index = 0;
721    sport = &pnx8xxx_ports[co->index];
722
723    if (options)
724        uart_parse_options(options, &baud, &parity, &bits, &flow);
725
726    return uart_set_options(&sport->port, co, baud, parity, bits, flow);
727}
728
729static struct uart_driver pnx8xxx_reg;
730static struct console pnx8xxx_console = {
731    .name = "ttyS",
732    .write = pnx8xxx_console_write,
733    .device = uart_console_device,
734    .setup = pnx8xxx_console_setup,
735    .flags = CON_PRINTBUFFER,
736    .index = -1,
737    .data = &pnx8xxx_reg,
738};
739
740static int __init pnx8xxx_rs_console_init(void)
741{
742    pnx8xxx_init_ports();
743    register_console(&pnx8xxx_console);
744    return 0;
745}
746console_initcall(pnx8xxx_rs_console_init);
747
748#define PNX8XXX_CONSOLE &pnx8xxx_console
749#else
750#define PNX8XXX_CONSOLE NULL
751#endif
752
753static struct uart_driver pnx8xxx_reg = {
754    .owner = THIS_MODULE,
755    .driver_name = "ttyS",
756    .dev_name = "ttyS",
757    .major = SERIAL_PNX8XXX_MAJOR,
758    .minor = MINOR_START,
759    .nr = NR_PORTS,
760    .cons = PNX8XXX_CONSOLE,
761};
762
763static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state)
764{
765    struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
766
767    return uart_suspend_port(&pnx8xxx_reg, &sport->port);
768}
769
770static int pnx8xxx_serial_resume(struct platform_device *pdev)
771{
772    struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
773
774    return uart_resume_port(&pnx8xxx_reg, &sport->port);
775}
776
777static int pnx8xxx_serial_probe(struct platform_device *pdev)
778{
779    struct resource *res = pdev->resource;
780    int i;
781
782    for (i = 0; i < pdev->num_resources; i++, res++) {
783        if (!(res->flags & IORESOURCE_MEM))
784            continue;
785
786        for (i = 0; i < NR_PORTS; i++) {
787            if (pnx8xxx_ports[i].port.mapbase != res->start)
788                continue;
789
790            pnx8xxx_ports[i].port.dev = &pdev->dev;
791            uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port);
792            platform_set_drvdata(pdev, &pnx8xxx_ports[i]);
793            break;
794        }
795    }
796
797    return 0;
798}
799
800static int pnx8xxx_serial_remove(struct platform_device *pdev)
801{
802    struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
803
804    platform_set_drvdata(pdev, NULL);
805
806    if (sport)
807        uart_remove_one_port(&pnx8xxx_reg, &sport->port);
808
809    return 0;
810}
811
812static struct platform_driver pnx8xxx_serial_driver = {
813    .driver = {
814        .name = "pnx8xxx-uart",
815        .owner = THIS_MODULE,
816    },
817    .probe = pnx8xxx_serial_probe,
818    .remove = pnx8xxx_serial_remove,
819    .suspend = pnx8xxx_serial_suspend,
820    .resume = pnx8xxx_serial_resume,
821};
822
823static int __init pnx8xxx_serial_init(void)
824{
825    int ret;
826
827    printk(KERN_INFO "Serial: PNX8XXX driver\n");
828
829    pnx8xxx_init_ports();
830
831    ret = uart_register_driver(&pnx8xxx_reg);
832    if (ret == 0) {
833        ret = platform_driver_register(&pnx8xxx_serial_driver);
834        if (ret)
835            uart_unregister_driver(&pnx8xxx_reg);
836    }
837    return ret;
838}
839
840static void __exit pnx8xxx_serial_exit(void)
841{
842    platform_driver_unregister(&pnx8xxx_serial_driver);
843    uart_unregister_driver(&pnx8xxx_reg);
844}
845
846module_init(pnx8xxx_serial_init);
847module_exit(pnx8xxx_serial_exit);
848
849MODULE_AUTHOR("Embedded Alley Solutions, Inc.");
850MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver");
851MODULE_LICENSE("GPL");
852MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR);
853MODULE_ALIAS("platform:pnx8xxx-uart");
854

Archive Download this file



interactive