/** * serial_omap_irq() - This handles the interrupt from one port * @irq: uart port irq number * @dev_id: uart port info */ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; unsigned int iir, lsr; unsigned long flags; iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) return IRQ_NONE; spin_lock_irqsave(&up->port.lock, flags); lsr = serial_in(up, UART_LSR); if (iir & UART_IIR_RLSI) { if (!up->use_dma) { if (lsr & UART_LSR_DR) receive_chars(up, &lsr); } else { up->ier &= ~(UART_IER_RDI | UART_IER_RLSI); serial_out(up, UART_IER, up->ier); if ((serial_omap_start_rxdma(up) != 0) && (lsr & UART_LSR_DR)) receive_chars(up, &lsr); } } check_modem_status(up); if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI)) transmit_chars(up); spin_unlock_irqrestore(&up->port.lock, flags); up->port_activity = jiffies; return IRQ_HANDLED; }
/* * This handles the interrupt from one port. */ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; unsigned int iir, lsr; iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) return IRQ_NONE; lsr = serial_in(up, UART_LSR); if ((iir & 0x4) && up->use_dma) { up->ier &= ~UART_IER_RDI; serial_out(up, UART_IER, up->ier); serial_omap_start_rxdma(up); } else if (lsr & UART_LSR_DR) { receive_chars(up, &lsr); } check_modem_status(up); if ((lsr & UART_LSR_THRE) && (iir & 0x2)) { transmit_chars(up); } isr8250_activity = jiffies; return IRQ_HANDLED; }
/* * This handles the interrupt from one port. */ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; unsigned int iir, lsr; iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) return IRQ_NONE; lsr = serial_in(up, UART_LSR); if ((iir & 0x4) && up->use_dma) { up->ier &= ~UART_IER_RDI; serial_out(up, UART_IER, up->ier); serial_omap_start_rxdma(up); } else if (lsr & UART_LSR_DR) { receive_chars(up, &lsr); /* XXX: After driver resume optimization, lower this */ wake_lock_timeout(&omap_serial_wakelock, (HZ * 1)); } check_modem_status(up); if ((lsr & UART_LSR_THRE) && (iir & 0x2)) transmit_chars(up); isr8250_activity = jiffies; return IRQ_HANDLED; }
static void serial_omap_rx_timeout(unsigned long uart_no) { struct uart_omap_port *up = ui[uart_no - 1]; unsigned int curr_dma_pos; curr_dma_pos = omap_readl(OMAP34XX_DMA4_BASE + OMAP_DMA4_CDAC(up->uart_dma.rx_dma_channel)); if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) || (curr_dma_pos == 0)) { /* * If there is no transfer rx happening for 10sec then stop the dma * else just restart the timer. See if 10 sec can be improved. */ if (jiffies_to_msecs(jiffies - isr8250_activity) < 10000) mod_timer(&up->uart_dma.rx_timer, jiffies + usecs_to_jiffies(up->uart_dma.rx_timeout)); else { del_timer(&up->uart_dma.rx_timer); serial_omap_stop_rxdma(up); up->ier |= UART_IER_RDI; serial_out(up, UART_IER, up->ier); } return; } else { unsigned int curr_transmitted_size = curr_dma_pos - up->uart_dma.prev_rx_dma_pos; up->port.icount.rx += curr_transmitted_size; tty_insert_flip_string(up->port.state->port.tty, up->uart_dma.rx_buf + (up->uart_dma.prev_rx_dma_pos - up->uart_dma.rx_buf_dma_phys), curr_transmitted_size); queue_work(omap_serial_workqueue, &up->tty_work); up->uart_dma.prev_rx_dma_pos = curr_dma_pos; if (up->uart_dma.rx_buf_size + up->uart_dma.rx_buf_dma_phys == curr_dma_pos) { serial_omap_start_rxdma(up); } else mod_timer(&up->uart_dma.rx_timer, jiffies + usecs_to_jiffies(up->uart_dma.rx_timeout)); isr8250_activity = jiffies; } }
/** * serial_omap_irq() - This handles the interrupt from one port * @irq: uart port irq number * @dev_id: uart port info */ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; unsigned int iir, lsr; unsigned long flags; spin_lock_irqsave(&up->port.lock, flags); #ifdef CONFIG_PM /* * This will enable the clock for some reason if the * clocks get disabled. This would enable the ICK also * in case if the Idle state is set and the PRCM modul * just shutdown the ICK because of inactivity. */ omap_uart_enable_clock_from_irq(up->pdev->id); #endif iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) { spin_unlock_irqrestore(&up->port.lock, flags); return IRQ_NONE; } lsr = serial_in(up, UART_LSR); if (iir & UART_IIR_RLSI) { if (!up->use_dma) { if (lsr & UART_LSR_DR) { receive_chars(up, &lsr); if (omap_is_console_port(&up->port) && (up->plat_hold_wakelock)) { spin_unlock(&up->port.lock); up->plat_hold_wakelock(up, WAKELK_IRQ); spin_lock(&up->port.lock); } } } else { up->ier &= ~UART_IER_RDI; serial_out(up, UART_IER, up->ier); if (serial_omap_start_rxdma(up) != 0) if (lsr & UART_LSR_DR) receive_chars(up, &lsr); } } check_modem_status(up); if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI)) transmit_chars(up); spin_unlock_irqrestore(&up->port.lock, flags); up->port_activity = jiffies; return IRQ_HANDLED; }
/** * serial_omap_irq() - This handles the interrupt from one port * @irq: uart port irq number * @dev_id: uart port info */ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; unsigned int iir, lsr; unsigned int int_id; unsigned long flags; int ret = IRQ_HANDLED; u8 tx_fifo_lvl; serial_omap_port_enable(up); iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) { serial_omap_port_disable(up); return IRQ_NONE; } int_id = iir & UART_OMAP_IIR_ID; spin_lock_irqsave(&up->port.lock, flags); lsr = serial_in(up, UART_LSR); if (int_id == UART_IIR_RDI || int_id == UART_OMAP_IIR_RX_TIMEOUT || int_id == UART_IIR_RLSI) { if (!up->use_dma) { if (lsr & UART_LSR_DR) receive_chars(up, &lsr); } else { up->ier &= ~(UART_IER_RDI | UART_IER_RLSI); serial_out(up, UART_IER, up->ier); if ((serial_omap_start_rxdma(up) != 0) && (lsr & UART_LSR_DR)) receive_chars(up, &lsr); } } check_modem_status(up); if (int_id == UART_IIR_THRI) { tx_fifo_lvl = serial_in(up, UART_OMAP_TXFIFO_LVL); if (lsr & UART_LSR_THRE || tx_fifo_lvl < up->port.fifosize) transmit_chars(up, tx_fifo_lvl); else ret = IRQ_NONE; } spin_unlock_irqrestore(&up->port.lock, flags); serial_omap_port_disable(up); up->port_activity = jiffies; return ret; }
static void serial_omap_rxdma_poll(unsigned long uart_no) { struct uart_omap_port *up = ui[uart_no]; unsigned int curr_dma_pos, curr_transmitted_size; int ret = 0; curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel); if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) || (curr_dma_pos == 0)) { if (jiffies_to_msecs(jiffies - up->port_activity) < up->uart_dma.rx_timeout) { mod_timer(&up->uart_dma.rx_timer, jiffies + usecs_to_jiffies(up->uart_dma.rx_poll_rate)); } else { serial_omap_stop_rxdma(up); up->ier |= (UART_IER_RDI | UART_IER_RLSI); serial_out(up, UART_IER, up->ier); } return; } curr_transmitted_size = curr_dma_pos - up->uart_dma.prev_rx_dma_pos; up->port.icount.rx += curr_transmitted_size; tty_insert_flip_string(up->port.state->port.tty, up->uart_dma.rx_buf + (up->uart_dma.prev_rx_dma_pos - up->uart_dma.rx_buf_dma_phys), curr_transmitted_size); tty_flip_buffer_push(up->port.state->port.tty); up->uart_dma.prev_rx_dma_pos = curr_dma_pos; if (up->uart_dma.rx_buf_size + up->uart_dma.rx_buf_dma_phys == curr_dma_pos) { ret = serial_omap_start_rxdma(up); if (ret < 0) { serial_omap_stop_rxdma(up); up->ier |= (UART_IER_RDI | UART_IER_RLSI); serial_out(up, UART_IER, up->ier); } } else { mod_timer(&up->uart_dma.rx_timer, jiffies + usecs_to_jiffies(up->uart_dma.rx_poll_rate)); } up->port_activity = jiffies; }
static int serial_omap_startup(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; unsigned long flags; int irq_flags = 0; int retval; /* Zoom2 has GPIO_102 connected to Serial device: * Active High */ if (up->port.flags & UPF_TRIGGER_HIGH) irq_flags |= IRQF_TRIGGER_HIGH; /* * Allocate the IRQ */ retval = request_irq(up->port.irq, serial_omap_irq, irq_flags, up->name, up); if (retval) { return retval; } /* * Stop the baud clock and disable the UART. UART will be enabled * back in set_termios. This is essential for DMA mode operations. */ serial_out(up, UART_LCR, UART_LCR_DLAB); serial_out(up, UART_DLL, 0); serial_out(up, UART_DLM, 0); serial_out(up, UART_LCR, 0); serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE); /* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) */ serial_omap_clear_fifos(up); serial_out(up, UART_SCR, 0x00); /* For Hardware flow control */ serial_out(up, UART_MCR, 0x2); /* * Clear the interrupt registers. */ (void) serial_in(up, UART_LSR); (void) serial_in(up, UART_RX); (void) serial_in(up, UART_IIR); (void) serial_in(up, UART_MSR); /* * Now, initialize the UART */ serial_out(up, UART_LCR, UART_LCR_WLEN8); spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_FOURPORT) { if (!is_real_interrupt(up->port.irq)) up->port.mctrl |= TIOCM_OUT1; } else { /* * Most PC uarts need OUT2 raised to enable interrupts. */ if (is_real_interrupt(up->port.irq)) up->port.mctrl |= TIOCM_OUT2; } serial_omap_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); up->msr_saved_flags = 0; if (up->port.flags & UPF_FOURPORT) { unsigned int icp; /* * Enable interrupts on the AST Fourport board */ icp = (up->port.iobase & 0xfe0) | 0x01f; outb_p(0x80, icp); (void) inb_p(icp); } if (up->use_dma) { if (!up->is_buf_dma_alloced) { free_page((unsigned long)up->port.info->xmit.buf); up->port.info->xmit.buf = NULL; up->port.info->xmit.buf = dma_alloc_coherent(NULL, UART_XMIT_SIZE, (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys), 0); up->is_buf_dma_alloced = 1; } init_timer(&(up->uart_dma.rx_timer)); up->uart_dma.rx_timer.function = serial_omap_rx_timeout; up->uart_dma.rx_timer.data = up->pdev->id; /* Currently the buffer size is 4KB. Can increase it later*/ up->uart_dma.rx_buf = dma_alloc_coherent(NULL, up->uart_dma.rx_buf_size, (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0); serial_omap_start_rxdma(up); } else { /* * Finally, enable interrupts. Note: Modem status interrupts * are set via set_termios(), which will be occurring imminently * anyway, so we don't enable them here. */ up->ier = UART_IER_RLSI | UART_IER_RDI; //| UART_IER_RTOIE |UART_IER_THRI; serial_out(up, UART_IER, up->ier); } return 0; }