1ab4382d2SGreg Kroah-Hartman /* 2ab4382d2SGreg Kroah-Hartman * Driver for OMAP-UART controller. 3ab4382d2SGreg Kroah-Hartman * Based on drivers/serial/8250.c 4ab4382d2SGreg Kroah-Hartman * 5ab4382d2SGreg Kroah-Hartman * Copyright (C) 2010 Texas Instruments. 6ab4382d2SGreg Kroah-Hartman * 7ab4382d2SGreg Kroah-Hartman * Authors: 8ab4382d2SGreg Kroah-Hartman * Govindraj R <govindraj.raja@ti.com> 9ab4382d2SGreg Kroah-Hartman * Thara Gopinath <thara@ti.com> 10ab4382d2SGreg Kroah-Hartman * 11ab4382d2SGreg Kroah-Hartman * This program is free software; you can redistribute it and/or modify 12ab4382d2SGreg Kroah-Hartman * it under the terms of the GNU General Public License as published by 13ab4382d2SGreg Kroah-Hartman * the Free Software Foundation; either version 2 of the License, or 14ab4382d2SGreg Kroah-Hartman * (at your option) any later version. 15ab4382d2SGreg Kroah-Hartman * 1625985edcSLucas De Marchi * Note: This driver is made separate from 8250 driver as we cannot 17ab4382d2SGreg Kroah-Hartman * over load 8250 driver with omap platform specific configuration for 18ab4382d2SGreg Kroah-Hartman * features like DMA, it makes easier to implement features like DMA and 19ab4382d2SGreg Kroah-Hartman * hardware flow control and software flow control configuration with 20ab4382d2SGreg Kroah-Hartman * this driver as required for the omap-platform. 21ab4382d2SGreg Kroah-Hartman */ 22ab4382d2SGreg Kroah-Hartman 23364a6eceSThomas Weber #if defined(CONFIG_SERIAL_OMAP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) 24364a6eceSThomas Weber #define SUPPORT_SYSRQ 25364a6eceSThomas Weber #endif 26364a6eceSThomas Weber 27ab4382d2SGreg Kroah-Hartman #include <linux/module.h> 28ab4382d2SGreg Kroah-Hartman #include <linux/init.h> 29ab4382d2SGreg Kroah-Hartman #include <linux/console.h> 30ab4382d2SGreg Kroah-Hartman #include <linux/serial_reg.h> 31ab4382d2SGreg Kroah-Hartman #include <linux/delay.h> 32ab4382d2SGreg Kroah-Hartman #include <linux/slab.h> 33ab4382d2SGreg Kroah-Hartman #include <linux/tty.h> 34ab4382d2SGreg Kroah-Hartman #include <linux/tty_flip.h> 35d21e4005SFelipe Balbi #include <linux/platform_device.h> 36ab4382d2SGreg Kroah-Hartman #include <linux/io.h> 37ab4382d2SGreg Kroah-Hartman #include <linux/clk.h> 38ab4382d2SGreg Kroah-Hartman #include <linux/serial_core.h> 39ab4382d2SGreg Kroah-Hartman #include <linux/irq.h> 40fcdca757SGovindraj.R #include <linux/pm_runtime.h> 41d92b0dfcSRajendra Nayak #include <linux/of.h> 429574f36fSNeilBrown #include <linux/gpio.h> 433dbc5ce2STony Lindgren #include <linux/pinctrl/consumer.h> 44ab4382d2SGreg Kroah-Hartman 45ab4382d2SGreg Kroah-Hartman #include <plat/omap-serial.h> 46ab4382d2SGreg Kroah-Hartman 477c77c8deSGovindraj.R #define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) 487c77c8deSGovindraj.R 497c77c8deSGovindraj.R #define OMAP_UART_REV_42 0x0402 507c77c8deSGovindraj.R #define OMAP_UART_REV_46 0x0406 517c77c8deSGovindraj.R #define OMAP_UART_REV_52 0x0502 527c77c8deSGovindraj.R #define OMAP_UART_REV_63 0x0603 537c77c8deSGovindraj.R 548fe789dcSRajendra Nayak #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/ 558fe789dcSRajendra Nayak 560ba5f668SPaul Walmsley /* SCR register bitmasks */ 570ba5f668SPaul Walmsley #define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7) 580ba5f668SPaul Walmsley 590ba5f668SPaul Walmsley /* FCR register bitmasks */ 600ba5f668SPaul Walmsley #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6) 616721ab7fSFelipe Balbi #define OMAP_UART_FCR_TX_FIFO_TRIG_MASK (0x3 << 4) 620ba5f668SPaul Walmsley 637c77c8deSGovindraj.R /* MVR register bitmasks */ 647c77c8deSGovindraj.R #define OMAP_UART_MVR_SCHEME_SHIFT 30 657c77c8deSGovindraj.R 667c77c8deSGovindraj.R #define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0 677c77c8deSGovindraj.R #define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4 687c77c8deSGovindraj.R #define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f 697c77c8deSGovindraj.R 707c77c8deSGovindraj.R #define OMAP_UART_MVR_MAJ_MASK 0x700 717c77c8deSGovindraj.R #define OMAP_UART_MVR_MAJ_SHIFT 8 727c77c8deSGovindraj.R #define OMAP_UART_MVR_MIN_MASK 0x3f 737c77c8deSGovindraj.R 74d37c6cebSFelipe Balbi struct uart_omap_port { 75d37c6cebSFelipe Balbi struct uart_port port; 76d37c6cebSFelipe Balbi struct uart_omap_dma uart_dma; 77d37c6cebSFelipe Balbi struct device *dev; 78d37c6cebSFelipe Balbi 79d37c6cebSFelipe Balbi unsigned char ier; 80d37c6cebSFelipe Balbi unsigned char lcr; 81d37c6cebSFelipe Balbi unsigned char mcr; 82d37c6cebSFelipe Balbi unsigned char fcr; 83d37c6cebSFelipe Balbi unsigned char efr; 84d37c6cebSFelipe Balbi unsigned char dll; 85d37c6cebSFelipe Balbi unsigned char dlh; 86d37c6cebSFelipe Balbi unsigned char mdr1; 87d37c6cebSFelipe Balbi unsigned char scr; 88d37c6cebSFelipe Balbi 89d37c6cebSFelipe Balbi int use_dma; 90d37c6cebSFelipe Balbi /* 91d37c6cebSFelipe Balbi * Some bits in registers are cleared on a read, so they must 92d37c6cebSFelipe Balbi * be saved whenever the register is read but the bits will not 93d37c6cebSFelipe Balbi * be immediately processed. 94d37c6cebSFelipe Balbi */ 95d37c6cebSFelipe Balbi unsigned int lsr_break_flag; 96d37c6cebSFelipe Balbi unsigned char msr_saved_flags; 97d37c6cebSFelipe Balbi char name[20]; 98d37c6cebSFelipe Balbi unsigned long port_activity; 9939aee51dSShubhrajyoti D int context_loss_cnt; 100d37c6cebSFelipe Balbi u32 errata; 101d37c6cebSFelipe Balbi u8 wakeups_enabled; 102d37c6cebSFelipe Balbi unsigned int irq_pending:1; 103d37c6cebSFelipe Balbi 104e36851d0SFelipe Balbi int DTR_gpio; 105e36851d0SFelipe Balbi int DTR_inverted; 106e36851d0SFelipe Balbi int DTR_active; 107e36851d0SFelipe Balbi 108d37c6cebSFelipe Balbi struct pm_qos_request pm_qos_request; 109d37c6cebSFelipe Balbi u32 latency; 110d37c6cebSFelipe Balbi u32 calc_latency; 111d37c6cebSFelipe Balbi struct work_struct qos_work; 1123dbc5ce2STony Lindgren struct pinctrl *pins; 113d37c6cebSFelipe Balbi }; 114d37c6cebSFelipe Balbi 115d37c6cebSFelipe Balbi #define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) 116d37c6cebSFelipe Balbi 117ab4382d2SGreg Kroah-Hartman static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; 118ab4382d2SGreg Kroah-Hartman 119ab4382d2SGreg Kroah-Hartman /* Forward declaration of functions */ 12094734749SGovindraj.R static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1); 121ab4382d2SGreg Kroah-Hartman 1222fd14964SGovindraj.R static struct workqueue_struct *serial_omap_uart_wq; 123ab4382d2SGreg Kroah-Hartman 124ab4382d2SGreg Kroah-Hartman static inline unsigned int serial_in(struct uart_omap_port *up, int offset) 125ab4382d2SGreg Kroah-Hartman { 126ab4382d2SGreg Kroah-Hartman offset <<= up->port.regshift; 127ab4382d2SGreg Kroah-Hartman return readw(up->port.membase + offset); 128ab4382d2SGreg Kroah-Hartman } 129ab4382d2SGreg Kroah-Hartman 130ab4382d2SGreg Kroah-Hartman static inline void serial_out(struct uart_omap_port *up, int offset, int value) 131ab4382d2SGreg Kroah-Hartman { 132ab4382d2SGreg Kroah-Hartman offset <<= up->port.regshift; 133ab4382d2SGreg Kroah-Hartman writew(value, up->port.membase + offset); 134ab4382d2SGreg Kroah-Hartman } 135ab4382d2SGreg Kroah-Hartman 136ab4382d2SGreg Kroah-Hartman static inline void serial_omap_clear_fifos(struct uart_omap_port *up) 137ab4382d2SGreg Kroah-Hartman { 138ab4382d2SGreg Kroah-Hartman serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); 139ab4382d2SGreg Kroah-Hartman serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | 140ab4382d2SGreg Kroah-Hartman UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); 141ab4382d2SGreg Kroah-Hartman serial_out(up, UART_FCR, 0); 142ab4382d2SGreg Kroah-Hartman } 143ab4382d2SGreg Kroah-Hartman 144e5b57c03SFelipe Balbi static int serial_omap_get_context_loss_count(struct uart_omap_port *up) 145e5b57c03SFelipe Balbi { 146d8ee4ea6SFelipe Balbi struct omap_uart_port_info *pdata = up->dev->platform_data; 147e5b57c03SFelipe Balbi 148ce2f08deSFelipe Balbi if (!pdata || !pdata->get_context_loss_count) 149e5b57c03SFelipe Balbi return 0; 150e5b57c03SFelipe Balbi 151d8ee4ea6SFelipe Balbi return pdata->get_context_loss_count(up->dev); 152e5b57c03SFelipe Balbi } 153e5b57c03SFelipe Balbi 154e5b57c03SFelipe Balbi static void serial_omap_set_forceidle(struct uart_omap_port *up) 155e5b57c03SFelipe Balbi { 156d8ee4ea6SFelipe Balbi struct omap_uart_port_info *pdata = up->dev->platform_data; 157e5b57c03SFelipe Balbi 158ce2f08deSFelipe Balbi if (!pdata || !pdata->set_forceidle) 159ce2f08deSFelipe Balbi return; 160ce2f08deSFelipe Balbi 161d8ee4ea6SFelipe Balbi pdata->set_forceidle(up->dev); 162e5b57c03SFelipe Balbi } 163e5b57c03SFelipe Balbi 164e5b57c03SFelipe Balbi static void serial_omap_set_noidle(struct uart_omap_port *up) 165e5b57c03SFelipe Balbi { 166d8ee4ea6SFelipe Balbi struct omap_uart_port_info *pdata = up->dev->platform_data; 167e5b57c03SFelipe Balbi 168ce2f08deSFelipe Balbi if (!pdata || !pdata->set_noidle) 169ce2f08deSFelipe Balbi return; 170ce2f08deSFelipe Balbi 171d8ee4ea6SFelipe Balbi pdata->set_noidle(up->dev); 172e5b57c03SFelipe Balbi } 173e5b57c03SFelipe Balbi 174e5b57c03SFelipe Balbi static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) 175e5b57c03SFelipe Balbi { 176d8ee4ea6SFelipe Balbi struct omap_uart_port_info *pdata = up->dev->platform_data; 177e5b57c03SFelipe Balbi 178ce2f08deSFelipe Balbi if (!pdata || !pdata->enable_wakeup) 179ce2f08deSFelipe Balbi return; 180ce2f08deSFelipe Balbi 181d8ee4ea6SFelipe Balbi pdata->enable_wakeup(up->dev, enable); 182e5b57c03SFelipe Balbi } 183e5b57c03SFelipe Balbi 184ab4382d2SGreg Kroah-Hartman /* 185ab4382d2SGreg Kroah-Hartman * serial_omap_get_divisor - calculate divisor value 186ab4382d2SGreg Kroah-Hartman * @port: uart port info 187ab4382d2SGreg Kroah-Hartman * @baud: baudrate for which divisor needs to be calculated. 188ab4382d2SGreg Kroah-Hartman * 189ab4382d2SGreg Kroah-Hartman * We have written our own function to get the divisor so as to support 190ab4382d2SGreg Kroah-Hartman * 13x mode. 3Mbps Baudrate as an different divisor. 191ab4382d2SGreg Kroah-Hartman * Reference OMAP TRM Chapter 17: 192ab4382d2SGreg Kroah-Hartman * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates 193ab4382d2SGreg Kroah-Hartman * referring to oversampling - divisor value 194ab4382d2SGreg Kroah-Hartman * baudrate 460,800 to 3,686,400 all have divisor 13 195ab4382d2SGreg Kroah-Hartman * except 3,000,000 which has divisor value 16 196ab4382d2SGreg Kroah-Hartman */ 197ab4382d2SGreg Kroah-Hartman static unsigned int 198ab4382d2SGreg Kroah-Hartman serial_omap_get_divisor(struct uart_port *port, unsigned int baud) 199ab4382d2SGreg Kroah-Hartman { 200ab4382d2SGreg Kroah-Hartman unsigned int divisor; 201ab4382d2SGreg Kroah-Hartman 202ab4382d2SGreg Kroah-Hartman if (baud > OMAP_MODE13X_SPEED && baud != 3000000) 203ab4382d2SGreg Kroah-Hartman divisor = 13; 204ab4382d2SGreg Kroah-Hartman else 205ab4382d2SGreg Kroah-Hartman divisor = 16; 206ab4382d2SGreg Kroah-Hartman return port->uartclk/(baud * divisor); 207ab4382d2SGreg Kroah-Hartman } 208ab4382d2SGreg Kroah-Hartman 209ab4382d2SGreg Kroah-Hartman static void serial_omap_enable_ms(struct uart_port *port) 210ab4382d2SGreg Kroah-Hartman { 211c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 212ab4382d2SGreg Kroah-Hartman 213ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line); 214fcdca757SGovindraj.R 215d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 216ab4382d2SGreg Kroah-Hartman up->ier |= UART_IER_MSI; 217ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, up->ier); 218660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 219660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 220ab4382d2SGreg Kroah-Hartman } 221ab4382d2SGreg Kroah-Hartman 222ab4382d2SGreg Kroah-Hartman static void serial_omap_stop_tx(struct uart_port *port) 223ab4382d2SGreg Kroah-Hartman { 224c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 225ab4382d2SGreg Kroah-Hartman 226d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 227ab4382d2SGreg Kroah-Hartman if (up->ier & UART_IER_THRI) { 228ab4382d2SGreg Kroah-Hartman up->ier &= ~UART_IER_THRI; 229ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, up->ier); 230ab4382d2SGreg Kroah-Hartman } 231fcdca757SGovindraj.R 232e5b57c03SFelipe Balbi serial_omap_set_forceidle(up); 233be4b0281SPaul Walmsley 234d8ee4ea6SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 235d8ee4ea6SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 236ab4382d2SGreg Kroah-Hartman } 237ab4382d2SGreg Kroah-Hartman 238ab4382d2SGreg Kroah-Hartman static void serial_omap_stop_rx(struct uart_port *port) 239ab4382d2SGreg Kroah-Hartman { 240c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 241ab4382d2SGreg Kroah-Hartman 242d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 243ab4382d2SGreg Kroah-Hartman up->ier &= ~UART_IER_RLSI; 244ab4382d2SGreg Kroah-Hartman up->port.read_status_mask &= ~UART_LSR_DR; 245ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, up->ier); 246d8ee4ea6SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 247d8ee4ea6SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 248ab4382d2SGreg Kroah-Hartman } 249ab4382d2SGreg Kroah-Hartman 250bf63a086SFelipe Balbi static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) 251ab4382d2SGreg Kroah-Hartman { 252ab4382d2SGreg Kroah-Hartman struct circ_buf *xmit = &up->port.state->xmit; 253ab4382d2SGreg Kroah-Hartman int count; 254ab4382d2SGreg Kroah-Hartman 255bf63a086SFelipe Balbi if (!(lsr & UART_LSR_THRE)) 256bf63a086SFelipe Balbi return; 257bf63a086SFelipe Balbi 258ab4382d2SGreg Kroah-Hartman if (up->port.x_char) { 259ab4382d2SGreg Kroah-Hartman serial_out(up, UART_TX, up->port.x_char); 260ab4382d2SGreg Kroah-Hartman up->port.icount.tx++; 261ab4382d2SGreg Kroah-Hartman up->port.x_char = 0; 262ab4382d2SGreg Kroah-Hartman return; 263ab4382d2SGreg Kroah-Hartman } 264ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { 265ab4382d2SGreg Kroah-Hartman serial_omap_stop_tx(&up->port); 266ab4382d2SGreg Kroah-Hartman return; 267ab4382d2SGreg Kroah-Hartman } 268af681cadSGreg Kroah-Hartman count = up->port.fifosize / 4; 269ab4382d2SGreg Kroah-Hartman do { 270ab4382d2SGreg Kroah-Hartman serial_out(up, UART_TX, xmit->buf[xmit->tail]); 271ab4382d2SGreg Kroah-Hartman xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 272ab4382d2SGreg Kroah-Hartman up->port.icount.tx++; 273ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit)) 274ab4382d2SGreg Kroah-Hartman break; 275ab4382d2SGreg Kroah-Hartman } while (--count > 0); 276ab4382d2SGreg Kroah-Hartman 2770324a821SRuchika Kharwar if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { 2780324a821SRuchika Kharwar spin_unlock(&up->port.lock); 279ab4382d2SGreg Kroah-Hartman uart_write_wakeup(&up->port); 2800324a821SRuchika Kharwar spin_lock(&up->port.lock); 2810324a821SRuchika Kharwar } 282ab4382d2SGreg Kroah-Hartman 283ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit)) 284ab4382d2SGreg Kroah-Hartman serial_omap_stop_tx(&up->port); 285ab4382d2SGreg Kroah-Hartman } 286ab4382d2SGreg Kroah-Hartman 287ab4382d2SGreg Kroah-Hartman static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) 288ab4382d2SGreg Kroah-Hartman { 289ab4382d2SGreg Kroah-Hartman if (!(up->ier & UART_IER_THRI)) { 290ab4382d2SGreg Kroah-Hartman up->ier |= UART_IER_THRI; 291ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, up->ier); 292ab4382d2SGreg Kroah-Hartman } 293ab4382d2SGreg Kroah-Hartman } 294ab4382d2SGreg Kroah-Hartman 295ab4382d2SGreg Kroah-Hartman static void serial_omap_start_tx(struct uart_port *port) 296ab4382d2SGreg Kroah-Hartman { 297c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 298ab4382d2SGreg Kroah-Hartman 299d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 300ab4382d2SGreg Kroah-Hartman serial_omap_enable_ier_thri(up); 301e5b57c03SFelipe Balbi serial_omap_set_noidle(up); 302d8ee4ea6SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 303d8ee4ea6SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 304ab4382d2SGreg Kroah-Hartman } 305ab4382d2SGreg Kroah-Hartman 306ab4382d2SGreg Kroah-Hartman static unsigned int check_modem_status(struct uart_omap_port *up) 307ab4382d2SGreg Kroah-Hartman { 308ab4382d2SGreg Kroah-Hartman unsigned int status; 309ab4382d2SGreg Kroah-Hartman 310ab4382d2SGreg Kroah-Hartman status = serial_in(up, UART_MSR); 311ab4382d2SGreg Kroah-Hartman status |= up->msr_saved_flags; 312ab4382d2SGreg Kroah-Hartman up->msr_saved_flags = 0; 313ab4382d2SGreg Kroah-Hartman if ((status & UART_MSR_ANY_DELTA) == 0) 314ab4382d2SGreg Kroah-Hartman return status; 315ab4382d2SGreg Kroah-Hartman 316ab4382d2SGreg Kroah-Hartman if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && 317ab4382d2SGreg Kroah-Hartman up->port.state != NULL) { 318ab4382d2SGreg Kroah-Hartman if (status & UART_MSR_TERI) 319ab4382d2SGreg Kroah-Hartman up->port.icount.rng++; 320ab4382d2SGreg Kroah-Hartman if (status & UART_MSR_DDSR) 321ab4382d2SGreg Kroah-Hartman up->port.icount.dsr++; 322ab4382d2SGreg Kroah-Hartman if (status & UART_MSR_DDCD) 323ab4382d2SGreg Kroah-Hartman uart_handle_dcd_change 324ab4382d2SGreg Kroah-Hartman (&up->port, status & UART_MSR_DCD); 325ab4382d2SGreg Kroah-Hartman if (status & UART_MSR_DCTS) 326ab4382d2SGreg Kroah-Hartman uart_handle_cts_change 327ab4382d2SGreg Kroah-Hartman (&up->port, status & UART_MSR_CTS); 328ab4382d2SGreg Kroah-Hartman wake_up_interruptible(&up->port.state->port.delta_msr_wait); 329ab4382d2SGreg Kroah-Hartman } 330ab4382d2SGreg Kroah-Hartman 331ab4382d2SGreg Kroah-Hartman return status; 332ab4382d2SGreg Kroah-Hartman } 333ab4382d2SGreg Kroah-Hartman 33472256cbdSFelipe Balbi static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr) 33572256cbdSFelipe Balbi { 33672256cbdSFelipe Balbi unsigned int flag; 3379a12fcf8SShubhrajyoti D unsigned char ch = 0; 3389a12fcf8SShubhrajyoti D 3399a12fcf8SShubhrajyoti D if (likely(lsr & UART_LSR_DR)) 3409a12fcf8SShubhrajyoti D ch = serial_in(up, UART_RX); 34172256cbdSFelipe Balbi 34272256cbdSFelipe Balbi up->port.icount.rx++; 34372256cbdSFelipe Balbi flag = TTY_NORMAL; 34472256cbdSFelipe Balbi 34572256cbdSFelipe Balbi if (lsr & UART_LSR_BI) { 34672256cbdSFelipe Balbi flag = TTY_BREAK; 34772256cbdSFelipe Balbi lsr &= ~(UART_LSR_FE | UART_LSR_PE); 34872256cbdSFelipe Balbi up->port.icount.brk++; 34972256cbdSFelipe Balbi /* 35072256cbdSFelipe Balbi * We do the SysRQ and SAK checking 35172256cbdSFelipe Balbi * here because otherwise the break 35272256cbdSFelipe Balbi * may get masked by ignore_status_mask 35372256cbdSFelipe Balbi * or read_status_mask. 35472256cbdSFelipe Balbi */ 35572256cbdSFelipe Balbi if (uart_handle_break(&up->port)) 35672256cbdSFelipe Balbi return; 35772256cbdSFelipe Balbi 35872256cbdSFelipe Balbi } 35972256cbdSFelipe Balbi 36072256cbdSFelipe Balbi if (lsr & UART_LSR_PE) { 36172256cbdSFelipe Balbi flag = TTY_PARITY; 36272256cbdSFelipe Balbi up->port.icount.parity++; 36372256cbdSFelipe Balbi } 36472256cbdSFelipe Balbi 36572256cbdSFelipe Balbi if (lsr & UART_LSR_FE) { 36672256cbdSFelipe Balbi flag = TTY_FRAME; 36772256cbdSFelipe Balbi up->port.icount.frame++; 36872256cbdSFelipe Balbi } 36972256cbdSFelipe Balbi 37072256cbdSFelipe Balbi if (lsr & UART_LSR_OE) 37172256cbdSFelipe Balbi up->port.icount.overrun++; 37272256cbdSFelipe Balbi 37372256cbdSFelipe Balbi #ifdef CONFIG_SERIAL_OMAP_CONSOLE 37472256cbdSFelipe Balbi if (up->port.line == up->port.cons->index) { 37572256cbdSFelipe Balbi /* Recover the break flag from console xmit */ 37672256cbdSFelipe Balbi lsr |= up->lsr_break_flag; 37772256cbdSFelipe Balbi } 37872256cbdSFelipe Balbi #endif 37972256cbdSFelipe Balbi uart_insert_char(&up->port, lsr, UART_LSR_OE, 0, flag); 38072256cbdSFelipe Balbi } 38172256cbdSFelipe Balbi 38272256cbdSFelipe Balbi static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) 38372256cbdSFelipe Balbi { 38472256cbdSFelipe Balbi unsigned char ch = 0; 38572256cbdSFelipe Balbi unsigned int flag; 38672256cbdSFelipe Balbi 38772256cbdSFelipe Balbi if (!(lsr & UART_LSR_DR)) 38872256cbdSFelipe Balbi return; 38972256cbdSFelipe Balbi 39072256cbdSFelipe Balbi ch = serial_in(up, UART_RX); 39172256cbdSFelipe Balbi flag = TTY_NORMAL; 39272256cbdSFelipe Balbi up->port.icount.rx++; 39372256cbdSFelipe Balbi 39472256cbdSFelipe Balbi if (uart_handle_sysrq_char(&up->port, ch)) 39572256cbdSFelipe Balbi return; 39672256cbdSFelipe Balbi 39772256cbdSFelipe Balbi uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); 39872256cbdSFelipe Balbi } 39972256cbdSFelipe Balbi 400ab4382d2SGreg Kroah-Hartman /** 401ab4382d2SGreg Kroah-Hartman * serial_omap_irq() - This handles the interrupt from one port 402ab4382d2SGreg Kroah-Hartman * @irq: uart port irq number 403ab4382d2SGreg Kroah-Hartman * @dev_id: uart port info 404ab4382d2SGreg Kroah-Hartman */ 40552c5513dSFelipe Balbi static irqreturn_t serial_omap_irq(int irq, void *dev_id) 406ab4382d2SGreg Kroah-Hartman { 407ab4382d2SGreg Kroah-Hartman struct uart_omap_port *up = dev_id; 40872256cbdSFelipe Balbi struct tty_struct *tty = up->port.state->port.tty; 409ab4382d2SGreg Kroah-Hartman unsigned int iir, lsr; 41081b75aefSFelipe Balbi unsigned int type; 41181b75aefSFelipe Balbi irqreturn_t ret = IRQ_NONE; 41272256cbdSFelipe Balbi int max_count = 256; 413ab4382d2SGreg Kroah-Hartman 4146c3a30c7SFelipe Balbi spin_lock(&up->port.lock); 41581b75aefSFelipe Balbi pm_runtime_get_sync(up->dev); 41672256cbdSFelipe Balbi 41772256cbdSFelipe Balbi do { 41881b75aefSFelipe Balbi iir = serial_in(up, UART_IIR); 41981b75aefSFelipe Balbi if (iir & UART_IIR_NO_INT) 42072256cbdSFelipe Balbi break; 42181b75aefSFelipe Balbi 42281b75aefSFelipe Balbi ret = IRQ_HANDLED; 423ab4382d2SGreg Kroah-Hartman lsr = serial_in(up, UART_LSR); 42481b75aefSFelipe Balbi 42581b75aefSFelipe Balbi /* extract IRQ type from IIR register */ 42681b75aefSFelipe Balbi type = iir & 0x3e; 42781b75aefSFelipe Balbi 42881b75aefSFelipe Balbi switch (type) { 42981b75aefSFelipe Balbi case UART_IIR_MSI: 43081b75aefSFelipe Balbi check_modem_status(up); 43181b75aefSFelipe Balbi break; 43281b75aefSFelipe Balbi case UART_IIR_THRI: 433bf63a086SFelipe Balbi transmit_chars(up, lsr); 43481b75aefSFelipe Balbi break; 43572256cbdSFelipe Balbi case UART_IIR_RX_TIMEOUT: 43672256cbdSFelipe Balbi /* FALLTHROUGH */ 43781b75aefSFelipe Balbi case UART_IIR_RDI: 43872256cbdSFelipe Balbi serial_omap_rdi(up, lsr); 43981b75aefSFelipe Balbi break; 44081b75aefSFelipe Balbi case UART_IIR_RLSI: 44172256cbdSFelipe Balbi serial_omap_rlsi(up, lsr); 44281b75aefSFelipe Balbi break; 44381b75aefSFelipe Balbi case UART_IIR_CTS_RTS_DSR: 44472256cbdSFelipe Balbi /* simply try again */ 44572256cbdSFelipe Balbi break; 44681b75aefSFelipe Balbi case UART_IIR_XOFF: 44781b75aefSFelipe Balbi /* FALLTHROUGH */ 44881b75aefSFelipe Balbi default: 44981b75aefSFelipe Balbi break; 450ab4382d2SGreg Kroah-Hartman } 45172256cbdSFelipe Balbi } while (!(iir & UART_IIR_NO_INT) && max_count--); 452ab4382d2SGreg Kroah-Hartman 4536c3a30c7SFelipe Balbi spin_unlock(&up->port.lock); 45472256cbdSFelipe Balbi 45572256cbdSFelipe Balbi tty_flip_buffer_push(tty); 45672256cbdSFelipe Balbi 457d8ee4ea6SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 458d8ee4ea6SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 459ab4382d2SGreg Kroah-Hartman up->port_activity = jiffies; 46081b75aefSFelipe Balbi 46181b75aefSFelipe Balbi return ret; 462ab4382d2SGreg Kroah-Hartman } 463ab4382d2SGreg Kroah-Hartman 464ab4382d2SGreg Kroah-Hartman static unsigned int serial_omap_tx_empty(struct uart_port *port) 465ab4382d2SGreg Kroah-Hartman { 466c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 467ab4382d2SGreg Kroah-Hartman unsigned long flags = 0; 468ab4382d2SGreg Kroah-Hartman unsigned int ret = 0; 469ab4382d2SGreg Kroah-Hartman 470d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 471ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line); 472ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&up->port.lock, flags); 473ab4382d2SGreg Kroah-Hartman ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; 474ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&up->port.lock, flags); 475660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 476660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 477ab4382d2SGreg Kroah-Hartman return ret; 478ab4382d2SGreg Kroah-Hartman } 479ab4382d2SGreg Kroah-Hartman 480ab4382d2SGreg Kroah-Hartman static unsigned int serial_omap_get_mctrl(struct uart_port *port) 481ab4382d2SGreg Kroah-Hartman { 482c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 483514f31d1SShubhrajyoti D unsigned int status; 484ab4382d2SGreg Kroah-Hartman unsigned int ret = 0; 485ab4382d2SGreg Kroah-Hartman 486d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 487ab4382d2SGreg Kroah-Hartman status = check_modem_status(up); 488660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 489660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 490fcdca757SGovindraj.R 491ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->port.line); 492ab4382d2SGreg Kroah-Hartman 493ab4382d2SGreg Kroah-Hartman if (status & UART_MSR_DCD) 494ab4382d2SGreg Kroah-Hartman ret |= TIOCM_CAR; 495ab4382d2SGreg Kroah-Hartman if (status & UART_MSR_RI) 496ab4382d2SGreg Kroah-Hartman ret |= TIOCM_RNG; 497ab4382d2SGreg Kroah-Hartman if (status & UART_MSR_DSR) 498ab4382d2SGreg Kroah-Hartman ret |= TIOCM_DSR; 499ab4382d2SGreg Kroah-Hartman if (status & UART_MSR_CTS) 500ab4382d2SGreg Kroah-Hartman ret |= TIOCM_CTS; 501ab4382d2SGreg Kroah-Hartman return ret; 502ab4382d2SGreg Kroah-Hartman } 503ab4382d2SGreg Kroah-Hartman 504ab4382d2SGreg Kroah-Hartman static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) 505ab4382d2SGreg Kroah-Hartman { 506c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 507ab4382d2SGreg Kroah-Hartman unsigned char mcr = 0; 508ab4382d2SGreg Kroah-Hartman 509ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line); 510ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_RTS) 511ab4382d2SGreg Kroah-Hartman mcr |= UART_MCR_RTS; 512ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_DTR) 513ab4382d2SGreg Kroah-Hartman mcr |= UART_MCR_DTR; 514ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_OUT1) 515ab4382d2SGreg Kroah-Hartman mcr |= UART_MCR_OUT1; 516ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_OUT2) 517ab4382d2SGreg Kroah-Hartman mcr |= UART_MCR_OUT2; 518ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_LOOP) 519ab4382d2SGreg Kroah-Hartman mcr |= UART_MCR_LOOP; 520ab4382d2SGreg Kroah-Hartman 521d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 522c538d20cSGovindraj.R up->mcr = serial_in(up, UART_MCR); 523c538d20cSGovindraj.R up->mcr |= mcr; 524c538d20cSGovindraj.R serial_out(up, UART_MCR, up->mcr); 525660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 526660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 5279574f36fSNeilBrown 5289574f36fSNeilBrown if (gpio_is_valid(up->DTR_gpio) && 5299574f36fSNeilBrown !!(mctrl & TIOCM_DTR) != up->DTR_active) { 5309574f36fSNeilBrown up->DTR_active = !up->DTR_active; 5319574f36fSNeilBrown if (gpio_cansleep(up->DTR_gpio)) 5329574f36fSNeilBrown schedule_work(&up->qos_work); 5339574f36fSNeilBrown else 5349574f36fSNeilBrown gpio_set_value(up->DTR_gpio, 5359574f36fSNeilBrown up->DTR_active != up->DTR_inverted); 5369574f36fSNeilBrown } 537ab4382d2SGreg Kroah-Hartman } 538ab4382d2SGreg Kroah-Hartman 539ab4382d2SGreg Kroah-Hartman static void serial_omap_break_ctl(struct uart_port *port, int break_state) 540ab4382d2SGreg Kroah-Hartman { 541c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 542ab4382d2SGreg Kroah-Hartman unsigned long flags = 0; 543ab4382d2SGreg Kroah-Hartman 544ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line); 545d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 546ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&up->port.lock, flags); 547ab4382d2SGreg Kroah-Hartman if (break_state == -1) 548ab4382d2SGreg Kroah-Hartman up->lcr |= UART_LCR_SBC; 549ab4382d2SGreg Kroah-Hartman else 550ab4382d2SGreg Kroah-Hartman up->lcr &= ~UART_LCR_SBC; 551ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, up->lcr); 552ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&up->port.lock, flags); 553660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 554660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 555ab4382d2SGreg Kroah-Hartman } 556ab4382d2SGreg Kroah-Hartman 557ab4382d2SGreg Kroah-Hartman static int serial_omap_startup(struct uart_port *port) 558ab4382d2SGreg Kroah-Hartman { 559c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 560ab4382d2SGreg Kroah-Hartman unsigned long flags = 0; 561ab4382d2SGreg Kroah-Hartman int retval; 562ab4382d2SGreg Kroah-Hartman 563ab4382d2SGreg Kroah-Hartman /* 564ab4382d2SGreg Kroah-Hartman * Allocate the IRQ 565ab4382d2SGreg Kroah-Hartman */ 566ab4382d2SGreg Kroah-Hartman retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags, 567ab4382d2SGreg Kroah-Hartman up->name, up); 568ab4382d2SGreg Kroah-Hartman if (retval) 569ab4382d2SGreg Kroah-Hartman return retval; 570ab4382d2SGreg Kroah-Hartman 571ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); 572ab4382d2SGreg Kroah-Hartman 573d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 574ab4382d2SGreg Kroah-Hartman /* 575ab4382d2SGreg Kroah-Hartman * Clear the FIFO buffers and disable them. 576ab4382d2SGreg Kroah-Hartman * (they will be reenabled in set_termios()) 577ab4382d2SGreg Kroah-Hartman */ 578ab4382d2SGreg Kroah-Hartman serial_omap_clear_fifos(up); 579ab4382d2SGreg Kroah-Hartman /* For Hardware flow control */ 580ab4382d2SGreg Kroah-Hartman serial_out(up, UART_MCR, UART_MCR_RTS); 581ab4382d2SGreg Kroah-Hartman 582ab4382d2SGreg Kroah-Hartman /* 583ab4382d2SGreg Kroah-Hartman * Clear the interrupt registers. 584ab4382d2SGreg Kroah-Hartman */ 585ab4382d2SGreg Kroah-Hartman (void) serial_in(up, UART_LSR); 586ab4382d2SGreg Kroah-Hartman if (serial_in(up, UART_LSR) & UART_LSR_DR) 587ab4382d2SGreg Kroah-Hartman (void) serial_in(up, UART_RX); 588ab4382d2SGreg Kroah-Hartman (void) serial_in(up, UART_IIR); 589ab4382d2SGreg Kroah-Hartman (void) serial_in(up, UART_MSR); 590ab4382d2SGreg Kroah-Hartman 591ab4382d2SGreg Kroah-Hartman /* 592ab4382d2SGreg Kroah-Hartman * Now, initialize the UART 593ab4382d2SGreg Kroah-Hartman */ 594ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_WLEN8); 595ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&up->port.lock, flags); 596ab4382d2SGreg Kroah-Hartman /* 597ab4382d2SGreg Kroah-Hartman * Most PC uarts need OUT2 raised to enable interrupts. 598ab4382d2SGreg Kroah-Hartman */ 599ab4382d2SGreg Kroah-Hartman up->port.mctrl |= TIOCM_OUT2; 600ab4382d2SGreg Kroah-Hartman serial_omap_set_mctrl(&up->port, up->port.mctrl); 601ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&up->port.lock, flags); 602ab4382d2SGreg Kroah-Hartman 603ab4382d2SGreg Kroah-Hartman up->msr_saved_flags = 0; 604ab4382d2SGreg Kroah-Hartman /* 605ab4382d2SGreg Kroah-Hartman * Finally, enable interrupts. Note: Modem status interrupts 606ab4382d2SGreg Kroah-Hartman * are set via set_termios(), which will be occurring imminently 607ab4382d2SGreg Kroah-Hartman * anyway, so we don't enable them here. 608ab4382d2SGreg Kroah-Hartman */ 609ab4382d2SGreg Kroah-Hartman up->ier = UART_IER_RLSI | UART_IER_RDI; 610ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, up->ier); 611ab4382d2SGreg Kroah-Hartman 61278841462SJarkko Nikula /* Enable module level wake up */ 61378841462SJarkko Nikula serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP); 61478841462SJarkko Nikula 615d8ee4ea6SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 616d8ee4ea6SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 617ab4382d2SGreg Kroah-Hartman up->port_activity = jiffies; 618ab4382d2SGreg Kroah-Hartman return 0; 619ab4382d2SGreg Kroah-Hartman } 620ab4382d2SGreg Kroah-Hartman 621ab4382d2SGreg Kroah-Hartman static void serial_omap_shutdown(struct uart_port *port) 622ab4382d2SGreg Kroah-Hartman { 623c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 624ab4382d2SGreg Kroah-Hartman unsigned long flags = 0; 625ab4382d2SGreg Kroah-Hartman 626ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line); 627fcdca757SGovindraj.R 628d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 629ab4382d2SGreg Kroah-Hartman /* 630ab4382d2SGreg Kroah-Hartman * Disable interrupts from this port 631ab4382d2SGreg Kroah-Hartman */ 632ab4382d2SGreg Kroah-Hartman up->ier = 0; 633ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, 0); 634ab4382d2SGreg Kroah-Hartman 635ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&up->port.lock, flags); 636ab4382d2SGreg Kroah-Hartman up->port.mctrl &= ~TIOCM_OUT2; 637ab4382d2SGreg Kroah-Hartman serial_omap_set_mctrl(&up->port, up->port.mctrl); 638ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&up->port.lock, flags); 639ab4382d2SGreg Kroah-Hartman 640ab4382d2SGreg Kroah-Hartman /* 641ab4382d2SGreg Kroah-Hartman * Disable break condition and FIFOs 642ab4382d2SGreg Kroah-Hartman */ 643ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); 644ab4382d2SGreg Kroah-Hartman serial_omap_clear_fifos(up); 645ab4382d2SGreg Kroah-Hartman 646ab4382d2SGreg Kroah-Hartman /* 647ab4382d2SGreg Kroah-Hartman * Read data port to reset things, and then free the irq 648ab4382d2SGreg Kroah-Hartman */ 649ab4382d2SGreg Kroah-Hartman if (serial_in(up, UART_LSR) & UART_LSR_DR) 650ab4382d2SGreg Kroah-Hartman (void) serial_in(up, UART_RX); 651fcdca757SGovindraj.R 652660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 653660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 654ab4382d2SGreg Kroah-Hartman free_irq(up->port.irq, up); 655ab4382d2SGreg Kroah-Hartman } 656ab4382d2SGreg Kroah-Hartman 657ab4382d2SGreg Kroah-Hartman static inline void 658ab4382d2SGreg Kroah-Hartman serial_omap_configure_xonxoff 659ab4382d2SGreg Kroah-Hartman (struct uart_omap_port *up, struct ktermios *termios) 660ab4382d2SGreg Kroah-Hartman { 661ab4382d2SGreg Kroah-Hartman up->lcr = serial_in(up, UART_LCR); 662ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 663ab4382d2SGreg Kroah-Hartman up->efr = serial_in(up, UART_EFR); 664ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB); 665ab4382d2SGreg Kroah-Hartman 666ab4382d2SGreg Kroah-Hartman serial_out(up, UART_XON1, termios->c_cc[VSTART]); 667ab4382d2SGreg Kroah-Hartman serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]); 668ab4382d2SGreg Kroah-Hartman 669ab4382d2SGreg Kroah-Hartman /* clear SW control mode bits */ 670c538d20cSGovindraj.R up->efr &= OMAP_UART_SW_CLR; 671ab4382d2SGreg Kroah-Hartman 672ab4382d2SGreg Kroah-Hartman /* 673ab4382d2SGreg Kroah-Hartman * IXON Flag: 674957ee727SVikram Pandita * Flow control for OMAP.TX 675957ee727SVikram Pandita * OMAP.RX should listen for XON/XOFF 676ab4382d2SGreg Kroah-Hartman */ 677ab4382d2SGreg Kroah-Hartman if (termios->c_iflag & IXON) 678957ee727SVikram Pandita up->efr |= OMAP_UART_SW_RX; 679ab4382d2SGreg Kroah-Hartman 680ab4382d2SGreg Kroah-Hartman /* 681ab4382d2SGreg Kroah-Hartman * IXOFF Flag: 682957ee727SVikram Pandita * Flow control for OMAP.RX 683957ee727SVikram Pandita * OMAP.TX should send XON/XOFF 684ab4382d2SGreg Kroah-Hartman */ 685ab4382d2SGreg Kroah-Hartman if (termios->c_iflag & IXOFF) 686957ee727SVikram Pandita up->efr |= OMAP_UART_SW_TX; 687ab4382d2SGreg Kroah-Hartman 688ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); 689ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 690ab4382d2SGreg Kroah-Hartman 691ab4382d2SGreg Kroah-Hartman up->mcr = serial_in(up, UART_MCR); 692ab4382d2SGreg Kroah-Hartman 693ab4382d2SGreg Kroah-Hartman /* 694ab4382d2SGreg Kroah-Hartman * IXANY Flag: 695ab4382d2SGreg Kroah-Hartman * Enable any character to restart output. 696ab4382d2SGreg Kroah-Hartman * Operation resumes after receiving any 697ab4382d2SGreg Kroah-Hartman * character after recognition of the XOFF character 698ab4382d2SGreg Kroah-Hartman */ 699ab4382d2SGreg Kroah-Hartman if (termios->c_iflag & IXANY) 700ab4382d2SGreg Kroah-Hartman up->mcr |= UART_MCR_XONANY; 701ab4382d2SGreg Kroah-Hartman 702ab4382d2SGreg Kroah-Hartman serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); 703ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 704ab4382d2SGreg Kroah-Hartman serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); 7057ba897d7SShubhrajyoti D 706ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 707ab4382d2SGreg Kroah-Hartman 708ab4382d2SGreg Kroah-Hartman serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR); 709ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, up->lcr); 710ab4382d2SGreg Kroah-Hartman } 711ab4382d2SGreg Kroah-Hartman 7122fd14964SGovindraj.R static void serial_omap_uart_qos_work(struct work_struct *work) 7132fd14964SGovindraj.R { 7142fd14964SGovindraj.R struct uart_omap_port *up = container_of(work, struct uart_omap_port, 7152fd14964SGovindraj.R qos_work); 7162fd14964SGovindraj.R 7172fd14964SGovindraj.R pm_qos_update_request(&up->pm_qos_request, up->latency); 7189574f36fSNeilBrown if (gpio_is_valid(up->DTR_gpio)) 7199574f36fSNeilBrown gpio_set_value_cansleep(up->DTR_gpio, 7209574f36fSNeilBrown up->DTR_active != up->DTR_inverted); 7212fd14964SGovindraj.R } 7222fd14964SGovindraj.R 723ab4382d2SGreg Kroah-Hartman static void 724ab4382d2SGreg Kroah-Hartman serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, 725ab4382d2SGreg Kroah-Hartman struct ktermios *old) 726ab4382d2SGreg Kroah-Hartman { 727c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 728ab4382d2SGreg Kroah-Hartman unsigned char cval = 0; 729ab4382d2SGreg Kroah-Hartman unsigned char efr = 0; 730ab4382d2SGreg Kroah-Hartman unsigned long flags = 0; 731ab4382d2SGreg Kroah-Hartman unsigned int baud, quot; 732ab4382d2SGreg Kroah-Hartman 733ab4382d2SGreg Kroah-Hartman switch (termios->c_cflag & CSIZE) { 734ab4382d2SGreg Kroah-Hartman case CS5: 735ab4382d2SGreg Kroah-Hartman cval = UART_LCR_WLEN5; 736ab4382d2SGreg Kroah-Hartman break; 737ab4382d2SGreg Kroah-Hartman case CS6: 738ab4382d2SGreg Kroah-Hartman cval = UART_LCR_WLEN6; 739ab4382d2SGreg Kroah-Hartman break; 740ab4382d2SGreg Kroah-Hartman case CS7: 741ab4382d2SGreg Kroah-Hartman cval = UART_LCR_WLEN7; 742ab4382d2SGreg Kroah-Hartman break; 743ab4382d2SGreg Kroah-Hartman default: 744ab4382d2SGreg Kroah-Hartman case CS8: 745ab4382d2SGreg Kroah-Hartman cval = UART_LCR_WLEN8; 746ab4382d2SGreg Kroah-Hartman break; 747ab4382d2SGreg Kroah-Hartman } 748ab4382d2SGreg Kroah-Hartman 749ab4382d2SGreg Kroah-Hartman if (termios->c_cflag & CSTOPB) 750ab4382d2SGreg Kroah-Hartman cval |= UART_LCR_STOP; 751ab4382d2SGreg Kroah-Hartman if (termios->c_cflag & PARENB) 752ab4382d2SGreg Kroah-Hartman cval |= UART_LCR_PARITY; 753ab4382d2SGreg Kroah-Hartman if (!(termios->c_cflag & PARODD)) 754ab4382d2SGreg Kroah-Hartman cval |= UART_LCR_EPAR; 755ab4382d2SGreg Kroah-Hartman 756ab4382d2SGreg Kroah-Hartman /* 757ab4382d2SGreg Kroah-Hartman * Ask the core to calculate the divisor for us. 758ab4382d2SGreg Kroah-Hartman */ 759ab4382d2SGreg Kroah-Hartman 760ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13); 761ab4382d2SGreg Kroah-Hartman quot = serial_omap_get_divisor(port, baud); 762ab4382d2SGreg Kroah-Hartman 7632fd14964SGovindraj.R /* calculate wakeup latency constraint */ 76419723452SPaul Walmsley up->calc_latency = (USEC_PER_SEC * up->port.fifosize) / (baud / 8); 7652fd14964SGovindraj.R up->latency = up->calc_latency; 7662fd14964SGovindraj.R schedule_work(&up->qos_work); 7672fd14964SGovindraj.R 768c538d20cSGovindraj.R up->dll = quot & 0xff; 769c538d20cSGovindraj.R up->dlh = quot >> 8; 770c538d20cSGovindraj.R up->mdr1 = UART_OMAP_MDR1_DISABLE; 771c538d20cSGovindraj.R 772ab4382d2SGreg Kroah-Hartman up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 | 773ab4382d2SGreg Kroah-Hartman UART_FCR_ENABLE_FIFO; 774ab4382d2SGreg Kroah-Hartman 775ab4382d2SGreg Kroah-Hartman /* 776ab4382d2SGreg Kroah-Hartman * Ok, we're now changing the port state. Do it with 777ab4382d2SGreg Kroah-Hartman * interrupts disabled. 778ab4382d2SGreg Kroah-Hartman */ 779d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 780ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&up->port.lock, flags); 781ab4382d2SGreg Kroah-Hartman 782ab4382d2SGreg Kroah-Hartman /* 783ab4382d2SGreg Kroah-Hartman * Update the per-port timeout. 784ab4382d2SGreg Kroah-Hartman */ 785ab4382d2SGreg Kroah-Hartman uart_update_timeout(port, termios->c_cflag, baud); 786ab4382d2SGreg Kroah-Hartman 787ab4382d2SGreg Kroah-Hartman up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 788ab4382d2SGreg Kroah-Hartman if (termios->c_iflag & INPCK) 789ab4382d2SGreg Kroah-Hartman up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; 790ab4382d2SGreg Kroah-Hartman if (termios->c_iflag & (BRKINT | PARMRK)) 791ab4382d2SGreg Kroah-Hartman up->port.read_status_mask |= UART_LSR_BI; 792ab4382d2SGreg Kroah-Hartman 793ab4382d2SGreg Kroah-Hartman /* 794ab4382d2SGreg Kroah-Hartman * Characters to ignore 795ab4382d2SGreg Kroah-Hartman */ 796ab4382d2SGreg Kroah-Hartman up->port.ignore_status_mask = 0; 797ab4382d2SGreg Kroah-Hartman if (termios->c_iflag & IGNPAR) 798ab4382d2SGreg Kroah-Hartman up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; 799ab4382d2SGreg Kroah-Hartman if (termios->c_iflag & IGNBRK) { 800ab4382d2SGreg Kroah-Hartman up->port.ignore_status_mask |= UART_LSR_BI; 801ab4382d2SGreg Kroah-Hartman /* 802ab4382d2SGreg Kroah-Hartman * If we're ignoring parity and break indicators, 803ab4382d2SGreg Kroah-Hartman * ignore overruns too (for real raw support). 804ab4382d2SGreg Kroah-Hartman */ 805ab4382d2SGreg Kroah-Hartman if (termios->c_iflag & IGNPAR) 806ab4382d2SGreg Kroah-Hartman up->port.ignore_status_mask |= UART_LSR_OE; 807ab4382d2SGreg Kroah-Hartman } 808ab4382d2SGreg Kroah-Hartman 809ab4382d2SGreg Kroah-Hartman /* 810ab4382d2SGreg Kroah-Hartman * ignore all characters if CREAD is not set 811ab4382d2SGreg Kroah-Hartman */ 812ab4382d2SGreg Kroah-Hartman if ((termios->c_cflag & CREAD) == 0) 813ab4382d2SGreg Kroah-Hartman up->port.ignore_status_mask |= UART_LSR_DR; 814ab4382d2SGreg Kroah-Hartman 815ab4382d2SGreg Kroah-Hartman /* 816ab4382d2SGreg Kroah-Hartman * Modem status interrupts 817ab4382d2SGreg Kroah-Hartman */ 818ab4382d2SGreg Kroah-Hartman up->ier &= ~UART_IER_MSI; 819ab4382d2SGreg Kroah-Hartman if (UART_ENABLE_MS(&up->port, termios->c_cflag)) 820ab4382d2SGreg Kroah-Hartman up->ier |= UART_IER_MSI; 821ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, up->ier); 822ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, cval); /* reset DLAB */ 823c538d20cSGovindraj.R up->lcr = cval; 82432212897SGovindraj.R up->scr = OMAP_UART_SCR_TX_EMPTY; 825ab4382d2SGreg Kroah-Hartman 826ab4382d2SGreg Kroah-Hartman /* FIFOs and DMA Settings */ 827ab4382d2SGreg Kroah-Hartman 828ab4382d2SGreg Kroah-Hartman /* FCR can be changed only when the 829ab4382d2SGreg Kroah-Hartman * baud clock is not running 830ab4382d2SGreg Kroah-Hartman * DLL_REG and DLH_REG set to 0. 831ab4382d2SGreg Kroah-Hartman */ 832ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 833ab4382d2SGreg Kroah-Hartman serial_out(up, UART_DLL, 0); 834ab4382d2SGreg Kroah-Hartman serial_out(up, UART_DLM, 0); 835ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, 0); 836ab4382d2SGreg Kroah-Hartman 837ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 838ab4382d2SGreg Kroah-Hartman 839ab4382d2SGreg Kroah-Hartman up->efr = serial_in(up, UART_EFR); 840ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); 841ab4382d2SGreg Kroah-Hartman 842ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 843ab4382d2SGreg Kroah-Hartman up->mcr = serial_in(up, UART_MCR); 844ab4382d2SGreg Kroah-Hartman serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); 845ab4382d2SGreg Kroah-Hartman /* FIFO ENABLE, DMA MODE */ 8460ba5f668SPaul Walmsley 8470ba5f668SPaul Walmsley up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK; 8480a697b22SPaul Walmsley 8496721ab7fSFelipe Balbi /* Set receive FIFO threshold to 16 characters and 8506721ab7fSFelipe Balbi * transmit FIFO threshold to 16 spaces 8516721ab7fSFelipe Balbi */ 8520ba5f668SPaul Walmsley up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; 8536721ab7fSFelipe Balbi up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK; 8546721ab7fSFelipe Balbi up->fcr |= UART_FCR6_R_TRIGGER_16 | UART_FCR6_T_TRIGGER_24 | 8556721ab7fSFelipe Balbi UART_FCR_ENABLE_FIFO; 8568a74e9ffSGreg Kroah-Hartman 8570ba5f668SPaul Walmsley serial_out(up, UART_FCR, up->fcr); 8580ba5f668SPaul Walmsley serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 8590ba5f668SPaul Walmsley 860c538d20cSGovindraj.R serial_out(up, UART_OMAP_SCR, up->scr); 861c538d20cSGovindraj.R 862ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, up->efr); 863ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 864ab4382d2SGreg Kroah-Hartman serial_out(up, UART_MCR, up->mcr); 865ab4382d2SGreg Kroah-Hartman 866ab4382d2SGreg Kroah-Hartman /* Protocol, Baud Rate, and Interrupt Settings */ 867ab4382d2SGreg Kroah-Hartman 86894734749SGovindraj.R if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) 86994734749SGovindraj.R serial_omap_mdr1_errataset(up, up->mdr1); 87094734749SGovindraj.R else 871c538d20cSGovindraj.R serial_out(up, UART_OMAP_MDR1, up->mdr1); 87294734749SGovindraj.R 873ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 874ab4382d2SGreg Kroah-Hartman 875ab4382d2SGreg Kroah-Hartman up->efr = serial_in(up, UART_EFR); 876ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); 877ab4382d2SGreg Kroah-Hartman 878ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, 0); 879ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, 0); 880ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 881ab4382d2SGreg Kroah-Hartman 882c538d20cSGovindraj.R serial_out(up, UART_DLL, up->dll); /* LS of divisor */ 883c538d20cSGovindraj.R serial_out(up, UART_DLM, up->dlh); /* MS of divisor */ 884ab4382d2SGreg Kroah-Hartman 885ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, 0); 886ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, up->ier); 887ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 888ab4382d2SGreg Kroah-Hartman 889ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, up->efr); 890ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, cval); 891ab4382d2SGreg Kroah-Hartman 892ab4382d2SGreg Kroah-Hartman if (baud > 230400 && baud != 3000000) 893c538d20cSGovindraj.R up->mdr1 = UART_OMAP_MDR1_13X_MODE; 894ab4382d2SGreg Kroah-Hartman else 895c538d20cSGovindraj.R up->mdr1 = UART_OMAP_MDR1_16X_MODE; 896c538d20cSGovindraj.R 89794734749SGovindraj.R if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) 89894734749SGovindraj.R serial_omap_mdr1_errataset(up, up->mdr1); 89994734749SGovindraj.R else 900c538d20cSGovindraj.R serial_out(up, UART_OMAP_MDR1, up->mdr1); 901ab4382d2SGreg Kroah-Hartman 902ab4382d2SGreg Kroah-Hartman /* Hardware Flow Control Configuration */ 903ab4382d2SGreg Kroah-Hartman 904ab4382d2SGreg Kroah-Hartman if (termios->c_cflag & CRTSCTS) { 905ab4382d2SGreg Kroah-Hartman efr |= (UART_EFR_CTS | UART_EFR_RTS); 906ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 907ab4382d2SGreg Kroah-Hartman 908ab4382d2SGreg Kroah-Hartman up->mcr = serial_in(up, UART_MCR); 909ab4382d2SGreg Kroah-Hartman serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); 910ab4382d2SGreg Kroah-Hartman 911ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 912ab4382d2SGreg Kroah-Hartman up->efr = serial_in(up, UART_EFR); 913ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); 914ab4382d2SGreg Kroah-Hartman 915ab4382d2SGreg Kroah-Hartman serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); 916ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */ 917ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 918ab4382d2SGreg Kroah-Hartman serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS); 919ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, cval); 920ab4382d2SGreg Kroah-Hartman } 921ab4382d2SGreg Kroah-Hartman 922ab4382d2SGreg Kroah-Hartman serial_omap_set_mctrl(&up->port, up->port.mctrl); 923ab4382d2SGreg Kroah-Hartman /* Software Flow Control Configuration */ 924ab4382d2SGreg Kroah-Hartman serial_omap_configure_xonxoff(up, termios); 925ab4382d2SGreg Kroah-Hartman 926ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&up->port.lock, flags); 927660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 928660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 929ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); 930ab4382d2SGreg Kroah-Hartman } 931ab4382d2SGreg Kroah-Hartman 9329727faf4SFelipe Balbi static int serial_omap_set_wake(struct uart_port *port, unsigned int state) 9339727faf4SFelipe Balbi { 9349727faf4SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 9359727faf4SFelipe Balbi 9369727faf4SFelipe Balbi serial_omap_enable_wakeup(up, state); 9379727faf4SFelipe Balbi 9389727faf4SFelipe Balbi return 0; 9399727faf4SFelipe Balbi } 9409727faf4SFelipe Balbi 941ab4382d2SGreg Kroah-Hartman static void 942ab4382d2SGreg Kroah-Hartman serial_omap_pm(struct uart_port *port, unsigned int state, 943ab4382d2SGreg Kroah-Hartman unsigned int oldstate) 944ab4382d2SGreg Kroah-Hartman { 945c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 946ab4382d2SGreg Kroah-Hartman unsigned char efr; 947ab4382d2SGreg Kroah-Hartman 948ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line); 949fcdca757SGovindraj.R 950d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 951ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 952ab4382d2SGreg Kroah-Hartman efr = serial_in(up, UART_EFR); 953ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, efr | UART_EFR_ECB); 954ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, 0); 955ab4382d2SGreg Kroah-Hartman 956ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0); 957ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); 958ab4382d2SGreg Kroah-Hartman serial_out(up, UART_EFR, efr); 959ab4382d2SGreg Kroah-Hartman serial_out(up, UART_LCR, 0); 960fcdca757SGovindraj.R 961d8ee4ea6SFelipe Balbi if (!device_may_wakeup(up->dev)) { 962fcdca757SGovindraj.R if (!state) 963d8ee4ea6SFelipe Balbi pm_runtime_forbid(up->dev); 964fcdca757SGovindraj.R else 965d8ee4ea6SFelipe Balbi pm_runtime_allow(up->dev); 966fcdca757SGovindraj.R } 967fcdca757SGovindraj.R 968660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 969660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 970ab4382d2SGreg Kroah-Hartman } 971ab4382d2SGreg Kroah-Hartman 972ab4382d2SGreg Kroah-Hartman static void serial_omap_release_port(struct uart_port *port) 973ab4382d2SGreg Kroah-Hartman { 974ab4382d2SGreg Kroah-Hartman dev_dbg(port->dev, "serial_omap_release_port+\n"); 975ab4382d2SGreg Kroah-Hartman } 976ab4382d2SGreg Kroah-Hartman 977ab4382d2SGreg Kroah-Hartman static int serial_omap_request_port(struct uart_port *port) 978ab4382d2SGreg Kroah-Hartman { 979ab4382d2SGreg Kroah-Hartman dev_dbg(port->dev, "serial_omap_request_port+\n"); 980ab4382d2SGreg Kroah-Hartman return 0; 981ab4382d2SGreg Kroah-Hartman } 982ab4382d2SGreg Kroah-Hartman 983ab4382d2SGreg Kroah-Hartman static void serial_omap_config_port(struct uart_port *port, int flags) 984ab4382d2SGreg Kroah-Hartman { 985c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 986ab4382d2SGreg Kroah-Hartman 987ab4382d2SGreg Kroah-Hartman dev_dbg(up->port.dev, "serial_omap_config_port+%d\n", 988ba77433dSRajendra Nayak up->port.line); 989ab4382d2SGreg Kroah-Hartman up->port.type = PORT_OMAP; 990ab4382d2SGreg Kroah-Hartman } 991ab4382d2SGreg Kroah-Hartman 992ab4382d2SGreg Kroah-Hartman static int 993ab4382d2SGreg Kroah-Hartman serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser) 994ab4382d2SGreg Kroah-Hartman { 995ab4382d2SGreg Kroah-Hartman /* we don't want the core code to modify any port params */ 996ab4382d2SGreg Kroah-Hartman dev_dbg(port->dev, "serial_omap_verify_port+\n"); 997ab4382d2SGreg Kroah-Hartman return -EINVAL; 998ab4382d2SGreg Kroah-Hartman } 999ab4382d2SGreg Kroah-Hartman 1000ab4382d2SGreg Kroah-Hartman static const char * 1001ab4382d2SGreg Kroah-Hartman serial_omap_type(struct uart_port *port) 1002ab4382d2SGreg Kroah-Hartman { 1003c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 1004ab4382d2SGreg Kroah-Hartman 1005ba77433dSRajendra Nayak dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->port.line); 1006ab4382d2SGreg Kroah-Hartman return up->name; 1007ab4382d2SGreg Kroah-Hartman } 1008ab4382d2SGreg Kroah-Hartman 1009ab4382d2SGreg Kroah-Hartman #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) 1010ab4382d2SGreg Kroah-Hartman 1011ab4382d2SGreg Kroah-Hartman static inline void wait_for_xmitr(struct uart_omap_port *up) 1012ab4382d2SGreg Kroah-Hartman { 1013ab4382d2SGreg Kroah-Hartman unsigned int status, tmout = 10000; 1014ab4382d2SGreg Kroah-Hartman 1015ab4382d2SGreg Kroah-Hartman /* Wait up to 10ms for the character(s) to be sent. */ 1016ab4382d2SGreg Kroah-Hartman do { 1017ab4382d2SGreg Kroah-Hartman status = serial_in(up, UART_LSR); 1018ab4382d2SGreg Kroah-Hartman 1019ab4382d2SGreg Kroah-Hartman if (status & UART_LSR_BI) 1020ab4382d2SGreg Kroah-Hartman up->lsr_break_flag = UART_LSR_BI; 1021ab4382d2SGreg Kroah-Hartman 1022ab4382d2SGreg Kroah-Hartman if (--tmout == 0) 1023ab4382d2SGreg Kroah-Hartman break; 1024ab4382d2SGreg Kroah-Hartman udelay(1); 1025ab4382d2SGreg Kroah-Hartman } while ((status & BOTH_EMPTY) != BOTH_EMPTY); 1026ab4382d2SGreg Kroah-Hartman 1027ab4382d2SGreg Kroah-Hartman /* Wait up to 1s for flow control if necessary */ 1028ab4382d2SGreg Kroah-Hartman if (up->port.flags & UPF_CONS_FLOW) { 1029ab4382d2SGreg Kroah-Hartman tmout = 1000000; 1030ab4382d2SGreg Kroah-Hartman for (tmout = 1000000; tmout; tmout--) { 1031ab4382d2SGreg Kroah-Hartman unsigned int msr = serial_in(up, UART_MSR); 1032ab4382d2SGreg Kroah-Hartman 1033ab4382d2SGreg Kroah-Hartman up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; 1034ab4382d2SGreg Kroah-Hartman if (msr & UART_MSR_CTS) 1035ab4382d2SGreg Kroah-Hartman break; 1036ab4382d2SGreg Kroah-Hartman 1037ab4382d2SGreg Kroah-Hartman udelay(1); 1038ab4382d2SGreg Kroah-Hartman } 1039ab4382d2SGreg Kroah-Hartman } 1040ab4382d2SGreg Kroah-Hartman } 1041ab4382d2SGreg Kroah-Hartman 1042ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL 1043ab4382d2SGreg Kroah-Hartman 1044ab4382d2SGreg Kroah-Hartman static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) 1045ab4382d2SGreg Kroah-Hartman { 1046c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 1047fcdca757SGovindraj.R 1048d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 1049ab4382d2SGreg Kroah-Hartman wait_for_xmitr(up); 1050ab4382d2SGreg Kroah-Hartman serial_out(up, UART_TX, ch); 1051660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 1052660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 1053ab4382d2SGreg Kroah-Hartman } 1054ab4382d2SGreg Kroah-Hartman 1055ab4382d2SGreg Kroah-Hartman static int serial_omap_poll_get_char(struct uart_port *port) 1056ab4382d2SGreg Kroah-Hartman { 1057c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 1058fcdca757SGovindraj.R unsigned int status; 1059ab4382d2SGreg Kroah-Hartman 1060d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 1061fcdca757SGovindraj.R status = serial_in(up, UART_LSR); 1062a6b19c33SFelipe Balbi if (!(status & UART_LSR_DR)) { 1063a6b19c33SFelipe Balbi status = NO_POLL_CHAR; 1064a6b19c33SFelipe Balbi goto out; 1065a6b19c33SFelipe Balbi } 1066ab4382d2SGreg Kroah-Hartman 1067fcdca757SGovindraj.R status = serial_in(up, UART_RX); 1068a6b19c33SFelipe Balbi 1069a6b19c33SFelipe Balbi out: 1070660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 1071660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 1072a6b19c33SFelipe Balbi 1073fcdca757SGovindraj.R return status; 1074ab4382d2SGreg Kroah-Hartman } 1075ab4382d2SGreg Kroah-Hartman 1076ab4382d2SGreg Kroah-Hartman #endif /* CONFIG_CONSOLE_POLL */ 1077ab4382d2SGreg Kroah-Hartman 1078ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_OMAP_CONSOLE 1079ab4382d2SGreg Kroah-Hartman 1080ab4382d2SGreg Kroah-Hartman static struct uart_omap_port *serial_omap_console_ports[4]; 1081ab4382d2SGreg Kroah-Hartman 1082ab4382d2SGreg Kroah-Hartman static struct uart_driver serial_omap_reg; 1083ab4382d2SGreg Kroah-Hartman 1084ab4382d2SGreg Kroah-Hartman static void serial_omap_console_putchar(struct uart_port *port, int ch) 1085ab4382d2SGreg Kroah-Hartman { 1086c990f351SFelipe Balbi struct uart_omap_port *up = to_uart_omap_port(port); 1087ab4382d2SGreg Kroah-Hartman 1088ab4382d2SGreg Kroah-Hartman wait_for_xmitr(up); 1089ab4382d2SGreg Kroah-Hartman serial_out(up, UART_TX, ch); 1090ab4382d2SGreg Kroah-Hartman } 1091ab4382d2SGreg Kroah-Hartman 1092ab4382d2SGreg Kroah-Hartman static void 1093ab4382d2SGreg Kroah-Hartman serial_omap_console_write(struct console *co, const char *s, 1094ab4382d2SGreg Kroah-Hartman unsigned int count) 1095ab4382d2SGreg Kroah-Hartman { 1096ab4382d2SGreg Kroah-Hartman struct uart_omap_port *up = serial_omap_console_ports[co->index]; 1097ab4382d2SGreg Kroah-Hartman unsigned long flags; 1098ab4382d2SGreg Kroah-Hartman unsigned int ier; 1099ab4382d2SGreg Kroah-Hartman int locked = 1; 1100ab4382d2SGreg Kroah-Hartman 1101d8ee4ea6SFelipe Balbi pm_runtime_get_sync(up->dev); 1102fcdca757SGovindraj.R 1103ab4382d2SGreg Kroah-Hartman local_irq_save(flags); 1104ab4382d2SGreg Kroah-Hartman if (up->port.sysrq) 1105ab4382d2SGreg Kroah-Hartman locked = 0; 1106ab4382d2SGreg Kroah-Hartman else if (oops_in_progress) 1107ab4382d2SGreg Kroah-Hartman locked = spin_trylock(&up->port.lock); 1108ab4382d2SGreg Kroah-Hartman else 1109ab4382d2SGreg Kroah-Hartman spin_lock(&up->port.lock); 1110ab4382d2SGreg Kroah-Hartman 1111ab4382d2SGreg Kroah-Hartman /* 1112ab4382d2SGreg Kroah-Hartman * First save the IER then disable the interrupts 1113ab4382d2SGreg Kroah-Hartman */ 1114ab4382d2SGreg Kroah-Hartman ier = serial_in(up, UART_IER); 1115ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, 0); 1116ab4382d2SGreg Kroah-Hartman 1117ab4382d2SGreg Kroah-Hartman uart_console_write(&up->port, s, count, serial_omap_console_putchar); 1118ab4382d2SGreg Kroah-Hartman 1119ab4382d2SGreg Kroah-Hartman /* 1120ab4382d2SGreg Kroah-Hartman * Finally, wait for transmitter to become empty 1121ab4382d2SGreg Kroah-Hartman * and restore the IER 1122ab4382d2SGreg Kroah-Hartman */ 1123ab4382d2SGreg Kroah-Hartman wait_for_xmitr(up); 1124ab4382d2SGreg Kroah-Hartman serial_out(up, UART_IER, ier); 1125ab4382d2SGreg Kroah-Hartman /* 1126ab4382d2SGreg Kroah-Hartman * The receive handling will happen properly because the 1127ab4382d2SGreg Kroah-Hartman * receive ready bit will still be set; it is not cleared 1128ab4382d2SGreg Kroah-Hartman * on read. However, modem control will not, we must 1129ab4382d2SGreg Kroah-Hartman * call it if we have saved something in the saved flags 1130ab4382d2SGreg Kroah-Hartman * while processing with interrupts off. 1131ab4382d2SGreg Kroah-Hartman */ 1132ab4382d2SGreg Kroah-Hartman if (up->msr_saved_flags) 1133ab4382d2SGreg Kroah-Hartman check_modem_status(up); 1134ab4382d2SGreg Kroah-Hartman 1135d8ee4ea6SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 1136d8ee4ea6SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 1137ab4382d2SGreg Kroah-Hartman if (locked) 1138ab4382d2SGreg Kroah-Hartman spin_unlock(&up->port.lock); 1139ab4382d2SGreg Kroah-Hartman local_irq_restore(flags); 1140ab4382d2SGreg Kroah-Hartman } 1141ab4382d2SGreg Kroah-Hartman 1142ab4382d2SGreg Kroah-Hartman static int __init 1143ab4382d2SGreg Kroah-Hartman serial_omap_console_setup(struct console *co, char *options) 1144ab4382d2SGreg Kroah-Hartman { 1145ab4382d2SGreg Kroah-Hartman struct uart_omap_port *up; 1146ab4382d2SGreg Kroah-Hartman int baud = 115200; 1147ab4382d2SGreg Kroah-Hartman int bits = 8; 1148ab4382d2SGreg Kroah-Hartman int parity = 'n'; 1149ab4382d2SGreg Kroah-Hartman int flow = 'n'; 1150ab4382d2SGreg Kroah-Hartman 1151ab4382d2SGreg Kroah-Hartman if (serial_omap_console_ports[co->index] == NULL) 1152ab4382d2SGreg Kroah-Hartman return -ENODEV; 1153ab4382d2SGreg Kroah-Hartman up = serial_omap_console_ports[co->index]; 1154ab4382d2SGreg Kroah-Hartman 1155ab4382d2SGreg Kroah-Hartman if (options) 1156ab4382d2SGreg Kroah-Hartman uart_parse_options(options, &baud, &parity, &bits, &flow); 1157ab4382d2SGreg Kroah-Hartman 1158ab4382d2SGreg Kroah-Hartman return uart_set_options(&up->port, co, baud, parity, bits, flow); 1159ab4382d2SGreg Kroah-Hartman } 1160ab4382d2SGreg Kroah-Hartman 1161ab4382d2SGreg Kroah-Hartman static struct console serial_omap_console = { 1162ab4382d2SGreg Kroah-Hartman .name = OMAP_SERIAL_NAME, 1163ab4382d2SGreg Kroah-Hartman .write = serial_omap_console_write, 1164ab4382d2SGreg Kroah-Hartman .device = uart_console_device, 1165ab4382d2SGreg Kroah-Hartman .setup = serial_omap_console_setup, 1166ab4382d2SGreg Kroah-Hartman .flags = CON_PRINTBUFFER, 1167ab4382d2SGreg Kroah-Hartman .index = -1, 1168ab4382d2SGreg Kroah-Hartman .data = &serial_omap_reg, 1169ab4382d2SGreg Kroah-Hartman }; 1170ab4382d2SGreg Kroah-Hartman 1171ab4382d2SGreg Kroah-Hartman static void serial_omap_add_console_port(struct uart_omap_port *up) 1172ab4382d2SGreg Kroah-Hartman { 1173ba77433dSRajendra Nayak serial_omap_console_ports[up->port.line] = up; 1174ab4382d2SGreg Kroah-Hartman } 1175ab4382d2SGreg Kroah-Hartman 1176ab4382d2SGreg Kroah-Hartman #define OMAP_CONSOLE (&serial_omap_console) 1177ab4382d2SGreg Kroah-Hartman 1178ab4382d2SGreg Kroah-Hartman #else 1179ab4382d2SGreg Kroah-Hartman 1180ab4382d2SGreg Kroah-Hartman #define OMAP_CONSOLE NULL 1181ab4382d2SGreg Kroah-Hartman 1182ab4382d2SGreg Kroah-Hartman static inline void serial_omap_add_console_port(struct uart_omap_port *up) 1183ab4382d2SGreg Kroah-Hartman {} 1184ab4382d2SGreg Kroah-Hartman 1185ab4382d2SGreg Kroah-Hartman #endif 1186ab4382d2SGreg Kroah-Hartman 1187ab4382d2SGreg Kroah-Hartman static struct uart_ops serial_omap_pops = { 1188ab4382d2SGreg Kroah-Hartman .tx_empty = serial_omap_tx_empty, 1189ab4382d2SGreg Kroah-Hartman .set_mctrl = serial_omap_set_mctrl, 1190ab4382d2SGreg Kroah-Hartman .get_mctrl = serial_omap_get_mctrl, 1191ab4382d2SGreg Kroah-Hartman .stop_tx = serial_omap_stop_tx, 1192ab4382d2SGreg Kroah-Hartman .start_tx = serial_omap_start_tx, 1193ab4382d2SGreg Kroah-Hartman .stop_rx = serial_omap_stop_rx, 1194ab4382d2SGreg Kroah-Hartman .enable_ms = serial_omap_enable_ms, 1195ab4382d2SGreg Kroah-Hartman .break_ctl = serial_omap_break_ctl, 1196ab4382d2SGreg Kroah-Hartman .startup = serial_omap_startup, 1197ab4382d2SGreg Kroah-Hartman .shutdown = serial_omap_shutdown, 1198ab4382d2SGreg Kroah-Hartman .set_termios = serial_omap_set_termios, 1199ab4382d2SGreg Kroah-Hartman .pm = serial_omap_pm, 12009727faf4SFelipe Balbi .set_wake = serial_omap_set_wake, 1201ab4382d2SGreg Kroah-Hartman .type = serial_omap_type, 1202ab4382d2SGreg Kroah-Hartman .release_port = serial_omap_release_port, 1203ab4382d2SGreg Kroah-Hartman .request_port = serial_omap_request_port, 1204ab4382d2SGreg Kroah-Hartman .config_port = serial_omap_config_port, 1205ab4382d2SGreg Kroah-Hartman .verify_port = serial_omap_verify_port, 1206ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_CONSOLE_POLL 1207ab4382d2SGreg Kroah-Hartman .poll_put_char = serial_omap_poll_put_char, 1208ab4382d2SGreg Kroah-Hartman .poll_get_char = serial_omap_poll_get_char, 1209ab4382d2SGreg Kroah-Hartman #endif 1210ab4382d2SGreg Kroah-Hartman }; 1211ab4382d2SGreg Kroah-Hartman 1212ab4382d2SGreg Kroah-Hartman static struct uart_driver serial_omap_reg = { 1213ab4382d2SGreg Kroah-Hartman .owner = THIS_MODULE, 1214ab4382d2SGreg Kroah-Hartman .driver_name = "OMAP-SERIAL", 1215ab4382d2SGreg Kroah-Hartman .dev_name = OMAP_SERIAL_NAME, 1216ab4382d2SGreg Kroah-Hartman .nr = OMAP_MAX_HSUART_PORTS, 1217ab4382d2SGreg Kroah-Hartman .cons = OMAP_CONSOLE, 1218ab4382d2SGreg Kroah-Hartman }; 1219ab4382d2SGreg Kroah-Hartman 12203bc4f0d8SShubhrajyoti D #ifdef CONFIG_PM_SLEEP 1221fcdca757SGovindraj.R static int serial_omap_suspend(struct device *dev) 1222ab4382d2SGreg Kroah-Hartman { 1223fcdca757SGovindraj.R struct uart_omap_port *up = dev_get_drvdata(dev); 1224ab4382d2SGreg Kroah-Hartman 1225ab4382d2SGreg Kroah-Hartman uart_suspend_port(&serial_omap_reg, &up->port); 122643829731STejun Heo flush_work(&up->qos_work); 12272fd14964SGovindraj.R 1228ab4382d2SGreg Kroah-Hartman return 0; 1229ab4382d2SGreg Kroah-Hartman } 1230ab4382d2SGreg Kroah-Hartman 1231fcdca757SGovindraj.R static int serial_omap_resume(struct device *dev) 1232ab4382d2SGreg Kroah-Hartman { 1233fcdca757SGovindraj.R struct uart_omap_port *up = dev_get_drvdata(dev); 1234ab4382d2SGreg Kroah-Hartman 1235ab4382d2SGreg Kroah-Hartman uart_resume_port(&serial_omap_reg, &up->port); 1236ac57e7f3SSourav Poddar 1237ab4382d2SGreg Kroah-Hartman return 0; 1238ab4382d2SGreg Kroah-Hartman } 1239fcdca757SGovindraj.R #endif 1240ab4382d2SGreg Kroah-Hartman 12416d608ef3SFelipe Balbi static void __devinit omap_serial_fill_features_erratas(struct uart_omap_port *up) 12427c77c8deSGovindraj.R { 12437c77c8deSGovindraj.R u32 mvr, scheme; 12447c77c8deSGovindraj.R u16 revision, major, minor; 12457c77c8deSGovindraj.R 12467c77c8deSGovindraj.R mvr = serial_in(up, UART_OMAP_MVER); 12477c77c8deSGovindraj.R 12487c77c8deSGovindraj.R /* Check revision register scheme */ 12497c77c8deSGovindraj.R scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT; 12507c77c8deSGovindraj.R 12517c77c8deSGovindraj.R switch (scheme) { 12527c77c8deSGovindraj.R case 0: /* Legacy Scheme: OMAP2/3 */ 12537c77c8deSGovindraj.R /* MINOR_REV[0:4], MAJOR_REV[4:7] */ 12547c77c8deSGovindraj.R major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >> 12557c77c8deSGovindraj.R OMAP_UART_LEGACY_MVR_MAJ_SHIFT; 12567c77c8deSGovindraj.R minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK); 12577c77c8deSGovindraj.R break; 12587c77c8deSGovindraj.R case 1: 12597c77c8deSGovindraj.R /* New Scheme: OMAP4+ */ 12607c77c8deSGovindraj.R /* MINOR_REV[0:5], MAJOR_REV[8:10] */ 12617c77c8deSGovindraj.R major = (mvr & OMAP_UART_MVR_MAJ_MASK) >> 12627c77c8deSGovindraj.R OMAP_UART_MVR_MAJ_SHIFT; 12637c77c8deSGovindraj.R minor = (mvr & OMAP_UART_MVR_MIN_MASK); 12647c77c8deSGovindraj.R break; 12657c77c8deSGovindraj.R default: 1266d8ee4ea6SFelipe Balbi dev_warn(up->dev, 12677c77c8deSGovindraj.R "Unknown %s revision, defaulting to highest\n", 12687c77c8deSGovindraj.R up->name); 12697c77c8deSGovindraj.R /* highest possible revision */ 12707c77c8deSGovindraj.R major = 0xff; 12717c77c8deSGovindraj.R minor = 0xff; 12727c77c8deSGovindraj.R } 12737c77c8deSGovindraj.R 12747c77c8deSGovindraj.R /* normalize revision for the driver */ 12757c77c8deSGovindraj.R revision = UART_BUILD_REVISION(major, minor); 12767c77c8deSGovindraj.R 12777c77c8deSGovindraj.R switch (revision) { 12787c77c8deSGovindraj.R case OMAP_UART_REV_46: 12797c77c8deSGovindraj.R up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | 12807c77c8deSGovindraj.R UART_ERRATA_i291_DMA_FORCEIDLE); 12817c77c8deSGovindraj.R break; 12827c77c8deSGovindraj.R case OMAP_UART_REV_52: 12837c77c8deSGovindraj.R up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | 12847c77c8deSGovindraj.R UART_ERRATA_i291_DMA_FORCEIDLE); 12857c77c8deSGovindraj.R break; 12867c77c8deSGovindraj.R case OMAP_UART_REV_63: 12877c77c8deSGovindraj.R up->errata |= UART_ERRATA_i202_MDR1_ACCESS; 12887c77c8deSGovindraj.R break; 12897c77c8deSGovindraj.R default: 12907c77c8deSGovindraj.R break; 12917c77c8deSGovindraj.R } 12927c77c8deSGovindraj.R } 12937c77c8deSGovindraj.R 12946d608ef3SFelipe Balbi static __devinit struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) 1295d92b0dfcSRajendra Nayak { 1296d92b0dfcSRajendra Nayak struct omap_uart_port_info *omap_up_info; 1297d92b0dfcSRajendra Nayak 1298d92b0dfcSRajendra Nayak omap_up_info = devm_kzalloc(dev, sizeof(*omap_up_info), GFP_KERNEL); 1299d92b0dfcSRajendra Nayak if (!omap_up_info) 1300d92b0dfcSRajendra Nayak return NULL; /* out of memory */ 1301d92b0dfcSRajendra Nayak 1302d92b0dfcSRajendra Nayak of_property_read_u32(dev->of_node, "clock-frequency", 1303d92b0dfcSRajendra Nayak &omap_up_info->uartclk); 1304d92b0dfcSRajendra Nayak return omap_up_info; 1305d92b0dfcSRajendra Nayak } 1306d92b0dfcSRajendra Nayak 13076d608ef3SFelipe Balbi static int __devinit serial_omap_probe(struct platform_device *pdev) 1308ab4382d2SGreg Kroah-Hartman { 1309ab4382d2SGreg Kroah-Hartman struct uart_omap_port *up; 131049457430SFelipe Balbi struct resource *mem, *irq; 1311ab4382d2SGreg Kroah-Hartman struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; 13129574f36fSNeilBrown int ret; 1313ab4382d2SGreg Kroah-Hartman 1314d92b0dfcSRajendra Nayak if (pdev->dev.of_node) 1315d92b0dfcSRajendra Nayak omap_up_info = of_get_uart_port_info(&pdev->dev); 1316d92b0dfcSRajendra Nayak 1317ab4382d2SGreg Kroah-Hartman mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1318ab4382d2SGreg Kroah-Hartman if (!mem) { 1319ab4382d2SGreg Kroah-Hartman dev_err(&pdev->dev, "no mem resource?\n"); 1320ab4382d2SGreg Kroah-Hartman return -ENODEV; 1321ab4382d2SGreg Kroah-Hartman } 1322ab4382d2SGreg Kroah-Hartman 1323ab4382d2SGreg Kroah-Hartman irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 1324ab4382d2SGreg Kroah-Hartman if (!irq) { 1325ab4382d2SGreg Kroah-Hartman dev_err(&pdev->dev, "no irq resource?\n"); 1326ab4382d2SGreg Kroah-Hartman return -ENODEV; 1327ab4382d2SGreg Kroah-Hartman } 1328ab4382d2SGreg Kroah-Hartman 1329388bc262SShubhrajyoti D if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), 1330ab4382d2SGreg Kroah-Hartman pdev->dev.driver->name)) { 1331ab4382d2SGreg Kroah-Hartman dev_err(&pdev->dev, "memory region already claimed\n"); 1332ab4382d2SGreg Kroah-Hartman return -EBUSY; 1333ab4382d2SGreg Kroah-Hartman } 1334ab4382d2SGreg Kroah-Hartman 13359574f36fSNeilBrown if (gpio_is_valid(omap_up_info->DTR_gpio) && 13369574f36fSNeilBrown omap_up_info->DTR_present) { 13379574f36fSNeilBrown ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial"); 13389574f36fSNeilBrown if (ret < 0) 13399574f36fSNeilBrown return ret; 13409574f36fSNeilBrown ret = gpio_direction_output(omap_up_info->DTR_gpio, 13419574f36fSNeilBrown omap_up_info->DTR_inverted); 13429574f36fSNeilBrown if (ret < 0) 13439574f36fSNeilBrown return ret; 13449574f36fSNeilBrown } 13459574f36fSNeilBrown 1346388bc262SShubhrajyoti D up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL); 1347388bc262SShubhrajyoti D if (!up) 1348388bc262SShubhrajyoti D return -ENOMEM; 1349388bc262SShubhrajyoti D 13509574f36fSNeilBrown if (gpio_is_valid(omap_up_info->DTR_gpio) && 13519574f36fSNeilBrown omap_up_info->DTR_present) { 13529574f36fSNeilBrown up->DTR_gpio = omap_up_info->DTR_gpio; 13539574f36fSNeilBrown up->DTR_inverted = omap_up_info->DTR_inverted; 13549574f36fSNeilBrown } else 13559574f36fSNeilBrown up->DTR_gpio = -EINVAL; 13569574f36fSNeilBrown up->DTR_active = 0; 13579574f36fSNeilBrown 1358d8ee4ea6SFelipe Balbi up->dev = &pdev->dev; 1359ab4382d2SGreg Kroah-Hartman up->port.dev = &pdev->dev; 1360ab4382d2SGreg Kroah-Hartman up->port.type = PORT_OMAP; 1361ab4382d2SGreg Kroah-Hartman up->port.iotype = UPIO_MEM; 1362ab4382d2SGreg Kroah-Hartman up->port.irq = irq->start; 1363ab4382d2SGreg Kroah-Hartman 1364ab4382d2SGreg Kroah-Hartman up->port.regshift = 2; 1365ab4382d2SGreg Kroah-Hartman up->port.fifosize = 64; 1366ab4382d2SGreg Kroah-Hartman up->port.ops = &serial_omap_pops; 1367ab4382d2SGreg Kroah-Hartman 1368d92b0dfcSRajendra Nayak if (pdev->dev.of_node) 1369d92b0dfcSRajendra Nayak up->port.line = of_alias_get_id(pdev->dev.of_node, "serial"); 1370d92b0dfcSRajendra Nayak else 1371ab4382d2SGreg Kroah-Hartman up->port.line = pdev->id; 1372ab4382d2SGreg Kroah-Hartman 1373d92b0dfcSRajendra Nayak if (up->port.line < 0) { 1374d92b0dfcSRajendra Nayak dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n", 1375d92b0dfcSRajendra Nayak up->port.line); 1376d92b0dfcSRajendra Nayak ret = -ENODEV; 1377388bc262SShubhrajyoti D goto err_port_line; 1378d92b0dfcSRajendra Nayak } 1379d92b0dfcSRajendra Nayak 13803dbc5ce2STony Lindgren up->pins = devm_pinctrl_get_select_default(&pdev->dev); 13813dbc5ce2STony Lindgren if (IS_ERR(up->pins)) { 13823dbc5ce2STony Lindgren dev_warn(&pdev->dev, "did not get pins for uart%i error: %li\n", 13833dbc5ce2STony Lindgren up->port.line, PTR_ERR(up->pins)); 13843dbc5ce2STony Lindgren up->pins = NULL; 13853dbc5ce2STony Lindgren } 13863dbc5ce2STony Lindgren 1387d92b0dfcSRajendra Nayak sprintf(up->name, "OMAP UART%d", up->port.line); 1388edd70ad7SGovindraj.R up->port.mapbase = mem->start; 1389388bc262SShubhrajyoti D up->port.membase = devm_ioremap(&pdev->dev, mem->start, 1390388bc262SShubhrajyoti D resource_size(mem)); 1391edd70ad7SGovindraj.R if (!up->port.membase) { 1392edd70ad7SGovindraj.R dev_err(&pdev->dev, "can't ioremap UART\n"); 1393edd70ad7SGovindraj.R ret = -ENOMEM; 1394388bc262SShubhrajyoti D goto err_ioremap; 1395edd70ad7SGovindraj.R } 1396edd70ad7SGovindraj.R 1397ab4382d2SGreg Kroah-Hartman up->port.flags = omap_up_info->flags; 1398ab4382d2SGreg Kroah-Hartman up->port.uartclk = omap_up_info->uartclk; 13998fe789dcSRajendra Nayak if (!up->port.uartclk) { 14008fe789dcSRajendra Nayak up->port.uartclk = DEFAULT_CLK_SPEED; 14018fe789dcSRajendra Nayak dev_warn(&pdev->dev, "No clock speed specified: using default:" 14028fe789dcSRajendra Nayak "%d\n", DEFAULT_CLK_SPEED); 14038fe789dcSRajendra Nayak } 1404ab4382d2SGreg Kroah-Hartman 14052fd14964SGovindraj.R up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; 14062fd14964SGovindraj.R up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; 14072fd14964SGovindraj.R pm_qos_add_request(&up->pm_qos_request, 14082fd14964SGovindraj.R PM_QOS_CPU_DMA_LATENCY, up->latency); 14092fd14964SGovindraj.R serial_omap_uart_wq = create_singlethread_workqueue(up->name); 14102fd14964SGovindraj.R INIT_WORK(&up->qos_work, serial_omap_uart_qos_work); 14112fd14964SGovindraj.R 141293220dccSFelipe Balbi platform_set_drvdata(pdev, up); 1413856e35bfSRuchika Kharwar pm_runtime_enable(&pdev->dev); 1414fcdca757SGovindraj.R pm_runtime_use_autosuspend(&pdev->dev); 1415fcdca757SGovindraj.R pm_runtime_set_autosuspend_delay(&pdev->dev, 1416c86845dbSDeepak K omap_up_info->autosuspend_timeout); 1417fcdca757SGovindraj.R 1418fcdca757SGovindraj.R pm_runtime_irq_safe(&pdev->dev); 1419fcdca757SGovindraj.R pm_runtime_get_sync(&pdev->dev); 1420fcdca757SGovindraj.R 14217c77c8deSGovindraj.R omap_serial_fill_features_erratas(up); 14227c77c8deSGovindraj.R 1423ba77433dSRajendra Nayak ui[up->port.line] = up; 1424ab4382d2SGreg Kroah-Hartman serial_omap_add_console_port(up); 1425ab4382d2SGreg Kroah-Hartman 1426ab4382d2SGreg Kroah-Hartman ret = uart_add_one_port(&serial_omap_reg, &up->port); 1427ab4382d2SGreg Kroah-Hartman if (ret != 0) 1428388bc262SShubhrajyoti D goto err_add_port; 1429ab4382d2SGreg Kroah-Hartman 1430660ac5f4SFelipe Balbi pm_runtime_mark_last_busy(up->dev); 1431660ac5f4SFelipe Balbi pm_runtime_put_autosuspend(up->dev); 1432ab4382d2SGreg Kroah-Hartman return 0; 1433388bc262SShubhrajyoti D 1434388bc262SShubhrajyoti D err_add_port: 1435388bc262SShubhrajyoti D pm_runtime_put(&pdev->dev); 1436388bc262SShubhrajyoti D pm_runtime_disable(&pdev->dev); 1437388bc262SShubhrajyoti D err_ioremap: 1438388bc262SShubhrajyoti D err_port_line: 1439ab4382d2SGreg Kroah-Hartman dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", 1440ab4382d2SGreg Kroah-Hartman pdev->id, __func__, ret); 1441ab4382d2SGreg Kroah-Hartman return ret; 1442ab4382d2SGreg Kroah-Hartman } 1443ab4382d2SGreg Kroah-Hartman 14446d608ef3SFelipe Balbi static int __devexit serial_omap_remove(struct platform_device *dev) 1445ab4382d2SGreg Kroah-Hartman { 1446ab4382d2SGreg Kroah-Hartman struct uart_omap_port *up = platform_get_drvdata(dev); 1447ab4382d2SGreg Kroah-Hartman 14487e9c8e7dSFelipe Balbi pm_runtime_put_sync(up->dev); 1449d8ee4ea6SFelipe Balbi pm_runtime_disable(up->dev); 1450ab4382d2SGreg Kroah-Hartman uart_remove_one_port(&serial_omap_reg, &up->port); 14512fd14964SGovindraj.R pm_qos_remove_request(&up->pm_qos_request); 1452fcdca757SGovindraj.R 1453ab4382d2SGreg Kroah-Hartman return 0; 1454ab4382d2SGreg Kroah-Hartman } 1455ab4382d2SGreg Kroah-Hartman 145694734749SGovindraj.R /* 145794734749SGovindraj.R * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460) 145894734749SGovindraj.R * The access to uart register after MDR1 Access 145994734749SGovindraj.R * causes UART to corrupt data. 146094734749SGovindraj.R * 146194734749SGovindraj.R * Need a delay = 146294734749SGovindraj.R * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) 146394734749SGovindraj.R * give 10 times as much 146494734749SGovindraj.R */ 146594734749SGovindraj.R static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1) 146694734749SGovindraj.R { 146794734749SGovindraj.R u8 timeout = 255; 146894734749SGovindraj.R 146994734749SGovindraj.R serial_out(up, UART_OMAP_MDR1, mdr1); 147094734749SGovindraj.R udelay(2); 147194734749SGovindraj.R serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT | 147294734749SGovindraj.R UART_FCR_CLEAR_RCVR); 147394734749SGovindraj.R /* 147494734749SGovindraj.R * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and 147594734749SGovindraj.R * TX_FIFO_E bit is 1. 147694734749SGovindraj.R */ 147794734749SGovindraj.R while (UART_LSR_THRE != (serial_in(up, UART_LSR) & 147894734749SGovindraj.R (UART_LSR_THRE | UART_LSR_DR))) { 147994734749SGovindraj.R timeout--; 148094734749SGovindraj.R if (!timeout) { 148194734749SGovindraj.R /* Should *never* happen. we warn and carry on */ 1482d8ee4ea6SFelipe Balbi dev_crit(up->dev, "Errata i202: timedout %x\n", 148394734749SGovindraj.R serial_in(up, UART_LSR)); 148494734749SGovindraj.R break; 148594734749SGovindraj.R } 148694734749SGovindraj.R udelay(1); 148794734749SGovindraj.R } 148894734749SGovindraj.R } 148994734749SGovindraj.R 1490b5148856SShubhrajyoti D #ifdef CONFIG_PM_RUNTIME 14919f9ac1e8SGovindraj.R static void serial_omap_restore_context(struct uart_omap_port *up) 14929f9ac1e8SGovindraj.R { 149394734749SGovindraj.R if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) 149494734749SGovindraj.R serial_omap_mdr1_errataset(up, UART_OMAP_MDR1_DISABLE); 149594734749SGovindraj.R else 14969f9ac1e8SGovindraj.R serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE); 149794734749SGovindraj.R 14989f9ac1e8SGovindraj.R serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */ 14999f9ac1e8SGovindraj.R serial_out(up, UART_EFR, UART_EFR_ECB); 15009f9ac1e8SGovindraj.R serial_out(up, UART_LCR, 0x0); /* Operational mode */ 15019f9ac1e8SGovindraj.R serial_out(up, UART_IER, 0x0); 15029f9ac1e8SGovindraj.R serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */ 1503c538d20cSGovindraj.R serial_out(up, UART_DLL, up->dll); 1504c538d20cSGovindraj.R serial_out(up, UART_DLM, up->dlh); 15059f9ac1e8SGovindraj.R serial_out(up, UART_LCR, 0x0); /* Operational mode */ 15069f9ac1e8SGovindraj.R serial_out(up, UART_IER, up->ier); 15079f9ac1e8SGovindraj.R serial_out(up, UART_FCR, up->fcr); 15089f9ac1e8SGovindraj.R serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); 15099f9ac1e8SGovindraj.R serial_out(up, UART_MCR, up->mcr); 15109f9ac1e8SGovindraj.R serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */ 1511c538d20cSGovindraj.R serial_out(up, UART_OMAP_SCR, up->scr); 15129f9ac1e8SGovindraj.R serial_out(up, UART_EFR, up->efr); 15139f9ac1e8SGovindraj.R serial_out(up, UART_LCR, up->lcr); 151494734749SGovindraj.R if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) 151594734749SGovindraj.R serial_omap_mdr1_errataset(up, up->mdr1); 151694734749SGovindraj.R else 1517c538d20cSGovindraj.R serial_out(up, UART_OMAP_MDR1, up->mdr1); 15189f9ac1e8SGovindraj.R } 15199f9ac1e8SGovindraj.R 1520fcdca757SGovindraj.R static int serial_omap_runtime_suspend(struct device *dev) 1521fcdca757SGovindraj.R { 1522ec3bebc6SGovindraj.R struct uart_omap_port *up = dev_get_drvdata(dev); 1523ec3bebc6SGovindraj.R struct omap_uart_port_info *pdata = dev->platform_data; 1524ec3bebc6SGovindraj.R 1525ec3bebc6SGovindraj.R if (!up) 1526ec3bebc6SGovindraj.R return -EINVAL; 1527ec3bebc6SGovindraj.R 1528e5b57c03SFelipe Balbi if (!pdata) 152962f3ec5fSGovindraj.R return 0; 153062f3ec5fSGovindraj.R 1531e5b57c03SFelipe Balbi up->context_loss_cnt = serial_omap_get_context_loss_count(up); 1532ec3bebc6SGovindraj.R 153362f3ec5fSGovindraj.R if (device_may_wakeup(dev)) { 153462f3ec5fSGovindraj.R if (!up->wakeups_enabled) { 1535e5b57c03SFelipe Balbi serial_omap_enable_wakeup(up, true); 153662f3ec5fSGovindraj.R up->wakeups_enabled = true; 153762f3ec5fSGovindraj.R } 153862f3ec5fSGovindraj.R } else { 153962f3ec5fSGovindraj.R if (up->wakeups_enabled) { 1540e5b57c03SFelipe Balbi serial_omap_enable_wakeup(up, false); 154162f3ec5fSGovindraj.R up->wakeups_enabled = false; 154262f3ec5fSGovindraj.R } 154362f3ec5fSGovindraj.R } 154462f3ec5fSGovindraj.R 15452fd14964SGovindraj.R up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; 15462fd14964SGovindraj.R schedule_work(&up->qos_work); 15472fd14964SGovindraj.R 1548fcdca757SGovindraj.R return 0; 1549fcdca757SGovindraj.R } 1550fcdca757SGovindraj.R 1551fcdca757SGovindraj.R static int serial_omap_runtime_resume(struct device *dev) 1552fcdca757SGovindraj.R { 15539f9ac1e8SGovindraj.R struct uart_omap_port *up = dev_get_drvdata(dev); 15549f9ac1e8SGovindraj.R 155539aee51dSShubhrajyoti D int loss_cnt = serial_omap_get_context_loss_count(up); 1556ec3bebc6SGovindraj.R 155739aee51dSShubhrajyoti D if (loss_cnt < 0) { 155839aee51dSShubhrajyoti D dev_err(dev, "serial_omap_get_context_loss_count failed : %d\n", 155939aee51dSShubhrajyoti D loss_cnt); 15609f9ac1e8SGovindraj.R serial_omap_restore_context(up); 156139aee51dSShubhrajyoti D } else if (up->context_loss_cnt != loss_cnt) { 156239aee51dSShubhrajyoti D serial_omap_restore_context(up); 156339aee51dSShubhrajyoti D } 15642fd14964SGovindraj.R up->latency = up->calc_latency; 15652fd14964SGovindraj.R schedule_work(&up->qos_work); 15669f9ac1e8SGovindraj.R 1567fcdca757SGovindraj.R return 0; 1568fcdca757SGovindraj.R } 1569fcdca757SGovindraj.R #endif 1570fcdca757SGovindraj.R 1571fcdca757SGovindraj.R static const struct dev_pm_ops serial_omap_dev_pm_ops = { 1572fcdca757SGovindraj.R SET_SYSTEM_SLEEP_PM_OPS(serial_omap_suspend, serial_omap_resume) 1573fcdca757SGovindraj.R SET_RUNTIME_PM_OPS(serial_omap_runtime_suspend, 1574fcdca757SGovindraj.R serial_omap_runtime_resume, NULL) 1575fcdca757SGovindraj.R }; 1576fcdca757SGovindraj.R 1577d92b0dfcSRajendra Nayak #if defined(CONFIG_OF) 1578d92b0dfcSRajendra Nayak static const struct of_device_id omap_serial_of_match[] = { 1579d92b0dfcSRajendra Nayak { .compatible = "ti,omap2-uart" }, 1580d92b0dfcSRajendra Nayak { .compatible = "ti,omap3-uart" }, 1581d92b0dfcSRajendra Nayak { .compatible = "ti,omap4-uart" }, 1582d92b0dfcSRajendra Nayak {}, 1583d92b0dfcSRajendra Nayak }; 1584d92b0dfcSRajendra Nayak MODULE_DEVICE_TABLE(of, omap_serial_of_match); 1585d92b0dfcSRajendra Nayak #endif 1586d92b0dfcSRajendra Nayak 1587ab4382d2SGreg Kroah-Hartman static struct platform_driver serial_omap_driver = { 1588ab4382d2SGreg Kroah-Hartman .probe = serial_omap_probe, 15896d608ef3SFelipe Balbi .remove = __devexit_p(serial_omap_remove), 1590ab4382d2SGreg Kroah-Hartman .driver = { 1591ab4382d2SGreg Kroah-Hartman .name = DRIVER_NAME, 1592fcdca757SGovindraj.R .pm = &serial_omap_dev_pm_ops, 1593d92b0dfcSRajendra Nayak .of_match_table = of_match_ptr(omap_serial_of_match), 1594ab4382d2SGreg Kroah-Hartman }, 1595ab4382d2SGreg Kroah-Hartman }; 1596ab4382d2SGreg Kroah-Hartman 1597ab4382d2SGreg Kroah-Hartman static int __init serial_omap_init(void) 1598ab4382d2SGreg Kroah-Hartman { 1599ab4382d2SGreg Kroah-Hartman int ret; 1600ab4382d2SGreg Kroah-Hartman 1601ab4382d2SGreg Kroah-Hartman ret = uart_register_driver(&serial_omap_reg); 1602ab4382d2SGreg Kroah-Hartman if (ret != 0) 1603ab4382d2SGreg Kroah-Hartman return ret; 1604ab4382d2SGreg Kroah-Hartman ret = platform_driver_register(&serial_omap_driver); 1605ab4382d2SGreg Kroah-Hartman if (ret != 0) 1606ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&serial_omap_reg); 1607ab4382d2SGreg Kroah-Hartman return ret; 1608ab4382d2SGreg Kroah-Hartman } 1609ab4382d2SGreg Kroah-Hartman 1610ab4382d2SGreg Kroah-Hartman static void __exit serial_omap_exit(void) 1611ab4382d2SGreg Kroah-Hartman { 1612ab4382d2SGreg Kroah-Hartman platform_driver_unregister(&serial_omap_driver); 1613ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&serial_omap_reg); 1614ab4382d2SGreg Kroah-Hartman } 1615ab4382d2SGreg Kroah-Hartman 1616ab4382d2SGreg Kroah-Hartman module_init(serial_omap_init); 1617ab4382d2SGreg Kroah-Hartman module_exit(serial_omap_exit); 1618ab4382d2SGreg Kroah-Hartman 1619ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("OMAP High Speed UART driver"); 1620ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 1621ab4382d2SGreg Kroah-Hartman MODULE_AUTHOR("Texas Instruments Inc"); 1622