11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on drivers/serial/8250.c by Russell King. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: Nicolas Pitre 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Created: Feb 20, 2003 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright: (C) 2003 Monta Vista Software, Inc. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note 1: This driver is made separate from the already too overloaded 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8250.c because it needs some kirks of its own and that'll make it 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * easier to add DMA support. 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note 2: I'm too sick of device allocation policies for serial ports. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If someone else wants to request an "official" allocation of major/minor 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for this driver please be my guest. And don't forget that new hardware 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to come from Intel might have more than 3 or 4 of those UARTs. Let's 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hope for a better port registration and dynamic device allocation scheme 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the serial core maintainer satisfaction to appear soon. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SUPPORT_SYSRQ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sysrq.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial_reg.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/circ_buf.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 39699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang#include <linux/of.h> 40d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial_core.h> 44b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King#include <linux/clk.h> 45290a5589ce83540d0aba811c3d15af34aa373533Eric Miao#include <linux/io.h> 465a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang#define PXA_NAME_LEN 8 49699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct uart_pxa_port { 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_port port; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char ier; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char lcr; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char mcr; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int lsr_break_flag; 56b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King struct clk *clk; 57699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang char name[PXA_NAME_LEN]; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned int serial_in(struct uart_pxa_port *up, int offset) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset <<= 2; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return readl(up->port.membase + offset); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void serial_out(struct uart_pxa_port *up, int offset, int value) 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset <<= 2; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(value, up->port.membase + offset); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_enable_ms(struct uart_port *port) 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->ier |= UART_IER_MSI; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_IER, up->ier); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80b129a8ccd53f74c43e4c83c8e0031a4990040830Russell Kingstatic void serial_pxa_stop_tx(struct uart_port *port) 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (up->ier & UART_IER_THRI) { 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->ier &= ~UART_IER_THRI; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_IER, up->ier); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_stop_rx(struct uart_port *port) 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->ier &= ~UART_IER_RLSI; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.read_status_mask &= ~UART_LSR_DR; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_IER, up->ier); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 997d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic inline void receive_chars(struct uart_pxa_port *up, int *status) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 101ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct tty_struct *tty = up->port.state->port.tty; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ch, flag; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_count = 256; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 106e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson /* work around Errata #20 according to 107e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * Intel(R) PXA27x Processor Family 108e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * Specification Update (May 2005) 109e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * 110e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * Step 2 111e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * Disable the Reciever Time Out Interrupt via IER[RTOEI] 112e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson */ 113e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson up->ier &= ~UART_IER_RTOIE; 114e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson serial_out(up, UART_IER, up->ier); 115e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ch = serial_in(up, UART_RX); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flag = TTY_NORMAL; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.icount.rx++; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds UART_LSR_FE | UART_LSR_OE))) { 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For statistics only 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*status & UART_LSR_BI) { 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *status &= ~(UART_LSR_FE | UART_LSR_PE); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.icount.brk++; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We do the SysRQ and SAK checking 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here because otherwise the break 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may get masked by ignore_status_mask 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or read_status_mask. 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_handle_break(&up->port)) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto ignore_char; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (*status & UART_LSR_PE) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.icount.parity++; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (*status & UART_LSR_FE) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.icount.frame++; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*status & UART_LSR_OE) 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.icount.overrun++; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Mask off conditions which should be ignored. 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *status &= up->port.read_status_mask; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SERIAL_PXA_CONSOLE 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (up->port.line == up->port.cons->index) { 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Recover the break flag from console xmit */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *status |= up->lsr_break_flag; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->lsr_break_flag = 0; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*status & UART_LSR_BI) { 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flag = TTY_BREAK; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (*status & UART_LSR_PE) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flag = TTY_PARITY; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (*status & UART_LSR_FE) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flag = TTY_FRAME; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16205ab3014636ff60a319d37cdf37dca594b015eecRussell King 1637d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells if (uart_handle_sysrq_char(&up->port, ch)) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto ignore_char; 16505ab3014636ff60a319d37cdf37dca594b015eecRussell King 16605ab3014636ff60a319d37cdf37dca594b015eecRussell King uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); 16705ab3014636ff60a319d37cdf37dca594b015eecRussell King 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ignore_char: 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *status = serial_in(up, UART_LSR); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while ((*status & UART_LSR_DR) && (max_count-- > 0)); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flip_buffer_push(tty); 172e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson 173e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson /* work around Errata #20 according to 174e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * Intel(R) PXA27x Processor Family 175e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * Specification Update (May 2005) 176e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * 177e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * Step 6: 178e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE] 179e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson */ 180e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson up->ier |= UART_IER_RTOIE; 181e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson serial_out(up, UART_IER, up->ier); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void transmit_chars(struct uart_pxa_port *up) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 186ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox struct circ_buf *xmit = &up->port.state->xmit; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (up->port.x_char) { 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_TX, up->port.x_char); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.icount.tx++; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.x_char = 0; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { 196b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King serial_pxa_stop_tx(&up->port); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = up->port.fifosize / 2; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_TX, xmit->buf[xmit->tail]); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.icount.tx++; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_empty(xmit)) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (--count > 0); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_write_wakeup(&up->port); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (uart_circ_empty(xmit)) 214b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King serial_pxa_stop_tx(&up->port); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 217b129a8ccd53f74c43e4c83c8e0031a4990040830Russell Kingstatic void serial_pxa_start_tx(struct uart_port *port) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(up->ier & UART_IER_THRI)) { 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->ier |= UART_IER_THRI; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_IER, up->ier); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void check_modem_status(struct uart_pxa_port *up) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = serial_in(up, UART_MSR); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & UART_MSR_ANY_DELTA) == 0) 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART_MSR_TERI) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.icount.rng++; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART_MSR_DDSR) 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.icount.dsr++; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART_MSR_DDCD) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART_MSR_DCTS) 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_handle_cts_change(&up->port, status & UART_MSR_CTS); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 245bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox wake_up_interruptible(&up->port.state->port.delta_msr_wait); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This handles the interrupt from one port. 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2517d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 253c7bec5aba52392aa8d675b8722735caf4a8b7265Jeff Garzik struct uart_pxa_port *up = dev_id; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int iir, lsr; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iir = serial_in(up, UART_IIR); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (iir & UART_IIR_NO_INT) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lsr = serial_in(up, UART_LSR); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lsr & UART_LSR_DR) 2617d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells receive_chars(up, &lsr); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds check_modem_status(up); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lsr & UART_LSR_THRE) 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds transmit_chars(up); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int serial_pxa_tx_empty(struct uart_port *port) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ret; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&up->port.lock, flags); 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&up->port.lock, flags); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int serial_pxa_get_mctrl(struct uart_port *port) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char status; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ret; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = serial_in(up, UART_MSR); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART_MSR_DCD) 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret |= TIOCM_CAR; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART_MSR_RI) 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret |= TIOCM_RNG; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART_MSR_DSR) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret |= TIOCM_DSR; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART_MSR_CTS) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret |= TIOCM_CTS; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl) 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char mcr = 0; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mctrl & TIOCM_RTS) 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr |= UART_MCR_RTS; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mctrl & TIOCM_DTR) 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr |= UART_MCR_DTR; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mctrl & TIOCM_OUT1) 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr |= UART_MCR_OUT1; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mctrl & TIOCM_OUT2) 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr |= UART_MCR_OUT2; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mctrl & TIOCM_LOOP) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr |= UART_MCR_LOOP; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr |= up->mcr; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_MCR, mcr); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_break_ctl(struct uart_port *port, int break_state) 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&up->port.lock, flags); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (break_state == -1) 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->lcr |= UART_LCR_SBC; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->lcr &= ~UART_LCR_SBC; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_LCR, up->lcr); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&up->port.lock, flags); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_dma_init(struct pxa_uart *up) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->rxdma = 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (up->rxdma < 0) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->txdma = 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (up->txdma < 0) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_txdma; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!up->dmadesc) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_alloc; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ... */ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_alloc: 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxa_free_dma(up->txdma); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_rxdma: 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pxa_free_dma(up->rxdma); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int serial_pxa_startup(struct uart_port *port) 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 367d9e29649875df82828167dd45c802d942db863baMatt Reimer if (port->line == 3) /* HWUART */ 368d9e29649875df82828167dd45c802d942db863baMatt Reimer up->mcr |= UART_MCR_AFE; 369d9e29649875df82828167dd45c802d942db863baMatt Reimer else 370f02aa3f9a3dea4375759ae1d87bebf2467719b72Erik Hovland up->mcr = 0; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 372b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King up->port.uartclk = clk_get_rate(up->clk); 373b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the IRQ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the FIFO buffers and disable them. 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (they will be reenabled in set_termios()) 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_FCR, 0); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the interrupt registers. 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) serial_in(up, UART_LSR); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) serial_in(up, UART_RX); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) serial_in(up, UART_IIR); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) serial_in(up, UART_MSR); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now, initialize the UART 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_LCR, UART_LCR_WLEN8); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&up->port.lock, flags); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.mctrl |= TIOCM_OUT2; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_pxa_set_mctrl(&up->port, up->port.mctrl); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&up->port.lock, flags); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finally, enable interrupts. Note: Modem status interrupts 41080f7228b59e4bbe9d840af3ff0f2fe480d6e7c79Adrian Bunk * are set via set_termios(), which will be occurring imminently 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * anyway, so we don't enable them here. 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_IER, up->ier); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And clear the interrupt registers again for luck. 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) serial_in(up, UART_LSR); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) serial_in(up, UART_RX); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) serial_in(up, UART_IIR); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) serial_in(up, UART_MSR); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_shutdown(struct uart_port *port) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(up->port.irq, up); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable interrupts from this port 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->ier = 0; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_IER, 0); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&up->port.lock, flags); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.mctrl &= ~TIOCM_OUT2; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_pxa_set_mctrl(&up->port, up->port.mctrl); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&up->port.lock, flags); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable break condition and FIFOs 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds UART_FCR_CLEAR_RCVR | 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds UART_FCR_CLEAR_XMIT); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_FCR, 0); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 456606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxserial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, 457606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *old) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char cval, fcr = 0; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int baud, quot; 463c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König unsigned int dll; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (termios->c_cflag & CSIZE) { 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS5: 4670a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King cval = UART_LCR_WLEN5; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS6: 4700a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King cval = UART_LCR_WLEN6; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS7: 4730a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King cval = UART_LCR_WLEN7; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CS8: 4770a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King cval = UART_LCR_WLEN8; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & CSTOPB) 4820a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King cval |= UART_LCR_STOP; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_cflag & PARENB) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cval |= UART_LCR_PARITY; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(termios->c_cflag & PARODD)) 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cval |= UART_LCR_EPAR; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ask the core to calculate the divisor for us. 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds quot = uart_get_divisor(port, baud); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((up->port.uartclk / quot) < (2400 * 16)) 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; 496d9e29649875df82828167dd45c802d942db863baMatt Reimer else if ((up->port.uartclk / quot) < (230400 * 16)) 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8; 498d9e29649875df82828167dd45c802d942db863baMatt Reimer else 499d9e29649875df82828167dd45c802d942db863baMatt Reimer fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ok, we're now changing the port state. Do it with 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts disabled. 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&up->port.lock, flags); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ensure the port will be enabled. 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is required especially for serial console. 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 511290a5589ce83540d0aba811c3d15af34aa373533Eric Miao up->ier |= UART_IER_UUE; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the per-port timeout. 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 516e6158b4a5647624ceb90074bfcc248ea3152c906Lothar Wassmann uart_update_timeout(port, termios->c_cflag, baud); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & INPCK) 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & (BRKINT | PARMRK)) 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.read_status_mask |= UART_LSR_BI; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Characters to ignore 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.ignore_status_mask = 0; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & IGNPAR) 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & IGNBRK) { 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.ignore_status_mask |= UART_LSR_BI; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're ignoring parity and break indicators, 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ignore overruns too (for real raw support). 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (termios->c_iflag & IGNPAR) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.ignore_status_mask |= UART_LSR_OE; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ignore all characters if CREAD is not set 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((termios->c_cflag & CREAD) == 0) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.ignore_status_mask |= UART_LSR_DR; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CTS flow control flag and modem status interrupts 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->ier &= ~UART_IER_MSI; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (UART_ENABLE_MS(&up->port, termios->c_cflag)) 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->ier |= UART_IER_MSI; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_IER, up->ier); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5552276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik if (termios->c_cflag & CRTSCTS) 5562276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik up->mcr |= UART_MCR_AFE; 5572276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik else 5582276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik up->mcr &= ~UART_MCR_AFE; 5592276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik 560c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ 562c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König 563c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König /* 564c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König * work around Errata #75 according to Intel(R) PXA27x Processor Family 565c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König * Specification Update (Nov 2005) 566c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König */ 567c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König dll = serial_in(up, UART_DLL); 568c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König WARN_ON(dll != (quot & 0xff)); 569c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ 571c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König serial_out(up, UART_LCR, cval); /* reset DLAB */ 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->lcr = cval; /* Save LCR */ 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_pxa_set_mctrl(&up->port, up->port.mctrl); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_FCR, fcr); 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&up->port.lock, flags); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_pm(struct uart_port *port, unsigned int state, 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int oldstate) 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 583b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!state) 585fb8ebec00b04f921ea1614a7303f1a8e5e9e47c5Philipp Zabel clk_prepare_enable(up->clk); 586b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King else 587fb8ebec00b04f921ea1614a7303f1a8e5e9e47c5Philipp Zabel clk_disable_unprepare(up->clk); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_release_port(struct uart_port *port) 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int serial_pxa_request_port(struct uart_port *port) 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_config_port(struct uart_port *port, int flags) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->port.type = PORT_PXA; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser) 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we don't want the core code to modify any port params */ 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char * 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_type(struct uart_port *port) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up = (struct uart_pxa_port *)port; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return up->name; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 619e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell Kingstatic struct uart_pxa_port *serial_pxa_ports[4]; 6202d93486c6c110cf81db720359b4ec20de9c91450Vincent Sandersstatic struct uart_driver serial_pxa_reg; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 622fa7f1518e8a107e1feab0357b18c745b9a6927c5Philipp Zabel#ifdef CONFIG_SERIAL_PXA_CONSOLE 623fa7f1518e8a107e1feab0357b18c745b9a6927c5Philipp Zabel 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for transmitter & holding register to empty 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void wait_for_xmitr(struct uart_pxa_port *up) 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status, tmout = 10000; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait up to 10ms for the character(s) to be sent. */ 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = serial_in(up, UART_LSR); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & UART_LSR_BI) 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up->lsr_break_flag = UART_LSR_BI; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (--tmout == 0) 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while ((status & BOTH_EMPTY) != BOTH_EMPTY); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait up to 1s for flow control if necessary */ 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (up->port.flags & UPF_CONS_FLOW) { 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmout = 1000000; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (--tmout && 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 654d358788f3f30113e49882187d794832905e42592Russell Kingstatic void serial_pxa_console_putchar(struct uart_port *port, int ch) 655d358788f3f30113e49882187d794832905e42592Russell King{ 656d358788f3f30113e49882187d794832905e42592Russell King struct uart_pxa_port *up = (struct uart_pxa_port *)port; 657d358788f3f30113e49882187d794832905e42592Russell King 658d358788f3f30113e49882187d794832905e42592Russell King wait_for_xmitr(up); 659d358788f3f30113e49882187d794832905e42592Russell King serial_out(up, UART_TX, ch); 660d358788f3f30113e49882187d794832905e42592Russell King} 661d358788f3f30113e49882187d794832905e42592Russell King 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Print a string to the serial port trying not to disturb 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any possible real use of the port... 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The console_lock must be held when we get here. 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_console_write(struct console *co, const char *s, unsigned int count) 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 671e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King struct uart_pxa_port *up = serial_pxa_ports[co->index]; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ier; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 674fb8ebec00b04f921ea1614a7303f1a8e5e9e47c5Philipp Zabel clk_prepare_enable(up->clk); 675b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 677f02aa3f9a3dea4375759ae1d87bebf2467719b72Erik Hovland * First save the IER then disable the interrupts 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ier = serial_in(up, UART_IER); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_IER, UART_IER_UUE); 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 682d358788f3f30113e49882187d794832905e42592Russell King uart_console_write(&up->port, s, count, serial_pxa_console_putchar); 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finally, wait for transmitter to become empty 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and restore the IER 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_for_xmitr(up); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial_out(up, UART_IER, ier); 690b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King 691fb8ebec00b04f921ea1614a7303f1a8e5e9e47c5Philipp Zabel clk_disable_unprepare(up->clk); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_console_setup(struct console *co, char *options) 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct uart_pxa_port *up; 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int baud = 9600; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bits = 8; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int parity = 'n'; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flow = 'n'; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (co->index == -1 || co->index >= serial_pxa_reg.nr) 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds co->index = 0; 705e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King up = serial_pxa_ports[co->index]; 706e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King if (!up) 707e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King return -ENODEV; 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (options) 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_parse_options(options, &baud, &parity, &bits, &flow); 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return uart_set_options(&up->port, co, baud, parity, bits, flow); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct console serial_pxa_console = { 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "ttyS", 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = serial_pxa_console_write, 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .device = uart_console_device, 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .setup = serial_pxa_console_setup, 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flags = CON_PRINTBUFFER, 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .index = -1, 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .data = &serial_pxa_reg, 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PXA_CONSOLE &serial_pxa_console 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PXA_CONSOLE NULL 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct uart_ops serial_pxa_pops = { 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tx_empty = serial_pxa_tx_empty, 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_mctrl = serial_pxa_set_mctrl, 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_mctrl = serial_pxa_get_mctrl, 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop_tx = serial_pxa_stop_tx, 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .start_tx = serial_pxa_start_tx, 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .stop_rx = serial_pxa_stop_rx, 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .enable_ms = serial_pxa_enable_ms, 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .break_ctl = serial_pxa_break_ctl, 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .startup = serial_pxa_startup, 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .shutdown = serial_pxa_shutdown, 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = serial_pxa_set_termios, 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pm = serial_pxa_pm, 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .type = serial_pxa_type, 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release_port = serial_pxa_release_port, 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .request_port = serial_pxa_request_port, 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .config_port = serial_pxa_config_port, 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .verify_port = serial_pxa_verify_port, 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_driver serial_pxa_reg = { 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_name = "PXA serial", 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dev_name = "ttyS", 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .major = TTY_MAJOR, 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .minor = 64, 756e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King .nr = 4, 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cons = PXA_CONSOLE, 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 760bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport#ifdef CONFIG_PM 761bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoportstatic int serial_pxa_suspend(struct device *dev) 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 763bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport struct uart_pxa_port *sport = dev_get_drvdata(dev); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7659480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King if (sport) 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_suspend_port(&serial_pxa_reg, &sport->port); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoportstatic int serial_pxa_resume(struct device *dev) 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 773bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport struct uart_pxa_port *sport = dev_get_drvdata(dev); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7759480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King if (sport) 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_resume_port(&serial_pxa_reg, &sport->port); 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops serial_pxa_pm_ops = { 782bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport .suspend = serial_pxa_suspend, 783bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport .resume = serial_pxa_resume, 784bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport}; 785bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport#endif 786bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport 787699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuangstatic struct of_device_id serial_pxa_dt_ids[] = { 788699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang { .compatible = "mrvl,pxa-uart", }, 789699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang { .compatible = "mrvl,mmp-uart", }, 790699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang {} 791699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang}; 792699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian ZhuangMODULE_DEVICE_TABLE(of, serial_pxa_dt_ids); 793699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang 794699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuangstatic int serial_pxa_probe_dt(struct platform_device *pdev, 795699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang struct uart_pxa_port *sport) 796699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang{ 797699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang struct device_node *np = pdev->dev.of_node; 798699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang int ret; 799699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang 800699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang if (!np) 801699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang return 1; 802699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang 803699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang ret = of_alias_get_id(np, "serial"); 804699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang if (ret < 0) { 805699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); 806699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang return ret; 807699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang } 808699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang sport->port.line = ret; 809699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang return 0; 810699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang} 811699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang 8123ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int serial_pxa_probe(struct platform_device *dev) 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 814e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King struct uart_pxa_port *sport; 815e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King struct resource *mmres, *irqres; 816e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King int ret; 817e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King 818e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King mmres = platform_get_resource(dev, IORESOURCE_MEM, 0); 819e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0); 820e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King if (!mmres || !irqres) 821e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King return -ENODEV; 822e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King 823e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL); 824e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King if (!sport) 825e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King return -ENOMEM; 826e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King 827e0d8b13ae1e3ea747620580b6f777992148de182Russell King sport->clk = clk_get(&dev->dev, NULL); 828b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King if (IS_ERR(sport->clk)) { 829b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King ret = PTR_ERR(sport->clk); 830b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King goto err_free; 831b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King } 832b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King 833e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King sport->port.type = PORT_PXA; 834e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King sport->port.iotype = UPIO_MEM; 835e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King sport->port.mapbase = mmres->start; 836e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King sport->port.irq = irqres->start; 837e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King sport->port.fifosize = 64; 838e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King sport->port.ops = &serial_pxa_pops; 839e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King sport->port.dev = &dev->dev; 840e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; 841b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King sport->port.uartclk = clk_get_rate(sport->clk); 842e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King 843699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang ret = serial_pxa_probe_dt(dev, sport); 844699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang if (ret > 0) 845699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang sport->port.line = dev->id; 846699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang else if (ret < 0) 847699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang goto err_clk; 848699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1); 849e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King 85028f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches sport->port.membase = ioremap(mmres->start, resource_size(mmres)); 851e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King if (!sport->port.membase) { 852e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King ret = -ENOMEM; 853b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King goto err_clk; 854e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King } 855e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King 856699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang serial_pxa_ports[sport->port.line] = sport; 857e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King 858e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King uart_add_one_port(&serial_pxa_reg, &sport->port); 859e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King platform_set_drvdata(dev, sport); 860e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 862e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King 863b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King err_clk: 864b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King clk_put(sport->clk); 865e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King err_free: 866e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King kfree(sport); 867e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King return ret; 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8703ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int serial_pxa_remove(struct platform_device *dev) 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8723ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King struct uart_pxa_port *sport = platform_get_drvdata(dev); 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8743ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_set_drvdata(dev, NULL); 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 876e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King uart_remove_one_port(&serial_pxa_reg, &sport->port); 877b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King clk_put(sport->clk); 878e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King kfree(sport); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8833ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver serial_pxa_driver = { 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = serial_pxa_probe, 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = serial_pxa_remove, 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8873ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .driver = { 8883ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King .name = "pxa2xx-uart", 889e169c139642fb4c682ec12a409725508dbefa520Kay Sievers .owner = THIS_MODULE, 890bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport#ifdef CONFIG_PM 891bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport .pm = &serial_pxa_pm_ops, 892bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport#endif 893699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang .of_match_table = serial_pxa_dt_ids, 8943ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King }, 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init serial_pxa_init(void) 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = uart_register_driver(&serial_pxa_reg); 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 0) 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9053ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King ret = platform_driver_register(&serial_pxa_driver); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != 0) 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_unregister_driver(&serial_pxa_reg); 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __exit serial_pxa_exit(void) 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9143ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King platform_driver_unregister(&serial_pxa_driver); 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart_unregister_driver(&serial_pxa_reg); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(serial_pxa_init); 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(serial_pxa_exit); 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 922e169c139642fb4c682ec12a409725508dbefa520Kay SieversMODULE_ALIAS("platform:pxa2xx-uart"); 923