コード例 #1
0
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;
}
コード例 #2
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);
}
コード例 #3
0
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);
}
コード例 #4
0
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;
	}
}
コード例 #5
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);
	}
}