diff options
Diffstat (limited to 'drivers/tty/serial/imx.c')
| -rw-r--r-- | drivers/tty/serial/imx.c | 952 |
1 files changed, 674 insertions, 278 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 0b7fed746b2..044e86d528a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -47,10 +47,12 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> -#include <asm/io.h> #include <asm/irq.h> -#include <mach/imx-uart.h> +#include <linux/platform_data/serial-imx.h> +#include <linux/platform_data/dma-imx.h> /* Register definitions */ #define URXD0 0x0 /* Receiver Register */ @@ -72,103 +74,106 @@ #define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/ /* UART Control Register Bit Fields.*/ -#define URXD_CHARRDY (1<<15) -#define URXD_ERR (1<<14) -#define URXD_OVRRUN (1<<13) -#define URXD_FRMERR (1<<12) -#define URXD_BRK (1<<11) -#define URXD_PRERR (1<<10) -#define UCR1_ADEN (1<<15) /* Auto detect interrupt */ -#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ -#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ -#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ -#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ -#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ -#define UCR1_IREN (1<<7) /* Infrared interface enable */ -#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ -#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ -#define UCR1_SNDBRK (1<<4) /* Send break */ -#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ -#define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */ -#define UCR1_DOZE (1<<1) /* Doze */ -#define UCR1_UARTEN (1<<0) /* UART enabled */ -#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ -#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ -#define UCR2_CTSC (1<<13) /* CTS pin control */ -#define UCR2_CTS (1<<12) /* Clear to send */ -#define UCR2_ESCEN (1<<11) /* Escape enable */ -#define UCR2_PREN (1<<8) /* Parity enable */ -#define UCR2_PROE (1<<7) /* Parity odd/even */ -#define UCR2_STPB (1<<6) /* Stop */ -#define UCR2_WS (1<<5) /* Word size */ -#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ -#define UCR2_ATEN (1<<3) /* Aging Timer Enable */ -#define UCR2_TXEN (1<<2) /* Transmitter enabled */ -#define UCR2_RXEN (1<<1) /* Receiver enabled */ -#define UCR2_SRST (1<<0) /* SW reset */ -#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ -#define UCR3_PARERREN (1<<12) /* Parity enable */ -#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ -#define UCR3_DSR (1<<10) /* Data set ready */ -#define UCR3_DCD (1<<9) /* Data carrier detect */ -#define UCR3_RI (1<<8) /* Ring indicator */ -#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */ -#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ -#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ -#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ -#define IMX21_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select */ -#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ -#define UCR3_BPEN (1<<0) /* Preset registers enable */ -#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */ -#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */ -#define UCR4_INVR (1<<9) /* Inverted infrared reception */ -#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ -#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ -#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ -#define UCR4_IRSC (1<<5) /* IR special case */ -#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ -#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ -#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ -#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ -#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ -#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ -#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) -#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ -#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ -#define USR1_RTSS (1<<14) /* RTS pin status */ -#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ -#define USR1_RTSD (1<<12) /* RTS delta */ -#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ -#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ -#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ -#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ -#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ -#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ -#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ -#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ -#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ -#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ -#define USR2_IDLE (1<<12) /* Idle condition */ -#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ -#define USR2_WAKE (1<<7) /* Wake */ -#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ -#define USR2_TXDC (1<<3) /* Transmitter complete */ -#define USR2_BRCD (1<<2) /* Break condition */ -#define USR2_ORE (1<<1) /* Overrun error */ -#define USR2_RDR (1<<0) /* Recv data ready */ -#define UTS_FRCPERR (1<<13) /* Force parity error */ -#define UTS_LOOP (1<<12) /* Loop tx and rx */ -#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ -#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ -#define UTS_TXFULL (1<<4) /* TxFIFO full */ -#define UTS_RXFULL (1<<3) /* RxFIFO full */ -#define UTS_SOFTRST (1<<0) /* Software reset */ +#define URXD_CHARRDY (1<<15) +#define URXD_ERR (1<<14) +#define URXD_OVRRUN (1<<13) +#define URXD_FRMERR (1<<12) +#define URXD_BRK (1<<11) +#define URXD_PRERR (1<<10) +#define UCR1_ADEN (1<<15) /* Auto detect interrupt */ +#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ +#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ +#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ +#define UCR1_ICD_REG(x) (((x) & 3) << 10) /* idle condition detect */ +#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ +#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ +#define UCR1_IREN (1<<7) /* Infrared interface enable */ +#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ +#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ +#define UCR1_SNDBRK (1<<4) /* Send break */ +#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ +#define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */ +#define UCR1_ATDMAEN (1<<2) /* Aging DMA Timer Enable */ +#define UCR1_DOZE (1<<1) /* Doze */ +#define UCR1_UARTEN (1<<0) /* UART enabled */ +#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ +#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ +#define UCR2_CTSC (1<<13) /* CTS pin control */ +#define UCR2_CTS (1<<12) /* Clear to send */ +#define UCR2_ESCEN (1<<11) /* Escape enable */ +#define UCR2_PREN (1<<8) /* Parity enable */ +#define UCR2_PROE (1<<7) /* Parity odd/even */ +#define UCR2_STPB (1<<6) /* Stop */ +#define UCR2_WS (1<<5) /* Word size */ +#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ +#define UCR2_ATEN (1<<3) /* Aging Timer Enable */ +#define UCR2_TXEN (1<<2) /* Transmitter enabled */ +#define UCR2_RXEN (1<<1) /* Receiver enabled */ +#define UCR2_SRST (1<<0) /* SW reset */ +#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ +#define UCR3_PARERREN (1<<12) /* Parity enable */ +#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ +#define UCR3_DSR (1<<10) /* Data set ready */ +#define UCR3_DCD (1<<9) /* Data carrier detect */ +#define UCR3_RI (1<<8) /* Ring indicator */ +#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */ +#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ +#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ +#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ +#define IMX21_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select */ +#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ +#define UCR3_BPEN (1<<0) /* Preset registers enable */ +#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */ +#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */ +#define UCR4_INVR (1<<9) /* Inverted infrared reception */ +#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ +#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ +#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ +#define UCR4_IDDMAEN (1<<6) /* DMA IDLE Condition Detected */ +#define UCR4_IRSC (1<<5) /* IR special case */ +#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ +#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ +#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ +#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ +#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ +#define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */ +#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) +#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ +#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ +#define USR1_RTSS (1<<14) /* RTS pin status */ +#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ +#define USR1_RTSD (1<<12) /* RTS delta */ +#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ +#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ +#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ +#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ +#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ +#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ +#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ +#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ +#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ +#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ +#define USR2_IDLE (1<<12) /* Idle condition */ +#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ +#define USR2_WAKE (1<<7) /* Wake */ +#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ +#define USR2_TXDC (1<<3) /* Transmitter complete */ +#define USR2_BRCD (1<<2) /* Break condition */ +#define USR2_ORE (1<<1) /* Overrun error */ +#define USR2_RDR (1<<0) /* Recv data ready */ +#define UTS_FRCPERR (1<<13) /* Force parity error */ +#define UTS_LOOP (1<<12) /* Loop tx and rx */ +#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ +#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ +#define UTS_TXFULL (1<<4) /* TxFIFO full */ +#define UTS_RXFULL (1<<3) /* RxFIFO full */ +#define UTS_SOFTRST (1<<0) /* Software reset */ /* We've been assigned a range on the "Low-density serial ports" major */ -#define SERIAL_IMX_MAJOR 207 -#define MINOR_START 16 +#define SERIAL_IMX_MAJOR 207 +#define MINOR_START 16 #define DEV_NAME "ttymxc" -#define MAX_INTERNAL_IRQ MXC_INTERNAL_IRQS /* * This determines how often we check the modem status signals @@ -186,6 +191,7 @@ enum imx_uart_type { IMX1_UART, IMX21_UART, + IMX6Q_UART, }; /* device type dependent stuff */ @@ -198,14 +204,28 @@ struct imx_port { struct uart_port port; struct timer_list timer; unsigned int old_status; - int txirq,rxirq,rtsirq; + int txirq, rxirq, rtsirq; unsigned int have_rtscts:1; + unsigned int dte_mode:1; unsigned int use_irda:1; unsigned int irda_inv_rx:1; unsigned int irda_inv_tx:1; unsigned short trcv_delay; /* transceiver delay */ - struct clk *clk; - struct imx_uart_data *devdata; + struct clk *clk_ipg; + struct clk *clk_per; + const struct imx_uart_data *devdata; + + /* DMA fields */ + unsigned int dma_is_inited:1; + unsigned int dma_is_enabled:1; + unsigned int dma_is_rxing:1; + unsigned int dma_is_txing:1; + struct dma_chan *dma_chan_rx, *dma_chan_tx; + struct scatterlist rx_sgl, tx_sgl[2]; + void *rx_buf; + unsigned int tx_bytes; + unsigned int dma_tx_nents; + wait_queue_head_t dma_wait; }; struct imx_port_ucrs { @@ -229,6 +249,10 @@ static struct imx_uart_data imx_uart_devdata[] = { .uts_reg = IMX21_UTS, .devtype = IMX21_UART, }, + [IMX6Q_UART] = { + .uts_reg = IMX21_UTS, + .devtype = IMX6Q_UART, + }, }; static struct platform_device_id imx_uart_devtype[] = { @@ -239,12 +263,16 @@ static struct platform_device_id imx_uart_devtype[] = { .name = "imx21-uart", .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART], }, { + .name = "imx6q-uart", + .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART], + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, imx_uart_devtype); static struct of_device_id imx_uart_dt_ids[] = { + { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], }, { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], }, { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], }, { /* sentinel */ } @@ -266,9 +294,14 @@ static inline int is_imx21_uart(struct imx_port *sport) return sport->devdata->devtype == IMX21_UART; } +static inline int is_imx6q_uart(struct imx_port *sport) +{ + return sport->devdata->devtype == IMX6Q_UART; +} /* * Save and restore functions for UCR1, UCR2 and UCR3 registers */ +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_IMX_CONSOLE) static void imx_port_ucrs_save(struct uart_port *port, struct imx_port_ucrs *ucr) { @@ -286,6 +319,7 @@ static void imx_port_ucrs_restore(struct uart_port *port, writel(ucr->ucr2, port->membase + UCR2); writel(ucr->ucr3, port->membase + UCR3); } +#endif /* * Handle any change of modem status signal since we were last called. @@ -382,6 +416,13 @@ static void imx_stop_tx(struct uart_port *port) return; } + /* + * We are maybe in the SMP context, so if the DMA TX thread is running + * on other cpu, we have to wait for it to finish. + */ + if (sport->dma_is_enabled && sport->dma_is_txing) + return; + temp = readl(sport->port.membase + UCR1); writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); } @@ -394,8 +435,19 @@ static void imx_stop_rx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + /* + * We are maybe in the SMP context, so if the DMA TX thread is running + * on other cpu, we have to wait for it to finish. + */ + if (sport->dma_is_enabled && sport->dma_is_rxing) + return; + temp = readl(sport->port.membase + UCR2); - writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2); + writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); + + /* disable the `Receiver Ready Interrrupt` */ + temp = readl(sport->port.membase + UCR1); + writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1); } /* @@ -429,6 +481,84 @@ static inline void imx_transmit_buffer(struct imx_port *sport) imx_stop_tx(&sport->port); } +static void dma_tx_callback(void *data) +{ + struct imx_port *sport = data; + struct scatterlist *sgl = &sport->tx_sgl[0]; + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long flags; + + dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + + sport->dma_is_txing = 0; + + /* update the stat */ + spin_lock_irqsave(&sport->port.lock, flags); + xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx += sport->tx_bytes; + spin_unlock_irqrestore(&sport->port.lock, flags); + + dev_dbg(sport->port.dev, "we finish the TX DMA.\n"); + + uart_write_wakeup(&sport->port); + + if (waitqueue_active(&sport->dma_wait)) { + wake_up(&sport->dma_wait); + dev_dbg(sport->port.dev, "exit in %s.\n", __func__); + return; + } +} + +static void imx_dma_tx(struct imx_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + struct scatterlist *sgl = sport->tx_sgl; + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = sport->dma_chan_tx; + struct device *dev = sport->port.dev; + enum dma_status status; + int ret; + + status = dmaengine_tx_status(chan, (dma_cookie_t)0, NULL); + if (DMA_IN_PROGRESS == status) + return; + + sport->tx_bytes = uart_circ_chars_pending(xmit); + + if (xmit->tail > xmit->head && xmit->head > 0) { + sport->dma_tx_nents = 2; + sg_init_table(sgl, 2); + sg_set_buf(sgl, xmit->buf + xmit->tail, + UART_XMIT_SIZE - xmit->tail); + sg_set_buf(sgl + 1, xmit->buf, xmit->head); + } else { + sport->dma_tx_nents = 1; + sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes); + } + + ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + if (ret == 0) { + dev_err(dev, "DMA mapping error for TX.\n"); + return; + } + desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(dev, "We cannot prepare for the TX slave dma!\n"); + return; + } + desc->callback = dma_tx_callback; + desc->callback_param = sport; + + dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n", + uart_circ_chars_pending(xmit)); + /* fire it */ + sport->dma_is_txing = 1; + dmaengine_submit(desc); + dma_async_issue_pending(chan); + return; +} + /* * interrupts disabled on entry */ @@ -437,6 +567,9 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + if (uart_circ_empty(&port->state->xmit)) + return; + if (USE_IRDA(sport)) { /* half duplex in IrDA mode; have to disable receive mode */ temp = readl(sport->port.membase + UCR4); @@ -447,9 +580,18 @@ static void imx_start_tx(struct uart_port *port) temp &= ~(UCR1_RRDYEN); writel(temp, sport->port.membase + UCR1); } + /* Clear any pending ORE flag before enabling interrupt */ + temp = readl(sport->port.membase + USR2); + writel(temp | USR2_ORE, sport->port.membase + USR2); - temp = readl(sport->port.membase + UCR1); - writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_OREN; + writel(temp, sport->port.membase + UCR4); + + if (!sport->dma_is_enabled) { + temp = readl(sport->port.membase + UCR1); + writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); + } if (USE_IRDA(sport)) { temp = readl(sport->port.membase + UCR1); @@ -461,6 +603,11 @@ static void imx_start_tx(struct uart_port *port) writel(temp, sport->port.membase + UCR4); } + if (sport->dma_is_enabled) { + imx_dma_tx(sport); + return; + } + if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY) imx_transmit_buffer(sport); } @@ -488,9 +635,8 @@ static irqreturn_t imx_txint(int irq, void *dev_id) struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; - spin_lock_irqsave(&sport->port.lock,flags); - if (sport->port.x_char) - { + spin_lock_irqsave(&sport->port.lock, flags); + if (sport->port.x_char) { /* Send next char */ writel(sport->port.x_char, sport->port.membase + URTX0); goto out; @@ -507,18 +653,18 @@ static irqreturn_t imx_txint(int irq, void *dev_id) uart_write_wakeup(&sport->port); out: - spin_unlock_irqrestore(&sport->port.lock,flags); + spin_unlock_irqrestore(&sport->port.lock, flags); return IRQ_HANDLED; } static irqreturn_t imx_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int rx,flg,ignored = 0; - struct tty_struct *tty = sport->port.state->port.tty; + unsigned int rx, flg, ignored = 0; + struct tty_port *port = &sport->port.state->port; unsigned long flags, temp; - spin_lock_irqsave(&sport->port.lock,flags); + spin_lock_irqsave(&sport->port.lock, flags); while (readl(sport->port.membase + USR2) & USR2_RDR) { flg = TTY_NORMAL; @@ -568,24 +714,52 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) #endif } - tty_insert_flip_char(tty, rx, flg); + tty_insert_flip_char(port, rx, flg); } out: - spin_unlock_irqrestore(&sport->port.lock,flags); - tty_flip_buffer_push(tty); + spin_unlock_irqrestore(&sport->port.lock, flags); + tty_flip_buffer_push(port); return IRQ_HANDLED; } +static int start_rx_dma(struct imx_port *sport); +/* + * If the RXFIFO is filled with some data, and then we + * arise a DMA operation to receive them. + */ +static void imx_dma_rxint(struct imx_port *sport) +{ + unsigned long temp; + + temp = readl(sport->port.membase + USR2); + if ((temp & USR2_RDR) && !sport->dma_is_rxing) { + sport->dma_is_rxing = 1; + + /* disable the `Recerver Ready Interrrupt` */ + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_RRDYEN); + writel(temp, sport->port.membase + UCR1); + + /* tell the DMA to receive the data. */ + start_rx_dma(sport); + } +} + static irqreturn_t imx_int(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int sts; + unsigned int sts2; sts = readl(sport->port.membase + USR1); - if (sts & USR1_RRDY) - imx_rxint(irq, dev_id); + if (sts & USR1_RRDY) { + if (sport->dma_is_enabled) + imx_dma_rxint(sport); + else + imx_rxint(irq, dev_id); + } if (sts & USR1_TRDY && readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) @@ -597,6 +771,13 @@ static irqreturn_t imx_int(int irq, void *dev_id) if (sts & USR1_AWAKE) writel(USR1_AWAKE, sport->port.membase + USR1); + sts2 = readl(sport->port.membase + USR2); + if (sts2 & USR2_ORE) { + dev_err(sport->port.dev, "Rx FIFO overrun\n"); + sport->port.icount.overrun++; + writel(sts2 | USR2_ORE, sport->port.membase + USR2); + } + return IRQ_HANDLED; } @@ -606,8 +787,15 @@ static irqreturn_t imx_int(int irq, void *dev_id) static unsigned int imx_tx_empty(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; + unsigned int ret; - return (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; + ret = (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; + + /* If the TX DMA is working, return 0. */ + if (sport->dma_is_enabled && sport->dma_is_txing) + ret = 0; + + return ret; } /* @@ -624,6 +812,9 @@ static unsigned int imx_get_mctrl(struct uart_port *port) if (readl(sport->port.membase + UCR2) & UCR2_CTS) tmp |= TIOCM_RTS; + if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP) + tmp |= TIOCM_LOOP; + return tmp; } @@ -635,9 +826,15 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; if (mctrl & TIOCM_RTS) - temp |= UCR2_CTS; + if (!sport->dma_is_enabled) + temp |= UCR2_CTS; writel(temp, sport->port.membase + UCR2); + + temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP; + if (mctrl & TIOCM_LOOP) + temp |= UTS_LOOP; + writel(temp, sport->port.membase + uts_reg(sport)); } /* @@ -652,7 +849,7 @@ static void imx_break_ctl(struct uart_port *port, int break_state) temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK; - if ( break_state != 0 ) + if (break_state != 0) temp |= UCR1_SNDBRK; writel(temp, sport->port.membase + UCR1); @@ -666,23 +863,212 @@ static void imx_break_ctl(struct uart_port *port, int break_state) static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) { unsigned int val; - unsigned int ufcr_rfdiv; - /* set receiver / transmitter trigger level. - * RFDIV is set such way to satisfy requested uartclk value - */ - val = TXTL << 10 | RXTL; - ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2) - / sport->port.uartclk; + /* set receiver / transmitter trigger level */ + val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE); + val |= TXTL << UFCR_TXTL_SHF | RXTL; + writel(val, sport->port.membase + UFCR); + return 0; +} + +#define RX_BUF_SIZE (PAGE_SIZE) +static void imx_rx_dma_done(struct imx_port *sport) +{ + unsigned long temp; - if(!ufcr_rfdiv) - ufcr_rfdiv = 1; + /* Enable this interrupt when the RXFIFO is empty. */ + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RRDYEN; + writel(temp, sport->port.membase + UCR1); - val |= UFCR_RFDIV_REG(ufcr_rfdiv); + sport->dma_is_rxing = 0; - writel(val, sport->port.membase + UFCR); + /* Is the shutdown waiting for us? */ + if (waitqueue_active(&sport->dma_wait)) + wake_up(&sport->dma_wait); +} + +/* + * There are three kinds of RX DMA interrupts(such as in the MX6Q): + * [1] the RX DMA buffer is full. + * [2] the Aging timer expires(wait for 8 bytes long) + * [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN). + * + * The [2] is trigger when a character was been sitting in the FIFO + * meanwhile [3] can wait for 32 bytes long when the RX line is + * on IDLE state and RxFIFO is empty. + */ +static void dma_rx_callback(void *data) +{ + struct imx_port *sport = data; + struct dma_chan *chan = sport->dma_chan_rx; + struct scatterlist *sgl = &sport->rx_sgl; + struct tty_port *port = &sport->port.state->port; + struct dma_tx_state state; + enum dma_status status; + unsigned int count; + + /* unmap it first */ + dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE); + + status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); + count = RX_BUF_SIZE - state.residue; + dev_dbg(sport->port.dev, "We get %d bytes.\n", count); + + if (count) { + tty_insert_flip_string(port, sport->rx_buf, count); + tty_flip_buffer_push(port); + + start_rx_dma(sport); + } else + imx_rx_dma_done(sport); +} + +static int start_rx_dma(struct imx_port *sport) +{ + struct scatterlist *sgl = &sport->rx_sgl; + struct dma_chan *chan = sport->dma_chan_rx; + struct device *dev = sport->port.dev; + struct dma_async_tx_descriptor *desc; + int ret; + + sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE); + ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE); + if (ret == 0) { + dev_err(dev, "DMA mapping error for RX.\n"); + return -EINVAL; + } + desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(dev, "We cannot prepare for the RX slave dma!\n"); + return -EINVAL; + } + desc->callback = dma_rx_callback; + desc->callback_param = sport; + + dev_dbg(dev, "RX: prepare for the DMA.\n"); + dmaengine_submit(desc); + dma_async_issue_pending(chan); + return 0; +} + +static void imx_uart_dma_exit(struct imx_port *sport) +{ + if (sport->dma_chan_rx) { + dma_release_channel(sport->dma_chan_rx); + sport->dma_chan_rx = NULL; + + kfree(sport->rx_buf); + sport->rx_buf = NULL; + } + + if (sport->dma_chan_tx) { + dma_release_channel(sport->dma_chan_tx); + sport->dma_chan_tx = NULL; + } + + sport->dma_is_inited = 0; +} + +static int imx_uart_dma_init(struct imx_port *sport) +{ + struct dma_slave_config slave_config = {}; + struct device *dev = sport->port.dev; + int ret; + + /* Prepare for RX : */ + sport->dma_chan_rx = dma_request_slave_channel(dev, "rx"); + if (!sport->dma_chan_rx) { + dev_dbg(dev, "cannot get the DMA channel.\n"); + ret = -EINVAL; + goto err; + } + + slave_config.direction = DMA_DEV_TO_MEM; + slave_config.src_addr = sport->port.mapbase + URXD0; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_maxburst = RXTL; + ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config); + if (ret) { + dev_err(dev, "error in RX dma configuration.\n"); + goto err; + } + + sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!sport->rx_buf) { + dev_err(dev, "cannot alloc DMA buffer.\n"); + ret = -ENOMEM; + goto err; + } + + /* Prepare for TX : */ + sport->dma_chan_tx = dma_request_slave_channel(dev, "tx"); + if (!sport->dma_chan_tx) { + dev_err(dev, "cannot get the TX DMA channel!\n"); + ret = -EINVAL; + goto err; + } + + slave_config.direction = DMA_MEM_TO_DEV; + slave_config.dst_addr = sport->port.mapbase + URTX0; + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_maxburst = TXTL; + ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config); + if (ret) { + dev_err(dev, "error in TX dma configuration."); + goto err; + } + + sport->dma_is_inited = 1; return 0; +err: + imx_uart_dma_exit(sport); + return ret; +} + +static void imx_enable_dma(struct imx_port *sport) +{ + unsigned long temp; + + init_waitqueue_head(&sport->dma_wait); + + /* set UCR1 */ + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN | + /* wait for 32 idle frames for IDDMA interrupt */ + UCR1_ICD_REG(3); + writel(temp, sport->port.membase + UCR1); + + /* set UCR4 */ + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_IDDMAEN; + writel(temp, sport->port.membase + UCR4); + + sport->dma_is_enabled = 1; +} + +static void imx_disable_dma(struct imx_port *sport) +{ + unsigned long temp; + + /* clear UCR1 */ + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN); + writel(temp, sport->port.membase + UCR1); + + /* clear UCR2 */ + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_CTSC | UCR2_CTS); + writel(temp, sport->port.membase + UCR2); + + /* clear UCR4 */ + temp = readl(sport->port.membase + UCR4); + temp &= ~UCR4_IDDMAEN; + writel(temp, sport->port.membase + UCR4); + + sport->dma_is_enabled = 0; } /* half the RX buffer size */ @@ -691,9 +1077,18 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) static int imx_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - int retval; + int retval, i; unsigned long flags, temp; + retval = clk_prepare_enable(sport->clk_per); + if (retval) + goto error_out1; + retval = clk_prepare_enable(sport->clk_ipg); + if (retval) { + clk_disable_unprepare(sport->clk_per); + goto error_out1; + } + imx_setup_ufcr(sport, 0); /* disable the DREN bit (Data Ready interrupt enable) before @@ -705,22 +1100,20 @@ static int imx_startup(struct uart_port *port) temp |= UCR4_IRSC; /* set the trigger level for CTS */ - temp &= ~(UCR4_CTSTL_MASK<< UCR4_CTSTL_SHF); - temp |= CTSTL<< UCR4_CTSTL_SHF; + temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF); + temp |= CTSTL << UCR4_CTSTL_SHF; writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); - if (USE_IRDA(sport)) { - /* reset fifo's and state machines */ - int i = 100; - temp = readl(sport->port.membase + UCR2); - temp &= ~UCR2_SRST; - writel(temp, sport->port.membase + UCR2); - while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && - (--i > 0)) { - udelay(1); - } - } + /* Reset fifo's and state machines */ + i = 100; + + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_SRST; + writel(temp, sport->port.membase + UCR2); + + while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) + udelay(1); /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later @@ -728,34 +1121,32 @@ static int imx_startup(struct uart_port *port) */ if (sport->txirq > 0) { retval = request_irq(sport->rxirq, imx_rxint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out1; retval = request_irq(sport->txirq, imx_txint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out2; /* do not use RTS IRQ on IrDA */ if (!USE_IRDA(sport)) { - retval = request_irq(sport->rtsirq, imx_rtsint, - (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : - IRQF_TRIGGER_FALLING | - IRQF_TRIGGER_RISING, - DRIVER_NAME, sport); + retval = request_irq(sport->rtsirq, imx_rtsint, 0, + dev_name(port->dev), sport); if (retval) goto error_out3; } } else { retval = request_irq(sport->port.irq, imx_int, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) { free_irq(sport->port.irq, sport); goto error_out1; } } + spin_lock_irqsave(&sport->port.lock, flags); /* * Finally, clear and enable interrupts */ @@ -773,20 +1164,13 @@ static int imx_startup(struct uart_port *port) temp = readl(sport->port.membase + UCR2); temp |= (UCR2_RXEN | UCR2_TXEN); + if (!sport->have_rtscts) + temp |= UCR2_IRTS; writel(temp, sport->port.membase + UCR2); - if (USE_IRDA(sport)) { - /* clear RX-FIFO */ - int i = 64; - while ((--i > 0) && - (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { - barrier(); - } - } - - if (is_imx21_uart(sport)) { + if (!is_imx1_uart(sport)) { temp = readl(sport->port.membase + UCR3); - temp |= IMX21_UCR3_RXDMUXSEL; + temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP; writel(temp, sport->port.membase + UCR3); } @@ -809,13 +1193,12 @@ static int imx_startup(struct uart_port *port) /* * Enable modem status interrupts */ - spin_lock_irqsave(&sport->port.lock,flags); imx_enable_ms(&sport->port); - spin_unlock_irqrestore(&sport->port.lock,flags); + spin_unlock_irqrestore(&sport->port.lock, flags); if (USE_IRDA(sport)) { struct imxuart_platform_data *pdata; - pdata = sport->port.dev->platform_data; + pdata = dev_get_platdata(sport->port.dev); sport->irda_inv_rx = pdata->irda_inv_rx; sport->irda_inv_tx = pdata->irda_inv_tx; sport->trcv_delay = pdata->transceiver_delay; @@ -839,14 +1222,26 @@ static void imx_shutdown(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + unsigned long flags; + + if (sport->dma_is_enabled) { + /* We have to wait for the DMA to finish. */ + wait_event(sport->dma_wait, + !sport->dma_is_rxing && !sport->dma_is_txing); + imx_stop_rx(port); + imx_disable_dma(sport); + imx_uart_dma_exit(sport); + } + spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR2); temp &= ~(UCR2_TXEN); writel(temp, sport->port.membase + UCR2); + spin_unlock_irqrestore(&sport->port.lock, flags); if (USE_IRDA(sport)) { struct imxuart_platform_data *pdata; - pdata = sport->port.dev->platform_data; + pdata = dev_get_platdata(sport->port.dev); if (pdata->irda_enable) pdata->irda_enable(0); } @@ -871,12 +1266,27 @@ static void imx_shutdown(struct uart_port *port) * Disable all interrupts, port and break condition. */ + spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); if (USE_IRDA(sport)) temp &= ~(UCR1_IREN); writel(temp, sport->port.membase + UCR1); + spin_unlock_irqrestore(&sport->port.lock, flags); + + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); +} + +static void imx_flush_buffer(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + + if (sport->dma_is_enabled) { + sport->tx_bytes = 0; + dmaengine_terminate_all(sport->dma_chan_tx); + } } static void @@ -916,9 +1326,14 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, ucr2 = UCR2_SRST | UCR2_IRTS; if (termios->c_cflag & CRTSCTS) { - if( sport->have_rtscts ) { + if (sport->have_rtscts) { ucr2 &= ~UCR2_IRTS; ucr2 |= UCR2_CTSC; + + /* Can we enable the DMA support? */ + if (is_imx6q_uart(sport) && !uart_console(port) + && !sport->dma_is_inited) + imx_uart_dma_init(sport); } else { termios->c_cflag &= ~CRTSCTS; } @@ -976,12 +1391,12 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), sport->port.membase + UCR1); - while ( !(readl(sport->port.membase + USR2) & USR2_TXDC)) + while (!(readl(sport->port.membase + USR2) & USR2_TXDC)) barrier(); /* then, disable everything */ old_txrxen = readl(sport->port.membase + UCR2); - writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN), + writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN), sport->port.membase + UCR2); old_txrxen &= (UCR2_TXEN | UCR2_RXEN); @@ -992,6 +1407,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, */ div = 1; } else { + /* custom-baudrate handling */ + div = sport->port.uartclk / (baud * 16); + if (baud == 38400 && quot != div) + baud = sport->port.uartclk / (quot * 16); + div = sport->port.uartclk / (baud * 16); if (div > 7) div = 7; @@ -1013,12 +1433,14 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, ufcr = readl(sport->port.membase + UFCR); ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); + if (sport->dte_mode) + ufcr |= UFCR_DCEDTE; writel(ufcr, sport->port.membase + UFCR); writel(num, sport->port.membase + UBIR); writel(denom, sport->port.membase + UBMR); - if (is_imx21_uart(sport)) + if (!is_imx1_uart(sport)) writel(sport->port.uartclk / div / 1000, sport->port.membase + IMX21_ONEMS); @@ -1030,6 +1452,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) imx_enable_ms(&sport->port); + if (sport->dma_is_inited && !sport->dma_is_enabled) + imx_enable_dma(sport); spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -1041,44 +1465,13 @@ static const char *imx_type(struct uart_port *port) } /* - * Release the memory region(s) being used by 'port'. - */ -static void imx_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mmres->start, resource_size(mmres)); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int imx_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - void *ret; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mmres) - return -ENODEV; - - ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart"); - - return ret ? 0 : -EBUSY; -} - -/* * Configure/autoconfigure the port. */ static void imx_config_port(struct uart_port *port, int flags) { struct imx_port *sport = (struct imx_port *)port; - if (flags & UART_CONFIG_TYPE && - imx_request_port(&sport->port) == 0) + if (flags & UART_CONFIG_TYPE) sport->port.type = PORT_IMX; } @@ -1101,7 +1494,7 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser) ret = -EINVAL; if (sport->port.uartclk / 16 != ser->baud_base) ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) + if (sport->port.mapbase != (unsigned long)ser->iomem_base) ret = -EINVAL; if (sport->port.iobase != ser->port) ret = -EINVAL; @@ -1185,10 +1578,9 @@ static struct uart_ops imx_pops = { .break_ctl = imx_break_ctl, .startup = imx_startup, .shutdown = imx_shutdown, + .flush_buffer = imx_flush_buffer, .set_termios = imx_set_termios, .type = imx_type, - .release_port = imx_release_port, - .request_port = imx_request_port, .config_port = imx_config_port, .verify_port = imx_verify_port, #if defined(CONFIG_CONSOLE_POLL) @@ -1219,6 +1611,25 @@ imx_console_write(struct console *co, const char *s, unsigned int count) struct imx_port *sport = imx_ports[co->index]; struct imx_port_ucrs old_ucr; unsigned int ucr1; + unsigned long flags = 0; + int locked = 1; + int retval; + + retval = clk_enable(sport->clk_per); + if (retval) + return; + retval = clk_enable(sport->clk_ipg); + if (retval) { + clk_disable(sport->clk_per); + return; + } + + if (sport->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock_irqsave(&sport->port.lock, flags); + else + spin_lock_irqsave(&sport->port.lock, flags); /* * First, save UCR1/2/3 and then disable interrupts @@ -1244,6 +1655,12 @@ imx_console_write(struct console *co, const char *s, unsigned int count) while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); imx_port_ucrs_restore(&sport->port, &old_ucr); + + if (locked) + spin_unlock_irqrestore(&sport->port.lock, flags); + + clk_disable(sport->clk_ipg); + clk_disable(sport->clk_per); } /* @@ -1257,7 +1674,7 @@ imx_console_get_options(struct imx_port *sport, int *baud, if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) { /* ok, the port was enabled */ - unsigned int ucr2, ubir,ubmr, uartclk; + unsigned int ucr2, ubir, ubmr, uartclk; unsigned int baud_raw; unsigned int ucfr_rfdiv; @@ -1285,7 +1702,7 @@ imx_console_get_options(struct imx_port *sport, int *baud, else ucfr_rfdiv = 6 - ucfr_rfdiv; - uartclk = clk_get_rate(sport->clk); + uartclk = clk_get_rate(sport->clk_per); uartclk /= ucfr_rfdiv; { /* @@ -1303,8 +1720,8 @@ imx_console_get_options(struct imx_port *sport, int *baud, *baud = (baud_raw + 50) / 100 * 100; } - if(*baud != baud_raw) - printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n", + if (*baud != baud_raw) + pr_info("Console IMX rounded baud rate from %d to %d\n", baud_raw, *baud); } } @@ -1317,6 +1734,7 @@ imx_console_setup(struct console *co, char *options) int bits = 8; int parity = 'n'; int flow = 'n'; + int retval; /* * Check whether an invalid uart number has been specified, and @@ -1326,9 +1744,14 @@ imx_console_setup(struct console *co, char *options) if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) co->index = 0; sport = imx_ports[co->index]; - if(sport == NULL) + if (sport == NULL) return -ENODEV; + /* For setting the registers, we only need to enable the ipg clock. */ + retval = clk_prepare_enable(sport->clk_ipg); + if (retval) + goto error_console; + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else @@ -1336,7 +1759,20 @@ imx_console_setup(struct console *co, char *options) imx_setup_ufcr(sport, 0); - return uart_set_options(&sport->port, co, baud, parity, bits, flow); + retval = uart_set_options(&sport->port, co, baud, parity, bits, flow); + + clk_disable(sport->clk_ipg); + if (retval) { + clk_unprepare(sport->clk_ipg); + goto error_console; + } + + retval = clk_prepare(sport->clk_per); + if (retval) + clk_disable_unprepare(sport->clk_ipg); + +error_console: + return retval; } static struct uart_driver imx_reg; @@ -1375,8 +1811,7 @@ static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) val |= UCR3_AWAKEN; writel(val, sport->port.membase + UCR3); - if (sport) - uart_suspend_port(&imx_reg, &sport->port); + uart_suspend_port(&imx_reg, &sport->port); return 0; } @@ -1391,8 +1826,7 @@ static int serial_imx_resume(struct platform_device *dev) val &= ~UCR3_AWAKEN; writel(val, sport->port.membase + UCR3); - if (sport) - uart_resume_port(&imx_reg, &sport->port); + uart_resume_port(&imx_reg, &sport->port); return 0; } @@ -1427,6 +1861,9 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "fsl,irda-mode", NULL)) sport->use_irda = 1; + if (of_get_property(np, "fsl,dte-mode", NULL)) + sport->dte_mode = 1; + sport->devdata = of_id->data; return 0; @@ -1442,7 +1879,7 @@ static inline int serial_imx_probe_dt(struct imx_port *sport, static void serial_imx_probe_pdata(struct imx_port *sport, struct platform_device *pdev) { - struct imxuart_platform_data *pdata = pdev->dev.platform_data; + struct imxuart_platform_data *pdata = dev_get_platdata(&pdev->dev); sport->port.line = pdev->id; sport->devdata = (struct imx_uart_data *) pdev->id_entry->driver_data; @@ -1460,12 +1897,11 @@ static void serial_imx_probe_pdata(struct imx_port *sport, static int serial_imx_probe(struct platform_device *pdev) { struct imx_port *sport; - struct imxuart_platform_data *pdata; void __iomem *base; int ret = 0; struct resource *res; - sport = kzalloc(sizeof(*sport), GFP_KERNEL); + sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); if (!sport) return -ENOMEM; @@ -1473,19 +1909,12 @@ static int serial_imx_probe(struct platform_device *pdev) if (ret > 0) serial_imx_probe_pdata(sport, pdev); else if (ret < 0) - goto free; + return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto free; - } - - base = ioremap(res->start, PAGE_SIZE); - if (!base) { - ret = -ENOMEM; - goto free; - } + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; @@ -1503,67 +1932,34 @@ static int serial_imx_probe(struct platform_device *pdev) sport->timer.function = imx_timeout; sport->timer.data = (unsigned long)sport; - sport->clk = clk_get(&pdev->dev, "uart"); - if (IS_ERR(sport->clk)) { - ret = PTR_ERR(sport->clk); - goto unmap; + sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(sport->clk_ipg)) { + ret = PTR_ERR(sport->clk_ipg); + dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret); + return ret; } - clk_enable(sport->clk); - sport->port.uartclk = clk_get_rate(sport->clk); - - imx_ports[sport->port.line] = sport; - - pdata = pdev->dev.platform_data; - if (pdata && pdata->init) { - ret = pdata->init(pdev); - if (ret) - goto clkput; + sport->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(sport->clk_per)) { + ret = PTR_ERR(sport->clk_per); + dev_err(&pdev->dev, "failed to get per clk: %d\n", ret); + return ret; } - ret = uart_add_one_port(&imx_reg, &sport->port); - if (ret) - goto deinit; - platform_set_drvdata(pdev, &sport->port); + sport->port.uartclk = clk_get_rate(sport->clk_per); - return 0; -deinit: - if (pdata && pdata->exit) - pdata->exit(pdev); -clkput: - clk_put(sport->clk); - clk_disable(sport->clk); -unmap: - iounmap(sport->port.membase); -free: - kfree(sport); + imx_ports[sport->port.line] = sport; - return ret; + platform_set_drvdata(pdev, sport); + + return uart_add_one_port(&imx_reg, &sport->port); } static int serial_imx_remove(struct platform_device *pdev) { - struct imxuart_platform_data *pdata; struct imx_port *sport = platform_get_drvdata(pdev); - pdata = pdev->dev.platform_data; - - platform_set_drvdata(pdev, NULL); - - if (sport) { - uart_remove_one_port(&imx_reg, &sport->port); - clk_put(sport->clk); - } - - clk_disable(sport->clk); - - if (pdata && pdata->exit) - pdata->exit(pdev); - - iounmap(sport->port.membase); - kfree(sport); - - return 0; + return uart_remove_one_port(&imx_reg, &sport->port); } static struct platform_driver serial_imx_driver = { @@ -1584,7 +1980,7 @@ static int __init imx_serial_init(void) { int ret; - printk(KERN_INFO "Serial: IMX driver\n"); + pr_info("Serial: IMX driver\n"); ret = uart_register_driver(&imx_reg); if (ret) |
