static int s3c2410_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *clk) { unsigned long ucon = rd_regl(port, S3C2410_UCON); clk->divisor = 1; clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk"; return 0; }
static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port)) cpu_relax(); wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch); }
/* getchar routine in polling mode. Added to support KGDB */ static int s3c24xx_serial_getchar(struct uart_port *port) { unsigned long ufstat, utrstat; unsigned int ufcon = rd_regl(port, S3C2410_UFCON); if (ufcon & S3C2410_UFCON_FIFOMODE) { /* fifo mode - check ammount of data in fifo registers... */ do { ufstat = rd_regl(port, S3C2410_UFSTAT); } while (!(ufstat & S3C2410_UFSTAT_RXMASK)); /* blocked until there is data in the fifo */ } else { /* non fifo mode - check just the rx buffer register */ do { utrstat = rd_regl(port, S3C2410_UTRSTAT); } while (!(utrstat & S3C2410_UTRSTAT_RXDR)); /* blocked until there is data in the RX register */ } return (rd_regb(port, S3C2410_URXH)); }
static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned int umcon = rd_regl(port, S3C2410_UMCON); if (mctrl & TIOCM_RTS) umcon |= S3C2410_UMCOM_RTS_LOW; else umcon &= ~S3C2410_UMCOM_RTS_LOW; wr_regl(port, S3C2410_UMCON, umcon); }
static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; unsigned int assert = mctrl & TIOCM_RTS; unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0; unsigned int current_val; if (mctrl & TIOCM_LOOP) { if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) wr_regl(port, ureg->sirfsoc_line_ctrl, rd_regl(port, ureg->sirfsoc_line_ctrl) | SIRFUART_LOOP_BACK); else wr_regl(port, ureg->sirfsoc_mode1, rd_regl(port, ureg->sirfsoc_mode1) | SIRFSOC_USP_LOOP_BACK_CTRL); } else { if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) wr_regl(port, ureg->sirfsoc_line_ctrl, rd_regl(port, ureg->sirfsoc_line_ctrl) & ~SIRFUART_LOOP_BACK); else wr_regl(port, ureg->sirfsoc_mode1, rd_regl(port, ureg->sirfsoc_mode1) & ~SIRFSOC_USP_LOOP_BACK_CTRL); } if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled) return; if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { current_val = rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0xFF; val |= current_val; wr_regl(port, ureg->sirfsoc_afc_ctrl, val); } else { if (!val) gpio_set_value(sirfport->rts_gpio, 1); else gpio_set_value(sirfport->rts_gpio, 0); } }
static unsigned int imapx200_serial_tx_empty(struct uart_port *port) { struct imapx200_uart_info *info = imapx200_port_to_info(port); unsigned long usr, iir; int ret = 0; iir = rd_regl(port, IMAPX200_IIR); if ((iir & IMAPX200_IIR_FIFOSE_MASK) == IMAPX200_IIR_FIFOSE_ENABLE) { /* fifo mode - check ammount of data in fifo registers... */ usr = rd_regl(port, IMAPX200_USR); ret = (usr & info->tx_fifoempty) ? 1 : 0; } else { /* in non-fifo mode, we go and use the tx buffer empty */ ret = imapx200_serial_txempty_nofifo(port); } return ret; }
/* submit rx dma task into dmaengine */ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; int i; sirfport->rx_io_count = 0; wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & ~SIRFUART_IO_MODE); for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) sirfsoc_rx_submit_one_dma_desc(port, i); sirfport->rx_completed = sirfport->rx_issued = 0; if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) | SIRFUART_RX_DMA_INT_EN(port, uint_en)); else wr_regl(port, ureg->sirfsoc_int_en_reg, SIRFUART_RX_DMA_INT_EN(port, uint_en)); }
static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); unsigned int assert = mctrl & TIOCM_RTS; unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0; unsigned int current_val; if (sirfport->hw_flow_ctrl) { current_val = rd_regl(port, SIRFUART_AFC_CTRL) & ~0xFF; val |= current_val; wr_regl(port, SIRFUART_AFC_CTRL, val); } }
static unsigned int sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) { unsigned int ch, rx_count = 0; while (!(rd_regl(port, SIRFUART_RX_FIFO_STATUS) & SIRFUART_FIFOEMPTY_MASK(port))) { ch = rd_regl(port, SIRFUART_RX_FIFO_DATA) | SIRFUART_DUMMY_READ; if (unlikely(uart_handle_sysrq_char(port, ch))) continue; uart_insert_char(port, 0, 0, ch, TTY_NORMAL); rx_count++; if (rx_count >= max_rx_count) break; } port->icount.rx += rx_count; tty_flip_buffer_push(&port->state->port); return rx_count; }
static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { unsigned long ulcon = rd_regl(port, ureg->sirfsoc_line_ctrl); if (break_state) ulcon |= SIRFUART_SET_BREAK; else ulcon &= ~SIRFUART_SET_BREAK; wr_regl(port, ureg->sirfsoc_line_ctrl, ulcon); } }
static void sirfsoc_uart_disable_ms(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; if (!sirfport->hw_flow_ctrl) return; sirfport->ms_enabled = false; if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { wr_regl(port, ureg->sirfsoc_afc_ctrl, rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg)& ~uint_en->sirfsoc_cts_en); else wr_regl(port, SIRFUART_INT_EN_CLR, uint_en->sirfsoc_cts_en); } else disable_irq(gpio_to_irq(sirfport->cts_gpio)); }
static int s3c2410_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *clk) { unsigned long ucon = rd_regl(port, S3C2410_UCON); if (strcmp(clk->name, "uclk") == 0) ucon |= S3C2410_UCON_UCLK; else ucon &= ~S3C2410_UCON_UCLK; wr_regl(port, S3C2410_UCON, ucon); return 0; }
static void s3c24xx_serial_rx_enable(struct uart_port *port) { unsigned long flags; unsigned int ucon, ufcon; int count = 10000; spin_lock_irqsave(&port->lock, flags); while (--count && !s3c24xx_serial_txempty_nofifo(port)) udelay(100); ufcon = rd_regl(port, S3C2410_UFCON); ufcon |= S3C2410_UFCON_RESETRX; wr_regl(port, S3C2410_UFCON, ufcon); ucon = rd_regl(port, S3C2410_UCON); ucon |= S3C2410_UCON_RXIRQMODE; wr_regl(port, S3C2410_UCON, ucon); rx_enabled(port) = 1; spin_unlock_irqrestore(&port->lock, flags); }
static void sirfsoc_uart_start_tx(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; if (sirfport->tx_dma_chan) sirfsoc_uart_tx_with_dma(sirfport); else { if (sirfport->uart_reg->uart_type == SIRF_USP_UART) wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port, ureg->sirfsoc_tx_rx_en) | SIRFUART_TX_EN); wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP); sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize); wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg)| uint_en->sirfsoc_txfifo_empty_en); else wr_regl(port, ureg->sirfsoc_int_en_reg, uint_en->sirfsoc_txfifo_empty_en); } }
static void sirfsoc_uart_enable_ms(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; if (!sirfport->hw_flow_ctrl) return; sirfport->ms_enabled = true; if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { wr_regl(port, ureg->sirfsoc_afc_ctrl, rd_regl(port, ureg->sirfsoc_afc_ctrl) | SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) | uint_en->sirfsoc_cts_en); else wr_regl(port, ureg->sirfsoc_int_en_reg, uint_en->sirfsoc_cts_en); } else enable_irq(gpio_to_irq(sirfport->cts_gpio)); }
static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) { /* todo - possibly remove AFC and do manual CTS */ if(port->line == 0){ unsigned int umcon = 0; umcon = rd_regl(port, S3C2410_UMCON); if (mctrl & TIOCM_RTS) umcon |= S3C2410_UMCOM_AFC; else umcon &= ~S3C2410_UMCOM_AFC; wr_regl(port, S3C2410_UMCON, umcon); } }
static void s3c24xx_serial_rx_disable(struct uart_port *port) { unsigned long flags; unsigned int ucon; spin_lock_irqsave(&port->lock, flags); ucon = rd_regl(port, S3C2410_UCON); ucon &= ~S3C2410_UCON_RXIRQMODE; wr_regl(port, S3C2410_UCON, ucon); rx_enabled(port) = 0; spin_unlock_irqrestore(&port->lock, flags); }
static irqreturn_t s3c_serial_interrupt(int irq, void *dev_id) { struct s3c_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; uint intpnd; intpnd = rd_regl(port, S3C_UINTPND); if (intpnd & UART_RX_INT) { wr_regl(port, S3C_UINTPND, UART_RX_INT); rd_regl(port, S3C_UINTPND); /*clearing the interrupt*/ return s3c_serial_rx_chars( irq, dev_id); } else if (intpnd & UART_TX_INT) { wr_regl(port, S3C_UINTPND, UART_TX_INT); rd_regl(port, S3C_UINTPND); /*clearing the interrupt*/ return s3c_serial_tx_chars(irq, dev_id); } else if (intpnd & UART_ERR_INT) { printk("UART err int.\n"); wr_regl(port, S3C_UINTPND, UART_ERR_INT); rd_regl(port, S3C_UINTPND); /*clearing the interrupt*/ return IRQ_HANDLED; } else if (intpnd & UART_MODEM_INT) { printk("In Modem ... other case\n"); wr_regl(port, S3C_UINTPND, UART_MODEM_INT); rd_regl(port, S3C_UINTPND); /*clearing the interrupt*/ return IRQ_HANDLED; } // work around h/w problem : interrupt status bit update delay //return IRQ_NONE; return IRQ_HANDLED; }
static int s5pv210_serial_resetport(struct uart_port *port, struct s3c2410_uartcfg *cfg) { unsigned long ucon = rd_regl(port, S3C2410_UCON); ucon &= S5PV210_UCON_CLKMASK; wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); wr_regl(port, S3C2410_ULCON, cfg->ulcon); /* reset both fifos */ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); wr_regl(port, S3C2410_UFCON, cfg->ufcon); return 0; }
/* interrupt handler for s3c64xx and later SoC's.*/ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) { struct s3c24xx_uart_port *ourport = id; struct uart_port *port = &ourport->port; unsigned int pend = rd_regl(port, S3C64XX_UINTP); irqreturn_t ret = IRQ_HANDLED; if (pend & S3C64XX_UINTM_RXD_MSK) { ret = s3c24xx_serial_rx_chars(irq, id); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK); } if (pend & S3C64XX_UINTM_TXD_MSK) { ret = s3c24xx_serial_tx_chars(irq, id); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK); } return ret; }
static int s5pv210_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *clk) { unsigned long ucon = rd_regl(port, S3C2410_UCON); if (strcmp(clk->name, "pclk") == 0) ucon &= ~S5PV210_UCON_CLKMASK; else if (strcmp(clk->name, "uclk1") == 0) ucon |= S5PV210_UCON_CLKMASK; else { printk(KERN_ERR "unknown clock source %s\n", clk->name); return -EINVAL; } wr_regl(port, S3C2410_UCON, ucon); return 0; }
static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); if (!(sirfport->ms_enabled)) { goto cts_asserted; } else if (sirfport->hw_flow_ctrl) { if (!(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS)) goto cts_asserted; else goto cts_deasserted; } cts_deasserted: return TIOCM_CAR | TIOCM_DSR; cts_asserted: return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; }
static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) { unsigned long flags; unsigned int ucon; spin_lock_irqsave(&port->lock, flags); ucon = rd_regl(port, S3C2410_UCON); if (break_state) ucon |= S3C2410_UCON_SBREAK; else ucon &= ~S3C2410_UCON_SBREAK; wr_regl(port, S3C2410_UCON, ucon); spin_unlock_irqrestore(&port->lock, flags); }
static int s5pv210_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *clk) { u32 ucon = rd_regl(port, S3C2410_UCON); clk->divisor = 1; switch (ucon & S5PV210_UCON_CLKMASK) { case S5PV210_UCON_PCLK: clk->name = "pclk"; break; case S5PV210_UCON_UCLK: clk->name = "uclk1"; break; } return 0; }
static void imapx200_serial_break_ctl(struct uart_port *port, int break_state) { unsigned long flags; unsigned int lcr; spin_lock_irqsave(&port->lock, flags); lcr = rd_regl(port, IMAPX200_LCR); if (break_state) lcr |= IMAPX200_LCR_Break_ENABLE; else lcr &= ~IMAPX200_LCR_Break_ENABLE; wr_regl(port, IMAPX200_LCR, lcr); spin_unlock_irqrestore(&port->lock, flags); }
static irqreturn_t s3c_serial_tx_chars(int irq, void *id) { struct s3c_uart_port *ourport = id; struct uart_port *port = &ourport->port; struct circ_buf *xmit = &port->info->xmit; int count = 256; if (port->x_char) { wr_regb(port, S3C_UTXH, port->x_char); port->icount.tx++; port->x_char = 0; goto out; } /* if there isnt anything more to transmit, or the uart is now * stopped, disable the uart and exit */ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { s3c_serial_stop_tx(port); goto out; } /* try and drain the buffer... */ while (!uart_circ_empty(xmit) && count-- > 0) { if (rd_regl(port, S3C_UFSTAT) & ourport->info->tx_fifofull) break; wr_regb(port, S3C_UTXH, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); if (uart_circ_empty(xmit)) s3c_serial_stop_tx(port); out: wake_lock_timeout(&uart_wakelock, HZ / 2); return IRQ_HANDLED; }
static void enable_rx_pio(struct s3c24xx_uart_port *ourport) { struct uart_port *port = &ourport->port; unsigned int ucon; /* set Rx mode to DMA mode */ ucon = rd_regl(port, S3C2410_UCON); ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK | S3C64XX_UCON_EMPTYINT_EN | S3C64XX_UCON_DMASUS_EN | S3C64XX_UCON_TIMEOUT_EN | S3C64XX_UCON_RXMODE_MASK); ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT | S3C64XX_UCON_TIMEOUT_EN | S3C64XX_UCON_RXMODE_CPU; wr_regl(port, S3C2410_UCON, ucon); ourport->rx_mode = S3C24XX_RX_PIO; }
static void sirfsoc_uart_start_tx(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) sirfsoc_uart_tx_with_dma(sirfport); else { sirfsoc_uart_pio_tx_chars(sirfport, 1); wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START); if (!sirfport->is_marco) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg)| uint_en->sirfsoc_txfifo_empty_en); else wr_regl(port, ureg->sirfsoc_int_en_reg, uint_en->sirfsoc_txfifo_empty_en); } }
static unsigned int sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count) { struct uart_port *port = &sirfport->port; struct circ_buf *xmit = &port->state->xmit; unsigned int num_tx = 0; while (!uart_circ_empty(xmit) && !(rd_regl(port, SIRFUART_TX_FIFO_STATUS) & SIRFUART_FIFOFULL_MASK(port)) && count--) { wr_regl(port, SIRFUART_TX_FIFO_DATA, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; num_tx++; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); return num_tx; }
static int s3c6400_serial_resetport(struct uart_port *port, struct s3c2410_uartcfg *cfg) { unsigned long ucon = rd_regl(port, S3C2410_UCON); dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n", port, port->mapbase, cfg); ucon &= S3C6400_UCON_CLKMASK; wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); wr_regl(port, S3C2410_ULCON, cfg->ulcon); /* reset both fifos */ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); wr_regl(port, S3C2410_UFCON, cfg->ufcon); return 0; }