static inline void wait_for_xmitr(struct uart_port *port, int bits) { unsigned int status, mr, tmout = 10000; do { status = msm_read(port, UART_SR); if (--tmout == 0) break; udelay(1); } while ((status & bits) != bits); mr = msm_read(port, UART_MR1); if (mr & UART_MR1_CTS_CTL) { unsigned int tmout; for (tmout = 1000000; tmout; tmout--) { unsigned int isr = msm_read(port, UART_ISR); if (!(isr & UART_IMR_CURRENT_CTS)) break; udelay(1); touch_nmi_watchdog(); } } }
/* * Wait for transmitter & holding register to empty * Derived from wait_for_xmitr in 8250 serial driver by Russell King */ static inline void wait_for_xmitr(struct uart_port *port, int bits) { unsigned int status, mr, tmout = 10000; /* Wait up to 10ms for the character(s) to be sent. */ do { status = msm_read(port, UART_SR); if (--tmout == 0) break; udelay(1); } while ((status & bits) != bits); mr = msm_read(port, UART_MR1); /* Wait up to 1s for flow control if necessary */ if (mr & UART_MR1_CTS_CTL) { unsigned int tmout; for (tmout = 1000000; tmout; tmout--) { unsigned int isr = msm_read(port, UART_ISR); /* CTS input is active lo */ if (!(isr & UART_IMR_CURRENT_CTS)) break; udelay(1); touch_nmi_watchdog(); } } }
static int msm_startup(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); unsigned int data, rfr_level; int ret; snprintf(msm_port->name, sizeof(msm_port->name), "msm_serial%d", port->line); ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, msm_port->name, port); if (unlikely(ret)) return ret; msm_init_clock(port); if (likely(port->fifosize > 12)) rfr_level = port->fifosize - 12; else rfr_level = port->fifosize; /* set automatic RFR level */ data = msm_read(port, UART_MR1); data &= ~UART_MR1_AUTO_RFR_LEVEL1; data &= ~UART_MR1_AUTO_RFR_LEVEL0; data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; msm_write(port, data, UART_MR1); /* make sure that RXSTALE count is non-zero */ data = msm_read(port, UART_IPR); if (unlikely(!data)) { data |= UART_IPR_RXSTALE_LAST; data |= UART_IPR_STALE_LSB; msm_write(port, data, UART_IPR); } msm_reset(port); msm_write(port, 0x05, UART_CR); /* enable TX & RX */ /* turn on RX and CTS interrupts */ msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | UART_IMR_CURRENT_CTS; msm_write(port, msm_port->imr, UART_IMR); #ifdef CONFIG_SERIAL_MSM_RX_WAKEUP /* Apply the RX GPIO wake irq workaround to the bluetooth uart */ if (port->line == 0) { /* BT is serial device 0 */ ret = request_irq(MSM_GPIO_TO_INT(45), msm_rx_irq, IRQF_TRIGGER_FALLING, "msm_serial0_rx", port); if (unlikely(ret)) return ret; } #endif return 0; }
static inline int debug_getc(void) { if (msm_read(UART_SR) & UART_SR_RX_READY) { return msm_read(UART_RF); } else { return -1; } }
static void handle_rx_dm(struct uart_port *port, unsigned int misr) { struct tty_struct *tty = port->state->port.tty; unsigned int sr; int count = 0; struct msm_port *msm_port = UART_TO_MSM(port); if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { port->icount.overrun++; tty_insert_flip_char(tty, 0, TTY_OVERRUN); msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); } if (misr & UART_IMR_RXSTALE) { count = msm_read(port, UARTDM_RX_TOTAL_SNAP) - msm_port->old_snap_state; msm_port->old_snap_state = 0; } else { count = 4 * (msm_read(port, UART_RFWR)); msm_port->old_snap_state += count; } /* TODO: Precise error reporting */ port->icount.rx += count; while (count > 0) { unsigned int c; sr = msm_read(port, UART_SR); if ((sr & UART_SR_RX_READY) == 0) { msm_port->old_snap_state -= count; break; } c = msm_read(port, UARTDM_RF); if (sr & UART_SR_RX_BREAK) { port->icount.brk++; if (uart_handle_break(port)) continue; } else if (sr & UART_SR_PAR_FRAME_ERR) port->icount.frame++; /* TODO: handle sysrq */ tty_insert_flip_string(tty, (char *) &c, (count > 4) ? 4 : count); count -= 4; } tty_flip_buffer_push(tty); if (misr & (UART_IMR_RXSTALE)) msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); }
static int msm_startup(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); unsigned int data, rfr_level; int ret; snprintf(msm_port->name, sizeof(msm_port->name), "msm_serial%d", port->line); ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, msm_port->name, port); if (unlikely(ret)) return ret; msm_init_clock(port); if (likely(port->fifosize > 12)) rfr_level = port->fifosize - 12; else rfr_level = port->fifosize; /* set automatic RFR level */ data = msm_read(port, UART_MR1); data &= ~UART_MR1_AUTO_RFR_LEVEL1; data &= ~UART_MR1_AUTO_RFR_LEVEL0; data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; msm_write(port, data, UART_MR1); /* make sure that RXSTALE count is non-zero */ data = msm_read(port, UART_IPR); if (unlikely(!data)) { data |= UART_IPR_RXSTALE_LAST; data |= UART_IPR_STALE_LSB; msm_write(port, data, UART_IPR); } msm_reset(port); msm_write(port, 0x05, UART_CR); /* enable TX & RX */ /* turn on RX and CTS interrupts */ msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | UART_IMR_CURRENT_CTS; msm_write(port, msm_port->imr, UART_IMR); return 0; }
static irqreturn_t msm_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; struct msm_port *msm_port = UART_TO_MSM(port); unsigned int misr; spin_lock(&port->lock); misr = msm_read(port, UART_MISR); msm_write(port, 0, UART_IMR); /* disable interrupt */ if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) { if (msm_port->is_uartdm) handle_rx_dm(port, misr); else handle_rx(port); } if (misr & UART_IMR_TXLEV) handle_tx(port); if (misr & UART_IMR_DELTA_CTS) handle_delta_cts(port); msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ spin_unlock(&port->lock); return IRQ_HANDLED; }
static irqreturn_t msm_irq(int irq, void *dev_id) { unsigned long flags; struct uart_port *port = dev_id; struct msm_port *msm_port = UART_TO_MSM(port); unsigned int misr; spin_lock_irqsave(&port->lock, flags); clk_enable(msm_port->clk); misr = msm_read(port, UART_MISR); msm_write(port, 0, UART_IMR); /* disable interrupt */ if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) handle_rx(port); if (misr & UART_IMR_TXLEV) handle_tx(port); if (misr & UART_IMR_DELTA_CTS) handle_delta_cts(port); msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ clk_disable(msm_port->clk); spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; }
static void handle_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; struct msm_port *msm_port = UART_TO_MSM(port); int sent_tx; if (port->x_char) { msm_write(port, port->x_char, UART_TF); port->icount.tx++; port->x_char = 0; } while (msm_read(port, UART_SR) & UART_SR_TX_READY) { if (uart_circ_empty(xmit)) { /* disable tx interrupts */ msm_port->imr &= ~UART_IMR_TXLEV; msm_write(port, msm_port->imr, UART_IMR); break; } msm_write(port, xmit->buf[xmit->tail], UART_TF); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; sent_tx = 1; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); }
static unsigned int msm_tx_empty(struct uart_port *port) { unsigned int ret; ret = (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; return ret; }
static void handle_rx(struct uart_port *port) { struct tty_struct *tty = port->info->port.tty; unsigned int sr; /* * Handle overrun. My understanding of the hardware is that overrun * is not tied to the RX buffer, so we handle the case out of band. */ if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { port->icount.overrun++; tty_insert_flip_char(tty, 0, TTY_OVERRUN); msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); } /* and now the main RX loop */ while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { unsigned int c; char flag = TTY_NORMAL; c = msm_read(port, UART_RF); if (sr & UART_SR_RX_BREAK) { port->icount.brk++; if (uart_handle_break(port)) continue; } else if (sr & UART_SR_PAR_FRAME_ERR) { port->icount.frame++; } else { port->icount.rx++; } /* Mask conditions we're ignorning. */ sr &= port->read_status_mask; if (sr & UART_SR_RX_BREAK) { flag = TTY_BREAK; } else if (sr & UART_SR_PAR_FRAME_ERR) { flag = TTY_FRAME; } if (!uart_handle_sysrq_char(port, c)) tty_insert_flip_char(tty, c, flag); } tty_flip_buffer_push(tty); }
static inline void wait_for_xmitr_done(struct uart_port *port, int bits) { unsigned int status, tmout = 10000; do { status = msm_read(port, UART_SR); if (--tmout == 0) break; udelay(1); } while ((status&bits) != bits); }
static void handle_rx(struct uart_port *port) { struct tty_struct *tty = port->state->port.tty; unsigned int sr; if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { port->icount.overrun++; tty_insert_flip_char(tty, 0, TTY_OVERRUN); msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); } while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { unsigned int c; char flag = TTY_NORMAL; c = msm_read(port, UART_RF); if (sr & UART_SR_RX_BREAK) { port->icount.brk++; if (uart_handle_break(port)) continue; } else if (sr & UART_SR_PAR_FRAME_ERR) { port->icount.frame++; } else { port->icount.rx++; } sr &= port->read_status_mask; if (sr & UART_SR_RX_BREAK) { flag = TTY_BREAK; } else if (sr & UART_SR_PAR_FRAME_ERR) { flag = TTY_FRAME; } if (!uart_handle_sysrq_char(port, c)) tty_insert_flip_char(tty, c, flag); } tty_flip_buffer_push(tty); }
static unsigned int msm_tx_empty(struct uart_port *port) { unsigned int ret; struct msm_port *msm_port = UART_TO_MSM(port); clk_enable(msm_port->clk); ret = (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; clk_disable(msm_port->clk); return ret; }
static void msm_console_putchar(struct uart_port *port, int c) { struct msm_port *msm_port = UART_TO_MSM(port); if (msm_port->is_uartdm) reset_dm_count(port); while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) ; msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); }
void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned int mr; mr = msm_read(port, UART_MR1); if (!(mctrl & TIOCM_RTS)) { mr &= ~UART_MR1_RX_RDY_CTL; msm_write(port, mr, UART_MR1); msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); } else { mr |= UART_MR1_RX_RDY_CTL; msm_write(port, mr, UART_MR1); } }
static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned int mr; struct msm_port *msm_port = UART_TO_MSM(port); clk_enable(msm_port->clk); mr = msm_read(port, UART_MR1); if (!(mctrl & TIOCM_RTS)) { mr &= ~UART_MR1_RX_RDY_CTL; msm_write(port, mr, UART_MR1); msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); } else { mr |= UART_MR1_RX_RDY_CTL; msm_write(port, mr, UART_MR1); } clk_disable(msm_port->clk); }
static void handle_tx(struct uart_port *port) { struct circ_buf *xmit = &port->info->xmit; struct msm_port *msm_port = UART_TO_MSM(port); int sent_tx; if (port->x_char) { msm_write(port, port->x_char, UART_TF); port->icount.tx++; port->x_char = 0; } while (msm_read(port, UART_SR) & UART_SR_TX_READY) { if (uart_circ_empty(xmit)) { /* disable tx interrupts */ msm_port->imr &= ~UART_IMR_TXLEV; msm_write(port, msm_port->imr, UART_IMR); break; } msm_write(port, xmit->buf[xmit->tail], UART_TF); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; sent_tx = 1; } #ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL if (sent_tx && msm_port->clk_state == MSM_CLK_REQUEST_OFF) /* new TX - restart the timer */ if (hrtimer_try_to_cancel(&msm_port->clk_off_timer) == 1) hrtimer_start(&msm_port->clk_off_timer, msm_port->clk_off_delay, HRTIMER_MODE_REL); #endif if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); }
static inline void debug_flush(void) { while (!(msm_read(UART_SR) & UART_SR_TX_EMPTY)) ; }
static inline void debug_putc(unsigned int c) { while (!(msm_read(UART_SR) & UART_SR_TX_READY)) ; msm_write(c, UART_TF); }
static int msm_startup(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); unsigned int data, rfr_level; int ret; snprintf(msm_port->name, sizeof(msm_port->name), "msm_serial%d", port->line); ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, msm_port->name, port); if (unlikely(ret)) return ret; #ifndef CONFIG_PM_RUNTIME msm_init_clock(port); #endif pm_runtime_get_sync(port->dev); if (likely(port->fifosize > 12)) rfr_level = port->fifosize - 12; else rfr_level = port->fifosize; /* set automatic RFR level */ data = msm_read(port, UART_MR1); data &= ~UART_MR1_AUTO_RFR_LEVEL1; data &= ~UART_MR1_AUTO_RFR_LEVEL0; data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; msm_write(port, data, UART_MR1); /* make sure that RXSTALE count is non-zero */ data = msm_read(port, UART_IPR); if (unlikely(!data)) { data |= UART_IPR_RXSTALE_LAST; data |= UART_IPR_STALE_LSB; msm_write(port, data, UART_IPR); } msm_reset(port); msm_write(port, 0x05, UART_CR); /* enable TX & RX */ /* turn on RX and CTS interrupts */ msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | UART_IMR_CURRENT_CTS; msm_write(port, msm_port->imr, UART_IMR); #ifdef CONFIG_SERIAL_MSM_RX_WAKEUP if (use_low_power_wakeup(msm_port)) { ret = set_irq_wake(msm_port->wakeup.irq, 1); if (unlikely(ret)) return ret; ret = request_irq(msm_port->wakeup.irq, msm_rx_irq, IRQF_TRIGGER_FALLING, "msm_serial_wakeup", msm_port); if (unlikely(ret)) return ret; disable_irq(msm_port->wakeup.irq); } #endif return 0; }
static int msm_startup(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); unsigned int data, rfr_level; int ret; snprintf(msm_port->name, sizeof(msm_port->name), "msm_serial%d", port->line); ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, msm_port->name, port); if (unlikely(ret)) return ret; msm_init_clock(port); if (likely(port->fifosize > 12)) rfr_level = port->fifosize - 12; else rfr_level = port->fifosize; /* set automatic RFR level */ data = msm_read(port, UART_MR1); data &= ~UART_MR1_AUTO_RFR_LEVEL1; data &= ~UART_MR1_AUTO_RFR_LEVEL0; data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; msm_write(port, data, UART_MR1); /* make sure that RXSTALE count is non-zero */ data = msm_read(port, UART_IPR); if (unlikely(!data)) { data |= UART_IPR_RXSTALE_LAST; data |= UART_IPR_STALE_LSB; msm_write(port, data, UART_IPR); } data = 0; if (!port->cons || (port->cons && !(port->cons->flags & CON_ENABLED))) { msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); msm_reset(port); data = UART_CR_TX_ENABLE; } data |= UART_CR_RX_ENABLE; msm_write(port, data, UART_CR); /* enable TX & RX */ /* Make sure IPR is not 0 to start with*/ if (msm_port->is_uartdm) msm_write(port, UART_IPR_STALE_LSB, UART_IPR); /* turn on RX and CTS interrupts */ msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | UART_IMR_CURRENT_CTS; if (msm_port->is_uartdm) { msm_write(port, 0xFFFFFF, UARTDM_DMRX); msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); } msm_write(port, msm_port->imr, UART_IMR); return 0; }
static void msm_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned long flags; unsigned int baud, mr; struct msm_port *msm_port = UART_TO_MSM(port); spin_lock_irqsave(&port->lock, flags); clk_enable(msm_port->clk); /* calculate and set baud rate */ baud = uart_get_baud_rate(port, termios, old, 300, 115200); msm_set_baud_rate(port, baud); /* calculate parity */ mr = msm_read(port, UART_MR2); mr &= ~UART_MR2_PARITY_MODE; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) mr |= UART_MR2_PARITY_MODE_ODD; else if (termios->c_cflag & CMSPAR) mr |= UART_MR2_PARITY_MODE_SPACE; else mr |= UART_MR2_PARITY_MODE_EVEN; } /* calculate bits per char */ mr &= ~UART_MR2_BITS_PER_CHAR; switch (termios->c_cflag & CSIZE) { case CS5: mr |= UART_MR2_BITS_PER_CHAR_5; break; case CS6: mr |= UART_MR2_BITS_PER_CHAR_6; break; case CS7: mr |= UART_MR2_BITS_PER_CHAR_7; break; case CS8: default: mr |= UART_MR2_BITS_PER_CHAR_8; break; } /* calculate stop bits */ mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO); if (termios->c_cflag & CSTOPB) mr |= UART_MR2_STOP_BIT_LEN_TWO; else mr |= UART_MR2_STOP_BIT_LEN_ONE; /* set parity, bits per char, and stop bit */ msm_write(port, mr, UART_MR2); /* calculate and set hardware flow control */ mr = msm_read(port, UART_MR1); mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL); if (termios->c_cflag & CRTSCTS) { mr |= UART_MR1_CTS_CTL; mr |= UART_MR1_RX_RDY_CTL; } msm_write(port, mr, UART_MR1); /* Configure status bits to ignore based on termio flags. */ port->read_status_mask = 0; if (termios->c_iflag & INPCK) port->read_status_mask |= UART_SR_PAR_FRAME_ERR; if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= UART_SR_RX_BREAK; uart_update_timeout(port, termios->c_cflag, baud); clk_disable(msm_port->clk); spin_unlock_irqrestore(&port->lock, flags); }
static void msm_console_putchar(struct uart_port *port, int c) { while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) ; msm_write(port, c, UART_TF); }
static inline void wait_for_xmitr(struct uart_port *port, int bits) { if (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) while ((msm_read(port, UART_ISR) & bits) != bits) cpu_relax(); }