Root/target/linux/ifxmips/files-2.6.33/drivers/serial/ifxmips.c

1/*
2 * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Copyright (C) 2004 Infineon IFAP DC COM CPE
19 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
20 * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
21 */
22
23#include <linux/module.h>
24#include <linux/errno.h>
25#include <linux/signal.h>
26#include <linux/sched.h>
27#include <linux/interrupt.h>
28#include <linux/tty.h>
29#include <linux/tty_flip.h>
30#include <linux/major.h>
31#include <linux/string.h>
32#include <linux/fcntl.h>
33#include <linux/ptrace.h>
34#include <linux/ioport.h>
35#include <linux/mm.h>
36#include <linux/slab.h>
37#include <linux/init.h>
38#include <linux/circ_buf.h>
39#include <linux/serial.h>
40#include <linux/serial_core.h>
41#include <linux/console.h>
42#include <linux/sysrq.h>
43#include <linux/irq.h>
44#include <linux/platform_device.h>
45#include <linux/io.h>
46#include <linux/uaccess.h>
47#include <linux/bitops.h>
48
49#include <asm/system.h>
50
51#include <ifxmips.h>
52#include <ifxmips_irq.h>
53
54#define PORT_IFXMIPSASC 111
55
56#include <linux/serial_core.h>
57
58#define UART_DUMMY_UER_RX 1
59
60static void ifxmipsasc_tx_chars(struct uart_port *port);
61extern void prom_printf(const char *fmt, ...);
62static struct uart_port ifxmipsasc_port[2];
63static struct uart_driver ifxmipsasc_reg;
64extern unsigned int ifxmips_get_fpi_hz(void);
65
66static void ifxmipsasc_stop_tx(struct uart_port *port)
67{
68    return;
69}
70
71static void ifxmipsasc_start_tx(struct uart_port *port)
72{
73    unsigned long flags;
74    local_irq_save(flags);
75    ifxmipsasc_tx_chars(port);
76    local_irq_restore(flags);
77    return;
78}
79
80static void ifxmipsasc_stop_rx(struct uart_port *port)
81{
82    ifxmips_w32(ASCWHBSTATE_CLRREN, port->membase + IFXMIPS_ASC_WHBSTATE);
83}
84
85static void ifxmipsasc_enable_ms(struct uart_port *port)
86{
87}
88
89#include <linux/version.h>
90
91static void ifxmipsasc_rx_chars(struct uart_port *port)
92{
93    struct tty_struct *tty = port->state->port.tty;
94    unsigned int ch = 0, rsr = 0, fifocnt;
95
96    fifocnt = ifxmips_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
97    while (fifocnt--) {
98        u8 flag = TTY_NORMAL;
99        ch = ifxmips_r32(port->membase + IFXMIPS_ASC_RBUF);
100        rsr = (ifxmips_r32(port->membase + IFXMIPS_ASC_STATE) & ASCSTATE_ANY) | UART_DUMMY_UER_RX;
101        tty_flip_buffer_push(tty);
102        port->icount.rx++;
103
104        /*
105         * Note that the error handling code is
106         * out of the main execution path
107         */
108        if (rsr & ASCSTATE_ANY) {
109            if (rsr & ASCSTATE_PE) {
110                port->icount.parity++;
111                ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_WHBSTATE) | ASCWHBSTATE_CLRPE, port->membase + IFXMIPS_ASC_WHBSTATE);
112            } else if (rsr & ASCSTATE_FE) {
113                port->icount.frame++;
114                ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_WHBSTATE) | ASCWHBSTATE_CLRFE, port->membase + IFXMIPS_ASC_WHBSTATE);
115            }
116            if (rsr & ASCSTATE_ROE) {
117                port->icount.overrun++;
118                ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_WHBSTATE) | ASCWHBSTATE_CLRROE, port->membase + IFXMIPS_ASC_WHBSTATE);
119            }
120
121            rsr &= port->read_status_mask;
122
123            if (rsr & ASCSTATE_PE)
124                flag = TTY_PARITY;
125            else if (rsr & ASCSTATE_FE)
126                flag = TTY_FRAME;
127        }
128
129        if ((rsr & port->ignore_status_mask) == 0)
130            tty_insert_flip_char(tty, ch, flag);
131
132        if (rsr & ASCSTATE_ROE)
133            /*
134             * Overrun is special, since it's reported
135             * immediately, and doesn't affect the current
136             * character
137             */
138            tty_insert_flip_char(tty, 0, TTY_OVERRUN);
139    }
140    if (ch != 0)
141        tty_flip_buffer_push(tty);
142    return;
143}
144
145
146static void ifxmipsasc_tx_chars(struct uart_port *port)
147{
148    struct circ_buf *xmit = &port->state->xmit;
149    if (uart_tx_stopped(port)) {
150        ifxmipsasc_stop_tx(port);
151        return;
152    }
153
154    while (((ifxmips_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_TXFFLMASK)
155            >> ASCFSTAT_TXFFLOFF) != TXFIFO_FULL) {
156        if (port->x_char) {
157            ifxmips_w32(port->x_char, port->membase + IFXMIPS_ASC_TBUF);
158            port->icount.tx++;
159            port->x_char = 0;
160            continue;
161        }
162
163        if (uart_circ_empty(xmit))
164            break;
165
166        ifxmips_w32(port->state->xmit.buf[port->state->xmit.tail], port->membase + IFXMIPS_ASC_TBUF);
167        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
168        port->icount.tx++;
169    }
170
171    if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
172        uart_write_wakeup(port);
173}
174
175static irqreturn_t ifxmipsasc_tx_int(int irq, void *_port)
176{
177    struct uart_port *port = (struct uart_port *)_port;
178    ifxmips_w32(ASC_IRNCR_TIR, port->membase + IFXMIPS_ASC_IRNCR);
179    ifxmipsasc_start_tx(port);
180    ifxmips_mask_and_ack_irq(irq);
181    return IRQ_HANDLED;
182}
183
184static irqreturn_t ifxmipsasc_er_int(int irq, void *_port)
185{
186    struct uart_port *port = (struct uart_port *)_port;
187    /* clear any pending interrupts */
188    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_WHBSTATE) | ASCWHBSTATE_CLRPE |
189            ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE, port->membase + IFXMIPS_ASC_WHBSTATE);
190    return IRQ_HANDLED;
191}
192
193static irqreturn_t ifxmipsasc_rx_int(int irq, void *_port)
194{
195    struct uart_port *port = (struct uart_port *)_port;
196    ifxmips_w32(ASC_IRNCR_RIR, port->membase + IFXMIPS_ASC_IRNCR);
197    ifxmipsasc_rx_chars((struct uart_port *)port);
198    ifxmips_mask_and_ack_irq(irq);
199    return IRQ_HANDLED;
200}
201
202static unsigned int ifxmipsasc_tx_empty(struct uart_port *port)
203{
204    int status;
205    status = ifxmips_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
206    return status ? 0 : TIOCSER_TEMT;
207}
208
209static unsigned int ifxmipsasc_get_mctrl(struct uart_port *port)
210{
211    return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR;
212}
213
214static void ifxmipsasc_set_mctrl(struct uart_port *port, u_int mctrl)
215{
216}
217
218static void ifxmipsasc_break_ctl(struct uart_port *port, int break_state)
219{
220}
221
222static int ifxmipsasc_startup(struct uart_port *port)
223{
224    int retval;
225
226    port->uartclk = ifxmips_get_fpi_hz();
227
228    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CLC) & ~IFXMIPS_ASC_CLC_DISS, port->membase + IFXMIPS_ASC_CLC);
229    ifxmips_w32(((ifxmips_r32(port->membase + IFXMIPS_ASC_CLC) & ~ASCCLC_RMCMASK)) | (1 << ASCCLC_RMCOFFSET), port->membase + IFXMIPS_ASC_CLC);
230    ifxmips_w32(0, port->membase + IFXMIPS_ASC_PISEL);
231    ifxmips_w32(((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, port->membase + IFXMIPS_ASC_TXFCON);
232    ifxmips_w32(((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, port->membase + IFXMIPS_ASC_RXFCON);
233    wmb();
234    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) | ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN, port->membase + IFXMIPS_ASC_CON);
235
236    retval = request_irq(port->irq, ifxmipsasc_tx_int, IRQF_DISABLED, "asc_tx", port);
237    if (retval) {
238        printk(KERN_ERR "failed to request ifxmipsasc_tx_int\n");
239        return retval;
240    }
241
242    retval = request_irq(port->irq + 2, ifxmipsasc_rx_int, IRQF_DISABLED, "asc_rx", port);
243    if (retval) {
244        printk(KERN_ERR "failed to request ifxmipsasc_rx_int\n");
245        goto err1;
246    }
247
248    retval = request_irq(port->irq + 3, ifxmipsasc_er_int, IRQF_DISABLED, "asc_er", port);
249    if (retval) {
250        printk(KERN_ERR "failed to request ifxmipsasc_er_int\n");
251        goto err2;
252    }
253
254    ifxmips_w32(ASC_IRNREN_RX_BUF | ASC_IRNREN_TX_BUF | ASC_IRNREN_ERR | ASC_IRNREN_TX, port->membase + IFXMIPS_ASC_IRNREN);
255    return 0;
256
257err2:
258    free_irq(port->irq + 2, port);
259err1:
260    free_irq(port->irq, port);
261    return retval;
262}
263
264static void ifxmipsasc_shutdown(struct uart_port *port)
265{
266    free_irq(port->irq, port);
267    free_irq(port->irq + 2, port);
268    free_irq(port->irq + 3, port);
269
270    ifxmips_w32(0, port->membase + IFXMIPS_ASC_CON);
271    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_RXFCON) | ASCRXFCON_RXFFLU, port->membase + IFXMIPS_ASC_RXFCON);
272    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_RXFCON) & ~ASCRXFCON_RXFEN, port->membase + IFXMIPS_ASC_RXFCON);
273    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_TXFCON) | ASCTXFCON_TXFFLU, port->membase + IFXMIPS_ASC_TXFCON);
274    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_TXFCON) & ~ASCTXFCON_TXFEN, port->membase + IFXMIPS_ASC_TXFCON);
275}
276
277static void ifxmipsasc_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old)
278{
279    unsigned int cflag;
280    unsigned int iflag;
281    unsigned int quot;
282    unsigned int baud;
283    unsigned int con = 0;
284    unsigned long flags;
285
286    cflag = new->c_cflag;
287    iflag = new->c_iflag;
288
289    switch (cflag & CSIZE) {
290    case CS7:
291        con = ASCCON_M_7ASYNC;
292        break;
293
294    case CS5:
295    case CS6:
296    default:
297        con = ASCCON_M_8ASYNC;
298        break;
299    }
300
301    if (cflag & CSTOPB)
302        con |= ASCCON_STP;
303
304    if (cflag & PARENB) {
305        if (!(cflag & PARODD))
306            con &= ~ASCCON_ODD;
307        else
308            con |= ASCCON_ODD;
309    }
310
311    port->read_status_mask = ASCSTATE_ROE;
312    if (iflag & INPCK)
313        port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
314
315    port->ignore_status_mask = 0;
316    if (iflag & IGNPAR)
317        port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
318
319    if (iflag & IGNBRK) {
320        /*
321         * If we're ignoring parity and break indicators,
322         * ignore overruns too (for real raw support).
323         */
324        if (iflag & IGNPAR)
325            port->ignore_status_mask |= ASCSTATE_ROE;
326    }
327
328    if ((cflag & CREAD) == 0)
329        port->ignore_status_mask |= UART_DUMMY_UER_RX;
330
331    /* set error signals - framing, parity and overrun, enable receiver */
332    con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN;
333
334    local_irq_save(flags);
335
336    /* set up CON */
337    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) | con, port->membase + IFXMIPS_ASC_CON);
338
339    /* Set baud rate - take a divider of 2 into account */
340    baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
341    quot = uart_get_divisor(port, baud);
342    quot = quot / 2 - 1;
343
344    /* disable the baudrate generator */
345    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) & ~ASCCON_R, port->membase + IFXMIPS_ASC_CON);
346
347    /* make sure the fractional divider is off */
348    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) & ~ASCCON_FDE, port->membase + IFXMIPS_ASC_CON);
349
350    /* set up to use divisor of 2 */
351    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) & ~ASCCON_BRS, port->membase + IFXMIPS_ASC_CON);
352
353    /* now we can write the new baudrate into the register */
354    ifxmips_w32(quot, port->membase + IFXMIPS_ASC_BG);
355
356    /* turn the baudrate generator back on */
357    ifxmips_w32(ifxmips_r32(port->membase + IFXMIPS_ASC_CON) | ASCCON_R, port->membase + IFXMIPS_ASC_CON);
358
359    /* enable rx */
360    ifxmips_w32(ASCWHBSTATE_SETREN, port->membase + IFXMIPS_ASC_WHBSTATE);
361
362    local_irq_restore(flags);
363}
364
365static const char *ifxmipsasc_type(struct uart_port *port)
366{
367    if (port->type == PORT_IFXMIPSASC) {
368        if (port->membase == (void *)IFXMIPS_ASC_BASE_ADDR)
369            return "asc0";
370        else
371            return "asc1";
372    } else {
373        return NULL;
374    }
375}
376
377static void ifxmipsasc_release_port(struct uart_port *port)
378{
379}
380
381static int ifxmipsasc_request_port(struct uart_port *port)
382{
383    return 0;
384}
385
386static void ifxmipsasc_config_port(struct uart_port *port, int flags)
387{
388    if (flags & UART_CONFIG_TYPE) {
389        port->type = PORT_IFXMIPSASC;
390        ifxmipsasc_request_port(port);
391    }
392}
393
394static int ifxmipsasc_verify_port(struct uart_port *port, struct serial_struct *ser)
395{
396    int ret = 0;
397    if (ser->type != PORT_UNKNOWN && ser->type != PORT_IFXMIPSASC)
398        ret = -EINVAL;
399    if (ser->irq < 0 || ser->irq >= NR_IRQS)
400        ret = -EINVAL;
401    if (ser->baud_base < 9600)
402        ret = -EINVAL;
403    return ret;
404}
405
406static struct uart_ops ifxmipsasc_pops = {
407    .tx_empty = ifxmipsasc_tx_empty,
408    .set_mctrl = ifxmipsasc_set_mctrl,
409    .get_mctrl = ifxmipsasc_get_mctrl,
410    .stop_tx = ifxmipsasc_stop_tx,
411    .start_tx = ifxmipsasc_start_tx,
412    .stop_rx = ifxmipsasc_stop_rx,
413    .enable_ms = ifxmipsasc_enable_ms,
414    .break_ctl = ifxmipsasc_break_ctl,
415    .startup = ifxmipsasc_startup,
416    .shutdown = ifxmipsasc_shutdown,
417    .set_termios = ifxmipsasc_set_termios,
418    .type = ifxmipsasc_type,
419    .release_port = ifxmipsasc_release_port,
420    .request_port = ifxmipsasc_request_port,
421    .config_port = ifxmipsasc_config_port,
422    .verify_port = ifxmipsasc_verify_port,
423};
424
425static struct uart_port ifxmipsasc_port[2] = {
426    {
427        .membase = (void *)IFXMIPS_ASC_BASE_ADDR,
428        .mapbase = IFXMIPS_ASC_BASE_ADDR,
429        .iotype = SERIAL_IO_MEM,
430        .irq = IFXMIPSASC_TIR(0),
431        .uartclk = 0,
432        .fifosize = 16,
433        .type = PORT_IFXMIPSASC,
434        .ops = &ifxmipsasc_pops,
435        .flags = ASYNC_BOOT_AUTOCONF,
436        .line = 0
437    }, {
438        .membase = (void *)(IFXMIPS_ASC_BASE_ADDR + IFXMIPS_ASC_BASE_DIFF),
439        .mapbase = IFXMIPS_ASC_BASE_ADDR + IFXMIPS_ASC_BASE_DIFF,
440        .iotype = SERIAL_IO_MEM,
441        .irq = IFXMIPSASC_TIR(1),
442        .uartclk = 0,
443        .fifosize = 16,
444        .type = PORT_IFXMIPSASC,
445        .ops = &ifxmipsasc_pops,
446        .flags = ASYNC_BOOT_AUTOCONF,
447        .line = 1
448    }
449};
450
451static void ifxmipsasc_console_write(struct console *co, const char *s, u_int count)
452{
453    int port = co->index;
454    int i, fifocnt;
455    unsigned long flags;
456    local_irq_save(flags);
457    for (i = 0; i < count; i++) {
458        do {
459            fifocnt = (ifxmips_r32((u32 *)(IFXMIPS_ASC_BASE_ADDR + (port * IFXMIPS_ASC_BASE_DIFF) + IFXMIPS_ASC_FSTAT)) & ASCFSTAT_TXFFLMASK)
460                >> ASCFSTAT_TXFFLOFF;
461        } while (fifocnt == TXFIFO_FULL);
462
463        if (s[i] == '\0')
464            break;
465
466        if (s[i] == '\n') {
467            ifxmips_w32('\r', (u32 *)(IFXMIPS_ASC_BASE_ADDR + (port * IFXMIPS_ASC_BASE_DIFF) + IFXMIPS_ASC_TBUF));
468            do {
469                fifocnt = (ifxmips_r32((u32 *)(IFXMIPS_ASC_BASE_ADDR + (port * IFXMIPS_ASC_BASE_DIFF) + IFXMIPS_ASC_FSTAT)) & ASCFSTAT_TXFFLMASK)
470                    >> ASCFSTAT_TXFFLOFF;
471            } while (fifocnt == TXFIFO_FULL);
472        }
473        ifxmips_w32(s[i], (u32 *)(IFXMIPS_ASC_BASE_ADDR + (port * IFXMIPS_ASC_BASE_DIFF) + IFXMIPS_ASC_TBUF));
474    }
475
476    local_irq_restore(flags);
477}
478
479static int __init ifxmipsasc_console_setup(struct console *co, char *options)
480{
481    int port = co->index;
482    int baud = 115200;
483    int bits = 8;
484    int parity = 'n';
485    int flow = 'n';
486    ifxmipsasc_port[port].uartclk = ifxmips_get_fpi_hz();
487    ifxmipsasc_port[port].type = PORT_IFXMIPSASC;
488    if (options)
489        uart_parse_options(options, &baud, &parity, &bits, &flow);
490    return uart_set_options(&ifxmipsasc_port[port], co, baud, parity, bits, flow);
491}
492
493static struct console ifxmipsasc_console[2] =
494{
495    {
496        .name = "ttyS",
497        .write = ifxmipsasc_console_write,
498        .device = uart_console_device,
499        .setup = ifxmipsasc_console_setup,
500        .flags = CON_PRINTBUFFER,
501        .index = 0,
502        .data = &ifxmipsasc_reg,
503    }, {
504        .name = "ttyS",
505        .write = ifxmipsasc_console_write,
506        .device = uart_console_device,
507        .setup = ifxmipsasc_console_setup,
508        .flags = CON_PRINTBUFFER,
509        .index = 1,
510        .data = &ifxmipsasc_reg,
511    }
512};
513
514static int __init ifxmipsasc_console_init(void)
515{
516    register_console(&ifxmipsasc_console[0]);
517    register_console(&ifxmipsasc_console[1]);
518    return 0;
519}
520console_initcall(ifxmipsasc_console_init);
521
522static struct uart_driver ifxmipsasc_reg = {
523    .owner = THIS_MODULE,
524    .driver_name = "serial",
525    .dev_name = "ttyS",
526    .major = TTY_MAJOR,
527    .minor = 64,
528    .nr = 2,
529    .cons = &ifxmipsasc_console[1],
530};
531
532int __init ifxmipsasc_init(void)
533{
534    int ret;
535    uart_register_driver(&ifxmipsasc_reg);
536    ret = uart_add_one_port(&ifxmipsasc_reg, &ifxmipsasc_port[0]);
537    ret = uart_add_one_port(&ifxmipsasc_reg, &ifxmipsasc_port[1]);
538    return 0;
539}
540
541void __exit ifxmipsasc_exit(void)
542{
543    uart_unregister_driver(&ifxmipsasc_reg);
544}
545
546module_init(ifxmipsasc_init);
547module_exit(ifxmipsasc_exit);
548
549MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
550MODULE_DESCRIPTION("MIPS IFXMips serial port driver");
551MODULE_LICENSE("GPL");
552

Archive Download this file



interactive