X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fserial%2Fbfin_5xx.c;h=96f7e7484feebf4269c631862f9a01b227eac0f6;hb=2a0cb351001bebf195d3c43d0f70441eb6a62652;hp=69ac7007682e09a5abd797899b7200d7cd6c58a4;hpb=db288381e26e592b11572ce8199bedeadf0c0830;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 69ac700..96f7e74 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -1,7 +1,7 @@ /* * Blackfin On-Chip Serial Driver * - * Copyright 2006-2007 Analog Devices Inc. + * Copyright 2006-2008 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include #include @@ -22,13 +24,14 @@ #include #include -#ifdef CONFIG_KGDB_UART +#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) #include #include #endif #include -#include +#include #ifdef CONFIG_SERIAL_BFIN_DMA #include @@ -37,18 +40,39 @@ #include #endif +#ifdef CONFIG_SERIAL_BFIN_MODULE +# undef CONFIG_EARLY_PRINTK +#endif + +#ifdef CONFIG_SERIAL_BFIN_MODULE +# undef CONFIG_EARLY_PRINTK +#endif + /* UART name and device definitions */ #define BFIN_SERIAL_NAME "ttyBF" #define BFIN_SERIAL_MAJOR 204 #define BFIN_SERIAL_MINOR 64 +static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; +static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource); + +#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + +# ifndef CONFIG_SERIAL_BFIN_PIO +# error KGDB only support UART in PIO mode. +# endif + +static int kgdboc_port_line; +static int kgdboc_break_enabled; +#endif /* * Setup for console. Argument comes from the menuconfig */ #define DMA_RX_XCOUNT 512 #define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT) -#define DMA_RX_FLUSH_JIFFIES 5 +#define DMA_RX_FLUSH_JIFFIES (HZ / 50) #ifdef CONFIG_SERIAL_BFIN_DMA static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart); @@ -56,7 +80,64 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart); static void bfin_serial_tx_chars(struct bfin_serial_port *uart); #endif -static void bfin_serial_mctrl_check(struct bfin_serial_port *uart); +static void bfin_serial_reset_irda(struct uart_port *port); + +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +static unsigned int bfin_serial_get_mctrl(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + if (uart->cts_pin < 0) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + + /* CTS PIN is negative assertive. */ + if (UART_GET_CTS(uart)) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + else + return TIOCM_DSR | TIOCM_CAR; +} + +static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + if (uart->rts_pin < 0) + return; + + /* RTS PIN is negative assertive. */ + if (mctrl & TIOCM_RTS) + UART_ENABLE_RTS(uart); + else + UART_DISABLE_RTS(uart); +} + +/* + * Handle any change of modem status signal. + */ +static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + unsigned int status; + + status = bfin_serial_get_mctrl(&uart->port); + uart_handle_cts_change(&uart->port, status & TIOCM_CTS); +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + uart->scts = 1; + UART_CLEAR_SCTS(uart); + UART_CLEAR_IER(uart, EDSSI); +#endif + + return IRQ_HANDLED; +} +#else +static unsigned int bfin_serial_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} +#endif /* * interrupts are disabled on entry @@ -64,25 +145,25 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart); static void bfin_serial_stop_tx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -#if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA) - unsigned short ier; +#ifdef CONFIG_SERIAL_BFIN_DMA + struct circ_buf *xmit = &uart->port.state->xmit; #endif while (!(UART_GET_LSR(uart) & TEMT)) - continue; + cpu_relax(); #ifdef CONFIG_SERIAL_BFIN_DMA disable_dma(uart->tx_dma_channel); + xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); + uart->port.icount.tx += uart->tx_count; + uart->tx_count = 0; + uart->tx_done = 1; #else #ifdef CONFIG_BF54x /* Clear TFI bit */ UART_PUT_LSR(uart, TFI); - UART_CLEAR_IER(uart, ETBEI); -#else - ier = UART_GET_IER(uart); - ier &= ~ETBEI; - UART_PUT_IER(uart, ier); #endif + UART_CLEAR_IER(uart, ETBEI); #endif } @@ -92,18 +173,27 @@ static void bfin_serial_stop_tx(struct uart_port *port) static void bfin_serial_start_tx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + struct tty_struct *tty = uart->port.state->port.tty; + +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { + uart->scts = 0; + uart_handle_cts_change(&uart->port, uart->scts); + } +#endif + + /* + * To avoid losting RX interrupt, we reset IR function + * before sending data. + */ + if (tty->termios->c_line == N_IRDA) + bfin_serial_reset_irda(port); #ifdef CONFIG_SERIAL_BFIN_DMA - bfin_serial_dma_tx_chars(uart); + if (uart->tx_done) + bfin_serial_dma_tx_chars(uart); #else -#ifdef CONFIG_BF54x UART_SET_IER(uart, ETBEI); -#else - unsigned short ier; - ier = UART_GET_IER(uart); - ier |= ETBEI; - UART_PUT_IER(uart, ier); -#endif bfin_serial_tx_chars(uart); #endif } @@ -114,21 +204,8 @@ static void bfin_serial_start_tx(struct uart_port *port) static void bfin_serial_stop_rx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -#ifdef CONFIG_KGDB_UART - if (uart->port.line != CONFIG_KGDB_UART_PORT) { -#endif -#ifdef CONFIG_BF54x - UART_CLEAR_IER(uart, ERBFI); -#else - unsigned short ier; - ier = UART_GET_IER(uart); - ier &= ~ERBFI; - UART_PUT_IER(uart, ier); -#endif -#ifdef CONFIG_KGDB_UART - } -#endif + UART_CLEAR_IER(uart, ERBFI); } /* @@ -138,55 +215,8 @@ static void bfin_serial_enable_ms(struct uart_port *port) { } -#ifdef CONFIG_KGDB_UART -static int kgdb_entry_state; - -void kgdb_put_debug_char(int chr) -{ - struct bfin_serial_port *uart; - - if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS) - uart = &bfin_serial_ports[0]; - else - uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - - while (!(UART_GET_LSR(uart) & THRE)) { - SSYNC(); - } - -#ifndef CONFIG_BF54x - UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); - SSYNC(); -#endif - UART_PUT_CHAR(uart, (unsigned char)chr); - SSYNC(); -} - -int kgdb_get_debug_char(void) -{ - struct bfin_serial_port *uart; - unsigned char chr; - if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS) - uart = &bfin_serial_ports[0]; - else - uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - - while(!(UART_GET_LSR(uart) & DR)) { - SSYNC(); - } -#ifndef CONFIG_BF54x - UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); - SSYNC(); -#endif - chr = UART_GET_CHAR(uart); - SSYNC(); - - return chr; -} -#endif - -#if ANOMALY_05000230 && defined(CONFIG_SERIAL_BFIN_PIO) +#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO) # define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold) # define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v)) #else @@ -197,12 +227,9 @@ int kgdb_get_debug_char(void) #ifdef CONFIG_SERIAL_BFIN_PIO static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { - struct tty_struct *tty = uart->port.info->tty; + struct tty_struct *tty = NULL; unsigned int status, ch, flg; static struct timeval anomaly_start = { .tv_sec = 0 }; -#ifdef CONFIG_KGDB_UART - struct pt_regs *regs = get_irq_regs(); -#endif status = UART_GET_LSR(uart); UART_CLEAR_LSR(uart); @@ -210,28 +237,21 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) ch = UART_GET_CHAR(uart); uart->port.icount.rx++; -#ifdef CONFIG_KGDB_UART - if (uart->port.line == CONFIG_KGDB_UART_PORT) { - if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */ - kgdb_breakkey_pressed(regs); +#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + if (kgdb_connected && kgdboc_port_line == uart->port.line + && kgdboc_break_enabled) + if (ch == 0x3) {/* Ctrl + C */ + kgdb_breakpoint(); return; - } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */ - kgdb_entry_state = 1; - } else if (kgdb_entry_state == 1 && ch == 'q') { - kgdb_entry_state = 0; - kgdb_breakkey_pressed(regs); - return; - } else if (ch == 0x3) {/* Ctrl + C */ - kgdb_entry_state = 0; - kgdb_breakkey_pressed(regs); - return; - } else { - kgdb_entry_state = 0; } - } + + if (!uart->port.state || !uart->port.state->port.tty) + return; #endif + tty = uart->port.state->port.tty; - if (ANOMALY_05000230) { + if (ANOMALY_05000363) { /* The BF533 (and BF561) family of processors have a nice anomaly * where they continuously generate characters for a "single" break. * We have to basically ignore this flood until the "next" valid @@ -243,9 +263,6 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) * timeout was picked as it must absolutely be larger than 1 * character time +/- some percent. So 1.5 sounds good. All other * Blackfin families operate properly. Woo. - * Note: While Anomaly 05000230 does not directly address this, - * the changes that went in for it also fixed this issue. - * That anomaly was fixed in 0.5+ silicon. I like bunnies. */ if (anomaly_start.tv_sec) { struct timeval curr; @@ -274,12 +291,13 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) return; known_good_char: + status &= ~BI; anomaly_start.tv_sec = 0; } } if (status & BI) { - if (ANOMALY_05000230) + if (ANOMALY_05000363) if (bfin_revid() < 5) do_gettimeofday(&anomaly_start); uart->port.icount.brk++; @@ -316,23 +334,27 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) static void bfin_serial_tx_chars(struct bfin_serial_port *uart) { - struct circ_buf *xmit = &uart->port.info->xmit; + struct circ_buf *xmit = &uart->port.state->xmit; + + if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { +#ifdef CONFIG_BF54x + /* Clear TFI bit */ + UART_PUT_LSR(uart, TFI); +#endif + /* Anomaly notes: + * 05000215 - we always clear ETBEI within last UART TX + * interrupt to end a string. It is always set + * when start a new tx. + */ + UART_CLEAR_IER(uart, ETBEI); + return; + } if (uart->port.x_char) { UART_PUT_CHAR(uart, uart->port.x_char); uart->port.icount.tx++; uart->port.x_char = 0; } - /* - * Check the modem control lines before - * transmitting anything. - */ - bfin_serial_mctrl_check(uart); - - if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { - bfin_serial_stop_tx(&uart->port); - return; - } while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) { UART_PUT_CHAR(uart, xmit->buf[xmit->tail]); @@ -343,9 +365,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uart->port); - - if (uart_circ_empty(xmit)) - bfin_serial_stop_tx(&uart->port); } static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) @@ -364,6 +383,12 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { + uart->scts = 0; + uart_handle_cts_change(&uart->port, uart->scts); + } +#endif spin_lock(&uart->port.lock); if (UART_GET_LSR(uart) & THRE) bfin_serial_tx_chars(uart); @@ -373,28 +398,15 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) } #endif -#ifdef CONFIG_SERIAL_BFIN_CTSRTS -static void bfin_serial_do_work(struct work_struct *work) -{ - struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue); - - bfin_serial_mctrl_check(uart); -} -#endif - #ifdef CONFIG_SERIAL_BFIN_DMA static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) { - struct circ_buf *xmit = &uart->port.info->xmit; - unsigned short ier; - int flags = 0; + struct circ_buf *xmit = &uart->port.state->xmit; - if (!uart->tx_done) - return; uart->tx_done = 0; if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { - bfin_serial_stop_tx(&uart->port); + uart->tx_count = 0; uart->tx_done = 1; return; } @@ -405,13 +417,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) uart->port.x_char = 0; } - /* - * Check the modem control lines before - * transmitting anything. - */ - bfin_serial_mctrl_check(uart); - - spin_lock_irqsave(&uart->port.lock, flags); uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail)) uart->tx_count = UART_XMIT_SIZE - xmit->tail; @@ -426,30 +431,23 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); set_dma_x_count(uart->tx_dma_channel, uart->tx_count); set_dma_x_modify(uart->tx_dma_channel, 1); + SSYNC(); enable_dma(uart->tx_dma_channel); - xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); - uart->port.icount.tx += uart->tx_count; - -#ifdef CONFIG_BF54x UART_SET_IER(uart, ETBEI); -#else - ier = UART_GET_IER(uart); - ier |= ETBEI; - UART_PUT_IER(uart, ier); -#endif - spin_unlock_irqrestore(&uart->port.lock, flags); } static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) { - struct tty_struct *tty = uart->port.info->tty; + struct tty_struct *tty = uart->port.state->port.tty; int i, flg, status; status = UART_GET_LSR(uart); UART_CLEAR_LSR(uart); - uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);; + uart->port.icount.rx += + CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, + UART_XMIT_SIZE); if (status & BI) { uart->port.icount.brk++; @@ -475,10 +473,14 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) else flg = TTY_NORMAL; - for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) { - if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) - goto dma_ignore_char; - uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg); + for (i = uart->rx_dma_buf.tail; ; i++) { + if (i >= UART_XMIT_SIZE) + i = 0; + if (i == uart->rx_dma_buf.head) + break; + if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) + uart_insert_char(&uart->port, status, OE, + uart->rx_dma_buf.buf[i], flg); } dma_ignore_char: @@ -488,47 +490,75 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) { int x_pos, pos; - int flags = 0; - spin_lock_irqsave(&uart->port.lock, flags); - x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel); + dma_disable_irq(uart->tx_dma_channel); + dma_disable_irq(uart->rx_dma_channel); + spin_lock_bh(&uart->port.lock); + + /* 2D DMA RX buffer ring is used. Because curr_y_count and + * curr_x_count can't be read as an atomic operation, + * curr_y_count should be read before curr_x_count. When + * curr_x_count is read, curr_y_count may already indicate + * next buffer line. But, the position calculated here is + * still indicate the old line. The wrong position data may + * be smaller than current buffer tail, which cause garbages + * are received if it is not prohibit. + */ + uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); + x_pos = get_dma_curr_xcount(uart->rx_dma_channel); + uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; + if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) + uart->rx_dma_nrows = 0; + x_pos = DMA_RX_XCOUNT - x_pos; if (x_pos == DMA_RX_XCOUNT) x_pos = 0; pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; - - if (pos>uart->rx_dma_buf.tail) { - uart->rx_dma_buf.tail = pos; + /* Ignore receiving data if new position is in the same line of + * current buffer tail and small. + */ + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { + uart->rx_dma_buf.head = pos; bfin_serial_dma_rx_chars(uart); - uart->rx_dma_buf.head = uart->rx_dma_buf.tail; + uart->rx_dma_buf.tail = uart->rx_dma_buf.head; } - spin_unlock_irqrestore(&uart->port.lock, flags); - uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; - add_timer(&(uart->rx_dma_timer)); + + spin_unlock_bh(&uart->port.lock); + dma_enable_irq(uart->tx_dma_channel); + dma_enable_irq(uart->rx_dma_channel); + + mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); } static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; - struct circ_buf *xmit = &uart->port.info->xmit; - unsigned short ier; + struct circ_buf *xmit = &uart->port.state->xmit; + +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) { + uart->scts = 0; + uart_handle_cts_change(&uart->port, uart->scts); + } +#endif spin_lock(&uart->port.lock); if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { - clear_dma_irqstat(uart->tx_dma_channel); disable_dma(uart->tx_dma_channel); -#ifdef CONFIG_BF54x + clear_dma_irqstat(uart->tx_dma_channel); + /* Anomaly notes: + * 05000215 - we always clear ETBEI within last UART TX + * interrupt to end a string. It is always set + * when start a new tx. + */ UART_CLEAR_IER(uart, ETBEI); -#else - ier = UART_GET_IER(uart); - ier &= ~ETBEI; - UART_PUT_IER(uart, ier); -#endif + xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); + uart->port.icount.tx += uart->tx_count; + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uart->port); - uart->tx_done = 1; - bfin_serial_dma_tx_chars(uart); } @@ -540,19 +570,28 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; unsigned short irqstat; + int x_pos, pos; - uart->rx_dma_nrows++; - if (uart->rx_dma_nrows == DMA_RX_YCOUNT) { - uart->rx_dma_nrows = 0; - uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT; - bfin_serial_dma_rx_chars(uart); - uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0; - } spin_lock(&uart->port.lock); irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); clear_dma_irqstat(uart->rx_dma_channel); + uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); + x_pos = get_dma_curr_xcount(uart->rx_dma_channel); + uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; + if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) + uart->rx_dma_nrows = 0; + + pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { + uart->rx_dma_buf.head = pos; + bfin_serial_dma_rx_chars(uart); + uart->rx_dma_buf.tail = uart->rx_dma_buf.head; + } + spin_unlock(&uart->port.lock); + return IRQ_HANDLED; } #endif @@ -572,70 +611,6 @@ static unsigned int bfin_serial_tx_empty(struct uart_port *port) return 0; } -static unsigned int bfin_serial_get_mctrl(struct uart_port *port) -{ -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - if (uart->cts_pin < 0) - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - -# ifdef BF54x - if (UART_GET_MSR(uart) & CTS) -# else - if (gpio_get_value(uart->cts_pin)) -# endif - return TIOCM_DSR | TIOCM_CAR; - else -#endif - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -} - -static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - if (uart->rts_pin < 0) - return; - - if (mctrl & TIOCM_RTS) -# ifdef BF54x - UART_PUT_MCR(uart, UART_GET_MCR(uart) & ~MRTS); -# else - gpio_set_value(uart->rts_pin, 0); -# endif - else -# ifdef BF54x - UART_PUT_MCR(uart, UART_GET_MCR(uart) | MRTS); -# else - gpio_set_value(uart->rts_pin, 1); -# endif -#endif -} - -/* - * Handle any change of modem status signal since we were last called. - */ -static void bfin_serial_mctrl_check(struct bfin_serial_port *uart) -{ -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - unsigned int status; - struct uart_info *info = uart->port.info; - struct tty_struct *tty = info->tty; - - status = bfin_serial_get_mctrl(&uart->port); - uart_handle_cts_change(&uart->port, status & TIOCM_CTS); - if (!(status & TIOCM_CTS)) { - tty->hw_stopped = 1; - schedule_work(&uart->cts_workqueue); - } else { - tty->hw_stopped = 0; - } -#endif -} - -/* - * Interrupts are always disabled. - */ static void bfin_serial_break_ctl(struct uart_port *port, int break_state) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; @@ -691,19 +666,18 @@ static int bfin_serial_startup(struct uart_port *port) uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; add_timer(&(uart->rx_dma_timer)); #else +# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled) + kgdboc_break_enabled = 0; + else { +# endif if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, "BFIN_UART_RX", uart)) { -# ifdef CONFIG_KGDB_UART - if (uart->port.line != CONFIG_KGDB_UART_PORT) { -# endif printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); return -EBUSY; -# ifdef CONFIG_KGDB_UART - } -# endif } - if (request_irq (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED, "BFIN_UART_TX", uart)) { @@ -711,12 +685,78 @@ static int bfin_serial_startup(struct uart_port *port) free_irq(uart->port.irq, uart); return -EBUSY; } + +# ifdef CONFIG_BF54x + { + unsigned uart_dma_ch_rx, uart_dma_ch_tx; + + switch (uart->port.irq) { + case IRQ_UART3_RX: + uart_dma_ch_rx = CH_UART3_RX; + uart_dma_ch_tx = CH_UART3_TX; + break; + case IRQ_UART2_RX: + uart_dma_ch_rx = CH_UART2_RX; + uart_dma_ch_tx = CH_UART2_TX; + break; + default: + uart_dma_ch_rx = uart_dma_ch_tx = 0; + break; + }; + + if (uart_dma_ch_rx && + request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { + printk(KERN_NOTICE"Fail to attach UART interrupt\n"); + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq + 1, uart); + return -EBUSY; + } + if (uart_dma_ch_tx && + request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) { + printk(KERN_NOTICE "Fail to attach UART interrupt\n"); + free_dma(uart_dma_ch_rx); + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq + 1, uart); + return -EBUSY; + } + } +# endif +# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + } +# endif #endif -#ifdef CONFIG_BF54x - UART_SET_IER(uart, ERBFI); -#else - UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI); + +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (uart->cts_pin >= 0) { + if (request_irq(gpio_to_irq(uart->cts_pin), + bfin_serial_mctrl_cts_int, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_DISABLED, "BFIN_UART_CTS", uart)) { + uart->cts_pin = -1; + pr_info("Unable to attach BlackFin UART CTS interrupt.\ + So, disable it.\n"); + } + } + if (uart->rts_pin >= 0) { + gpio_request(uart->rts_pin, DRIVER_NAME); + gpio_direction_output(uart->rts_pin, 0); + } +#endif +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (request_irq(uart->status_irq, + bfin_serial_mctrl_cts_int, + IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) { + pr_info("Unable to attach BlackFin UART Modem \ + Status interrupt.\n"); + } + + /* CTS RTS PINs are negative assertive. */ + UART_PUT_MCR(uart, ACTS); + UART_SET_IER(uart, EDSSI); #endif + + UART_SET_IER(uart, ERBFI); return 0; } @@ -732,12 +772,34 @@ static void bfin_serial_shutdown(struct uart_port *port) del_timer(&(uart->rx_dma_timer)); dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0); #else -#ifdef CONFIG_KGDB_UART - if (uart->port.line != CONFIG_KGDB_UART_PORT) +#ifdef CONFIG_BF54x + switch (uart->port.irq) { + case IRQ_UART3_RX: + free_dma(CH_UART3_RX); + free_dma(CH_UART3_TX); + break; + case IRQ_UART2_RX: + free_dma(CH_UART2_RX); + free_dma(CH_UART2_TX); + break; + default: + break; + }; #endif free_irq(uart->port.irq, uart); free_irq(uart->port.irq+1, uart); #endif + +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (uart->cts_pin >= 0) + free_irq(gpio_to_irq(uart->cts_pin), uart); + if (uart->rts_pin >= 0) + gpio_free(uart->rts_pin); +#endif +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (UART_GET_IER(uart) && EDSSI) + free_irq(uart->status_irq, uart); +#endif } static void @@ -747,7 +809,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, struct bfin_serial_port *uart = (struct bfin_serial_port *)port; unsigned long flags; unsigned int baud, quot; - unsigned short val, ier, lsr, lcr = 0; + unsigned short val, ier, lcr = 0; switch (termios->c_cflag & CSIZE) { case CS8: @@ -764,11 +826,19 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, break; default: printk(KERN_ERR "%s: word lengh not supported\n", - __FUNCTION__); + __func__); } - if (termios->c_cflag & CSTOPB) - lcr |= STB; + /* Anomaly notes: + * 05000231 - STOP bit is always set to 1 whatever the user is set. + */ + if (termios->c_cflag & CSTOPB) { + if (ANOMALY_05000231) + printk(KERN_WARNING "STOP bits other than 1 is not " + "supported in case of anomaly 05000231.\n"); + else + lcr |= STB; + } if (termios->c_cflag & PARENB) lcr |= PEN; if (!(termios->c_cflag & PARODD)) @@ -799,57 +869,37 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, } baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); + quot = uart_get_divisor(port, baud) - ANOMALY_05000230; spin_lock_irqsave(&uart->port.lock, flags); UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15); - do { - lsr = UART_GET_LSR(uart); - } while (!(lsr & TEMT)); - /* Disable UART */ ier = UART_GET_IER(uart); -#ifdef CONFIG_BF54x - UART_CLEAR_IER(uart, 0xF); -#else - UART_PUT_IER(uart, 0); -#endif + UART_DISABLE_INTS(uart); -#ifndef CONFIG_BF54x /* Set DLAB in LCR to Access DLL and DLH */ - val = UART_GET_LCR(uart); - val |= DLAB; - UART_PUT_LCR(uart, val); - SSYNC(); -#endif + UART_SET_DLAB(uart); UART_PUT_DLL(uart, quot & 0xFF); - SSYNC(); UART_PUT_DLH(uart, (quot >> 8) & 0xFF); SSYNC(); -#ifndef CONFIG_BF54x /* Clear DLAB in LCR to Access THR RBR IER */ - val = UART_GET_LCR(uart); - val &= ~DLAB; - UART_PUT_LCR(uart, val); - SSYNC(); -#endif + UART_CLEAR_DLAB(uart); UART_PUT_LCR(uart, lcr); /* Enable UART */ -#ifdef CONFIG_BF54x - UART_SET_IER(uart, ier); -#else - UART_PUT_IER(uart, ier); -#endif + UART_ENABLE_INTS(uart, ier); val = UART_GET_GCTL(uart); val |= UCEN; UART_PUT_GCTL(uart, val); + /* Port speed changed, update the per-port timeout. */ + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock_irqrestore(&uart->port.lock, flags); } @@ -898,6 +948,94 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser) return 0; } +/* + * Enable the IrDA function if tty->ldisc.num is N_IRDA. + * In other cases, disable IrDA function. + */ +static void bfin_serial_set_ldisc(struct uart_port *port) +{ + int line = port->line; + unsigned short val; + + if (line >= port->state->port.tty->driver->num) + return; + + switch (port->state->port.tty->termios->c_line) { + case N_IRDA: + val = UART_GET_GCTL(&bfin_serial_ports[line]); + val |= (IREN | RPOLC); + UART_PUT_GCTL(&bfin_serial_ports[line], val); + break; + default: + val = UART_GET_GCTL(&bfin_serial_ports[line]); + val &= ~(IREN | RPOLC); + UART_PUT_GCTL(&bfin_serial_ports[line], val); + } +} + +static void bfin_serial_reset_irda(struct uart_port *port) +{ + int line = port->line; + unsigned short val; + + val = UART_GET_GCTL(&bfin_serial_ports[line]); + val &= ~(IREN | RPOLC); + UART_PUT_GCTL(&bfin_serial_ports[line], val); + SSYNC(); + val |= (IREN | RPOLC); + UART_PUT_GCTL(&bfin_serial_ports[line], val); + SSYNC(); +} + +#ifdef CONFIG_CONSOLE_POLL +/* Anomaly notes: + * 05000099 - Because we only use THRE in poll_put and DR in poll_get, + * losing other bits of UART_LSR is not a problem here. + */ +static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + + while (!(UART_GET_LSR(uart) & THRE)) + cpu_relax(); + + UART_CLEAR_DLAB(uart); + UART_PUT_CHAR(uart, (unsigned char)chr); +} + +static int bfin_serial_poll_get_char(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + unsigned char chr; + + while (!(UART_GET_LSR(uart) & DR)) + cpu_relax(); + + UART_CLEAR_DLAB(uart); + chr = UART_GET_CHAR(uart); + + return chr; +} +#endif + +#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) +static void bfin_kgdboc_port_shutdown(struct uart_port *port) +{ + if (kgdboc_break_enabled) { + kgdboc_break_enabled = 0; + bfin_serial_shutdown(port); + } +} + +static int bfin_kgdboc_port_startup(struct uart_port *port) +{ + kgdboc_port_line = port->line; + kgdboc_break_enabled = !bfin_serial_startup(port); + return 0; +} +#endif + static struct uart_ops bfin_serial_pops = { .tx_empty = bfin_serial_tx_empty, .set_mctrl = bfin_serial_set_mctrl, @@ -910,13 +1048,56 @@ static struct uart_ops bfin_serial_pops = { .startup = bfin_serial_startup, .shutdown = bfin_serial_shutdown, .set_termios = bfin_serial_set_termios, + .set_ldisc = bfin_serial_set_ldisc, .type = bfin_serial_type, .release_port = bfin_serial_release_port, .request_port = bfin_serial_request_port, .config_port = bfin_serial_config_port, .verify_port = bfin_serial_verify_port, +#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + .kgdboc_port_startup = bfin_kgdboc_port_startup, + .kgdboc_port_shutdown = bfin_kgdboc_port_shutdown, +#endif +#ifdef CONFIG_CONSOLE_POLL + .poll_put_char = bfin_serial_poll_put_char, + .poll_get_char = bfin_serial_poll_get_char, +#endif }; +static void __init bfin_serial_hw_init(void) +{ +#ifdef CONFIG_SERIAL_BFIN_UART0 + peripheral_request(P_UART0_TX, DRIVER_NAME); + peripheral_request(P_UART0_RX, DRIVER_NAME); +#endif + +#ifdef CONFIG_SERIAL_BFIN_UART1 + peripheral_request(P_UART1_TX, DRIVER_NAME); + peripheral_request(P_UART1_RX, DRIVER_NAME); + +# if defined(CONFIG_BFIN_UART1_CTSRTS) && defined(CONFIG_BF54x) + peripheral_request(P_UART1_RTS, DRIVER_NAME); + peripheral_request(P_UART1_CTS, DRIVER_NAME); +# endif +#endif + +#ifdef CONFIG_SERIAL_BFIN_UART2 + peripheral_request(P_UART2_TX, DRIVER_NAME); + peripheral_request(P_UART2_RX, DRIVER_NAME); +#endif + +#ifdef CONFIG_SERIAL_BFIN_UART3 + peripheral_request(P_UART3_TX, DRIVER_NAME); + peripheral_request(P_UART3_RX, DRIVER_NAME); + +# if defined(CONFIG_BFIN_UART3_CTSRTS) && defined(CONFIG_BF54x) + peripheral_request(P_UART3_RTS, DRIVER_NAME); + peripheral_request(P_UART3_CTS, DRIVER_NAME); +# endif +#endif +} + static void __init bfin_serial_init_ports(void) { static int first = 1; @@ -926,8 +1107,12 @@ static void __init bfin_serial_init_ports(void) return; first = 0; - for (i = 0; i < nr_ports; i++) { + bfin_serial_hw_init(); + + for (i = 0; i < nr_active_ports; i++) { + spin_lock_init(&bfin_serial_ports[i].port.lock); bfin_serial_ports[i].port.uartclk = get_sclk(); + bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE; bfin_serial_ports[i].port.ops = &bfin_serial_pops; bfin_serial_ports[i].port.line = i; bfin_serial_ports[i].port.iotype = UPIO_MEM; @@ -937,6 +1122,8 @@ static void __init bfin_serial_init_ports(void) bfin_serial_resource[i].uart_base_addr; bfin_serial_ports[i].port.irq = bfin_serial_resource[i].uart_irq; + bfin_serial_ports[i].status_irq = + bfin_serial_resource[i].uart_status_irq; bfin_serial_ports[i].port.flags = UPF_BOOT_AUTOCONF; #ifdef CONFIG_SERIAL_BFIN_DMA bfin_serial_ports[i].tx_done = 1; @@ -947,19 +1134,17 @@ static void __init bfin_serial_init_ports(void) bfin_serial_resource[i].uart_rx_dma_channel; init_timer(&(bfin_serial_ports[i].rx_dma_timer)); #endif -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work); +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) bfin_serial_ports[i].cts_pin = bfin_serial_resource[i].uart_cts_pin; bfin_serial_ports[i].rts_pin = bfin_serial_resource[i].uart_rts_pin; #endif - bfin_serial_hw_init(&bfin_serial_ports[i]); } - } -#ifdef CONFIG_SERIAL_BFIN_CONSOLE +#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) /* * If the port was already initialised (eg, by a boot loader), * try to determine the current setup. @@ -973,8 +1158,7 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, status = UART_GET_IER(uart) & (ERBFI | ETBEI); if (status == (ERBFI | ETBEI)) { /* ok, the port was enabled */ - unsigned short lcr, val; - unsigned short dlh, dll; + u16 lcr, dlh, dll; lcr = UART_GET_LCR(uart); @@ -991,45 +1175,34 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, case 2: *bits = 7; break; case 3: *bits = 8; break; } -#ifndef CONFIG_BF54x /* Set DLAB in LCR to Access DLL and DLH */ - val = UART_GET_LCR(uart); - val |= DLAB; - UART_PUT_LCR(uart, val); -#endif + UART_SET_DLAB(uart); dll = UART_GET_DLL(uart); dlh = UART_GET_DLH(uart); -#ifndef CONFIG_BF54x /* Clear DLAB in LCR to Access THR RBR IER */ - val = UART_GET_LCR(uart); - val &= ~DLAB; - UART_PUT_LCR(uart, val); -#endif + UART_CLEAR_DLAB(uart); *baud = get_sclk() / (16*(dll | dlh << 8)); } - pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits); + pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits); } -#endif -#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) static struct uart_driver bfin_serial_reg; static int __init bfin_serial_console_setup(struct console *co, char *options) { struct bfin_serial_port *uart; -# ifdef CONFIG_SERIAL_BFIN_CONSOLE int baud = 57600; int bits = 8; int parity = 'n'; -# ifdef CONFIG_SERIAL_BFIN_CTSRTS +# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) int flow = 'r'; -# else +# else int flow = 'n'; -# endif # endif /* @@ -1037,20 +1210,16 @@ bfin_serial_console_setup(struct console *co, char *options) * if so, search for the first available port that does have * console support. */ - if (co->index == -1 || co->index >= nr_ports) + if (co->index == -1 || co->index >= nr_active_ports) co->index = 0; uart = &bfin_serial_ports[co->index]; -# ifdef CONFIG_SERIAL_BFIN_CONSOLE if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else bfin_serial_console_get_options(uart, &baud, &parity, &bits); return uart_set_options(&uart->port, co, baud, parity, bits, flow); -# else - return 0; -# endif } #endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) || defined (CONFIG_EARLY_PRINTK) */ @@ -1072,7 +1241,7 @@ static void bfin_serial_console_write(struct console *co, const char *s, unsigned int count) { struct bfin_serial_port *uart = &bfin_serial_ports[co->index]; - int flags = 0; + unsigned long flags; spin_lock_irqsave(&uart->port.lock, flags); uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); @@ -1094,10 +1263,7 @@ static int __init bfin_serial_rs_console_init(void) { bfin_serial_init_ports(); register_console(&bfin_serial_console); -#ifdef CONFIG_KGDB_UART - kgdb_entry_state = 0; - init_kgdb_uart(); -#endif + return 0; } console_initcall(bfin_serial_rs_console_init); @@ -1132,12 +1298,17 @@ static __init void early_serial_write(struct console *con, const char *s, } } -static struct __init console bfin_early_serial_console = { +/* + * This should have a .setup or .early_setup in it, but then things get called + * without the command line options, and the baud rate gets messed up - so + * don't let the common infrastructure play with things. (see calls to setup + * & earlysetup in ./kernel/printk.c:register_console() + */ +static struct __initdata console bfin_early_serial_console = { .name = "early_BFuart", .write = early_serial_write, .device = uart_console_device, .flags = CON_PRINTBUFFER, - .setup = bfin_serial_console_setup, .index = -1, .data = &bfin_serial_reg, }; @@ -1148,7 +1319,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port, struct bfin_serial_port *uart; struct ktermios t; - if (port == -1 || port >= nr_ports) + if (port == -1 || port >= nr_active_ports) port = 0; bfin_serial_init_ports(); bfin_early_serial_console.index = port; @@ -1162,7 +1333,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port, return &bfin_early_serial_console; } -#endif /* CONFIG_SERIAL_BFIN_CONSOLE */ +#endif /* CONFIG_EARLY_PRINTK */ static struct uart_driver bfin_serial_reg = { .owner = THIS_MODULE, @@ -1170,26 +1341,32 @@ static struct uart_driver bfin_serial_reg = { .dev_name = BFIN_SERIAL_NAME, .major = BFIN_SERIAL_MAJOR, .minor = BFIN_SERIAL_MINOR, - .nr = NR_PORTS, + .nr = BFIN_UART_NR_PORTS, .cons = BFIN_SERIAL_CONSOLE, }; static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state) { - struct bfin_serial_port *uart = platform_get_drvdata(dev); + int i; - if (uart) - uart_suspend_port(&bfin_serial_reg, &uart->port); + for (i = 0; i < nr_active_ports; i++) { + if (bfin_serial_ports[i].port.dev != &dev->dev) + continue; + uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + } return 0; } static int bfin_serial_resume(struct platform_device *dev) { - struct bfin_serial_port *uart = platform_get_drvdata(dev); + int i; - if (uart) - uart_resume_port(&bfin_serial_reg, &uart->port); + for (i = 0; i < nr_active_ports; i++) { + if (bfin_serial_ports[i].port.dev != &dev->dev) + continue; + uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + } return 0; } @@ -1204,32 +1381,31 @@ static int bfin_serial_probe(struct platform_device *dev) break; if (i < dev->num_resources) { - for (i = 0; i < nr_ports; i++, res++) { + for (i = 0; i < nr_active_ports; i++, res++) { if (bfin_serial_ports[i].port.mapbase != res->start) continue; bfin_serial_ports[i].port.dev = &dev->dev; uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); - platform_set_drvdata(dev, &bfin_serial_ports[i]); } } return 0; } -static int bfin_serial_remove(struct platform_device *pdev) +static int bfin_serial_remove(struct platform_device *dev) { - struct bfin_serial_port *uart = platform_get_drvdata(pdev); - + int i; -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - gpio_free(uart->cts_pin); - gpio_free(uart->rts_pin); + for (i = 0; i < nr_active_ports; i++) { + if (bfin_serial_ports[i].port.dev != &dev->dev) + continue; + uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + bfin_serial_ports[i].port.dev = NULL; +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) + gpio_free(bfin_serial_ports[i].cts_pin); + gpio_free(bfin_serial_ports[i].rts_pin); #endif - - platform_set_drvdata(pdev, NULL); - - if (uart) - uart_remove_one_port(&bfin_serial_reg, &uart->port); + } return 0; } @@ -1241,16 +1417,13 @@ static struct platform_driver bfin_serial_driver = { .resume = bfin_serial_resume, .driver = { .name = "bfin-uart", + .owner = THIS_MODULE, }, }; static int __init bfin_serial_init(void) { int ret; -#ifdef CONFIG_KGDB_UART - struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - struct ktermios t; -#endif pr_info("Serial: Blackfin serial driver\n"); @@ -1264,25 +1437,6 @@ static int __init bfin_serial_init(void) uart_unregister_driver(&bfin_serial_reg); } } -#ifdef CONFIG_KGDB_UART - if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) { - request_irq(uart->port.irq, bfin_serial_rx_int, - IRQF_DISABLED, "BFIN_UART_RX", uart); - pr_info("Request irq for kgdb uart port\n"); -#ifdef CONFIG_BF54x - UART_SET_IER(uart, ERBFI); -#else - UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI); -#endif - SSYNC(); - t.c_cflag = CS8|B57600; - t.c_iflag = 0; - t.c_oflag = 0; - t.c_lflag = ICANON; - t.c_line = CONFIG_KGDB_UART_PORT; - bfin_serial_set_termios(&uart->port, &t, &t); - } -#endif return ret; } @@ -1292,6 +1446,7 @@ static void __exit bfin_serial_exit(void) uart_unregister_driver(&bfin_serial_reg); } + module_init(bfin_serial_init); module_exit(bfin_serial_exit); @@ -1299,3 +1454,4 @@ MODULE_AUTHOR("Aubrey.Li "); MODULE_DESCRIPTION("Blackfin generic serial port driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR); +MODULE_ALIAS("platform:bfin-uart");