static int msm_hsl_loopback_enable_set(void *data, u64 val) { struct msm_hsl_port *msm_hsl_port = data; struct uart_port *port = &(msm_hsl_port->uart); unsigned int vid; unsigned long flags; int ret = 0; ret = clk_set_rate(msm_hsl_port->clk, 7372800); if (!ret) clk_en(port, 1); else { E("%s(): Error: Setting the clock rate\n", __func__); return -EINVAL; } vid = msm_hsl_port->ver_id; if (val) { spin_lock_irqsave(&port->lock, flags); ret = msm_hsl_read(port, regmap[vid][UARTDM_MR2]); ret |= UARTDM_MR2_LOOP_MODE_BMSK; msm_hsl_write(port, ret, regmap[vid][UARTDM_MR2]); spin_unlock_irqrestore(&port->lock, flags); E("%s(): irda loopback enabled for line(%d)\n", __func__, port->line); } else { spin_lock_irqsave(&port->lock, flags); ret = msm_hsl_read(port, regmap[vid][UARTDM_MR2]); ret &= ~UARTDM_MR2_LOOP_MODE_BMSK; msm_hsl_write(port, ret, regmap[vid][UARTDM_MR2]); spin_unlock_irqrestore(&port->lock, flags); } clk_en(port, 0); return 0; }
static void msm_hsl_set_mctrl_irda(struct uart_port *port, unsigned int mctrl) { unsigned int vid = UART_TO_MSM(port)->ver_id; unsigned int mr; unsigned int loop_mode; mr = msm_hsl_read(port, regmap[vid][UARTDM_MR1]); if (!(mctrl & TIOCM_RTS)) { mr &= ~UARTDM_MR1_RX_RDY_CTL_BMSK; msm_hsl_write(port, mr, regmap[vid][UARTDM_MR1]); msm_hsl_write(port, RFR_HIGH, regmap[vid][UARTDM_CR]); } else { mr |= UARTDM_MR1_RX_RDY_CTL_BMSK; msm_hsl_write(port, mr, regmap[vid][UARTDM_MR1]); } loop_mode = TIOCM_LOOP & mctrl; if (loop_mode) { mr = msm_hsl_read(port, regmap[vid][UARTDM_MR2]); mr |= UARTDM_MR2_LOOP_MODE_BMSK; msm_hsl_write(port, mr, regmap[vid][UARTDM_MR2]); /* Reset TX */ msm_hsl_reset(port); /* Turn on Uart Receiver & Transmitter*/ msm_hsl_write(port, UARTDM_CR_RX_EN_BMSK | UARTDM_CR_TX_EN_BMSK, regmap[vid][UARTDM_CR]); } }
static int msm_hsl_loopback_enable_set(void *data, u64 val) { struct msm_hsl_port *msm_hsl_port = data; struct uart_port *port = &(msm_hsl_port->uart); unsigned long flags; int ret = 0; ret = clk_set_rate(msm_hsl_port->clk, 7372800); if (!ret) clk_en(port, 1); else { pr_err("%s(): Error: Setting the clock rate\n", __func__); return -EINVAL; } if (val) { spin_lock_irqsave(&port->lock, flags); ret = msm_hsl_read(port, UARTDM_MR2_ADDR); ret |= UARTDM_MR2_LOOP_MODE_BMSK; msm_hsl_write(port, ret, UARTDM_MR2_ADDR); spin_unlock_irqrestore(&port->lock, flags); } else { spin_lock_irqsave(&port->lock, flags); ret = msm_hsl_read(port, UARTDM_MR2_ADDR); ret &= ~UARTDM_MR2_LOOP_MODE_BMSK; msm_hsl_write(port, ret, UARTDM_MR2_ADDR); spin_unlock_irqrestore(&port->lock, flags); } clk_en(port, 0); return 0; }
static void msm_hsl_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned int mr; unsigned int loop_mode; clk_en(port, 1); mr = msm_hsl_read(port, UARTDM_MR1_ADDR); if (!(mctrl & TIOCM_RTS)) { mr &= ~UARTDM_MR1_RX_RDY_CTL_BMSK; msm_hsl_write(port, mr, UARTDM_MR1_ADDR); msm_hsl_write(port, RFR_HIGH, UARTDM_CR_ADDR); } else { mr |= UARTDM_MR1_RX_RDY_CTL_BMSK; msm_hsl_write(port, mr, UARTDM_MR1_ADDR); } loop_mode = TIOCM_LOOP & mctrl; if (loop_mode) { mr = msm_hsl_read(port, UARTDM_MR2_ADDR); mr |= UARTDM_MR2_LOOP_MODE_BMSK; msm_hsl_write(port, mr, UARTDM_MR2_ADDR); /* Reset TX */ msm_hsl_reset(port); /* Turn on Uart Receiver & Transmitter*/ msm_hsl_write(port, UARTDM_CR_RX_EN_BMSK | UARTDM_CR_TX_EN_BMSK, UARTDM_CR_ADDR); } clk_en(port, 0); }
/* * Wait for transmitter & holding register to empty * Derived from wait_for_xmitr in 8250 serial driver by Russell King */ void wait_for_xmitr(struct uart_port *port, int bits) { if (!(msm_hsl_read(port, UARTDM_SR_ADDR) & UARTDM_SR_TXEMT_BMSK)) { while ((msm_hsl_read(port, UARTDM_ISR_ADDR) & bits) != bits) { udelay(1); touch_nmi_watchdog(); cpu_relax(); } msm_hsl_write(port, CLEAR_TX_READY, UARTDM_CR_ADDR); } }
static void msm_hsl_console_putchars(struct uart_port *port, int num, const char *s) { int word; int i; if (num == 0) return; wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK); msm_hsl_write(port, num, UARTDM_NCF_TX_ADDR); for (i = 0; i < num; i += 4) { word = 0; switch (num - i) { default: word |= s[i + 3] << 24; /* deliberate fall-through */ case 3: word |= s[i + 2] << 16; case 2: word |= s[i + 1] << 8; case 1: word |= s[i]; } while (!(msm_hsl_read(port, UARTDM_SR_ADDR) & UARTDM_SR_TXRDY_BMSK)) { udelay(1); touch_nmi_watchdog(); } msm_hsl_write(port, word, UARTDM_TF_ADDR); } }
/* * Wait for transmitter & holding register to empty * Derived from wait_for_xmitr in 8250 serial driver by Russell King */ void wait_for_xmitr(struct uart_port *port, int bits) { unsigned int vid = UART_TO_MSM(port)->ver_id; if (!(msm_hsl_read(port, regmap[vid][UARTDM_SR]) & UARTDM_SR_TXEMT_BMSK)) { while ((msm_hsl_read(port, regmap[vid][UARTDM_ISR]) & bits) != bits) { udelay(1); touch_nmi_watchdog(); cpu_relax(); } msm_hsl_write(port, CLEAR_TX_READY, regmap[vid][UARTDM_CR]); } D("%s ():port->line %d, ir\n", __func__, port->line); }
static int msm_hsl_startup_cir(struct uart_port *port) { struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); unsigned int data, rfr_level; unsigned int vid; int ret; unsigned long flags; snprintf(msm_hsl_port->name, sizeof(msm_hsl_port->name), "msm_serial_hsl%d", port->line); D("%s () :port->line %d, ir\n", __func__, port->line); if (!(is_console(port)) || (!port->cons) || (port->cons && (!(port->cons->flags & CON_ENABLED)))) { if (msm_serial_hsl_has_gsbi(port)) { D("%s () serial_hsl_has_gsbi:port->line %d, ir\n", __func__, port->line); if ((ioread32(msm_hsl_port->mapped_gsbi + GSBI_CONTROL_ADDR) & GSBI_PROTOCOL_I2C_UART) != GSBI_PROTOCOL_I2C_UART){ D("%s () iowrite32i:port->line %d, ir\n", __func__, port->line); iowrite32(GSBI_PROTOCOL_I2C_UART, msm_hsl_port->mapped_gsbi + GSBI_CONTROL_ADDR); } } } #ifndef CONFIG_PM_RUNTIME msm_hsl_init_clock(port); #endif pm_runtime_get_sync(port->dev); if (likely(port->fifosize > 48)) rfr_level = port->fifosize - 16; else rfr_level = port->fifosize; rfr_level = (rfr_level / 4); spin_lock_irqsave(&port->lock, flags); vid = msm_hsl_port->ver_id; data = msm_hsl_read(port, regmap[vid][UARTDM_MR1]); data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK; data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK; data |= UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2); data |= UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level; msm_hsl_write(port, data, regmap[vid][UARTDM_MR1]); spin_unlock_irqrestore(&port->lock, flags); ret = request_irq(port->irq, msm_hsl_irq, IRQF_TRIGGER_HIGH, msm_hsl_port->name, port); if (unlikely(ret)) { printk(KERN_ERR "%s: failed to request_irq\n", __func__); return ret; } return 0; }
static irqreturn_t msm_hsl_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); unsigned int vid; unsigned int misr; unsigned long flags; spin_lock_irqsave(&port->lock, flags); vid = msm_hsl_port->ver_id; misr = msm_hsl_read(port, regmap[vid][UARTDM_MISR]); msm_hsl_write(port, 0, regmap[vid][UARTDM_IMR]); if (misr & (UARTDM_ISR_RXSTALE_BMSK | UARTDM_ISR_RXLEV_BMSK)) { handle_rx(port, misr); if (misr & (UARTDM_ISR_RXSTALE_BMSK)) msm_hsl_write(port, RESET_STALE_INT, regmap[vid][UARTDM_CR]); msm_hsl_write(port, 6500, regmap[vid][UARTDM_DMRX]); msm_hsl_write(port, STALE_EVENT_ENABLE, regmap[vid][UARTDM_CR]); } if (misr & UARTDM_ISR_TXLEV_BMSK) handle_tx(port); if (misr & UARTDM_ISR_DELTA_CTS_BMSK) handle_delta_cts(port); msm_hsl_write(port, msm_hsl_port->imr, regmap[vid][UARTDM_IMR]); spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; }
static irqreturn_t msm_hsl_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); unsigned int misr; unsigned long flags; spin_lock_irqsave(&port->lock, flags); clk_en(port, 1); misr = msm_hsl_read(port, UARTDM_MISR_ADDR); msm_hsl_write(port, 0, UARTDM_IMR_ADDR); /* disable interrupt */ if (misr & (UARTDM_ISR_RXSTALE_BMSK | UARTDM_ISR_RXLEV_BMSK)) { handle_rx(port, misr); if (misr & (UARTDM_ISR_RXSTALE_BMSK)) msm_hsl_write(port, RESET_STALE_INT, UARTDM_CR_ADDR); msm_hsl_write(port, 6500, UARTDM_DMRX_ADDR); msm_hsl_write(port, STALE_EVENT_ENABLE, UARTDM_CR_ADDR); } if (misr & UARTDM_ISR_TXLEV_BMSK) handle_tx(port); if (misr & UARTDM_ISR_DELTA_CTS_BMSK) handle_delta_cts(port); /* restore interrupt */ msm_hsl_write(port, msm_hsl_port->imr, UARTDM_IMR_ADDR); clk_en(port, 0); spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; }
static unsigned int msm_hsl_tx_empty_irda(struct uart_port *port) { unsigned int ret; unsigned int vid = UART_TO_MSM(port)->ver_id; ret = (msm_hsl_read(port, regmap[vid][UARTDM_SR]) & UARTDM_SR_TXEMT_BMSK) ? TIOCSER_TEMT : 0; return ret; }
static unsigned int msm_hsl_tx_empty(struct uart_port *port) { unsigned int ret; clk_en(port, 1); ret = (msm_hsl_read(port, UARTDM_SR_ADDR) & UARTDM_SR_TXEMT_BMSK) ? TIOCSER_TEMT : 0; clk_en(port, 0); return ret; }
static unsigned int msm_hsl_tx_empty_cir(struct uart_port *port) { unsigned int vid = UART_TO_MSM(port)->ver_id; unsigned int ret; pr_info("%s ():port->line %d, ir\n", __func__, port->line); clk_en(port, 1); ret = (msm_hsl_read(port, regmap[vid][UARTDM_SR]) & UARTDM_SR_TXEMT_BMSK) ? TIOCSER_TEMT : 0; clk_en(port, 0); return ret; }
static void msm_hsl_console_putchar(struct uart_port *port, int ch) { wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK); msm_hsl_write(port, 1, UARTDM_NCF_TX_ADDR); while (!(msm_hsl_read(port, UARTDM_SR_ADDR) & UARTDM_SR_TXRDY_BMSK)) { udelay(1); touch_nmi_watchdog(); } msm_hsl_write(port, ch, UARTDM_TF_ADDR); }
static void msm_hsl_set_mctrl_cir(struct uart_port *port, unsigned int mctrl) { unsigned int vid = UART_TO_MSM(port)->ver_id; unsigned int mr; unsigned int loop_mode; clk_en(port, 1); mr = msm_hsl_read(port, regmap[vid][UARTDM_MR1]); if (!(mctrl & TIOCM_RTS)) { pr_info("%s ()mctrl & TIOCM_RTS:port->line %d, ir\n", __func__, port->line); mr &= ~UARTDM_MR1_RX_RDY_CTL_BMSK; msm_hsl_write(port, mr, regmap[vid][UARTDM_MR1]); msm_hsl_write(port, RFR_HIGH, regmap[vid][UARTDM_CR]); } else { mr |= UARTDM_MR1_RX_RDY_CTL_BMSK; msm_hsl_write(port, mr, regmap[vid][UARTDM_MR1]); pr_info("%s () TIOCM_RTS:port->line %d, ir\n", __func__, port->line); } loop_mode = TIOCM_LOOP & mctrl; if (loop_mode) { pr_info("%s ()loop_mode:port->line %d, ir\n", __func__, port->line); mr = msm_hsl_read(port, regmap[vid][UARTDM_MR2]); mr |= UARTDM_MR2_LOOP_MODE_BMSK; msm_hsl_write(port, mr, regmap[vid][UARTDM_MR2]); msm_hsl_reset(port); msm_hsl_write(port, UARTDM_CR_RX_EN_BMSK | UARTDM_CR_TX_EN_BMSK, regmap[vid][UARTDM_CR]); } clk_en(port, 0); }
static void msm_hsl_console_putchar(struct uart_port *port, int ch) { unsigned int vid = UART_TO_MSM(port)->ver_id; wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK); msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]); #if 1 while (!(msm_hsl_read(port, regmap[vid][UARTDM_SR]) & UARTDM_SR_TXRDY_BMSK)) { udelay(1); touch_nmi_watchdog(); } #else /* * Dummy read to add 1 AHB clock delay to fix UART hardware bug. * Bug: Delay required on TX-transfer-init. after writing to * NO_CHARS_FOR_TX register. */ msm_hsl_read(port, regmap[vid][UARTDM_SR]); #endif msm_hsl_write(port, ch, regmap[vid][UARTDM_TF]); D("%s ():port->line %d, ir\n", __func__, port->line); }
static void msm_hsl_console_putchar(struct uart_port *port, int ch) { unsigned int vid = UART_TO_MSM(port)->ver_id; wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK); msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]); while (!(msm_hsl_read(port, regmap[vid][UARTDM_SR]) & UARTDM_SR_TXRDY_BMSK)) { udelay(1); touch_nmi_watchdog(); } msm_hsl_write(port, ch, regmap[vid][UARTDM_TF]); D("%s ():port->line %d, ir\n", __func__, port->line); }
static int msm_hsl_loopback_enable_get(void *data, u64 *val) { struct msm_hsl_port *msm_hsl_port = data; struct uart_port *port = &(msm_hsl_port->uart); unsigned long flags; int ret = 0; ret = clk_set_rate(msm_hsl_port->clk, 7372800); if (!ret) clk_en(port, 1); else { pr_err("%s(): Error setting clk rate\n", __func__); return -EINVAL; } spin_lock_irqsave(&port->lock, flags); ret = msm_hsl_read(port, UARTDM_MR2_ADDR); spin_unlock_irqrestore(&port->lock, flags); clk_en(port, 0); *val = (ret & UARTDM_MR2_LOOP_MODE_BMSK) ? 1 : 0; return 0; }
static int msm_hsl_startup(struct uart_port *port) { struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); struct platform_device *pdev = to_platform_device(port->dev); struct msm_serial_hslite_platform_data *pdata = pdev->dev.platform_data; unsigned int data, rfr_level; int ret; unsigned long flags; snprintf(msm_hsl_port->name, sizeof(msm_hsl_port->name), "msm_serial_hsl%d", port->line); if (!(is_console(port)) || (!port->cons) || (port->cons && (!(port->cons->flags & CON_ENABLED)))) { if (msm_serial_hsl_has_gsbi()) if ((ioread32(msm_hsl_port->mapped_gsbi + GSBI_CONTROL_ADDR) & GSBI_PROTOCOL_I2C_UART) != GSBI_PROTOCOL_I2C_UART) iowrite32(GSBI_PROTOCOL_I2C_UART, msm_hsl_port->mapped_gsbi + GSBI_CONTROL_ADDR); if (pdata && pdata->config_gpio) { ret = gpio_request(pdata->uart_tx_gpio, "UART_TX_GPIO"); if (unlikely(ret)) { pr_err("%s: gpio request failed for:%d\n", __func__, pdata->uart_tx_gpio); return ret; } ret = gpio_request(pdata->uart_rx_gpio, "UART_RX_GPIO"); if (unlikely(ret)) { pr_err("%s: gpio request failed for:%d\n", __func__, pdata->uart_rx_gpio); gpio_free(pdata->uart_tx_gpio); return ret; } } } #ifndef CONFIG_PM_RUNTIME msm_hsl_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; spin_lock_irqsave(&port->lock, flags); /* set automatic RFR level */ data = msm_hsl_read(port, UARTDM_MR1_ADDR); data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK; data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK; data |= UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2); data |= UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level; msm_hsl_write(port, data, UARTDM_MR1_ADDR); /* Make sure IPR is not 0 to start with*/ msm_hsl_write(port, UARTDM_IPR_STALE_LSB_BMSK, UARTDM_IPR_ADDR); data = 0; if (!(is_console(port)) || (!port->cons) || (port->cons && (!(port->cons->flags & CON_ENABLED)))) { msm_hsl_write(port, CR_PROTECTION_EN, UARTDM_CR_ADDR); msm_hsl_write(port, UARTDM_MR2_BITS_PER_CHAR_8 | STOP_BIT_ONE, UARTDM_MR2_ADDR); /* 8N1 */ msm_hsl_reset(port); data = UARTDM_CR_TX_EN_BMSK; } data |= UARTDM_CR_RX_EN_BMSK; msm_hsl_write(port, data, UARTDM_CR_ADDR); /* enable TX & RX */ /* turn on RX and CTS interrupts */ msm_hsl_port->imr = UARTDM_ISR_RXSTALE_BMSK | UARTDM_ISR_DELTA_CTS_BMSK | UARTDM_ISR_RXLEV_BMSK; spin_unlock_irqrestore(&port->lock, flags); ret = request_irq(port->irq, msm_hsl_irq, IRQF_TRIGGER_HIGH, msm_hsl_port->name, port); if (unlikely(ret)) { printk(KERN_ERR "%s: failed to request_irq\n", __func__); return ret; } spin_lock_irqsave(&port->lock, flags); msm_hsl_write(port, RESET_STALE_INT, UARTDM_CR_ADDR); msm_hsl_write(port, 6500, UARTDM_DMRX_ADDR); msm_hsl_write(port, STALE_EVENT_ENABLE, UARTDM_CR_ADDR); msm_hsl_write(port, msm_hsl_port->imr, UARTDM_IMR_ADDR); spin_unlock_irqrestore(&port->lock, flags); return 0; }
static void handle_rx(struct uart_port *port, unsigned int misr) { struct tty_struct *tty = port->state->port.tty; unsigned int vid; unsigned int sr; int count = 0; struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); vid = msm_hsl_port->ver_id; if ((msm_hsl_read(port, regmap[vid][UARTDM_SR]) & UARTDM_SR_OVERRUN_BMSK)) { port->icount.overrun++; tty_insert_flip_char(tty, 0, TTY_OVERRUN); msm_hsl_write(port, RESET_ERROR_STATUS, regmap[vid][UARTDM_CR]); } if (misr & UARTDM_ISR_RXSTALE_BMSK) { count = msm_hsl_read(port, regmap[vid][UARTDM_RX_TOTAL_SNAP]) - msm_hsl_port->old_snap_state; msm_hsl_port->old_snap_state = 0; } else { count = 4 * (msm_hsl_read(port, regmap[vid][UARTDM_RFWR])); msm_hsl_port->old_snap_state += count; } while (count > 0) { unsigned int c; char flag = TTY_NORMAL; sr = msm_hsl_read(port, regmap[vid][UARTDM_SR]); if ((sr & UARTDM_SR_RXRDY_BMSK) == 0) { msm_hsl_port->old_snap_state -= count; break; } c = msm_hsl_read(port, regmap[vid][UARTDM_RF]); if (sr & UARTDM_SR_RX_BREAK_BMSK) { port->icount.brk++; if (uart_handle_break(port)) continue; } else if (sr & UARTDM_SR_PAR_FRAME_BMSK) { port->icount.frame++; } else { port->icount.rx++; } sr &= port->read_status_mask; if (sr & UARTDM_SR_RX_BREAK_BMSK) flag = TTY_BREAK; else if (sr & UARTDM_SR_PAR_FRAME_BMSK) flag = TTY_FRAME; tty_insert_flip_string(tty, (char *) &c, (count > 4) ? 4 : count); count -= 4; } tty_flip_buffer_push(tty); }
static void handle_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; int sent_tx; int tx_count; int x; unsigned int tf_pointer = 0; tx_count = uart_circ_chars_pending(xmit); if (tx_count > (UART_XMIT_SIZE - xmit->tail)) tx_count = UART_XMIT_SIZE - xmit->tail; if (tx_count >= port->fifosize) tx_count = port->fifosize; /* Handle x_char */ if (port->x_char) { wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK); msm_hsl_write(port, tx_count + 1, UARTDM_NCF_TX_ADDR); msm_hsl_write(port, port->x_char, UARTDM_TF_ADDR); port->icount.tx++; port->x_char = 0; } else if (tx_count) { wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK); msm_hsl_write(port, tx_count, UARTDM_NCF_TX_ADDR); } if (!tx_count) { msm_hsl_stop_tx(port); return; } #ifdef FELICA_DEBUG if (port->line == 3) pr_info("%s: count=%d\n", __func__, tx_count); #endif while (tf_pointer < tx_count) { if (unlikely(!(msm_hsl_read(port, UARTDM_SR_ADDR) & UARTDM_SR_TXRDY_BMSK))) continue; switch (tx_count - tf_pointer) { case 1: { x = xmit->buf[xmit->tail]; port->icount.tx++; break; } case 2: { x = xmit->buf[xmit->tail] | xmit->buf[xmit->tail+1] << 8; port->icount.tx += 2; break; } case 3: { x = xmit->buf[xmit->tail] | xmit->buf[xmit->tail+1] << 8 | xmit->buf[xmit->tail + 2] << 16; port->icount.tx += 3; break; } default: { x = *((int *)&(xmit->buf[xmit->tail])); port->icount.tx += 4; break; } } #ifdef FELICA_DEBUG if (port->line == 3) pr_info("%s: 0x%08X\n", __func__, x); #endif msm_hsl_write(port, x, UARTDM_TF_ADDR); xmit->tail = ((tx_count - tf_pointer < 4) ? (tx_count - tf_pointer + xmit->tail) : (xmit->tail + 4)) & (UART_XMIT_SIZE - 1); tf_pointer += 4; sent_tx = 1; } if (uart_circ_empty(xmit)) msm_hsl_stop_tx(port); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); }
static void handle_rx(struct uart_port *port, unsigned int misr) { struct tty_struct *tty = port->state->port.tty; unsigned int sr; int count = 0; struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); #ifdef FELICA_DEBUG if (port->line == 3) pr_info(">>> %s\n", __func__); #endif /* * 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_hsl_read(port, UARTDM_SR_ADDR) & UARTDM_SR_OVERRUN_BMSK)) { #ifdef FELICA_DEBUG if (port->line == 3) pr_info("%s: UARTDM_SR_OVERRUN_BMSK\n", __func__); #endif port->icount.overrun++; tty_insert_flip_char(tty, 0, TTY_OVERRUN); msm_hsl_write(port, RESET_ERROR_STATUS, UARTDM_CR_ADDR); } if (misr & UARTDM_ISR_RXSTALE_BMSK) { #ifdef FELICA_DEBUG if (port->line == 3) { pr_info("%s: UARTDM_ISR_RXSTALE_BMSK\n", __func__); pr_info("%s: rx_total_snap = %u\n", __func__, msm_hsl_read(port, UARTDM_RX_TOTAL_SNAP_ADDR)); pr_info("%s: old_snap_state = %u\n", __func__, msm_hsl_port->old_snap_state); } #endif count = msm_hsl_read(port, UARTDM_RX_TOTAL_SNAP_ADDR) - msm_hsl_port->old_snap_state; msm_hsl_port->old_snap_state = 0; } else { #ifdef FELICA_DEBUG if (port->line == 3) { pr_info("%s: else...\n", __func__); pr_info("%s: rfwr = %u\n", __func__, msm_hsl_read(port, UARTDM_RFWR_ADDR)); pr_info("%s: old_snap_state = %u\n", __func__, msm_hsl_port->old_snap_state); } #endif count = 4 * (msm_hsl_read(port, UARTDM_RFWR_ADDR)); msm_hsl_port->old_snap_state += count; #ifdef FELICA_DEBUG if (port->line == 3) { pr_info("%s: old_snap_state = %u\n", __func__, msm_hsl_port->old_snap_state); } #endif } #ifdef FELICA_DEBUG if (port->line == 3) pr_info("%s: count=%d\n", __func__, count); #endif /* and now the main RX loop */ while (count > 0) { unsigned int c; char flag = TTY_NORMAL; sr = msm_hsl_read(port, UARTDM_SR_ADDR); if ((sr & UARTDM_SR_RXRDY_BMSK) == 0) { #ifdef FELICA_DEBUG if (port->line == 3) { pr_info("%s: UARTDM_SR_RXRDY_BMSK\n", __func__); pr_info("%s: old_snap_state = %u, count = %d\n", __func__, msm_hsl_port->old_snap_state, count); } #endif #ifdef CONFIG_LGE_FELICA if (msm_hsl_port->old_snap_state < count) msm_hsl_port->old_snap_state = 0; else #endif msm_hsl_port->old_snap_state -= count; break; } c = msm_hsl_read(port, UARTDM_RF_ADDR); #ifdef FELICA_DEBUG if (port->line == 3) pr_info("%s: [%d] 0x%08X\n", __func__, (count > 4) ? 4 : count, c); #endif if (sr & UARTDM_SR_RX_BREAK_BMSK) { #ifdef FELICA_DEBUG if (port->line == 3) pr_info("%s: UARTDM_SR_RX_BREAK_BMSK\n", __func__); #endif port->icount.brk++; if (uart_handle_break(port)) { #ifdef FELICA_DEBUG if (port->line == 3) pr_info("%s: uart_handle_break\n", __func__); #endif continue; } } else if (sr & UARTDM_SR_PAR_FRAME_BMSK) { #ifdef FELICA_DEBUG if (port->line == 3) pr_info("%s: UARTDM_SR_PAR_FRAME_BMSK\n", __func__); #endif port->icount.frame++; } else { #ifdef FELICA_DEBUG if (port->line == 3) pr_info("%s: RX\n", __func__); #endif port->icount.rx++; } /* Mask conditions we're ignorning. */ sr &= port->read_status_mask; if (sr & UARTDM_SR_RX_BREAK_BMSK) flag = TTY_BREAK; else if (sr & UARTDM_SR_PAR_FRAME_BMSK) flag = TTY_FRAME; /* TODO: handle sysrq */ /* if (!uart_handle_sysrq_char(port, c)) */ tty_insert_flip_string(tty, (char *) &c, (count > 4) ? 4 : count); count -= 4; } tty_flip_buffer_push(tty); #ifdef FELICA_DEBUG if (port->line == 3) pr_info("<<< %s\n", __func__); #endif }
static void msm_hsl_set_termios_cir(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned long flags; unsigned int baud, mr; unsigned int vid; spin_lock_irqsave(&port->lock, flags); baud = uart_get_baud_rate(port, termios, old, 300, 460800); msm_hsl_set_baud_rate(port, baud); vid = UART_TO_MSM(port)->ver_id; mr = msm_hsl_read(port, regmap[vid][UARTDM_MR2]); mr &= ~UARTDM_MR2_PARITY_MODE_BMSK; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) mr |= ODD_PARITY; else if (termios->c_cflag & CMSPAR) mr |= SPACE_PARITY; else mr |= EVEN_PARITY; } mr &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK; switch (termios->c_cflag & CSIZE) { case CS5: mr |= FIVE_BPC; break; case CS6: mr |= SIX_BPC; break; case CS7: mr |= SEVEN_BPC; break; case CS8: default: mr |= EIGHT_BPC; break; } mr &= ~(STOP_BIT_ONE | STOP_BIT_TWO); if (termios->c_cflag & CSTOPB) mr |= STOP_BIT_TWO; else mr |= STOP_BIT_ONE; msm_hsl_write(port, mr, regmap[vid][UARTDM_MR2]); mr = msm_hsl_read(port, regmap[vid][UARTDM_MR1]); mr &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK); if (termios->c_cflag & CRTSCTS) { mr |= UARTDM_MR1_CTS_CTL_BMSK; mr |= UARTDM_MR1_RX_RDY_CTL_BMSK; } msm_hsl_write(port, mr, regmap[vid][UARTDM_MR1]); port->read_status_mask = 0; if (termios->c_iflag & INPCK) port->read_status_mask |= UARTDM_SR_PAR_FRAME_BMSK; if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= UARTDM_SR_RX_BREAK_BMSK; uart_update_timeout(port, termios->c_cflag, baud); spin_unlock_irqrestore(&port->lock, flags); D("%s: cir MR is 0x%x\n", __func__, mr); D("%s: cir baud is %d\n", __func__, baud); }
static void handle_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; int sent_tx; int tx_count; int x; unsigned int tf_pointer = 0; unsigned int vid; vid = UART_TO_MSM(port)->ver_id; tx_count = uart_circ_chars_pending(xmit); if (tx_count > (UART_XMIT_SIZE - xmit->tail)) tx_count = UART_XMIT_SIZE - xmit->tail; if (tx_count >= port->fifosize) tx_count = port->fifosize; /* Handle x_char */ if (port->x_char) { wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK); msm_hsl_write(port, tx_count + 1, regmap[vid][UARTDM_NCF_TX]); msm_hsl_write(port, port->x_char, regmap[vid][UARTDM_TF]); port->icount.tx++; port->x_char = 0; } else if (tx_count) { wait_for_xmitr(port, UARTDM_ISR_TX_READY_BMSK); msm_hsl_write(port, tx_count, regmap[vid][UARTDM_NCF_TX]); } if (!tx_count) { msm_hsl_stop_tx_irda(port); return; } while (tf_pointer < tx_count) { if (unlikely(!(msm_hsl_read(port, regmap[vid][UARTDM_SR]) & UARTDM_SR_TXRDY_BMSK))) continue; switch (tx_count - tf_pointer) { case 1: { x = xmit->buf[xmit->tail]; port->icount.tx++; break; } case 2: { x = xmit->buf[xmit->tail] | xmit->buf[xmit->tail+1] << 8; port->icount.tx += 2; break; } case 3: { x = xmit->buf[xmit->tail] | xmit->buf[xmit->tail+1] << 8 | xmit->buf[xmit->tail + 2] << 16; port->icount.tx += 3; break; } default: { x = *((int *)&(xmit->buf[xmit->tail])); port->icount.tx += 4; break; } } msm_hsl_write(port, x, regmap[vid][UARTDM_TF]); xmit->tail = ((tx_count - tf_pointer < 4) ? (tx_count - tf_pointer + xmit->tail) : (xmit->tail + 4)) & (UART_XMIT_SIZE - 1); tf_pointer += 4; sent_tx = 1; } if (uart_circ_empty(xmit)) msm_hsl_stop_tx_irda(port); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); }
static void msm_hsl_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned long flags; unsigned int baud, mr; spin_lock_irqsave(&port->lock, flags); clk_en(port, 1); /* calculate and set baud rate */ baud = uart_get_baud_rate(port, termios, old, 300, 115200); /* Workaround required for UART download feature. set_termios is getting called while opening port and while setting required baud rate using Ioctl. Adding delay allows this feature to work. Reason is still unknown. */ udelay(1000); msm_hsl_set_baud_rate(port, baud); /* calculate parity */ mr = msm_hsl_read(port, UARTDM_MR2_ADDR); mr &= ~UARTDM_MR2_PARITY_MODE_BMSK; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) mr |= ODD_PARITY; else if (termios->c_cflag & CMSPAR) mr |= SPACE_PARITY; else mr |= EVEN_PARITY; } /* calculate bits per char */ mr &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK; switch (termios->c_cflag & CSIZE) { case CS5: mr |= FIVE_BPC; break; case CS6: mr |= SIX_BPC; break; case CS7: mr |= SEVEN_BPC; break; case CS8: default: mr |= EIGHT_BPC; break; } /* calculate stop bits */ mr &= ~(STOP_BIT_ONE | STOP_BIT_TWO); if (termios->c_cflag & CSTOPB) mr |= STOP_BIT_TWO; else mr |= STOP_BIT_ONE; /* set parity, bits per char, and stop bit */ msm_hsl_write(port, mr, UARTDM_MR2_ADDR); /* calculate and set hardware flow control */ mr = msm_hsl_read(port, UARTDM_MR1_ADDR); mr &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK); if (termios->c_cflag & CRTSCTS) { mr |= UARTDM_MR1_CTS_CTL_BMSK; mr |= UARTDM_MR1_RX_RDY_CTL_BMSK; } msm_hsl_write(port, mr, UARTDM_MR1_ADDR); /* Configure status bits to ignore based on termio flags. */ port->read_status_mask = 0; if (termios->c_iflag & INPCK) port->read_status_mask |= UARTDM_SR_PAR_FRAME_BMSK; if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= UARTDM_SR_RX_BREAK_BMSK; uart_update_timeout(port, termios->c_cflag, baud); clk_en(port, 0); spin_unlock_irqrestore(&port->lock, flags); }
static int msm_hsl_startup(struct uart_port *port) { struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); unsigned int data, rfr_level; int ret; unsigned long flags; snprintf(msm_hsl_port->name, sizeof(msm_hsl_port->name), "msm_serial_hsl%d", port->line); #ifndef CONFIG_PM_RUNTIME msm_hsl_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; spin_lock_irqsave(&port->lock, flags); /* set automatic RFR level */ data = msm_hsl_read(port, UARTDM_MR1_ADDR); data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK; data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK; data |= UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2); data |= UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level; msm_hsl_write(port, data, UARTDM_MR1_ADDR); /* Make sure IPR is not 0 to start with*/ msm_hsl_write(port, UARTDM_IPR_STALE_LSB_BMSK, UARTDM_IPR_ADDR); data = 0; if (!(is_console(port)) || (!port->cons) || (port->cons && (!(port->cons->flags & CON_ENABLED)))) { msm_hsl_write(port, CR_PROTECTION_EN, UARTDM_CR_ADDR); msm_hsl_write(port, UARTDM_MR2_BITS_PER_CHAR_8 | STOP_BIT_ONE, UARTDM_MR2_ADDR); /* 8N1 */ msm_hsl_reset(port); data = UARTDM_CR_TX_EN_BMSK; } if(b_terminal_onoff == 0 && console_uart_port && (port == console_uart_port)){ msm_hsl_write(port, data, UARTDM_CR_ADDR); /* enable TX */ }else{ data |= UARTDM_CR_RX_EN_BMSK; msm_hsl_write(port, data, UARTDM_CR_ADDR); /* enable TX & RX */ } /* turn on RX and CTS interrupts */ msm_hsl_port->imr = UARTDM_ISR_RXSTALE_BMSK | UARTDM_ISR_DELTA_CTS_BMSK | UARTDM_ISR_RXLEV_BMSK; spin_unlock_irqrestore(&port->lock, flags); ret = request_irq(port->irq, msm_hsl_irq, IRQF_TRIGGER_HIGH, msm_hsl_port->name, port); if (unlikely(ret)) { printk(KERN_ERR "%s: failed to request_irq\n", __func__); return ret; } spin_lock_irqsave(&port->lock, flags); msm_hsl_write(port, RESET_STALE_INT, UARTDM_CR_ADDR); msm_hsl_write(port, 6500, UARTDM_DMRX_ADDR); msm_hsl_write(port, STALE_EVENT_ENABLE, UARTDM_CR_ADDR); msm_hsl_write(port, msm_hsl_port->imr, UARTDM_IMR_ADDR); spin_unlock_irqrestore(&port->lock, flags); return 0; }
static int msm_hsl_startup(struct uart_port *port) { struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); struct platform_device *pdev = to_platform_device(port->dev); const struct msm_serial_hslite_platform_data *pdata = pdev->dev.platform_data; unsigned int data, rfr_level; int ret; unsigned long flags; snprintf(msm_hsl_port->name, sizeof(msm_hsl_port->name), "msm_serial_hsl%d", port->line); if (!(is_console(port)) || (!port->cons) || (port->cons && (!(port->cons->flags & CON_ENABLED)))) { if (msm_serial_hsl_has_gsbi()) if ((ioread32(msm_hsl_port->mapped_gsbi + GSBI_CONTROL_ADDR) & GSBI_PROTOCOL_I2C_UART) != GSBI_PROTOCOL_I2C_UART) iowrite32(GSBI_PROTOCOL_I2C_UART, msm_hsl_port->mapped_gsbi + GSBI_CONTROL_ADDR); if (pdata && pdata->config_gpio) { ret = gpio_request(pdata->uart_tx_gpio, "UART_TX_GPIO"); if (unlikely(ret)) { pr_err("%s: gpio request failed for:%d\n", __func__, pdata->uart_tx_gpio); return ret; } ret = gpio_request(pdata->uart_rx_gpio, "UART_RX_GPIO"); if (unlikely(ret)) { pr_err("%s: gpio request failed for:%d\n", __func__, pdata->uart_rx_gpio); gpio_free(pdata->uart_tx_gpio); return ret; } } } #ifndef CONFIG_PM_RUNTIME msm_hsl_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; spin_lock_irqsave(&port->lock, flags); /* set automatic RFR level */ data = msm_hsl_read(port, UARTDM_MR1_ADDR); data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK; data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK; data |= UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2); data |= UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level; msm_hsl_write(port, data, UARTDM_MR1_ADDR); spin_unlock_irqrestore(&port->lock, flags); ret = request_irq(port->irq, msm_hsl_irq, IRQF_TRIGGER_HIGH, msm_hsl_port->name, port); if (unlikely(ret)) { printk(KERN_ERR "%s: failed to request_irq\n", __func__); return ret; } return 0; }
static void msm_hsl_set_termios_irda(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned long flags; unsigned int baud, mr; unsigned int vid; spin_lock_irqsave(&port->lock, flags); /* calculate and set baud rate */ baud = uart_get_baud_rate(port, termios, old, 300, 460800); msm_hsl_set_baud_rate(port, baud); vid = UART_TO_MSM(port)->ver_id; /* calculate parity */ mr = msm_hsl_read(port, regmap[vid][UARTDM_MR2]); mr &= ~UARTDM_MR2_PARITY_MODE_BMSK; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) mr |= ODD_PARITY; else if (termios->c_cflag & CMSPAR) mr |= SPACE_PARITY; else mr |= EVEN_PARITY; } /* calculate bits per char */ mr &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK; switch (termios->c_cflag & CSIZE) { case CS5: mr |= FIVE_BPC; break; case CS6: mr |= SIX_BPC; break; case CS7: mr |= SEVEN_BPC; break; case CS8: default: mr |= EIGHT_BPC; break; } /* calculate stop bits */ mr &= ~(STOP_BIT_ONE | STOP_BIT_TWO); if (termios->c_cflag & CSTOPB) mr |= STOP_BIT_TWO; else mr |= STOP_BIT_ONE; /* set parity, bits per char, and stop bit */ msm_hsl_write(port, mr, regmap[vid][UARTDM_MR2]); /* calculate and set hardware flow control */ mr = msm_hsl_read(port, regmap[vid][UARTDM_MR1]); mr &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK); if (termios->c_cflag & CRTSCTS) { mr |= UARTDM_MR1_CTS_CTL_BMSK; mr |= UARTDM_MR1_RX_RDY_CTL_BMSK; } msm_hsl_write(port, mr, regmap[vid][UARTDM_MR1]); /* Configure status bits to ignore based on termio flags. */ port->read_status_mask = 0; if (termios->c_iflag & INPCK) port->read_status_mask |= UARTDM_SR_PAR_FRAME_BMSK; if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= UARTDM_SR_RX_BREAK_BMSK; uart_update_timeout(port, termios->c_cflag, baud); spin_unlock_irqrestore(&port->lock, flags); D("%s: irda MR is 0x%x\n", __func__, mr); D("%s: irda baud is %d\n", __func__, baud); /* D("%s: irda parity is %d \n", __func__, (termios->c_cflag & PARENB)!=0?1:0); D("%s: irda csize is %d \n", __func__, (termios->c_cflag & CSIZE)==CS5 ? 5: (termios->c_cflag & CSIZE)==CS6 ? 6: (termios->c_cflag & CSIZE)==CS7 ? 7: (termios->c_cflag & CSIZE)==CS8 ? 8:(-1)); D("%s: irda stop is %d \n", __func__, (termios->c_cflag & CSTOPB)!=0?1:0); D("%s: irda hw-flow is %d \n", __func__, (termios->c_cflag & CRTSCTS)!=0?1:0); D("%s: irda INPCK is %d , BRKINT is %d , PARMRK is %d \n", __func__, (termios->c_iflag & INPCK)!=0?1:0, (termios->c_iflag & BRKINT)!=0?1:0, (termios->c_iflag & PARMRK)!=0?1:0); D("%s: irda xon is %d \n", __func__, (termios->c_iflag & IXON)!=0?1:0); D("%s: irda xoff is %d \n", __func__, (termios->c_iflag & IXOFF)!=0?1:0);*/ }
static void msm_hsl_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned long flags; unsigned int baud, mr; spin_lock_irqsave(&port->lock, flags); clk_en(port, 1); /* calculate and set baud rate */ /* [FELICA_S] [email protected] 20110419 */ /* change default baudrate for felica */ #ifdef CONFIG_LGE_FELICA if (port->line == 3) { termios->c_cflag |= B460800; baud = uart_get_baud_rate(port, termios, old, 300, 460800); msm_hsl_set_baud_rate(port, baud); } else { baud = uart_get_baud_rate(port, termios, old, 300, 115200); msm_hsl_set_baud_rate(port, baud); } #else baud = uart_get_baud_rate(port, termios, old, 300, 460800); msm_hsl_set_baud_rate(port, baud); #endif /* [FELICA_E] [email protected] 20110419 */ /* calculate parity */ mr = msm_hsl_read(port, UARTDM_MR2_ADDR); mr &= ~UARTDM_MR2_PARITY_MODE_BMSK; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) mr |= ODD_PARITY; else if (termios->c_cflag & CMSPAR) mr |= SPACE_PARITY; else mr |= EVEN_PARITY; } /* calculate bits per char */ mr &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK; switch (termios->c_cflag & CSIZE) { case CS5: mr |= FIVE_BPC; break; case CS6: mr |= SIX_BPC; break; case CS7: mr |= SEVEN_BPC; break; case CS8: default: mr |= EIGHT_BPC; break; } /* calculate stop bits */ mr &= ~(STOP_BIT_ONE | STOP_BIT_TWO); if (termios->c_cflag & CSTOPB) mr |= STOP_BIT_TWO; else mr |= STOP_BIT_ONE; /* set parity, bits per char, and stop bit */ msm_hsl_write(port, mr, UARTDM_MR2_ADDR); /* calculate and set hardware flow control */ mr = msm_hsl_read(port, UARTDM_MR1_ADDR); mr &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK); if (termios->c_cflag & CRTSCTS) { mr |= UARTDM_MR1_CTS_CTL_BMSK; mr |= UARTDM_MR1_RX_RDY_CTL_BMSK; } msm_hsl_write(port, mr, UARTDM_MR1_ADDR); /* Configure status bits to ignore based on termio flags. */ port->read_status_mask = 0; if (termios->c_iflag & INPCK) port->read_status_mask |= UARTDM_SR_PAR_FRAME_BMSK; if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= UARTDM_SR_RX_BREAK_BMSK; uart_update_timeout(port, termios->c_cflag, baud); clk_en(port, 0); spin_unlock_irqrestore(&port->lock, flags); }
static void handle_rx(struct uart_port *port, unsigned int misr) { struct tty_struct *tty = port->state->port.tty; unsigned int sr; int count = 0; struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port); /* * 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_hsl_read(port, UARTDM_SR_ADDR) & UARTDM_SR_OVERRUN_BMSK)) { port->icount.overrun++; tty_insert_flip_char(tty, 0, TTY_OVERRUN); msm_hsl_write(port, RESET_ERROR_STATUS, UARTDM_CR_ADDR); } if (misr & UARTDM_ISR_RXSTALE_BMSK) { count = msm_hsl_read(port, UARTDM_RX_TOTAL_SNAP_ADDR) - msm_hsl_port->old_snap_state; msm_hsl_port->old_snap_state = 0; } else { count = 4 * (msm_hsl_read(port, UARTDM_RFWR_ADDR)); msm_hsl_port->old_snap_state += count; } /* and now the main RX loop */ while (count > 0) { unsigned int c; char flag = TTY_NORMAL; sr = msm_hsl_read(port, UARTDM_SR_ADDR); if ((sr & UARTDM_SR_RXRDY_BMSK) == 0) { msm_hsl_port->old_snap_state -= count; break; } c = msm_hsl_read(port, UARTDM_RF_ADDR); if (sr & UARTDM_SR_RX_BREAK_BMSK) { port->icount.brk++; if (uart_handle_break(port)) continue; } else if (sr & UARTDM_SR_PAR_FRAME_BMSK) { port->icount.frame++; } else { port->icount.rx++; } /* Mask conditions we're ignorning. */ sr &= port->read_status_mask; if (sr & UARTDM_SR_RX_BREAK_BMSK) flag = TTY_BREAK; else if (sr & UARTDM_SR_PAR_FRAME_BMSK) flag = TTY_FRAME; /* TODO: handle sysrq */ /* if (!uart_handle_sysrq_char(port, c)) */ tty_insert_flip_string(tty, (char *) &c, (count > 4) ? 4 : count); count -= 4; } tty_flip_buffer_push(tty); }