147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer/* 247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Freescale STMP37XX/STMP378X Application UART driver 347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * 447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Author: dmitry pervushin <dimka@embeddedalley.com> 547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * 647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Copyright 2008-2010 Freescale Semiconductor, Inc. 747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. 847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * 947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * The code contained herein is licensed under the GNU General Public 1047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * License. You may obtain a copy of the GNU General Public License 1147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Version 2 or later at the following locations: 1247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * 1347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * http://www.opensource.org/licenses/gpl-license.html 1447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * http://www.gnu.org/copyleft/gpl.html 1547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer */ 1647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 1747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/kernel.h> 1847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/errno.h> 1947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/init.h> 2047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/console.h> 2147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/interrupt.h> 2247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/module.h> 2347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/slab.h> 2447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/wait.h> 2547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/tty.h> 2647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/tty_driver.h> 2747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/tty_flip.h> 2847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/serial.h> 2947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/serial_core.h> 3047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/platform_device.h> 3147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/device.h> 3247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/clk.h> 3347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/delay.h> 3447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/io.h> 3547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 3647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <asm/cacheflush.h> 3747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 3847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define MXS_AUART_PORTS 5 3947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 4047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0 0x00000000 4147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_SET 0x00000004 4247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_CLR 0x00000008 4347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_TOG 0x0000000c 4447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL1 0x00000010 4547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL1_SET 0x00000014 4647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL1_CLR 0x00000018 4747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL1_TOG 0x0000001c 4847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2 0x00000020 4947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_SET 0x00000024 5047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_CLR 0x00000028 5147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_TOG 0x0000002c 5247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL 0x00000030 5347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_SET 0x00000034 5447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_CLR 0x00000038 5547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_TOG 0x0000003c 5647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL2 0x00000040 5747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL2_SET 0x00000044 5847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL2_CLR 0x00000048 5947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL2_TOG 0x0000004c 6047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR 0x00000050 6147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_SET 0x00000054 6247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_CLR 0x00000058 6347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_TOG 0x0000005c 6447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_DATA 0x00000060 6547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT 0x00000070 6647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_DEBUG 0x00000080 6747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_VERSION 0x00000090 6847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_AUTOBAUD 0x000000a0 6947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 7047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_SFTRST (1 << 31) 7147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_CLKGATE (1 << 30) 7247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 7347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_CTSEN (1 << 15) 7447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_RTS (1 << 11) 7547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_RXE (1 << 9) 7647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_TXE (1 << 8) 7747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_UARTEN (1 << 0) 7847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 7947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVINT_SHIFT 16 8047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVINT_MASK 0xffff0000 8147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVINT(v) (((v) & 0xffff) << 16) 8247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVFRAC_SHIFT 8 8347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVFRAC_MASK 0x00003f00 8447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVFRAC(v) (((v) & 0x3f) << 8) 8547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_WLEN_MASK 0x00000060 8647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_WLEN(v) (((v) & 0x3) << 5) 8747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_FEN (1 << 4) 8847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_STP2 (1 << 3) 8947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_EPS (1 << 2) 9047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_PEN (1 << 1) 9147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BRK (1 << 0) 9247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 9347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_RTIEN (1 << 22) 9447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_TXIEN (1 << 21) 9547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_RXIEN (1 << 20) 9647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_CTSMIEN (1 << 17) 9747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_RTIS (1 << 6) 9847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_TXIS (1 << 5) 9947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_RXIS (1 << 4) 10047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_CTSMIS (1 << 1) 10147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 10247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_BUSY (1 << 29) 10347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_CTS (1 << 28) 10447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_TXFE (1 << 27) 10547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_TXFF (1 << 25) 10647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_RXFE (1 << 24) 10747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_OERR (1 << 19) 10847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_BERR (1 << 18) 10947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_PERR (1 << 17) 11047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_FERR (1 << 16) 11147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 11247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct uart_driver auart_driver; 11347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 11447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstruct mxs_auart_port { 11547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct uart_port port; 11647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 11747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer unsigned int flags; 11847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer unsigned int ctrl; 11947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 12047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer unsigned int irq; 12147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 12247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct clk *clk; 12347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct device *dev; 12447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}; 12547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 12647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_stop_tx(struct uart_port *u); 12747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 12847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define to_auart_port(u) container_of(u, struct mxs_auart_port, port) 12947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 13047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic inline void mxs_auart_tx_chars(struct mxs_auart_port *s) 13147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 13247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct circ_buf *xmit = &s->port.state->xmit; 13347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 13447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer while (!(readl(s->port.membase + AUART_STAT) & 13547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer AUART_STAT_TXFF)) { 13647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (s->port.x_char) { 13747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.icount.tx++; 13847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(s->port.x_char, 13947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.membase + AUART_DATA); 14047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.x_char = 0; 14147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer continue; 14247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 14347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) { 14447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.icount.tx++; 14547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(xmit->buf[xmit->tail], 14647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.membase + AUART_DATA); 14747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 14847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } else 14947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer break; 15047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 151d0758a285caaf86192cdb22136a5eb84ed72f276Uwe Kleine-König if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 152d0758a285caaf86192cdb22136a5eb84ed72f276Uwe Kleine-König uart_write_wakeup(&s->port); 153d0758a285caaf86192cdb22136a5eb84ed72f276Uwe Kleine-König 15447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (uart_circ_empty(&(s->port.state->xmit))) 15547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_INTR_TXIEN, 15647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.membase + AUART_INTR_CLR); 15747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer else 15847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_INTR_TXIEN, 15947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.membase + AUART_INTR_SET); 16047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 16147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (uart_tx_stopped(&s->port)) 16247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer mxs_auart_stop_tx(&s->port); 16347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 16447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 16547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_rx_char(struct mxs_auart_port *s) 16647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 16747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int flag; 16847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u32 stat; 16947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u8 c; 17047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 17147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer c = readl(s->port.membase + AUART_DATA); 17247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer stat = readl(s->port.membase + AUART_STAT); 17347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 17447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer flag = TTY_NORMAL; 17547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.icount.rx++; 17647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 17747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (stat & AUART_STAT_BERR) { 17847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.icount.brk++; 17947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (uart_handle_break(&s->port)) 18047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer goto out; 18147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } else if (stat & AUART_STAT_PERR) { 18247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.icount.parity++; 18347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } else if (stat & AUART_STAT_FERR) { 18447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.icount.frame++; 18547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 18647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 18747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* 18847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Mask off conditions which should be ingored. 18947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer */ 19047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer stat &= s->port.read_status_mask; 19147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 19247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (stat & AUART_STAT_BERR) { 19347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer flag = TTY_BREAK; 19447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } else if (stat & AUART_STAT_PERR) 19547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer flag = TTY_PARITY; 19647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer else if (stat & AUART_STAT_FERR) 19747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer flag = TTY_FRAME; 19847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 19947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (stat & AUART_STAT_OERR) 20047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.icount.overrun++; 20147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 20247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (uart_handle_sysrq_char(&s->port, c)) 20347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer goto out; 20447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 20547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer uart_insert_char(&s->port, stat, AUART_STAT_OERR, c, flag); 20647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout: 20747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(stat, s->port.membase + AUART_STAT); 20847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 20947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 21047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_rx_chars(struct mxs_auart_port *s) 21147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 21247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct tty_struct *tty = s->port.state->port.tty; 21347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u32 stat = 0; 21447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 21547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer for (;;) { 21647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer stat = readl(s->port.membase + AUART_STAT); 21747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (stat & AUART_STAT_RXFE) 21847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer break; 21947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer mxs_auart_rx_char(s); 22047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 22147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 22247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(stat, s->port.membase + AUART_STAT); 22347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer tty_flip_buffer_push(tty); 22447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 22547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 22647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int mxs_auart_request_port(struct uart_port *u) 22747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 22847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return 0; 22947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 23047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 23147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int mxs_auart_verify_port(struct uart_port *u, 23247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct serial_struct *ser) 23347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 23447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (u->type != PORT_UNKNOWN && u->type != PORT_IMX) 23547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return -EINVAL; 23647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return 0; 23747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 23847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 23947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_config_port(struct uart_port *u, int flags) 24047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 24147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 24247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 24347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic const char *mxs_auart_type(struct uart_port *u) 24447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 24547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s = to_auart_port(u); 24647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 24747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return dev_name(s->dev); 24847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 24947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 25047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_release_port(struct uart_port *u) 25147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 25247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 25347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 25447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) 25547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 25647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s = to_auart_port(u); 25747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 25847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u32 ctrl = readl(u->membase + AUART_CTRL2); 25947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 26047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl &= ~AUART_CTRL2_RTS; 26147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (mctrl & TIOCM_RTS) 26247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl |= AUART_CTRL2_RTS; 26347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->ctrl = mctrl; 26447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(ctrl, u->membase + AUART_CTRL2); 26547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 26647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 26747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic u32 mxs_auart_get_mctrl(struct uart_port *u) 26847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 26947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s = to_auart_port(u); 27047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u32 stat = readl(u->membase + AUART_STAT); 27147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int ctrl2 = readl(u->membase + AUART_CTRL2); 27247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u32 mctrl = s->ctrl; 27347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 27447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer mctrl &= ~TIOCM_CTS; 27547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (stat & AUART_STAT_CTS) 27647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer mctrl |= TIOCM_CTS; 27747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 27847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (ctrl2 & AUART_CTRL2_RTS) 27947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer mctrl |= TIOCM_RTS; 28047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 28147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return mctrl; 28247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 28347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 28447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_settermios(struct uart_port *u, 28547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct ktermios *termios, 28647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct ktermios *old) 28747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 28847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u32 bm, ctrl, ctrl2, div; 28947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer unsigned int cflag, baud; 29047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 29147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer cflag = termios->c_cflag; 29247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 29347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl = AUART_LINECTRL_FEN; 29447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl2 = readl(u->membase + AUART_CTRL2); 29547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 29647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* byte size */ 29747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer switch (cflag & CSIZE) { 29847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer case CS5: 29947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer bm = 0; 30047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer break; 30147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer case CS6: 30247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer bm = 1; 30347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer break; 30447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer case CS7: 30547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer bm = 2; 30647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer break; 30747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer case CS8: 30847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer bm = 3; 30947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer break; 31047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer default: 31147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return; 31247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 31347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 31447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl |= AUART_LINECTRL_WLEN(bm); 31547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 31647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* parity */ 31747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (cflag & PARENB) { 31847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl |= AUART_LINECTRL_PEN; 31947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if ((cflag & PARODD) == 0) 32047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl |= AUART_LINECTRL_EPS; 32147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 32247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 32347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->read_status_mask = 0; 32447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 32547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (termios->c_iflag & INPCK) 32647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->read_status_mask |= AUART_STAT_PERR; 32747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (termios->c_iflag & (BRKINT | PARMRK)) 32847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->read_status_mask |= AUART_STAT_BERR; 32947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 33047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* 33147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Characters to ignore 33247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer */ 33347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->ignore_status_mask = 0; 33447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (termios->c_iflag & IGNPAR) 33547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->ignore_status_mask |= AUART_STAT_PERR; 33647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (termios->c_iflag & IGNBRK) { 33747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->ignore_status_mask |= AUART_STAT_BERR; 33847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* 33947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * If we're ignoring parity and break indicators, 34047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * ignore overruns too (for real raw support). 34147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer */ 34247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (termios->c_iflag & IGNPAR) 34347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->ignore_status_mask |= AUART_STAT_OERR; 34447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 34547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 34647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* 34747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * ignore all characters if CREAD is not set 34847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer */ 34947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (cflag & CREAD) 35047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl2 |= AUART_CTRL2_RXE; 35147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer else 35247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl2 &= ~AUART_CTRL2_RXE; 35347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 35447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* figure out the stop bits requested */ 35547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (cflag & CSTOPB) 35647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl |= AUART_LINECTRL_STP2; 35747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 35847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* figure out the hardware flow control settings */ 35947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (cflag & CRTSCTS) 36047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl2 |= AUART_CTRL2_CTSEN; 36147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer else 36247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl2 &= ~AUART_CTRL2_CTSEN; 36347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 36447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* set baud rate */ 36547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk); 36647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer div = u->uartclk * 32 / baud; 36747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl |= AUART_LINECTRL_BAUD_DIVFRAC(div & 0x3F); 36847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ctrl |= AUART_LINECTRL_BAUD_DIVINT(div >> 6); 36947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 37047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(ctrl, u->membase + AUART_LINECTRL); 37147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(ctrl2, u->membase + AUART_CTRL2); 3722fa8ba3d8d0f49c4b087a026889a1154c3d94901Lothar Waßmann 3732fa8ba3d8d0f49c4b087a026889a1154c3d94901Lothar Waßmann uart_update_timeout(u, termios->c_cflag, baud); 37447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 37547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 37647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic irqreturn_t mxs_auart_irq_handle(int irq, void *context) 37747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 37847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u32 istatus, istat; 37947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s = context; 38047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u32 stat = readl(s->port.membase + AUART_STAT); 38147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 38247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer istatus = istat = readl(s->port.membase + AUART_INTR); 38347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 38447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (istat & AUART_INTR_CTSMIS) { 38547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS); 38647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_INTR_CTSMIS, 38747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.membase + AUART_INTR_CLR); 38847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer istat &= ~AUART_INTR_CTSMIS; 38947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 39047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 39147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (istat & (AUART_INTR_RTIS | AUART_INTR_RXIS)) { 39247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer mxs_auart_rx_chars(s); 39347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer istat &= ~(AUART_INTR_RTIS | AUART_INTR_RXIS); 39447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 39547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 39647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (istat & AUART_INTR_TXIS) { 39747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer mxs_auart_tx_chars(s); 39847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer istat &= ~AUART_INTR_TXIS; 39947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 40047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 40147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(istatus & (AUART_INTR_RTIS 40247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer | AUART_INTR_TXIS 40347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer | AUART_INTR_RXIS 40447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer | AUART_INTR_CTSMIS), 40547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.membase + AUART_INTR_CLR); 40647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 40747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return IRQ_HANDLED; 40847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 40947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 41047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_reset(struct uart_port *u) 41147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 41247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int i; 41347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer unsigned int reg; 41447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 41547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_CLR); 41647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 41747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer for (i = 0; i < 10000; i++) { 41847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer reg = readl(u->membase + AUART_CTRL0); 41947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (!(reg & AUART_CTRL0_SFTRST)) 42047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer break; 42147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer udelay(3); 42247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 42347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); 42447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 42547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 42647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int mxs_auart_startup(struct uart_port *u) 42747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 42847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s = to_auart_port(u); 42947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 430a481377013c1c07dac0421886db7a6b4c3081c49Shawn Guo clk_prepare_enable(s->clk); 43147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 43247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); 43347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 43447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_SET); 43547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 43647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, 43747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->membase + AUART_INTR); 43847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 43947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* 44047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Enable fifo so all four bytes of a DMA word are written to 44147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * output (otherwise, only the LSB is written, ie. 1 in 4 bytes) 44247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer */ 44347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_LINECTRL_FEN, u->membase + AUART_LINECTRL_SET); 44447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 44547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return 0; 44647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 44747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 44847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_shutdown(struct uart_port *u) 44947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 45047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s = to_auart_port(u); 45147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 45247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR); 45347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 45447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET); 45547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 45647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, 45747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->membase + AUART_INTR_CLR); 45847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 459a481377013c1c07dac0421886db7a6b4c3081c49Shawn Guo clk_disable_unprepare(s->clk); 46047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 46147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 46247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic unsigned int mxs_auart_tx_empty(struct uart_port *u) 46347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 46447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (readl(u->membase + AUART_STAT) & AUART_STAT_TXFE) 46547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return TIOCSER_TEMT; 46647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer else 46747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return 0; 46847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 46947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 47047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_start_tx(struct uart_port *u) 47147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 47247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s = to_auart_port(u); 47347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 47447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* enable transmitter */ 47547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_SET); 47647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 47747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer mxs_auart_tx_chars(s); 47847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 47947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 48047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_stop_tx(struct uart_port *u) 48147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 48247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_CLR); 48347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 48447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 48547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_stop_rx(struct uart_port *u) 48647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 48747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL2_RXE, u->membase + AUART_CTRL2_CLR); 48847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 48947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 49047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_break_ctl(struct uart_port *u, int ctl) 49147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 49247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (ctl) 49347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_LINECTRL_BRK, 49447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->membase + AUART_LINECTRL_SET); 49547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer else 49647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_LINECTRL_BRK, 49747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u->membase + AUART_LINECTRL_CLR); 49847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 49947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 50047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_enable_ms(struct uart_port *port) 50147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 50247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* just empty */ 50347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 50447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 50547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct uart_ops mxs_auart_ops = { 50647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .tx_empty = mxs_auart_tx_empty, 50747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .start_tx = mxs_auart_start_tx, 50847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .stop_tx = mxs_auart_stop_tx, 50947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .stop_rx = mxs_auart_stop_rx, 51047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .enable_ms = mxs_auart_enable_ms, 51147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .break_ctl = mxs_auart_break_ctl, 51247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .set_mctrl = mxs_auart_set_mctrl, 51347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .get_mctrl = mxs_auart_get_mctrl, 51447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .startup = mxs_auart_startup, 51547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .shutdown = mxs_auart_shutdown, 51647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .set_termios = mxs_auart_settermios, 51747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .type = mxs_auart_type, 51847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .release_port = mxs_auart_release_port, 51947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .request_port = mxs_auart_request_port, 52047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .config_port = mxs_auart_config_port, 52147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .verify_port = mxs_auart_verify_port, 52247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}; 52347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 52447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct mxs_auart_port *auart_port[MXS_AUART_PORTS]; 52547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 52647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE 52747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_console_putchar(struct uart_port *port, int ch) 52847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 52947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer unsigned int to = 1000; 53047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 53147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer while (readl(port->membase + AUART_STAT) & AUART_STAT_TXFF) { 53247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (!to--) 53347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer break; 53447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer udelay(1); 53547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 53647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 53747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(ch, port->membase + AUART_DATA); 53847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 53947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 54047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void 54147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerauart_console_write(struct console *co, const char *str, unsigned int count) 54247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 54347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s; 54447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct uart_port *port; 54547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer unsigned int old_ctrl0, old_ctrl2; 54647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer unsigned int to = 1000; 54747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 54847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (co->index > MXS_AUART_PORTS || co->index < 0) 54947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return; 55047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 55147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s = auart_port[co->index]; 55247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer port = &s->port; 55347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 55447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer clk_enable(s->clk); 55547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 55647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* First save the CR then disable the interrupts */ 55747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer old_ctrl2 = readl(port->membase + AUART_CTRL2); 55847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer old_ctrl0 = readl(port->membase + AUART_CTRL0); 55947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 56047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL0_CLKGATE, 56147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer port->membase + AUART_CTRL0_CLR); 56247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(AUART_CTRL2_UARTEN | AUART_CTRL2_TXE, 56347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer port->membase + AUART_CTRL2_SET); 56447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 56547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer uart_console_write(port, str, count, mxs_auart_console_putchar); 56647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 56747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* 56847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Finally, wait for transmitter to become empty 56947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * and restore the TCR 57047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer */ 57147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) { 57247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (!to--) 57347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer break; 57447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer udelay(1); 57547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 57647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 57747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(old_ctrl0, port->membase + AUART_CTRL0); 57847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer writel(old_ctrl2, port->membase + AUART_CTRL2); 57947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 58047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer clk_disable(s->clk); 58147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 58247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 58347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void __init 58447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerauart_console_get_options(struct uart_port *port, int *baud, 58547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int *parity, int *bits) 58647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 58747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer unsigned int lcr_h, quot; 58847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 58947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (!(readl(port->membase + AUART_CTRL2) & AUART_CTRL2_UARTEN)) 59047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return; 59147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 59247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer lcr_h = readl(port->membase + AUART_LINECTRL); 59347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 59447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *parity = 'n'; 59547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (lcr_h & AUART_LINECTRL_PEN) { 59647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (lcr_h & AUART_LINECTRL_EPS) 59747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *parity = 'e'; 59847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer else 59947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *parity = 'o'; 60047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 60147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 60247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(2)) 60347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *bits = 7; 60447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer else 60547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *bits = 8; 60647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 60747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer quot = ((readl(port->membase + AUART_LINECTRL) 60847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer & AUART_LINECTRL_BAUD_DIVINT_MASK)) 60947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer >> (AUART_LINECTRL_BAUD_DIVINT_SHIFT - 6); 61047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer quot |= ((readl(port->membase + AUART_LINECTRL) 61147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer & AUART_LINECTRL_BAUD_DIVFRAC_MASK)) 61247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer >> AUART_LINECTRL_BAUD_DIVFRAC_SHIFT; 61347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (quot == 0) 61447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer quot = 1; 61547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 61647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *baud = (port->uartclk << 2) / quot; 61747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 61847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 61947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int __init 62047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerauart_console_setup(struct console *co, char *options) 62147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 62247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s; 62347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int baud = 9600; 62447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int bits = 8; 62547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int parity = 'n'; 62647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int flow = 'n'; 62747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int ret; 62847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 62947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer /* 63047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Check whether an invalid uart number has been specified, and 63147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * if so, search for the first available port that does have 63247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * console support. 63347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer */ 63447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (co->index == -1 || co->index >= ARRAY_SIZE(auart_port)) 63547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer co->index = 0; 63647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s = auart_port[co->index]; 63747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (!s) 63847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return -ENODEV; 63947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 640a481377013c1c07dac0421886db7a6b4c3081c49Shawn Guo clk_prepare_enable(s->clk); 64147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 64247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (options) 64347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer uart_parse_options(options, &baud, &parity, &bits, &flow); 64447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer else 64547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer auart_console_get_options(&s->port, &baud, &parity, &bits); 64647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 64747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ret = uart_set_options(&s->port, co, baud, parity, bits, flow); 64847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 649a481377013c1c07dac0421886db7a6b4c3081c49Shawn Guo clk_disable_unprepare(s->clk); 65047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 65147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return ret; 65247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 65347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 65447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct console auart_console = { 65547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .name = "ttyAPP", 65647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .write = auart_console_write, 65747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .device = uart_console_device, 65847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .setup = auart_console_setup, 65947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .flags = CON_PRINTBUFFER, 66047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .index = -1, 66147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .data = &auart_driver, 66247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}; 66347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#endif 66447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 66547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct uart_driver auart_driver = { 66647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .owner = THIS_MODULE, 66747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .driver_name = "ttyAPP", 66847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .dev_name = "ttyAPP", 66947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .major = 0, 67047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .minor = 0, 67147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .nr = MXS_AUART_PORTS, 67247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE 67347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .cons = &auart_console, 67447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#endif 67547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}; 67647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 67747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int __devinit mxs_auart_probe(struct platform_device *pdev) 67847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 67947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s; 68047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer u32 version; 68147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int ret = 0; 68247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct resource *r; 68347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 68447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL); 68547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (!s) { 68647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ret = -ENOMEM; 68747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer goto out; 68847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 68947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 69047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->clk = clk_get(&pdev->dev, NULL); 69147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (IS_ERR(s->clk)) { 69247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ret = PTR_ERR(s->clk); 69347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer goto out_free; 69447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 69547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 69647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 69747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (!r) { 69847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ret = -ENXIO; 69947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer goto out_free_clk; 70047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer } 70147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 70247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.mapbase = r->start; 70347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.membase = ioremap(r->start, resource_size(r)); 70447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.ops = &mxs_auart_ops; 70547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.iotype = UPIO_MEM; 70647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.line = pdev->id < 0 ? 0 : pdev->id; 70747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.fifosize = 16; 70847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.uartclk = clk_get_rate(s->clk); 70947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.type = PORT_IMX; 71047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.dev = s->dev = get_device(&pdev->dev); 71147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 71247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->flags = 0; 71347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->ctrl = 0; 71447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 71547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->irq = platform_get_irq(pdev, 0); 71647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer s->port.irq = s->irq; 71747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s); 71847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (ret) 71947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer goto out_free_clk; 72047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 72147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer platform_set_drvdata(pdev, s); 72247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 72347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer auart_port[pdev->id] = s; 72447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 72547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer mxs_auart_reset(&s->port); 72647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 72747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer ret = uart_add_one_port(&auart_driver, &s->port); 72847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (ret) 72947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer goto out_free_irq; 73047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 73147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer version = readl(s->port.membase + AUART_VERSION); 73247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n", 73347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer (version >> 24) & 0xff, 73447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer (version >> 16) & 0xff, version & 0xffff); 73547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 73647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return 0; 73747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 73847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout_free_irq: 73947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer auart_port[pdev->id] = NULL; 74047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer free_irq(s->irq, s); 74147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout_free_clk: 74247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer clk_put(s->clk); 74347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout_free: 74447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer kfree(s); 74547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout: 74647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return ret; 74747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 74847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 74947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int __devexit mxs_auart_remove(struct platform_device *pdev) 75047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 75147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer struct mxs_auart_port *s = platform_get_drvdata(pdev); 75247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 75347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer uart_remove_one_port(&auart_driver, &s->port); 75447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 75547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer auart_port[pdev->id] = NULL; 75647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 75747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer clk_put(s->clk); 75847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer free_irq(s->irq, s); 75947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer kfree(s); 76047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 76147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return 0; 76247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 76347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 76447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct platform_driver mxs_auart_driver = { 76547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .probe = mxs_auart_probe, 76647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .remove = __devexit_p(mxs_auart_remove), 76747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .driver = { 76847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .name = "mxs-auart", 76947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer .owner = THIS_MODULE, 77047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer }, 77147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}; 77247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 77347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int __init mxs_auart_init(void) 77447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 77547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer int r; 77647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 77747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer r = uart_register_driver(&auart_driver); 77847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (r) 77947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer goto out; 78047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 78147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer r = platform_driver_register(&mxs_auart_driver); 78247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer if (r) 78347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer goto out_err; 78447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 78547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return 0; 78647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout_err: 78747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer uart_unregister_driver(&auart_driver); 78847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout: 78947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer return r; 79047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 79147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 79247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void __exit mxs_auart_exit(void) 79347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{ 79447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer platform_driver_unregister(&mxs_auart_driver); 79547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer uart_unregister_driver(&auart_driver); 79647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer} 79747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer 79847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauermodule_init(mxs_auart_init); 79947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauermodule_exit(mxs_auart_exit); 80047d37d6f94ccf32d302492f969209930b2411f9eSascha HauerMODULE_LICENSE("GPL"); 80147d37d6f94ccf32d302492f969209930b2411f9eSascha HauerMODULE_DESCRIPTION("Freescale MXS application uart driver"); 802