static int serial_omap_suspend(struct platform_device *pdev, pm_message_t state) { struct uart_omap_port *up = platform_get_drvdata(pdev); struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; static unsigned int fifo_suspendbrks; u8 lcr, efr; /* Reset the uart wakeup event */ omap_up_info->uart_wakeup_event = 0; /* Disable interrupts from this port */ serial_out(up, UART_IER, 0); /* If we're using auto-rts then disable it. */ lcr = serial_in(up, UART_LCR); serial_out(up, UART_LCR, 0xbf); efr = serial_in(up, UART_EFR); serial_out(up, UART_LCR, lcr); if (efr & UART_EFR_RTS) { serial_omap_set_autorts(up, 0); up->restore_autorts = 1; /* * Force RTS output to inactive (high) after disable autorts * mode. This RTS bit might not be restored when enable autorts * next time, since the RTS output controlled by hardware * flow control. */ serial_omap_set_mctrl(&up->port, (up->port.mctrl & ~TIOCM_RTS)); } /* * There seems to be a window here where * data could still be on the way to the * fifo. This delay is ~1 byte time @ 115.2k */ udelay(80); if (omap_uart_active(up->port.line, 0)) { fifo_suspendbrks++; printk(KERN_WARNING "UART%d FIFO break suspend %d\n", up->port.line, fifo_suspendbrks); if (up->restore_autorts) { up->restore_autorts = 0; serial_omap_set_autorts(up, 1); } serial_out(up, UART_IER, up->ier); return -EBUSY; } serial_out(up, UART_IER, up->ier); if (up) uart_suspend_port(&serial_omap_reg, &up->port); return 0; }
static void serial_omap_shutdown(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; unsigned long flags = 0; u8 lcr, efr; dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id); /* * Disable interrupts from this port */ up->ier = 0; serial_out(up, UART_IER, 0); /* If we're using auto-rts then disable it. */ spin_lock_irqsave(&up->port.lock, flags); lcr = serial_in(up, UART_LCR); serial_out(up, UART_LCR, 0xbf); efr = serial_in(up, UART_EFR); serial_out(up, UART_LCR, lcr); if (efr & UART_EFR_RTS) { serial_omap_set_autorts(up, 0); up->restore_autorts = 1; } up->port.mctrl &= ~TIOCM_OUT2; serial_omap_set_mctrl(&up->port, (up->port.mctrl & ~TIOCM_RTS)); spin_unlock_irqrestore(&up->port.lock, flags); /* * Disable break condition and FIFOs */ serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); serial_omap_clear_fifos(up); /* * Read data port to reset things, and then free the irq */ if (serial_in(up, UART_LSR) & UART_LSR_DR) (void) serial_in(up, UART_RX); if (up->use_dma) { int tmp; dma_free_coherent(up->port.dev, UART_XMIT_SIZE, up->port.state->xmit.buf, up->uart_dma.tx_buf_dma_phys); up->port.state->xmit.buf = NULL; serial_omap_stop_rx(port); dma_free_coherent(up->port.dev, up->uart_dma.rx_buf_size, up->uart_dma.rx_buf, up->uart_dma.rx_buf_dma_phys); up->uart_dma.rx_buf = NULL; tmp = serial_in(up, UART_OMAP_SYSC) & OMAP_UART_SYSC_RESET; serial_out(up, UART_OMAP_SYSC, tmp); /* force-idle */ } free_irq(up->port.irq, up); }
static void serial_omap_shutdown(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; unsigned long flags; u8 lcr, efr; DPRINTK("serial_omap_shutdown+%d\n", up->pdev->id); /* * If we're using auto-rts then disable it. */ lcr = serial_in(up, UART_LCR); serial_out(up, UART_LCR, 0xbf); efr = serial_in(up, UART_EFR); serial_out(up, UART_LCR, lcr); if (efr & UART_EFR_RTS) { serial_omap_set_autorts(up, 0); up->restore_autorts = 1; } /* * Disable interrupts from this port */ up->ier = 0; serial_out(up, UART_IER, 0); spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_FOURPORT) { /* reset interrupts on the AST Fourport board */ inb((up->port.iobase & 0xfe0) | 0x1f); up->port.mctrl |= TIOCM_OUT1; } else up->port.mctrl &= ~TIOCM_OUT2; serial_omap_set_mctrl(&up->port, (up->port.mctrl & ~TIOCM_RTS)); spin_unlock_irqrestore(&up->port.lock, flags); if (up->pdev->id == gps_port) { 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); } /* * Disable break condition and FIFOs */ serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); serial_omap_clear_fifos(up); /* * Read data port to reset things, and then free the irq */ if (serial_in(up, UART_LSR) & UART_LSR_DR) (void) serial_in(up, UART_RX); if (up->use_dma) { int tmp; if (up->is_buf_dma_alloced) { dma_free_coherent(up->port.dev, UART_XMIT_SIZE, up->port.state->xmit.buf, up->uart_dma.tx_buf_dma_phys); up->port.state->xmit.buf = NULL; up->is_buf_dma_alloced = 0; } /*TBD: Check if this is really needed here*/ serial_omap_stop_rx(port); dma_free_coherent(up->port.dev, up->uart_dma.rx_buf_size, up->uart_dma.rx_buf, up->uart_dma.rx_buf_dma_phys); up->uart_dma.rx_buf = NULL; tmp = serial_in(up, UART_OMAP_SYSC) & 0x7; serial_out(up, UART_OMAP_SYSC, tmp); /* force-idle */ } free_irq(up->port.irq, up); if (cancel_work_sync(&up->tty_work)) tty_flip_buffer_work(&up->tty_work); }
static void serial_omap_start_tx(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; #ifdef CONFIG_PM /* Disallow OCP bus idle. UART TX irqs are not seen during * bus idle. Alternative is to set kernel timer at fifo * drain rate. */ unsigned int tmp; tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7) | (1 << 3); serial_out(up, UART_OMAP_SYSC, tmp); /* no-idle */ #endif if (up->use_dma && !(up->port.x_char)) { struct circ_buf *xmit = &up->port.state->xmit; unsigned int start = up->uart_dma.tx_buf_dma_phys + (xmit->tail & (UART_XMIT_SIZE - 1)); if (uart_circ_empty(xmit) || up->uart_dma.tx_dma_state) return; spin_lock(&(up->uart_dma.tx_lock)); up->uart_dma.tx_dma_state = 1; spin_unlock(&(up->uart_dma.tx_lock)); up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit); /* It is a circular buffer. See if the buffer has wounded back. * If yes it will have to be transferred in two separate dma * transfers */ if (start + up->uart_dma.tx_buf_size >= up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) up->uart_dma.tx_buf_size = (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start; if (up->uart_dma.tx_dma_channel == 0xFF) { omap_request_dma(uart_dma_tx[up->pdev->id-1], "UART Tx DMA", (void *)uart_tx_dma_callback, up, &(up->uart_dma.tx_dma_channel)); } omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0, OMAP_DMA_AMODE_CONSTANT, UART_BASE(up->pdev->id - 1), 0, 0); omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0, OMAP_DMA_AMODE_POST_INC, start, 0, 0); omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel, OMAP_DMA_DATA_TYPE_S8, up->uart_dma.tx_buf_size, 1, OMAP_DMA_SYNC_ELEMENT, uart_dma_tx[(up->pdev->id)-1], 0); omap_start_dma(up->uart_dma.tx_dma_channel); } else if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; serial_out(up, UART_IER, up->ier); } if (up->restore_autorts) { serial_omap_set_autorts(up, 1); up->restore_autorts = 0; } }
static void serial_omap_start_tx(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; struct circ_buf *xmit; unsigned int start; int ret = 0; if (!up->use_dma) { serial_omap_enable_ier_thri(up); if (up->restore_autorts) { up->restore_autorts = 0; serial_omap_set_autorts(up, 1); } return; } xmit = &up->port.state->xmit; if (uart_circ_empty(xmit) || up->uart_dma.tx_dma_used) return; if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) ret = omap_request_dma(up->uart_dma.uart_dma_tx, "UART Tx DMA", (void *)uart_tx_dma_callback, up, &(up->uart_dma.tx_dma_channel)); if (ret < 0) { serial_omap_enable_ier_thri(up); return; } start = up->uart_dma.tx_buf_dma_phys + (xmit->tail & (UART_XMIT_SIZE - 1)); spin_lock(&(up->uart_dma.tx_lock)); up->uart_dma.tx_dma_used = true; spin_unlock(&(up->uart_dma.tx_lock)); up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit); /* * It is a circular buffer. See if the buffer has wounded back. * If yes it will have to be transferred in two separate dma * transfers */ if (start + up->uart_dma.tx_buf_size >= up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) up->uart_dma.tx_buf_size = (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start; omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0, OMAP_DMA_AMODE_CONSTANT, up->uart_dma.uart_base, 0, 0); omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0, OMAP_DMA_AMODE_POST_INC, start, 0, 0); omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel, OMAP_DMA_DATA_TYPE_S8, up->uart_dma.tx_buf_size, 1, OMAP_DMA_SYNC_ELEMENT, up->uart_dma.uart_dma_tx, 0); /* FIXME: Cache maintenance needed here? */ omap_start_dma(up->uart_dma.tx_dma_channel); if (up->restore_autorts) { up->restore_autorts = 0; serial_omap_set_autorts(up, 1); } }