1ab4382d2SGreg Kroah-Hartman /* 2ab4382d2SGreg Kroah-Hartman * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs. 3ab4382d2SGreg Kroah-Hartman * 4ab4382d2SGreg Kroah-Hartman * FIXME According to the usermanual the status bits in the status register 5ab4382d2SGreg Kroah-Hartman * are only updated when the peripherals access the FIFO and not when the 6ab4382d2SGreg Kroah-Hartman * CPU access them. So since we use this bits to know when we stop writing 7ab4382d2SGreg Kroah-Hartman * and reading, they may not be updated in-time and a race condition may 8ab4382d2SGreg Kroah-Hartman * exists. But I haven't be able to prove this and I don't care. But if 9ab4382d2SGreg Kroah-Hartman * any problem arises, it might worth checking. The TX/RX FIFO Stats 10ab4382d2SGreg Kroah-Hartman * registers should be used in addition. 11ab4382d2SGreg Kroah-Hartman * Update: Actually, they seem updated ... At least the bits we use. 12ab4382d2SGreg Kroah-Hartman * 13ab4382d2SGreg Kroah-Hartman * 14ab4382d2SGreg Kroah-Hartman * Maintainer : Sylvain Munaut <tnt@246tNt.com> 15ab4382d2SGreg Kroah-Hartman * 16ab4382d2SGreg Kroah-Hartman * Some of the code has been inspired/copied from the 2.4 code written 17ab4382d2SGreg Kroah-Hartman * by Dale Farnsworth <dfarnsworth@mvista.com>. 18ab4382d2SGreg Kroah-Hartman * 19ab4382d2SGreg Kroah-Hartman * Copyright (C) 2008 Freescale Semiconductor Inc. 20ab4382d2SGreg Kroah-Hartman * John Rigby <jrigby@gmail.com> 21ab4382d2SGreg Kroah-Hartman * Added support for MPC5121 22ab4382d2SGreg Kroah-Hartman * Copyright (C) 2006 Secret Lab Technologies Ltd. 23ab4382d2SGreg Kroah-Hartman * Grant Likely <grant.likely@secretlab.ca> 24ab4382d2SGreg Kroah-Hartman * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com> 25ab4382d2SGreg Kroah-Hartman * Copyright (C) 2003 MontaVista, Software, Inc. 26ab4382d2SGreg Kroah-Hartman * 27ab4382d2SGreg Kroah-Hartman * This file is licensed under the terms of the GNU General Public License 28ab4382d2SGreg Kroah-Hartman * version 2. This program is licensed "as is" without any warranty of any 29ab4382d2SGreg Kroah-Hartman * kind, whether express or implied. 30ab4382d2SGreg Kroah-Hartman */ 31ab4382d2SGreg Kroah-Hartman 32ab4382d2SGreg Kroah-Hartman #undef DEBUG 33ab4382d2SGreg Kroah-Hartman 34ab4382d2SGreg Kroah-Hartman #include <linux/device.h> 35ab4382d2SGreg Kroah-Hartman #include <linux/module.h> 36ab4382d2SGreg Kroah-Hartman #include <linux/tty.h> 37ee160a38SJiri Slaby #include <linux/tty_flip.h> 38ab4382d2SGreg Kroah-Hartman #include <linux/serial.h> 39ab4382d2SGreg Kroah-Hartman #include <linux/sysrq.h> 40ab4382d2SGreg Kroah-Hartman #include <linux/console.h> 41ab4382d2SGreg Kroah-Hartman #include <linux/delay.h> 42ab4382d2SGreg Kroah-Hartman #include <linux/io.h> 43ab4382d2SGreg Kroah-Hartman #include <linux/of.h> 44ab4382d2SGreg Kroah-Hartman #include <linux/of_platform.h> 45ab4382d2SGreg Kroah-Hartman #include <linux/clk.h> 46ab4382d2SGreg Kroah-Hartman 47ab4382d2SGreg Kroah-Hartman #include <asm/mpc52xx.h> 48ab4382d2SGreg Kroah-Hartman #include <asm/mpc52xx_psc.h> 49ab4382d2SGreg Kroah-Hartman 50ab4382d2SGreg Kroah-Hartman #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) 51ab4382d2SGreg Kroah-Hartman #define SUPPORT_SYSRQ 52ab4382d2SGreg Kroah-Hartman #endif 53ab4382d2SGreg Kroah-Hartman 54ab4382d2SGreg Kroah-Hartman #include <linux/serial_core.h> 55ab4382d2SGreg Kroah-Hartman 56ab4382d2SGreg Kroah-Hartman 57ab4382d2SGreg Kroah-Hartman /* We've been assigned a range on the "Low-density serial ports" major */ 58ab4382d2SGreg Kroah-Hartman #define SERIAL_PSC_MAJOR 204 59ab4382d2SGreg Kroah-Hartman #define SERIAL_PSC_MINOR 148 60ab4382d2SGreg Kroah-Hartman 61ab4382d2SGreg Kroah-Hartman 62ab4382d2SGreg Kroah-Hartman #define ISR_PASS_LIMIT 256 /* Max number of iteration in the interrupt */ 63ab4382d2SGreg Kroah-Hartman 64ab4382d2SGreg Kroah-Hartman 65ab4382d2SGreg Kroah-Hartman static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM]; 66ab4382d2SGreg Kroah-Hartman /* Rem: - We use the read_status_mask as a shadow of 67ab4382d2SGreg Kroah-Hartman * psc->mpc52xx_psc_imr 68ab4382d2SGreg Kroah-Hartman * - It's important that is array is all zero on start as we 69ab4382d2SGreg Kroah-Hartman * use it to know if it's initialized or not ! If it's not sure 70ab4382d2SGreg Kroah-Hartman * it's cleared, then a memset(...,0,...) should be added to 71ab4382d2SGreg Kroah-Hartman * the console_init 72ab4382d2SGreg Kroah-Hartman */ 73ab4382d2SGreg Kroah-Hartman 74ab4382d2SGreg Kroah-Hartman /* lookup table for matching device nodes to index numbers */ 75ab4382d2SGreg Kroah-Hartman static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM]; 76ab4382d2SGreg Kroah-Hartman 77ab4382d2SGreg Kroah-Hartman static void mpc52xx_uart_of_enumerate(void); 78ab4382d2SGreg Kroah-Hartman 79ab4382d2SGreg Kroah-Hartman 80ab4382d2SGreg Kroah-Hartman #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) 81ab4382d2SGreg Kroah-Hartman 82ab4382d2SGreg Kroah-Hartman 83ab4382d2SGreg Kroah-Hartman /* Forward declaration of the interruption handling routine */ 84ab4382d2SGreg Kroah-Hartman static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); 85ab4382d2SGreg Kroah-Hartman static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port); 86ab4382d2SGreg Kroah-Hartman 87ab4382d2SGreg Kroah-Hartman 88ab4382d2SGreg Kroah-Hartman /* Simple macro to test if a port is console or not. This one is taken 89ab4382d2SGreg Kroah-Hartman * for serial_core.c and maybe should be moved to serial_core.h ? */ 90ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_CORE_CONSOLE 91ab4382d2SGreg Kroah-Hartman #define uart_console(port) \ 92ab4382d2SGreg Kroah-Hartman ((port)->cons && (port)->cons->index == (port)->line) 93ab4382d2SGreg Kroah-Hartman #else 94ab4382d2SGreg Kroah-Hartman #define uart_console(port) (0) 95ab4382d2SGreg Kroah-Hartman #endif 96ab4382d2SGreg Kroah-Hartman 97ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 98ab4382d2SGreg Kroah-Hartman /* PSC fifo operations for isolating differences between 52xx and 512x */ 99ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 100ab4382d2SGreg Kroah-Hartman 101ab4382d2SGreg Kroah-Hartman struct psc_ops { 102ab4382d2SGreg Kroah-Hartman void (*fifo_init)(struct uart_port *port); 103ab4382d2SGreg Kroah-Hartman int (*raw_rx_rdy)(struct uart_port *port); 104ab4382d2SGreg Kroah-Hartman int (*raw_tx_rdy)(struct uart_port *port); 105ab4382d2SGreg Kroah-Hartman int (*rx_rdy)(struct uart_port *port); 106ab4382d2SGreg Kroah-Hartman int (*tx_rdy)(struct uart_port *port); 107ab4382d2SGreg Kroah-Hartman int (*tx_empty)(struct uart_port *port); 108ab4382d2SGreg Kroah-Hartman void (*stop_rx)(struct uart_port *port); 109ab4382d2SGreg Kroah-Hartman void (*start_tx)(struct uart_port *port); 110ab4382d2SGreg Kroah-Hartman void (*stop_tx)(struct uart_port *port); 111ab4382d2SGreg Kroah-Hartman void (*rx_clr_irq)(struct uart_port *port); 112ab4382d2SGreg Kroah-Hartman void (*tx_clr_irq)(struct uart_port *port); 113ab4382d2SGreg Kroah-Hartman void (*write_char)(struct uart_port *port, unsigned char c); 114ab4382d2SGreg Kroah-Hartman unsigned char (*read_char)(struct uart_port *port); 115ab4382d2SGreg Kroah-Hartman void (*cw_disable_ints)(struct uart_port *port); 116ab4382d2SGreg Kroah-Hartman void (*cw_restore_ints)(struct uart_port *port); 117ab4382d2SGreg Kroah-Hartman unsigned int (*set_baudrate)(struct uart_port *port, 118ab4382d2SGreg Kroah-Hartman struct ktermios *new, 119ab4382d2SGreg Kroah-Hartman struct ktermios *old); 120ab4382d2SGreg Kroah-Hartman int (*clock)(struct uart_port *port, int enable); 121ab4382d2SGreg Kroah-Hartman int (*fifoc_init)(void); 122ab4382d2SGreg Kroah-Hartman void (*fifoc_uninit)(void); 123ab4382d2SGreg Kroah-Hartman void (*get_irq)(struct uart_port *, struct device_node *); 124ab4382d2SGreg Kroah-Hartman irqreturn_t (*handle_irq)(struct uart_port *port); 125ab4382d2SGreg Kroah-Hartman }; 126ab4382d2SGreg Kroah-Hartman 127ab4382d2SGreg Kroah-Hartman /* setting the prescaler and divisor reg is common for all chips */ 128ab4382d2SGreg Kroah-Hartman static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc, 129ab4382d2SGreg Kroah-Hartman u16 prescaler, unsigned int divisor) 130ab4382d2SGreg Kroah-Hartman { 131ab4382d2SGreg Kroah-Hartman /* select prescaler */ 132ab4382d2SGreg Kroah-Hartman out_be16(&psc->mpc52xx_psc_clock_select, prescaler); 133ab4382d2SGreg Kroah-Hartman out_8(&psc->ctur, divisor >> 8); 134ab4382d2SGreg Kroah-Hartman out_8(&psc->ctlr, divisor & 0xff); 135ab4382d2SGreg Kroah-Hartman } 136ab4382d2SGreg Kroah-Hartman 137ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PPC_MPC52xx 138ab4382d2SGreg Kroah-Hartman #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) 139ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_fifo_init(struct uart_port *port) 140ab4382d2SGreg Kroah-Hartman { 141ab4382d2SGreg Kroah-Hartman struct mpc52xx_psc __iomem *psc = PSC(port); 142ab4382d2SGreg Kroah-Hartman struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port); 143ab4382d2SGreg Kroah-Hartman 144ab4382d2SGreg Kroah-Hartman out_8(&fifo->rfcntl, 0x00); 145ab4382d2SGreg Kroah-Hartman out_be16(&fifo->rfalarm, 0x1ff); 146ab4382d2SGreg Kroah-Hartman out_8(&fifo->tfcntl, 0x07); 147ab4382d2SGreg Kroah-Hartman out_be16(&fifo->tfalarm, 0x80); 148ab4382d2SGreg Kroah-Hartman 149ab4382d2SGreg Kroah-Hartman port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; 150ab4382d2SGreg Kroah-Hartman out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); 151ab4382d2SGreg Kroah-Hartman } 152ab4382d2SGreg Kroah-Hartman 153ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port) 154ab4382d2SGreg Kroah-Hartman { 155ab4382d2SGreg Kroah-Hartman return in_be16(&PSC(port)->mpc52xx_psc_status) 156ab4382d2SGreg Kroah-Hartman & MPC52xx_PSC_SR_RXRDY; 157ab4382d2SGreg Kroah-Hartman } 158ab4382d2SGreg Kroah-Hartman 159ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port) 160ab4382d2SGreg Kroah-Hartman { 161ab4382d2SGreg Kroah-Hartman return in_be16(&PSC(port)->mpc52xx_psc_status) 162ab4382d2SGreg Kroah-Hartman & MPC52xx_PSC_SR_TXRDY; 163ab4382d2SGreg Kroah-Hartman } 164ab4382d2SGreg Kroah-Hartman 165ab4382d2SGreg Kroah-Hartman 166ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_rx_rdy(struct uart_port *port) 167ab4382d2SGreg Kroah-Hartman { 168ab4382d2SGreg Kroah-Hartman return in_be16(&PSC(port)->mpc52xx_psc_isr) 169ab4382d2SGreg Kroah-Hartman & port->read_status_mask 170ab4382d2SGreg Kroah-Hartman & MPC52xx_PSC_IMR_RXRDY; 171ab4382d2SGreg Kroah-Hartman } 172ab4382d2SGreg Kroah-Hartman 173ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_tx_rdy(struct uart_port *port) 174ab4382d2SGreg Kroah-Hartman { 175ab4382d2SGreg Kroah-Hartman return in_be16(&PSC(port)->mpc52xx_psc_isr) 176ab4382d2SGreg Kroah-Hartman & port->read_status_mask 177ab4382d2SGreg Kroah-Hartman & MPC52xx_PSC_IMR_TXRDY; 178ab4382d2SGreg Kroah-Hartman } 179ab4382d2SGreg Kroah-Hartman 180ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_tx_empty(struct uart_port *port) 181ab4382d2SGreg Kroah-Hartman { 182ab4382d2SGreg Kroah-Hartman return in_be16(&PSC(port)->mpc52xx_psc_status) 183ab4382d2SGreg Kroah-Hartman & MPC52xx_PSC_SR_TXEMP; 184ab4382d2SGreg Kroah-Hartman } 185ab4382d2SGreg Kroah-Hartman 186ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_start_tx(struct uart_port *port) 187ab4382d2SGreg Kroah-Hartman { 188ab4382d2SGreg Kroah-Hartman port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; 189ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); 190ab4382d2SGreg Kroah-Hartman } 191ab4382d2SGreg Kroah-Hartman 192ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_stop_tx(struct uart_port *port) 193ab4382d2SGreg Kroah-Hartman { 194ab4382d2SGreg Kroah-Hartman port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; 195ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); 196ab4382d2SGreg Kroah-Hartman } 197ab4382d2SGreg Kroah-Hartman 198ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_stop_rx(struct uart_port *port) 199ab4382d2SGreg Kroah-Hartman { 200ab4382d2SGreg Kroah-Hartman port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; 201ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); 202ab4382d2SGreg Kroah-Hartman } 203ab4382d2SGreg Kroah-Hartman 204ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_rx_clr_irq(struct uart_port *port) 205ab4382d2SGreg Kroah-Hartman { 206ab4382d2SGreg Kroah-Hartman } 207ab4382d2SGreg Kroah-Hartman 208ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_tx_clr_irq(struct uart_port *port) 209ab4382d2SGreg Kroah-Hartman { 210ab4382d2SGreg Kroah-Hartman } 211ab4382d2SGreg Kroah-Hartman 212ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c) 213ab4382d2SGreg Kroah-Hartman { 214ab4382d2SGreg Kroah-Hartman out_8(&PSC(port)->mpc52xx_psc_buffer_8, c); 215ab4382d2SGreg Kroah-Hartman } 216ab4382d2SGreg Kroah-Hartman 217ab4382d2SGreg Kroah-Hartman static unsigned char mpc52xx_psc_read_char(struct uart_port *port) 218ab4382d2SGreg Kroah-Hartman { 219ab4382d2SGreg Kroah-Hartman return in_8(&PSC(port)->mpc52xx_psc_buffer_8); 220ab4382d2SGreg Kroah-Hartman } 221ab4382d2SGreg Kroah-Hartman 222ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_cw_disable_ints(struct uart_port *port) 223ab4382d2SGreg Kroah-Hartman { 224ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, 0); 225ab4382d2SGreg Kroah-Hartman } 226ab4382d2SGreg Kroah-Hartman 227ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_cw_restore_ints(struct uart_port *port) 228ab4382d2SGreg Kroah-Hartman { 229ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); 230ab4382d2SGreg Kroah-Hartman } 231ab4382d2SGreg Kroah-Hartman 232ab4382d2SGreg Kroah-Hartman static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port, 233ab4382d2SGreg Kroah-Hartman struct ktermios *new, 234ab4382d2SGreg Kroah-Hartman struct ktermios *old) 235ab4382d2SGreg Kroah-Hartman { 236ab4382d2SGreg Kroah-Hartman unsigned int baud; 237ab4382d2SGreg Kroah-Hartman unsigned int divisor; 238ab4382d2SGreg Kroah-Hartman 239ab4382d2SGreg Kroah-Hartman /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */ 240ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, new, old, 241ab4382d2SGreg Kroah-Hartman port->uartclk / (32 * 0xffff) + 1, 242ab4382d2SGreg Kroah-Hartman port->uartclk / 32); 243ab4382d2SGreg Kroah-Hartman divisor = (port->uartclk + 16 * baud) / (32 * baud); 244ab4382d2SGreg Kroah-Hartman 245ab4382d2SGreg Kroah-Hartman /* enable the /32 prescaler and set the divisor */ 246ab4382d2SGreg Kroah-Hartman mpc52xx_set_divisor(PSC(port), 0xdd00, divisor); 247ab4382d2SGreg Kroah-Hartman return baud; 248ab4382d2SGreg Kroah-Hartman } 249ab4382d2SGreg Kroah-Hartman 250ab4382d2SGreg Kroah-Hartman static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port, 251ab4382d2SGreg Kroah-Hartman struct ktermios *new, 252ab4382d2SGreg Kroah-Hartman struct ktermios *old) 253ab4382d2SGreg Kroah-Hartman { 254ab4382d2SGreg Kroah-Hartman unsigned int baud; 255ab4382d2SGreg Kroah-Hartman unsigned int divisor; 256ab4382d2SGreg Kroah-Hartman u16 prescaler; 257ab4382d2SGreg Kroah-Hartman 258ab4382d2SGreg Kroah-Hartman /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the 259ab4382d2SGreg Kroah-Hartman * ipb freq */ 260ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, new, old, 261ab4382d2SGreg Kroah-Hartman port->uartclk / (32 * 0xffff) + 1, 262ab4382d2SGreg Kroah-Hartman port->uartclk / 4); 263ab4382d2SGreg Kroah-Hartman divisor = (port->uartclk + 2 * baud) / (4 * baud); 264ab4382d2SGreg Kroah-Hartman 265*e0955aceSFrank Benkert /* select the proper prescaler and set the divisor 266*e0955aceSFrank Benkert * prefer high prescaler for more tolerance on low baudrates */ 267*e0955aceSFrank Benkert if (divisor > 0xffff || baud <= 115200) { 268ab4382d2SGreg Kroah-Hartman divisor = (divisor + 4) / 8; 269ab4382d2SGreg Kroah-Hartman prescaler = 0xdd00; /* /32 */ 270ab4382d2SGreg Kroah-Hartman } else 271ab4382d2SGreg Kroah-Hartman prescaler = 0xff00; /* /4 */ 272ab4382d2SGreg Kroah-Hartman mpc52xx_set_divisor(PSC(port), prescaler, divisor); 273ab4382d2SGreg Kroah-Hartman return baud; 274ab4382d2SGreg Kroah-Hartman } 275ab4382d2SGreg Kroah-Hartman 276ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np) 277ab4382d2SGreg Kroah-Hartman { 2789cfb5c05SYong Zhang port->irqflags = 0; 279ab4382d2SGreg Kroah-Hartman port->irq = irq_of_parse_and_map(np, 0); 280ab4382d2SGreg Kroah-Hartman } 281ab4382d2SGreg Kroah-Hartman 282ab4382d2SGreg Kroah-Hartman /* 52xx specific interrupt handler. The caller holds the port lock */ 283ab4382d2SGreg Kroah-Hartman static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port) 284ab4382d2SGreg Kroah-Hartman { 285ab4382d2SGreg Kroah-Hartman return mpc5xxx_uart_process_int(port); 286ab4382d2SGreg Kroah-Hartman } 287ab4382d2SGreg Kroah-Hartman 288ab4382d2SGreg Kroah-Hartman static struct psc_ops mpc52xx_psc_ops = { 289ab4382d2SGreg Kroah-Hartman .fifo_init = mpc52xx_psc_fifo_init, 290ab4382d2SGreg Kroah-Hartman .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, 291ab4382d2SGreg Kroah-Hartman .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, 292ab4382d2SGreg Kroah-Hartman .rx_rdy = mpc52xx_psc_rx_rdy, 293ab4382d2SGreg Kroah-Hartman .tx_rdy = mpc52xx_psc_tx_rdy, 294ab4382d2SGreg Kroah-Hartman .tx_empty = mpc52xx_psc_tx_empty, 295ab4382d2SGreg Kroah-Hartman .stop_rx = mpc52xx_psc_stop_rx, 296ab4382d2SGreg Kroah-Hartman .start_tx = mpc52xx_psc_start_tx, 297ab4382d2SGreg Kroah-Hartman .stop_tx = mpc52xx_psc_stop_tx, 298ab4382d2SGreg Kroah-Hartman .rx_clr_irq = mpc52xx_psc_rx_clr_irq, 299ab4382d2SGreg Kroah-Hartman .tx_clr_irq = mpc52xx_psc_tx_clr_irq, 300ab4382d2SGreg Kroah-Hartman .write_char = mpc52xx_psc_write_char, 301ab4382d2SGreg Kroah-Hartman .read_char = mpc52xx_psc_read_char, 302ab4382d2SGreg Kroah-Hartman .cw_disable_ints = mpc52xx_psc_cw_disable_ints, 303ab4382d2SGreg Kroah-Hartman .cw_restore_ints = mpc52xx_psc_cw_restore_ints, 304ab4382d2SGreg Kroah-Hartman .set_baudrate = mpc5200_psc_set_baudrate, 305ab4382d2SGreg Kroah-Hartman .get_irq = mpc52xx_psc_get_irq, 306ab4382d2SGreg Kroah-Hartman .handle_irq = mpc52xx_psc_handle_irq, 307ab4382d2SGreg Kroah-Hartman }; 308ab4382d2SGreg Kroah-Hartman 309ab4382d2SGreg Kroah-Hartman static struct psc_ops mpc5200b_psc_ops = { 310ab4382d2SGreg Kroah-Hartman .fifo_init = mpc52xx_psc_fifo_init, 311ab4382d2SGreg Kroah-Hartman .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, 312ab4382d2SGreg Kroah-Hartman .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, 313ab4382d2SGreg Kroah-Hartman .rx_rdy = mpc52xx_psc_rx_rdy, 314ab4382d2SGreg Kroah-Hartman .tx_rdy = mpc52xx_psc_tx_rdy, 315ab4382d2SGreg Kroah-Hartman .tx_empty = mpc52xx_psc_tx_empty, 316ab4382d2SGreg Kroah-Hartman .stop_rx = mpc52xx_psc_stop_rx, 317ab4382d2SGreg Kroah-Hartman .start_tx = mpc52xx_psc_start_tx, 318ab4382d2SGreg Kroah-Hartman .stop_tx = mpc52xx_psc_stop_tx, 319ab4382d2SGreg Kroah-Hartman .rx_clr_irq = mpc52xx_psc_rx_clr_irq, 320ab4382d2SGreg Kroah-Hartman .tx_clr_irq = mpc52xx_psc_tx_clr_irq, 321ab4382d2SGreg Kroah-Hartman .write_char = mpc52xx_psc_write_char, 322ab4382d2SGreg Kroah-Hartman .read_char = mpc52xx_psc_read_char, 323ab4382d2SGreg Kroah-Hartman .cw_disable_ints = mpc52xx_psc_cw_disable_ints, 324ab4382d2SGreg Kroah-Hartman .cw_restore_ints = mpc52xx_psc_cw_restore_ints, 325ab4382d2SGreg Kroah-Hartman .set_baudrate = mpc5200b_psc_set_baudrate, 326ab4382d2SGreg Kroah-Hartman .get_irq = mpc52xx_psc_get_irq, 327ab4382d2SGreg Kroah-Hartman .handle_irq = mpc52xx_psc_handle_irq, 328ab4382d2SGreg Kroah-Hartman }; 329ab4382d2SGreg Kroah-Hartman 330ab4382d2SGreg Kroah-Hartman #endif /* CONFIG_MPC52xx */ 331ab4382d2SGreg Kroah-Hartman 332ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PPC_MPC512x 333ab4382d2SGreg Kroah-Hartman #define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) 334ab4382d2SGreg Kroah-Hartman 335ab4382d2SGreg Kroah-Hartman /* PSC FIFO Controller for mpc512x */ 336ab4382d2SGreg Kroah-Hartman struct psc_fifoc { 337ab4382d2SGreg Kroah-Hartman u32 fifoc_cmd; 338ab4382d2SGreg Kroah-Hartman u32 fifoc_int; 339ab4382d2SGreg Kroah-Hartman u32 fifoc_dma; 340ab4382d2SGreg Kroah-Hartman u32 fifoc_axe; 341ab4382d2SGreg Kroah-Hartman u32 fifoc_debug; 342ab4382d2SGreg Kroah-Hartman }; 343ab4382d2SGreg Kroah-Hartman 344ab4382d2SGreg Kroah-Hartman static struct psc_fifoc __iomem *psc_fifoc; 345ab4382d2SGreg Kroah-Hartman static unsigned int psc_fifoc_irq; 346ab4382d2SGreg Kroah-Hartman 347ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_fifo_init(struct uart_port *port) 348ab4382d2SGreg Kroah-Hartman { 349ab4382d2SGreg Kroah-Hartman /* /32 prescaler */ 350ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00); 351ab4382d2SGreg Kroah-Hartman 352ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); 353ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); 354ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->txalarm, 1); 355ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, 0); 356ab4382d2SGreg Kroah-Hartman 357ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE); 358ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); 359ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rxalarm, 1); 360ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, 0); 361ab4382d2SGreg Kroah-Hartman 362ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM); 363ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM); 364ab4382d2SGreg Kroah-Hartman } 365ab4382d2SGreg Kroah-Hartman 366ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_raw_rx_rdy(struct uart_port *port) 367ab4382d2SGreg Kroah-Hartman { 368ab4382d2SGreg Kroah-Hartman return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); 369ab4382d2SGreg Kroah-Hartman } 370ab4382d2SGreg Kroah-Hartman 371ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_raw_tx_rdy(struct uart_port *port) 372ab4382d2SGreg Kroah-Hartman { 373ab4382d2SGreg Kroah-Hartman return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL); 374ab4382d2SGreg Kroah-Hartman } 375ab4382d2SGreg Kroah-Hartman 376ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_rx_rdy(struct uart_port *port) 377ab4382d2SGreg Kroah-Hartman { 378ab4382d2SGreg Kroah-Hartman return in_be32(&FIFO_512x(port)->rxsr) 379ab4382d2SGreg Kroah-Hartman & in_be32(&FIFO_512x(port)->rximr) 380ab4382d2SGreg Kroah-Hartman & MPC512x_PSC_FIFO_ALARM; 381ab4382d2SGreg Kroah-Hartman } 382ab4382d2SGreg Kroah-Hartman 383ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_tx_rdy(struct uart_port *port) 384ab4382d2SGreg Kroah-Hartman { 385ab4382d2SGreg Kroah-Hartman return in_be32(&FIFO_512x(port)->txsr) 386ab4382d2SGreg Kroah-Hartman & in_be32(&FIFO_512x(port)->tximr) 387ab4382d2SGreg Kroah-Hartman & MPC512x_PSC_FIFO_ALARM; 388ab4382d2SGreg Kroah-Hartman } 389ab4382d2SGreg Kroah-Hartman 390ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_tx_empty(struct uart_port *port) 391ab4382d2SGreg Kroah-Hartman { 392ab4382d2SGreg Kroah-Hartman return in_be32(&FIFO_512x(port)->txsr) 393ab4382d2SGreg Kroah-Hartman & MPC512x_PSC_FIFO_EMPTY; 394ab4382d2SGreg Kroah-Hartman } 395ab4382d2SGreg Kroah-Hartman 396ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_stop_rx(struct uart_port *port) 397ab4382d2SGreg Kroah-Hartman { 398ab4382d2SGreg Kroah-Hartman unsigned long rx_fifo_imr; 399ab4382d2SGreg Kroah-Hartman 400ab4382d2SGreg Kroah-Hartman rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr); 401ab4382d2SGreg Kroah-Hartman rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; 402ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr); 403ab4382d2SGreg Kroah-Hartman } 404ab4382d2SGreg Kroah-Hartman 405ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_start_tx(struct uart_port *port) 406ab4382d2SGreg Kroah-Hartman { 407ab4382d2SGreg Kroah-Hartman unsigned long tx_fifo_imr; 408ab4382d2SGreg Kroah-Hartman 409ab4382d2SGreg Kroah-Hartman tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); 410ab4382d2SGreg Kroah-Hartman tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM; 411ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); 412ab4382d2SGreg Kroah-Hartman } 413ab4382d2SGreg Kroah-Hartman 414ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_stop_tx(struct uart_port *port) 415ab4382d2SGreg Kroah-Hartman { 416ab4382d2SGreg Kroah-Hartman unsigned long tx_fifo_imr; 417ab4382d2SGreg Kroah-Hartman 418ab4382d2SGreg Kroah-Hartman tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); 419ab4382d2SGreg Kroah-Hartman tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; 420ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); 421ab4382d2SGreg Kroah-Hartman } 422ab4382d2SGreg Kroah-Hartman 423ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_rx_clr_irq(struct uart_port *port) 424ab4382d2SGreg Kroah-Hartman { 425ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr)); 426ab4382d2SGreg Kroah-Hartman } 427ab4382d2SGreg Kroah-Hartman 428ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_tx_clr_irq(struct uart_port *port) 429ab4382d2SGreg Kroah-Hartman { 430ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr)); 431ab4382d2SGreg Kroah-Hartman } 432ab4382d2SGreg Kroah-Hartman 433ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c) 434ab4382d2SGreg Kroah-Hartman { 435ab4382d2SGreg Kroah-Hartman out_8(&FIFO_512x(port)->txdata_8, c); 436ab4382d2SGreg Kroah-Hartman } 437ab4382d2SGreg Kroah-Hartman 438ab4382d2SGreg Kroah-Hartman static unsigned char mpc512x_psc_read_char(struct uart_port *port) 439ab4382d2SGreg Kroah-Hartman { 440ab4382d2SGreg Kroah-Hartman return in_8(&FIFO_512x(port)->rxdata_8); 441ab4382d2SGreg Kroah-Hartman } 442ab4382d2SGreg Kroah-Hartman 443ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_cw_disable_ints(struct uart_port *port) 444ab4382d2SGreg Kroah-Hartman { 445ab4382d2SGreg Kroah-Hartman port->read_status_mask = 446ab4382d2SGreg Kroah-Hartman in_be32(&FIFO_512x(port)->tximr) << 16 | 447ab4382d2SGreg Kroah-Hartman in_be32(&FIFO_512x(port)->rximr); 448ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, 0); 449ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, 0); 450ab4382d2SGreg Kroah-Hartman } 451ab4382d2SGreg Kroah-Hartman 452ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_cw_restore_ints(struct uart_port *port) 453ab4382d2SGreg Kroah-Hartman { 454ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, 455ab4382d2SGreg Kroah-Hartman (port->read_status_mask >> 16) & 0x7f); 456ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f); 457ab4382d2SGreg Kroah-Hartman } 458ab4382d2SGreg Kroah-Hartman 459ab4382d2SGreg Kroah-Hartman static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port, 460ab4382d2SGreg Kroah-Hartman struct ktermios *new, 461ab4382d2SGreg Kroah-Hartman struct ktermios *old) 462ab4382d2SGreg Kroah-Hartman { 463ab4382d2SGreg Kroah-Hartman unsigned int baud; 464ab4382d2SGreg Kroah-Hartman unsigned int divisor; 465ab4382d2SGreg Kroah-Hartman 466ab4382d2SGreg Kroah-Hartman /* 467ab4382d2SGreg Kroah-Hartman * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on 468ab4382d2SGreg Kroah-Hartman * pg. 30-10 that the chip supports a /32 and a /10 prescaler. 469ab4382d2SGreg Kroah-Hartman * Furthermore, it states that "After reset, the prescaler by 10 470ab4382d2SGreg Kroah-Hartman * for the UART mode is selected", but the reset register value is 471ab4382d2SGreg Kroah-Hartman * 0x0000 which means a /32 prescaler. This is wrong. 472ab4382d2SGreg Kroah-Hartman * 473ab4382d2SGreg Kroah-Hartman * In reality using /32 prescaler doesn't work, as it is not supported! 474ab4382d2SGreg Kroah-Hartman * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide", 475ab4382d2SGreg Kroah-Hartman * Chapter 4.1 PSC in UART Mode. 476ab4382d2SGreg Kroah-Hartman * Calculate with a /16 prescaler here. 477ab4382d2SGreg Kroah-Hartman */ 478ab4382d2SGreg Kroah-Hartman 479ab4382d2SGreg Kroah-Hartman /* uartclk contains the ips freq */ 480ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, new, old, 481ab4382d2SGreg Kroah-Hartman port->uartclk / (16 * 0xffff) + 1, 482ab4382d2SGreg Kroah-Hartman port->uartclk / 16); 483ab4382d2SGreg Kroah-Hartman divisor = (port->uartclk + 8 * baud) / (16 * baud); 484ab4382d2SGreg Kroah-Hartman 485ab4382d2SGreg Kroah-Hartman /* enable the /16 prescaler and set the divisor */ 486ab4382d2SGreg Kroah-Hartman mpc52xx_set_divisor(PSC(port), 0xdd00, divisor); 487ab4382d2SGreg Kroah-Hartman return baud; 488ab4382d2SGreg Kroah-Hartman } 489ab4382d2SGreg Kroah-Hartman 490ab4382d2SGreg Kroah-Hartman /* Init PSC FIFO Controller */ 491ab4382d2SGreg Kroah-Hartman static int __init mpc512x_psc_fifoc_init(void) 492ab4382d2SGreg Kroah-Hartman { 493ab4382d2SGreg Kroah-Hartman struct device_node *np; 494ab4382d2SGreg Kroah-Hartman 495ab4382d2SGreg Kroah-Hartman np = of_find_compatible_node(NULL, NULL, 496ab4382d2SGreg Kroah-Hartman "fsl,mpc5121-psc-fifo"); 497ab4382d2SGreg Kroah-Hartman if (!np) { 498ab4382d2SGreg Kroah-Hartman pr_err("%s: Can't find FIFOC node\n", __func__); 499ab4382d2SGreg Kroah-Hartman return -ENODEV; 500ab4382d2SGreg Kroah-Hartman } 501ab4382d2SGreg Kroah-Hartman 502ab4382d2SGreg Kroah-Hartman psc_fifoc = of_iomap(np, 0); 503ab4382d2SGreg Kroah-Hartman if (!psc_fifoc) { 504ab4382d2SGreg Kroah-Hartman pr_err("%s: Can't map FIFOC\n", __func__); 505ab4382d2SGreg Kroah-Hartman of_node_put(np); 506ab4382d2SGreg Kroah-Hartman return -ENODEV; 507ab4382d2SGreg Kroah-Hartman } 508ab4382d2SGreg Kroah-Hartman 509ab4382d2SGreg Kroah-Hartman psc_fifoc_irq = irq_of_parse_and_map(np, 0); 510ab4382d2SGreg Kroah-Hartman of_node_put(np); 511d4e33facSAlan Cox if (psc_fifoc_irq == 0) { 512ab4382d2SGreg Kroah-Hartman pr_err("%s: Can't get FIFOC irq\n", __func__); 513ab4382d2SGreg Kroah-Hartman iounmap(psc_fifoc); 514ab4382d2SGreg Kroah-Hartman return -ENODEV; 515ab4382d2SGreg Kroah-Hartman } 516ab4382d2SGreg Kroah-Hartman 517ab4382d2SGreg Kroah-Hartman return 0; 518ab4382d2SGreg Kroah-Hartman } 519ab4382d2SGreg Kroah-Hartman 520ab4382d2SGreg Kroah-Hartman static void __exit mpc512x_psc_fifoc_uninit(void) 521ab4382d2SGreg Kroah-Hartman { 522ab4382d2SGreg Kroah-Hartman iounmap(psc_fifoc); 523ab4382d2SGreg Kroah-Hartman } 524ab4382d2SGreg Kroah-Hartman 525ab4382d2SGreg Kroah-Hartman /* 512x specific interrupt handler. The caller holds the port lock */ 526ab4382d2SGreg Kroah-Hartman static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) 527ab4382d2SGreg Kroah-Hartman { 528ab4382d2SGreg Kroah-Hartman unsigned long fifoc_int; 529ab4382d2SGreg Kroah-Hartman int psc_num; 530ab4382d2SGreg Kroah-Hartman 531ab4382d2SGreg Kroah-Hartman /* Read pending PSC FIFOC interrupts */ 532ab4382d2SGreg Kroah-Hartman fifoc_int = in_be32(&psc_fifoc->fifoc_int); 533ab4382d2SGreg Kroah-Hartman 534ab4382d2SGreg Kroah-Hartman /* Check if it is an interrupt for this port */ 535ab4382d2SGreg Kroah-Hartman psc_num = (port->mapbase & 0xf00) >> 8; 536ab4382d2SGreg Kroah-Hartman if (test_bit(psc_num, &fifoc_int) || 537ab4382d2SGreg Kroah-Hartman test_bit(psc_num + 16, &fifoc_int)) 538ab4382d2SGreg Kroah-Hartman return mpc5xxx_uart_process_int(port); 539ab4382d2SGreg Kroah-Hartman 540ab4382d2SGreg Kroah-Hartman return IRQ_NONE; 541ab4382d2SGreg Kroah-Hartman } 542ab4382d2SGreg Kroah-Hartman 543ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_clock(struct uart_port *port, int enable) 544ab4382d2SGreg Kroah-Hartman { 545ab4382d2SGreg Kroah-Hartman struct clk *psc_clk; 546ab4382d2SGreg Kroah-Hartman int psc_num; 547ab4382d2SGreg Kroah-Hartman char clk_name[10]; 548ab4382d2SGreg Kroah-Hartman 549ab4382d2SGreg Kroah-Hartman if (uart_console(port)) 550ab4382d2SGreg Kroah-Hartman return 0; 551ab4382d2SGreg Kroah-Hartman 552ab4382d2SGreg Kroah-Hartman psc_num = (port->mapbase & 0xf00) >> 8; 553ab4382d2SGreg Kroah-Hartman snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num); 554ab4382d2SGreg Kroah-Hartman psc_clk = clk_get(port->dev, clk_name); 555ab4382d2SGreg Kroah-Hartman if (IS_ERR(psc_clk)) { 556ab4382d2SGreg Kroah-Hartman dev_err(port->dev, "Failed to get PSC clock entry!\n"); 557ab4382d2SGreg Kroah-Hartman return -ENODEV; 558ab4382d2SGreg Kroah-Hartman } 559ab4382d2SGreg Kroah-Hartman 560ab4382d2SGreg Kroah-Hartman dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis"); 561ab4382d2SGreg Kroah-Hartman 562ab4382d2SGreg Kroah-Hartman if (enable) 563ab4382d2SGreg Kroah-Hartman clk_enable(psc_clk); 564ab4382d2SGreg Kroah-Hartman else 565ab4382d2SGreg Kroah-Hartman clk_disable(psc_clk); 566ab4382d2SGreg Kroah-Hartman 567ab4382d2SGreg Kroah-Hartman return 0; 568ab4382d2SGreg Kroah-Hartman } 569ab4382d2SGreg Kroah-Hartman 570ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np) 571ab4382d2SGreg Kroah-Hartman { 572ab4382d2SGreg Kroah-Hartman port->irqflags = IRQF_SHARED; 573ab4382d2SGreg Kroah-Hartman port->irq = psc_fifoc_irq; 574ab4382d2SGreg Kroah-Hartman } 575ab4382d2SGreg Kroah-Hartman 576ab4382d2SGreg Kroah-Hartman static struct psc_ops mpc512x_psc_ops = { 577ab4382d2SGreg Kroah-Hartman .fifo_init = mpc512x_psc_fifo_init, 578ab4382d2SGreg Kroah-Hartman .raw_rx_rdy = mpc512x_psc_raw_rx_rdy, 579ab4382d2SGreg Kroah-Hartman .raw_tx_rdy = mpc512x_psc_raw_tx_rdy, 580ab4382d2SGreg Kroah-Hartman .rx_rdy = mpc512x_psc_rx_rdy, 581ab4382d2SGreg Kroah-Hartman .tx_rdy = mpc512x_psc_tx_rdy, 582ab4382d2SGreg Kroah-Hartman .tx_empty = mpc512x_psc_tx_empty, 583ab4382d2SGreg Kroah-Hartman .stop_rx = mpc512x_psc_stop_rx, 584ab4382d2SGreg Kroah-Hartman .start_tx = mpc512x_psc_start_tx, 585ab4382d2SGreg Kroah-Hartman .stop_tx = mpc512x_psc_stop_tx, 586ab4382d2SGreg Kroah-Hartman .rx_clr_irq = mpc512x_psc_rx_clr_irq, 587ab4382d2SGreg Kroah-Hartman .tx_clr_irq = mpc512x_psc_tx_clr_irq, 588ab4382d2SGreg Kroah-Hartman .write_char = mpc512x_psc_write_char, 589ab4382d2SGreg Kroah-Hartman .read_char = mpc512x_psc_read_char, 590ab4382d2SGreg Kroah-Hartman .cw_disable_ints = mpc512x_psc_cw_disable_ints, 591ab4382d2SGreg Kroah-Hartman .cw_restore_ints = mpc512x_psc_cw_restore_ints, 592ab4382d2SGreg Kroah-Hartman .set_baudrate = mpc512x_psc_set_baudrate, 593ab4382d2SGreg Kroah-Hartman .clock = mpc512x_psc_clock, 594ab4382d2SGreg Kroah-Hartman .fifoc_init = mpc512x_psc_fifoc_init, 595ab4382d2SGreg Kroah-Hartman .fifoc_uninit = mpc512x_psc_fifoc_uninit, 596ab4382d2SGreg Kroah-Hartman .get_irq = mpc512x_psc_get_irq, 597ab4382d2SGreg Kroah-Hartman .handle_irq = mpc512x_psc_handle_irq, 598ab4382d2SGreg Kroah-Hartman }; 599ab4382d2SGreg Kroah-Hartman #endif 600ab4382d2SGreg Kroah-Hartman 601ab4382d2SGreg Kroah-Hartman static struct psc_ops *psc_ops; 602ab4382d2SGreg Kroah-Hartman 603ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 604ab4382d2SGreg Kroah-Hartman /* UART operations */ 605ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 606ab4382d2SGreg Kroah-Hartman 607ab4382d2SGreg Kroah-Hartman static unsigned int 608ab4382d2SGreg Kroah-Hartman mpc52xx_uart_tx_empty(struct uart_port *port) 609ab4382d2SGreg Kroah-Hartman { 610ab4382d2SGreg Kroah-Hartman return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0; 611ab4382d2SGreg Kroah-Hartman } 612ab4382d2SGreg Kroah-Hartman 613ab4382d2SGreg Kroah-Hartman static void 614ab4382d2SGreg Kroah-Hartman mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) 615ab4382d2SGreg Kroah-Hartman { 616ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_RTS) 617ab4382d2SGreg Kroah-Hartman out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS); 618ab4382d2SGreg Kroah-Hartman else 619ab4382d2SGreg Kroah-Hartman out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS); 620ab4382d2SGreg Kroah-Hartman } 621ab4382d2SGreg Kroah-Hartman 622ab4382d2SGreg Kroah-Hartman static unsigned int 623ab4382d2SGreg Kroah-Hartman mpc52xx_uart_get_mctrl(struct uart_port *port) 624ab4382d2SGreg Kroah-Hartman { 625ab4382d2SGreg Kroah-Hartman unsigned int ret = TIOCM_DSR; 626ab4382d2SGreg Kroah-Hartman u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr); 627ab4382d2SGreg Kroah-Hartman 628ab4382d2SGreg Kroah-Hartman if (!(status & MPC52xx_PSC_CTS)) 629ab4382d2SGreg Kroah-Hartman ret |= TIOCM_CTS; 630ab4382d2SGreg Kroah-Hartman if (!(status & MPC52xx_PSC_DCD)) 631ab4382d2SGreg Kroah-Hartman ret |= TIOCM_CAR; 632ab4382d2SGreg Kroah-Hartman 633ab4382d2SGreg Kroah-Hartman return ret; 634ab4382d2SGreg Kroah-Hartman } 635ab4382d2SGreg Kroah-Hartman 636ab4382d2SGreg Kroah-Hartman static void 637ab4382d2SGreg Kroah-Hartman mpc52xx_uart_stop_tx(struct uart_port *port) 638ab4382d2SGreg Kroah-Hartman { 639ab4382d2SGreg Kroah-Hartman /* port->lock taken by caller */ 640ab4382d2SGreg Kroah-Hartman psc_ops->stop_tx(port); 641ab4382d2SGreg Kroah-Hartman } 642ab4382d2SGreg Kroah-Hartman 643ab4382d2SGreg Kroah-Hartman static void 644ab4382d2SGreg Kroah-Hartman mpc52xx_uart_start_tx(struct uart_port *port) 645ab4382d2SGreg Kroah-Hartman { 646ab4382d2SGreg Kroah-Hartman /* port->lock taken by caller */ 647ab4382d2SGreg Kroah-Hartman psc_ops->start_tx(port); 648ab4382d2SGreg Kroah-Hartman } 649ab4382d2SGreg Kroah-Hartman 650ab4382d2SGreg Kroah-Hartman static void 651ab4382d2SGreg Kroah-Hartman mpc52xx_uart_send_xchar(struct uart_port *port, char ch) 652ab4382d2SGreg Kroah-Hartman { 653ab4382d2SGreg Kroah-Hartman unsigned long flags; 654ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, flags); 655ab4382d2SGreg Kroah-Hartman 656ab4382d2SGreg Kroah-Hartman port->x_char = ch; 657ab4382d2SGreg Kroah-Hartman if (ch) { 658ab4382d2SGreg Kroah-Hartman /* Make sure tx interrupts are on */ 659ab4382d2SGreg Kroah-Hartman /* Truly necessary ??? They should be anyway */ 660ab4382d2SGreg Kroah-Hartman psc_ops->start_tx(port); 661ab4382d2SGreg Kroah-Hartman } 662ab4382d2SGreg Kroah-Hartman 663ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags); 664ab4382d2SGreg Kroah-Hartman } 665ab4382d2SGreg Kroah-Hartman 666ab4382d2SGreg Kroah-Hartman static void 667ab4382d2SGreg Kroah-Hartman mpc52xx_uart_stop_rx(struct uart_port *port) 668ab4382d2SGreg Kroah-Hartman { 669ab4382d2SGreg Kroah-Hartman /* port->lock taken by caller */ 670ab4382d2SGreg Kroah-Hartman psc_ops->stop_rx(port); 671ab4382d2SGreg Kroah-Hartman } 672ab4382d2SGreg Kroah-Hartman 673ab4382d2SGreg Kroah-Hartman static void 674ab4382d2SGreg Kroah-Hartman mpc52xx_uart_enable_ms(struct uart_port *port) 675ab4382d2SGreg Kroah-Hartman { 676ab4382d2SGreg Kroah-Hartman struct mpc52xx_psc __iomem *psc = PSC(port); 677ab4382d2SGreg Kroah-Hartman 678ab4382d2SGreg Kroah-Hartman /* clear D_*-bits by reading them */ 679ab4382d2SGreg Kroah-Hartman in_8(&psc->mpc52xx_psc_ipcr); 680ab4382d2SGreg Kroah-Hartman /* enable CTS and DCD as IPC interrupts */ 681ab4382d2SGreg Kroah-Hartman out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD); 682ab4382d2SGreg Kroah-Hartman 683ab4382d2SGreg Kroah-Hartman port->read_status_mask |= MPC52xx_PSC_IMR_IPC; 684ab4382d2SGreg Kroah-Hartman out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); 685ab4382d2SGreg Kroah-Hartman } 686ab4382d2SGreg Kroah-Hartman 687ab4382d2SGreg Kroah-Hartman static void 688ab4382d2SGreg Kroah-Hartman mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) 689ab4382d2SGreg Kroah-Hartman { 690ab4382d2SGreg Kroah-Hartman unsigned long flags; 691ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, flags); 692ab4382d2SGreg Kroah-Hartman 693ab4382d2SGreg Kroah-Hartman if (ctl == -1) 694ab4382d2SGreg Kroah-Hartman out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK); 695ab4382d2SGreg Kroah-Hartman else 696ab4382d2SGreg Kroah-Hartman out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK); 697ab4382d2SGreg Kroah-Hartman 698ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags); 699ab4382d2SGreg Kroah-Hartman } 700ab4382d2SGreg Kroah-Hartman 701ab4382d2SGreg Kroah-Hartman static int 702ab4382d2SGreg Kroah-Hartman mpc52xx_uart_startup(struct uart_port *port) 703ab4382d2SGreg Kroah-Hartman { 704ab4382d2SGreg Kroah-Hartman struct mpc52xx_psc __iomem *psc = PSC(port); 705ab4382d2SGreg Kroah-Hartman int ret; 706ab4382d2SGreg Kroah-Hartman 707ab4382d2SGreg Kroah-Hartman if (psc_ops->clock) { 708ab4382d2SGreg Kroah-Hartman ret = psc_ops->clock(port, 1); 709ab4382d2SGreg Kroah-Hartman if (ret) 710ab4382d2SGreg Kroah-Hartman return ret; 711ab4382d2SGreg Kroah-Hartman } 712ab4382d2SGreg Kroah-Hartman 713ab4382d2SGreg Kroah-Hartman /* Request IRQ */ 714ab4382d2SGreg Kroah-Hartman ret = request_irq(port->irq, mpc52xx_uart_int, 715ab4382d2SGreg Kroah-Hartman port->irqflags, "mpc52xx_psc_uart", port); 716ab4382d2SGreg Kroah-Hartman if (ret) 717ab4382d2SGreg Kroah-Hartman return ret; 718ab4382d2SGreg Kroah-Hartman 719ab4382d2SGreg Kroah-Hartman /* Reset/activate the port, clear and enable interrupts */ 720ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_RST_RX); 721ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_RST_TX); 722ab4382d2SGreg Kroah-Hartman 723ab4382d2SGreg Kroah-Hartman out_be32(&psc->sicr, 0); /* UART mode DCD ignored */ 724ab4382d2SGreg Kroah-Hartman 725ab4382d2SGreg Kroah-Hartman psc_ops->fifo_init(port); 726ab4382d2SGreg Kroah-Hartman 727ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); 728ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); 729ab4382d2SGreg Kroah-Hartman 730ab4382d2SGreg Kroah-Hartman return 0; 731ab4382d2SGreg Kroah-Hartman } 732ab4382d2SGreg Kroah-Hartman 733ab4382d2SGreg Kroah-Hartman static void 734ab4382d2SGreg Kroah-Hartman mpc52xx_uart_shutdown(struct uart_port *port) 735ab4382d2SGreg Kroah-Hartman { 736ab4382d2SGreg Kroah-Hartman struct mpc52xx_psc __iomem *psc = PSC(port); 737ab4382d2SGreg Kroah-Hartman 738ab4382d2SGreg Kroah-Hartman /* Shut down the port. Leave TX active if on a console port */ 739ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_RST_RX); 740ab4382d2SGreg Kroah-Hartman if (!uart_console(port)) 741ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_RST_TX); 742ab4382d2SGreg Kroah-Hartman 743ab4382d2SGreg Kroah-Hartman port->read_status_mask = 0; 744ab4382d2SGreg Kroah-Hartman out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); 745ab4382d2SGreg Kroah-Hartman 746ab4382d2SGreg Kroah-Hartman if (psc_ops->clock) 747ab4382d2SGreg Kroah-Hartman psc_ops->clock(port, 0); 748ab4382d2SGreg Kroah-Hartman 749ab4382d2SGreg Kroah-Hartman /* Release interrupt */ 750ab4382d2SGreg Kroah-Hartman free_irq(port->irq, port); 751ab4382d2SGreg Kroah-Hartman } 752ab4382d2SGreg Kroah-Hartman 753ab4382d2SGreg Kroah-Hartman static void 754ab4382d2SGreg Kroah-Hartman mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, 755ab4382d2SGreg Kroah-Hartman struct ktermios *old) 756ab4382d2SGreg Kroah-Hartman { 757ab4382d2SGreg Kroah-Hartman struct mpc52xx_psc __iomem *psc = PSC(port); 758ab4382d2SGreg Kroah-Hartman unsigned long flags; 759ab4382d2SGreg Kroah-Hartman unsigned char mr1, mr2; 760ab4382d2SGreg Kroah-Hartman unsigned int j; 761ab4382d2SGreg Kroah-Hartman unsigned int baud; 762ab4382d2SGreg Kroah-Hartman 763ab4382d2SGreg Kroah-Hartman /* Prepare what we're gonna write */ 764ab4382d2SGreg Kroah-Hartman mr1 = 0; 765ab4382d2SGreg Kroah-Hartman 766ab4382d2SGreg Kroah-Hartman switch (new->c_cflag & CSIZE) { 767ab4382d2SGreg Kroah-Hartman case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS; 768ab4382d2SGreg Kroah-Hartman break; 769ab4382d2SGreg Kroah-Hartman case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS; 770ab4382d2SGreg Kroah-Hartman break; 771ab4382d2SGreg Kroah-Hartman case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS; 772ab4382d2SGreg Kroah-Hartman break; 773ab4382d2SGreg Kroah-Hartman case CS8: 774ab4382d2SGreg Kroah-Hartman default: mr1 |= MPC52xx_PSC_MODE_8_BITS; 775ab4382d2SGreg Kroah-Hartman } 776ab4382d2SGreg Kroah-Hartman 777ab4382d2SGreg Kroah-Hartman if (new->c_cflag & PARENB) { 778ab4382d2SGreg Kroah-Hartman mr1 |= (new->c_cflag & PARODD) ? 779ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN; 780ab4382d2SGreg Kroah-Hartman } else 781ab4382d2SGreg Kroah-Hartman mr1 |= MPC52xx_PSC_MODE_PARNONE; 782ab4382d2SGreg Kroah-Hartman 783ab4382d2SGreg Kroah-Hartman 784ab4382d2SGreg Kroah-Hartman mr2 = 0; 785ab4382d2SGreg Kroah-Hartman 786ab4382d2SGreg Kroah-Hartman if (new->c_cflag & CSTOPB) 787ab4382d2SGreg Kroah-Hartman mr2 |= MPC52xx_PSC_MODE_TWO_STOP; 788ab4382d2SGreg Kroah-Hartman else 789ab4382d2SGreg Kroah-Hartman mr2 |= ((new->c_cflag & CSIZE) == CS5) ? 790ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_MODE_ONE_STOP_5_BITS : 791ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_MODE_ONE_STOP; 792ab4382d2SGreg Kroah-Hartman 793ab4382d2SGreg Kroah-Hartman if (new->c_cflag & CRTSCTS) { 794ab4382d2SGreg Kroah-Hartman mr1 |= MPC52xx_PSC_MODE_RXRTS; 795ab4382d2SGreg Kroah-Hartman mr2 |= MPC52xx_PSC_MODE_TXCTS; 796ab4382d2SGreg Kroah-Hartman } 797ab4382d2SGreg Kroah-Hartman 798ab4382d2SGreg Kroah-Hartman /* Get the lock */ 799ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, flags); 800ab4382d2SGreg Kroah-Hartman 801ab4382d2SGreg Kroah-Hartman /* Do our best to flush TX & RX, so we don't lose anything */ 802ab4382d2SGreg Kroah-Hartman /* But we don't wait indefinitely ! */ 803ab4382d2SGreg Kroah-Hartman j = 5000000; /* Maximum wait */ 804ab4382d2SGreg Kroah-Hartman /* FIXME Can't receive chars since set_termios might be called at early 805ab4382d2SGreg Kroah-Hartman * boot for the console, all stuff is not yet ready to receive at that 806ab4382d2SGreg Kroah-Hartman * time and that just makes the kernel oops */ 807ab4382d2SGreg Kroah-Hartman /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ 808ab4382d2SGreg Kroah-Hartman while (!mpc52xx_uart_tx_empty(port) && --j) 809ab4382d2SGreg Kroah-Hartman udelay(1); 810ab4382d2SGreg Kroah-Hartman 811ab4382d2SGreg Kroah-Hartman if (!j) 812ab4382d2SGreg Kroah-Hartman printk(KERN_ERR "mpc52xx_uart.c: " 813ab4382d2SGreg Kroah-Hartman "Unable to flush RX & TX fifos in-time in set_termios." 814ab4382d2SGreg Kroah-Hartman "Some chars may have been lost.\n"); 815ab4382d2SGreg Kroah-Hartman 816ab4382d2SGreg Kroah-Hartman /* Reset the TX & RX */ 817ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_RST_RX); 818ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_RST_TX); 819ab4382d2SGreg Kroah-Hartman 820ab4382d2SGreg Kroah-Hartman /* Send new mode settings */ 821ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); 822ab4382d2SGreg Kroah-Hartman out_8(&psc->mode, mr1); 823ab4382d2SGreg Kroah-Hartman out_8(&psc->mode, mr2); 824ab4382d2SGreg Kroah-Hartman baud = psc_ops->set_baudrate(port, new, old); 825ab4382d2SGreg Kroah-Hartman 826ab4382d2SGreg Kroah-Hartman /* Update the per-port timeout */ 827ab4382d2SGreg Kroah-Hartman uart_update_timeout(port, new->c_cflag, baud); 828ab4382d2SGreg Kroah-Hartman 829ab4382d2SGreg Kroah-Hartman if (UART_ENABLE_MS(port, new->c_cflag)) 830ab4382d2SGreg Kroah-Hartman mpc52xx_uart_enable_ms(port); 831ab4382d2SGreg Kroah-Hartman 832ab4382d2SGreg Kroah-Hartman /* Reenable TX & RX */ 833ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); 834ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); 835ab4382d2SGreg Kroah-Hartman 836ab4382d2SGreg Kroah-Hartman /* We're all set, release the lock */ 837ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags); 838ab4382d2SGreg Kroah-Hartman } 839ab4382d2SGreg Kroah-Hartman 840ab4382d2SGreg Kroah-Hartman static const char * 841ab4382d2SGreg Kroah-Hartman mpc52xx_uart_type(struct uart_port *port) 842ab4382d2SGreg Kroah-Hartman { 843ab4382d2SGreg Kroah-Hartman /* 844ab4382d2SGreg Kroah-Hartman * We keep using PORT_MPC52xx for historic reasons although it applies 845ab4382d2SGreg Kroah-Hartman * for MPC512x, too, but print "MPC5xxx" to not irritate users 846ab4382d2SGreg Kroah-Hartman */ 847ab4382d2SGreg Kroah-Hartman return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL; 848ab4382d2SGreg Kroah-Hartman } 849ab4382d2SGreg Kroah-Hartman 850ab4382d2SGreg Kroah-Hartman static void 851ab4382d2SGreg Kroah-Hartman mpc52xx_uart_release_port(struct uart_port *port) 852ab4382d2SGreg Kroah-Hartman { 853ab4382d2SGreg Kroah-Hartman /* remapped by us ? */ 854ab4382d2SGreg Kroah-Hartman if (port->flags & UPF_IOREMAP) { 855ab4382d2SGreg Kroah-Hartman iounmap(port->membase); 856ab4382d2SGreg Kroah-Hartman port->membase = NULL; 857ab4382d2SGreg Kroah-Hartman } 858ab4382d2SGreg Kroah-Hartman 859ab4382d2SGreg Kroah-Hartman release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); 860ab4382d2SGreg Kroah-Hartman } 861ab4382d2SGreg Kroah-Hartman 862ab4382d2SGreg Kroah-Hartman static int 863ab4382d2SGreg Kroah-Hartman mpc52xx_uart_request_port(struct uart_port *port) 864ab4382d2SGreg Kroah-Hartman { 865ab4382d2SGreg Kroah-Hartman int err; 866ab4382d2SGreg Kroah-Hartman 867ab4382d2SGreg Kroah-Hartman if (port->flags & UPF_IOREMAP) /* Need to remap ? */ 868ab4382d2SGreg Kroah-Hartman port->membase = ioremap(port->mapbase, 869ab4382d2SGreg Kroah-Hartman sizeof(struct mpc52xx_psc)); 870ab4382d2SGreg Kroah-Hartman 871ab4382d2SGreg Kroah-Hartman if (!port->membase) 872ab4382d2SGreg Kroah-Hartman return -EINVAL; 873ab4382d2SGreg Kroah-Hartman 874ab4382d2SGreg Kroah-Hartman err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc), 875ab4382d2SGreg Kroah-Hartman "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY; 876ab4382d2SGreg Kroah-Hartman 877ab4382d2SGreg Kroah-Hartman if (err && (port->flags & UPF_IOREMAP)) { 878ab4382d2SGreg Kroah-Hartman iounmap(port->membase); 879ab4382d2SGreg Kroah-Hartman port->membase = NULL; 880ab4382d2SGreg Kroah-Hartman } 881ab4382d2SGreg Kroah-Hartman 882ab4382d2SGreg Kroah-Hartman return err; 883ab4382d2SGreg Kroah-Hartman } 884ab4382d2SGreg Kroah-Hartman 885ab4382d2SGreg Kroah-Hartman static void 886ab4382d2SGreg Kroah-Hartman mpc52xx_uart_config_port(struct uart_port *port, int flags) 887ab4382d2SGreg Kroah-Hartman { 888ab4382d2SGreg Kroah-Hartman if ((flags & UART_CONFIG_TYPE) 889ab4382d2SGreg Kroah-Hartman && (mpc52xx_uart_request_port(port) == 0)) 890ab4382d2SGreg Kroah-Hartman port->type = PORT_MPC52xx; 891ab4382d2SGreg Kroah-Hartman } 892ab4382d2SGreg Kroah-Hartman 893ab4382d2SGreg Kroah-Hartman static int 894ab4382d2SGreg Kroah-Hartman mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) 895ab4382d2SGreg Kroah-Hartman { 896ab4382d2SGreg Kroah-Hartman if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx) 897ab4382d2SGreg Kroah-Hartman return -EINVAL; 898ab4382d2SGreg Kroah-Hartman 899ab4382d2SGreg Kroah-Hartman if ((ser->irq != port->irq) || 900ab4382d2SGreg Kroah-Hartman (ser->io_type != UPIO_MEM) || 901ab4382d2SGreg Kroah-Hartman (ser->baud_base != port->uartclk) || 902ab4382d2SGreg Kroah-Hartman (ser->iomem_base != (void *)port->mapbase) || 903ab4382d2SGreg Kroah-Hartman (ser->hub6 != 0)) 904ab4382d2SGreg Kroah-Hartman return -EINVAL; 905ab4382d2SGreg Kroah-Hartman 906ab4382d2SGreg Kroah-Hartman return 0; 907ab4382d2SGreg Kroah-Hartman } 908ab4382d2SGreg Kroah-Hartman 909ab4382d2SGreg Kroah-Hartman 910ab4382d2SGreg Kroah-Hartman static struct uart_ops mpc52xx_uart_ops = { 911ab4382d2SGreg Kroah-Hartman .tx_empty = mpc52xx_uart_tx_empty, 912ab4382d2SGreg Kroah-Hartman .set_mctrl = mpc52xx_uart_set_mctrl, 913ab4382d2SGreg Kroah-Hartman .get_mctrl = mpc52xx_uart_get_mctrl, 914ab4382d2SGreg Kroah-Hartman .stop_tx = mpc52xx_uart_stop_tx, 915ab4382d2SGreg Kroah-Hartman .start_tx = mpc52xx_uart_start_tx, 916ab4382d2SGreg Kroah-Hartman .send_xchar = mpc52xx_uart_send_xchar, 917ab4382d2SGreg Kroah-Hartman .stop_rx = mpc52xx_uart_stop_rx, 918ab4382d2SGreg Kroah-Hartman .enable_ms = mpc52xx_uart_enable_ms, 919ab4382d2SGreg Kroah-Hartman .break_ctl = mpc52xx_uart_break_ctl, 920ab4382d2SGreg Kroah-Hartman .startup = mpc52xx_uart_startup, 921ab4382d2SGreg Kroah-Hartman .shutdown = mpc52xx_uart_shutdown, 922ab4382d2SGreg Kroah-Hartman .set_termios = mpc52xx_uart_set_termios, 923ab4382d2SGreg Kroah-Hartman /* .pm = mpc52xx_uart_pm, Not supported yet */ 924ab4382d2SGreg Kroah-Hartman /* .set_wake = mpc52xx_uart_set_wake, Not supported yet */ 925ab4382d2SGreg Kroah-Hartman .type = mpc52xx_uart_type, 926ab4382d2SGreg Kroah-Hartman .release_port = mpc52xx_uart_release_port, 927ab4382d2SGreg Kroah-Hartman .request_port = mpc52xx_uart_request_port, 928ab4382d2SGreg Kroah-Hartman .config_port = mpc52xx_uart_config_port, 929ab4382d2SGreg Kroah-Hartman .verify_port = mpc52xx_uart_verify_port 930ab4382d2SGreg Kroah-Hartman }; 931ab4382d2SGreg Kroah-Hartman 932ab4382d2SGreg Kroah-Hartman 933ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 934ab4382d2SGreg Kroah-Hartman /* Interrupt handling */ 935ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 936ab4382d2SGreg Kroah-Hartman 937ab4382d2SGreg Kroah-Hartman static inline int 938ab4382d2SGreg Kroah-Hartman mpc52xx_uart_int_rx_chars(struct uart_port *port) 939ab4382d2SGreg Kroah-Hartman { 940ab4382d2SGreg Kroah-Hartman struct tty_struct *tty = port->state->port.tty; 941ab4382d2SGreg Kroah-Hartman unsigned char ch, flag; 942ab4382d2SGreg Kroah-Hartman unsigned short status; 943ab4382d2SGreg Kroah-Hartman 944ab4382d2SGreg Kroah-Hartman /* While we can read, do so ! */ 945ab4382d2SGreg Kroah-Hartman while (psc_ops->raw_rx_rdy(port)) { 946ab4382d2SGreg Kroah-Hartman /* Get the char */ 947ab4382d2SGreg Kroah-Hartman ch = psc_ops->read_char(port); 948ab4382d2SGreg Kroah-Hartman 949ab4382d2SGreg Kroah-Hartman /* Handle sysreq char */ 950ab4382d2SGreg Kroah-Hartman #ifdef SUPPORT_SYSRQ 951ab4382d2SGreg Kroah-Hartman if (uart_handle_sysrq_char(port, ch)) { 952ab4382d2SGreg Kroah-Hartman port->sysrq = 0; 953ab4382d2SGreg Kroah-Hartman continue; 954ab4382d2SGreg Kroah-Hartman } 955ab4382d2SGreg Kroah-Hartman #endif 956ab4382d2SGreg Kroah-Hartman 957ab4382d2SGreg Kroah-Hartman /* Store it */ 958ab4382d2SGreg Kroah-Hartman 959ab4382d2SGreg Kroah-Hartman flag = TTY_NORMAL; 960ab4382d2SGreg Kroah-Hartman port->icount.rx++; 961ab4382d2SGreg Kroah-Hartman 962ab4382d2SGreg Kroah-Hartman status = in_be16(&PSC(port)->mpc52xx_psc_status); 963ab4382d2SGreg Kroah-Hartman 964ab4382d2SGreg Kroah-Hartman if (status & (MPC52xx_PSC_SR_PE | 965ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_SR_FE | 966ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_SR_RB)) { 967ab4382d2SGreg Kroah-Hartman 968ab4382d2SGreg Kroah-Hartman if (status & MPC52xx_PSC_SR_RB) { 969ab4382d2SGreg Kroah-Hartman flag = TTY_BREAK; 970ab4382d2SGreg Kroah-Hartman uart_handle_break(port); 971ab4382d2SGreg Kroah-Hartman port->icount.brk++; 972ab4382d2SGreg Kroah-Hartman } else if (status & MPC52xx_PSC_SR_PE) { 973ab4382d2SGreg Kroah-Hartman flag = TTY_PARITY; 974ab4382d2SGreg Kroah-Hartman port->icount.parity++; 975ab4382d2SGreg Kroah-Hartman } 976ab4382d2SGreg Kroah-Hartman else if (status & MPC52xx_PSC_SR_FE) { 977ab4382d2SGreg Kroah-Hartman flag = TTY_FRAME; 978ab4382d2SGreg Kroah-Hartman port->icount.frame++; 979ab4382d2SGreg Kroah-Hartman } 980ab4382d2SGreg Kroah-Hartman 981ab4382d2SGreg Kroah-Hartman /* Clear error condition */ 982ab4382d2SGreg Kroah-Hartman out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT); 983ab4382d2SGreg Kroah-Hartman 984ab4382d2SGreg Kroah-Hartman } 985ab4382d2SGreg Kroah-Hartman tty_insert_flip_char(tty, ch, flag); 986ab4382d2SGreg Kroah-Hartman if (status & MPC52xx_PSC_SR_OE) { 987ab4382d2SGreg Kroah-Hartman /* 988ab4382d2SGreg Kroah-Hartman * Overrun is special, since it's 989ab4382d2SGreg Kroah-Hartman * reported immediately, and doesn't 990ab4382d2SGreg Kroah-Hartman * affect the current character 991ab4382d2SGreg Kroah-Hartman */ 992ab4382d2SGreg Kroah-Hartman tty_insert_flip_char(tty, 0, TTY_OVERRUN); 993ab4382d2SGreg Kroah-Hartman port->icount.overrun++; 994ab4382d2SGreg Kroah-Hartman } 995ab4382d2SGreg Kroah-Hartman } 996ab4382d2SGreg Kroah-Hartman 997ab4382d2SGreg Kroah-Hartman spin_unlock(&port->lock); 998ab4382d2SGreg Kroah-Hartman tty_flip_buffer_push(tty); 999ab4382d2SGreg Kroah-Hartman spin_lock(&port->lock); 1000ab4382d2SGreg Kroah-Hartman 1001ab4382d2SGreg Kroah-Hartman return psc_ops->raw_rx_rdy(port); 1002ab4382d2SGreg Kroah-Hartman } 1003ab4382d2SGreg Kroah-Hartman 1004ab4382d2SGreg Kroah-Hartman static inline int 1005ab4382d2SGreg Kroah-Hartman mpc52xx_uart_int_tx_chars(struct uart_port *port) 1006ab4382d2SGreg Kroah-Hartman { 1007ab4382d2SGreg Kroah-Hartman struct circ_buf *xmit = &port->state->xmit; 1008ab4382d2SGreg Kroah-Hartman 1009ab4382d2SGreg Kroah-Hartman /* Process out of band chars */ 1010ab4382d2SGreg Kroah-Hartman if (port->x_char) { 1011ab4382d2SGreg Kroah-Hartman psc_ops->write_char(port, port->x_char); 1012ab4382d2SGreg Kroah-Hartman port->icount.tx++; 1013ab4382d2SGreg Kroah-Hartman port->x_char = 0; 1014ab4382d2SGreg Kroah-Hartman return 1; 1015ab4382d2SGreg Kroah-Hartman } 1016ab4382d2SGreg Kroah-Hartman 1017ab4382d2SGreg Kroah-Hartman /* Nothing to do ? */ 1018ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { 1019ab4382d2SGreg Kroah-Hartman mpc52xx_uart_stop_tx(port); 1020ab4382d2SGreg Kroah-Hartman return 0; 1021ab4382d2SGreg Kroah-Hartman } 1022ab4382d2SGreg Kroah-Hartman 1023ab4382d2SGreg Kroah-Hartman /* Send chars */ 1024ab4382d2SGreg Kroah-Hartman while (psc_ops->raw_tx_rdy(port)) { 1025ab4382d2SGreg Kroah-Hartman psc_ops->write_char(port, xmit->buf[xmit->tail]); 1026ab4382d2SGreg Kroah-Hartman xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 1027ab4382d2SGreg Kroah-Hartman port->icount.tx++; 1028ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit)) 1029ab4382d2SGreg Kroah-Hartman break; 1030ab4382d2SGreg Kroah-Hartman } 1031ab4382d2SGreg Kroah-Hartman 1032ab4382d2SGreg Kroah-Hartman /* Wake up */ 1033ab4382d2SGreg Kroah-Hartman if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 1034ab4382d2SGreg Kroah-Hartman uart_write_wakeup(port); 1035ab4382d2SGreg Kroah-Hartman 1036ab4382d2SGreg Kroah-Hartman /* Maybe we're done after all */ 1037ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit)) { 1038ab4382d2SGreg Kroah-Hartman mpc52xx_uart_stop_tx(port); 1039ab4382d2SGreg Kroah-Hartman return 0; 1040ab4382d2SGreg Kroah-Hartman } 1041ab4382d2SGreg Kroah-Hartman 1042ab4382d2SGreg Kroah-Hartman return 1; 1043ab4382d2SGreg Kroah-Hartman } 1044ab4382d2SGreg Kroah-Hartman 1045ab4382d2SGreg Kroah-Hartman static irqreturn_t 1046ab4382d2SGreg Kroah-Hartman mpc5xxx_uart_process_int(struct uart_port *port) 1047ab4382d2SGreg Kroah-Hartman { 1048ab4382d2SGreg Kroah-Hartman unsigned long pass = ISR_PASS_LIMIT; 1049ab4382d2SGreg Kroah-Hartman unsigned int keepgoing; 1050ab4382d2SGreg Kroah-Hartman u8 status; 1051ab4382d2SGreg Kroah-Hartman 1052ab4382d2SGreg Kroah-Hartman /* While we have stuff to do, we continue */ 1053ab4382d2SGreg Kroah-Hartman do { 1054ab4382d2SGreg Kroah-Hartman /* If we don't find anything to do, we stop */ 1055ab4382d2SGreg Kroah-Hartman keepgoing = 0; 1056ab4382d2SGreg Kroah-Hartman 1057ab4382d2SGreg Kroah-Hartman psc_ops->rx_clr_irq(port); 1058ab4382d2SGreg Kroah-Hartman if (psc_ops->rx_rdy(port)) 1059ab4382d2SGreg Kroah-Hartman keepgoing |= mpc52xx_uart_int_rx_chars(port); 1060ab4382d2SGreg Kroah-Hartman 1061ab4382d2SGreg Kroah-Hartman psc_ops->tx_clr_irq(port); 1062ab4382d2SGreg Kroah-Hartman if (psc_ops->tx_rdy(port)) 1063ab4382d2SGreg Kroah-Hartman keepgoing |= mpc52xx_uart_int_tx_chars(port); 1064ab4382d2SGreg Kroah-Hartman 1065ab4382d2SGreg Kroah-Hartman status = in_8(&PSC(port)->mpc52xx_psc_ipcr); 1066ab4382d2SGreg Kroah-Hartman if (status & MPC52xx_PSC_D_DCD) 1067ab4382d2SGreg Kroah-Hartman uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD)); 1068ab4382d2SGreg Kroah-Hartman 1069ab4382d2SGreg Kroah-Hartman if (status & MPC52xx_PSC_D_CTS) 1070ab4382d2SGreg Kroah-Hartman uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS)); 1071ab4382d2SGreg Kroah-Hartman 1072ab4382d2SGreg Kroah-Hartman /* Limit number of iteration */ 1073ab4382d2SGreg Kroah-Hartman if (!(--pass)) 1074ab4382d2SGreg Kroah-Hartman keepgoing = 0; 1075ab4382d2SGreg Kroah-Hartman 1076ab4382d2SGreg Kroah-Hartman } while (keepgoing); 1077ab4382d2SGreg Kroah-Hartman 1078ab4382d2SGreg Kroah-Hartman return IRQ_HANDLED; 1079ab4382d2SGreg Kroah-Hartman } 1080ab4382d2SGreg Kroah-Hartman 1081ab4382d2SGreg Kroah-Hartman static irqreturn_t 1082ab4382d2SGreg Kroah-Hartman mpc52xx_uart_int(int irq, void *dev_id) 1083ab4382d2SGreg Kroah-Hartman { 1084ab4382d2SGreg Kroah-Hartman struct uart_port *port = dev_id; 1085ab4382d2SGreg Kroah-Hartman irqreturn_t ret; 1086ab4382d2SGreg Kroah-Hartman 1087ab4382d2SGreg Kroah-Hartman spin_lock(&port->lock); 1088ab4382d2SGreg Kroah-Hartman 1089ab4382d2SGreg Kroah-Hartman ret = psc_ops->handle_irq(port); 1090ab4382d2SGreg Kroah-Hartman 1091ab4382d2SGreg Kroah-Hartman spin_unlock(&port->lock); 1092ab4382d2SGreg Kroah-Hartman 1093ab4382d2SGreg Kroah-Hartman return ret; 1094ab4382d2SGreg Kroah-Hartman } 1095ab4382d2SGreg Kroah-Hartman 1096ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1097ab4382d2SGreg Kroah-Hartman /* Console ( if applicable ) */ 1098ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1099ab4382d2SGreg Kroah-Hartman 1100ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_MPC52xx_CONSOLE 1101ab4382d2SGreg Kroah-Hartman 1102ab4382d2SGreg Kroah-Hartman static void __init 1103ab4382d2SGreg Kroah-Hartman mpc52xx_console_get_options(struct uart_port *port, 1104ab4382d2SGreg Kroah-Hartman int *baud, int *parity, int *bits, int *flow) 1105ab4382d2SGreg Kroah-Hartman { 1106ab4382d2SGreg Kroah-Hartman struct mpc52xx_psc __iomem *psc = PSC(port); 1107ab4382d2SGreg Kroah-Hartman unsigned char mr1; 1108ab4382d2SGreg Kroah-Hartman 1109ab4382d2SGreg Kroah-Hartman pr_debug("mpc52xx_console_get_options(port=%p)\n", port); 1110ab4382d2SGreg Kroah-Hartman 1111ab4382d2SGreg Kroah-Hartman /* Read the mode registers */ 1112ab4382d2SGreg Kroah-Hartman out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); 1113ab4382d2SGreg Kroah-Hartman mr1 = in_8(&psc->mode); 1114ab4382d2SGreg Kroah-Hartman 1115ab4382d2SGreg Kroah-Hartman /* CT{U,L}R are write-only ! */ 1116ab4382d2SGreg Kroah-Hartman *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; 1117ab4382d2SGreg Kroah-Hartman 1118ab4382d2SGreg Kroah-Hartman /* Parse them */ 1119ab4382d2SGreg Kroah-Hartman switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) { 1120ab4382d2SGreg Kroah-Hartman case MPC52xx_PSC_MODE_5_BITS: 1121ab4382d2SGreg Kroah-Hartman *bits = 5; 1122ab4382d2SGreg Kroah-Hartman break; 1123ab4382d2SGreg Kroah-Hartman case MPC52xx_PSC_MODE_6_BITS: 1124ab4382d2SGreg Kroah-Hartman *bits = 6; 1125ab4382d2SGreg Kroah-Hartman break; 1126ab4382d2SGreg Kroah-Hartman case MPC52xx_PSC_MODE_7_BITS: 1127ab4382d2SGreg Kroah-Hartman *bits = 7; 1128ab4382d2SGreg Kroah-Hartman break; 1129ab4382d2SGreg Kroah-Hartman case MPC52xx_PSC_MODE_8_BITS: 1130ab4382d2SGreg Kroah-Hartman default: 1131ab4382d2SGreg Kroah-Hartman *bits = 8; 1132ab4382d2SGreg Kroah-Hartman } 1133ab4382d2SGreg Kroah-Hartman 1134ab4382d2SGreg Kroah-Hartman if (mr1 & MPC52xx_PSC_MODE_PARNONE) 1135ab4382d2SGreg Kroah-Hartman *parity = 'n'; 1136ab4382d2SGreg Kroah-Hartman else 1137ab4382d2SGreg Kroah-Hartman *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e'; 1138ab4382d2SGreg Kroah-Hartman } 1139ab4382d2SGreg Kroah-Hartman 1140ab4382d2SGreg Kroah-Hartman static void 1141ab4382d2SGreg Kroah-Hartman mpc52xx_console_write(struct console *co, const char *s, unsigned int count) 1142ab4382d2SGreg Kroah-Hartman { 1143ab4382d2SGreg Kroah-Hartman struct uart_port *port = &mpc52xx_uart_ports[co->index]; 1144ab4382d2SGreg Kroah-Hartman unsigned int i, j; 1145ab4382d2SGreg Kroah-Hartman 1146ab4382d2SGreg Kroah-Hartman /* Disable interrupts */ 1147ab4382d2SGreg Kroah-Hartman psc_ops->cw_disable_ints(port); 1148ab4382d2SGreg Kroah-Hartman 1149ab4382d2SGreg Kroah-Hartman /* Wait the TX buffer to be empty */ 1150ab4382d2SGreg Kroah-Hartman j = 5000000; /* Maximum wait */ 1151ab4382d2SGreg Kroah-Hartman while (!mpc52xx_uart_tx_empty(port) && --j) 1152ab4382d2SGreg Kroah-Hartman udelay(1); 1153ab4382d2SGreg Kroah-Hartman 1154ab4382d2SGreg Kroah-Hartman /* Write all the chars */ 1155ab4382d2SGreg Kroah-Hartman for (i = 0; i < count; i++, s++) { 1156ab4382d2SGreg Kroah-Hartman /* Line return handling */ 1157ab4382d2SGreg Kroah-Hartman if (*s == '\n') 1158ab4382d2SGreg Kroah-Hartman psc_ops->write_char(port, '\r'); 1159ab4382d2SGreg Kroah-Hartman 1160ab4382d2SGreg Kroah-Hartman /* Send the char */ 1161ab4382d2SGreg Kroah-Hartman psc_ops->write_char(port, *s); 1162ab4382d2SGreg Kroah-Hartman 1163ab4382d2SGreg Kroah-Hartman /* Wait the TX buffer to be empty */ 1164ab4382d2SGreg Kroah-Hartman j = 20000; /* Maximum wait */ 1165ab4382d2SGreg Kroah-Hartman while (!mpc52xx_uart_tx_empty(port) && --j) 1166ab4382d2SGreg Kroah-Hartman udelay(1); 1167ab4382d2SGreg Kroah-Hartman } 1168ab4382d2SGreg Kroah-Hartman 1169ab4382d2SGreg Kroah-Hartman /* Restore interrupt state */ 1170ab4382d2SGreg Kroah-Hartman psc_ops->cw_restore_ints(port); 1171ab4382d2SGreg Kroah-Hartman } 1172ab4382d2SGreg Kroah-Hartman 1173ab4382d2SGreg Kroah-Hartman 1174ab4382d2SGreg Kroah-Hartman static int __init 1175ab4382d2SGreg Kroah-Hartman mpc52xx_console_setup(struct console *co, char *options) 1176ab4382d2SGreg Kroah-Hartman { 1177ab4382d2SGreg Kroah-Hartman struct uart_port *port = &mpc52xx_uart_ports[co->index]; 1178ab4382d2SGreg Kroah-Hartman struct device_node *np = mpc52xx_uart_nodes[co->index]; 1179ab4382d2SGreg Kroah-Hartman unsigned int uartclk; 1180ab4382d2SGreg Kroah-Hartman struct resource res; 1181ab4382d2SGreg Kroah-Hartman int ret; 1182ab4382d2SGreg Kroah-Hartman 1183ab4382d2SGreg Kroah-Hartman int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; 1184ab4382d2SGreg Kroah-Hartman int bits = 8; 1185ab4382d2SGreg Kroah-Hartman int parity = 'n'; 1186ab4382d2SGreg Kroah-Hartman int flow = 'n'; 1187ab4382d2SGreg Kroah-Hartman 1188ab4382d2SGreg Kroah-Hartman pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n", 1189ab4382d2SGreg Kroah-Hartman co, co->index, options); 1190ab4382d2SGreg Kroah-Hartman 1191ab4382d2SGreg Kroah-Hartman if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) { 1192ab4382d2SGreg Kroah-Hartman pr_debug("PSC%x out of range\n", co->index); 1193ab4382d2SGreg Kroah-Hartman return -EINVAL; 1194ab4382d2SGreg Kroah-Hartman } 1195ab4382d2SGreg Kroah-Hartman 1196ab4382d2SGreg Kroah-Hartman if (!np) { 1197ab4382d2SGreg Kroah-Hartman pr_debug("PSC%x not found in device tree\n", co->index); 1198ab4382d2SGreg Kroah-Hartman return -EINVAL; 1199ab4382d2SGreg Kroah-Hartman } 1200ab4382d2SGreg Kroah-Hartman 1201ab4382d2SGreg Kroah-Hartman pr_debug("Console on ttyPSC%x is %s\n", 1202ab4382d2SGreg Kroah-Hartman co->index, mpc52xx_uart_nodes[co->index]->full_name); 1203ab4382d2SGreg Kroah-Hartman 1204ab4382d2SGreg Kroah-Hartman /* Fetch register locations */ 1205ab4382d2SGreg Kroah-Hartman ret = of_address_to_resource(np, 0, &res); 1206ab4382d2SGreg Kroah-Hartman if (ret) { 1207ab4382d2SGreg Kroah-Hartman pr_debug("Could not get resources for PSC%x\n", co->index); 1208ab4382d2SGreg Kroah-Hartman return ret; 1209ab4382d2SGreg Kroah-Hartman } 1210ab4382d2SGreg Kroah-Hartman 1211ab4382d2SGreg Kroah-Hartman uartclk = mpc5xxx_get_bus_frequency(np); 1212ab4382d2SGreg Kroah-Hartman if (uartclk == 0) { 1213ab4382d2SGreg Kroah-Hartman pr_debug("Could not find uart clock frequency!\n"); 1214ab4382d2SGreg Kroah-Hartman return -EINVAL; 1215ab4382d2SGreg Kroah-Hartman } 1216ab4382d2SGreg Kroah-Hartman 1217ab4382d2SGreg Kroah-Hartman /* Basic port init. Needed since we use some uart_??? func before 1218ab4382d2SGreg Kroah-Hartman * real init for early access */ 1219ab4382d2SGreg Kroah-Hartman spin_lock_init(&port->lock); 1220ab4382d2SGreg Kroah-Hartman port->uartclk = uartclk; 1221ab4382d2SGreg Kroah-Hartman port->ops = &mpc52xx_uart_ops; 1222ab4382d2SGreg Kroah-Hartman port->mapbase = res.start; 1223ab4382d2SGreg Kroah-Hartman port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); 1224ab4382d2SGreg Kroah-Hartman port->irq = irq_of_parse_and_map(np, 0); 1225ab4382d2SGreg Kroah-Hartman 1226ab4382d2SGreg Kroah-Hartman if (port->membase == NULL) 1227ab4382d2SGreg Kroah-Hartman return -EINVAL; 1228ab4382d2SGreg Kroah-Hartman 1229ab4382d2SGreg Kroah-Hartman pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n", 1230ab4382d2SGreg Kroah-Hartman (void *)port->mapbase, port->membase, 1231ab4382d2SGreg Kroah-Hartman port->irq, port->uartclk); 1232ab4382d2SGreg Kroah-Hartman 1233ab4382d2SGreg Kroah-Hartman /* Setup the port parameters accoding to options */ 1234ab4382d2SGreg Kroah-Hartman if (options) 1235ab4382d2SGreg Kroah-Hartman uart_parse_options(options, &baud, &parity, &bits, &flow); 1236ab4382d2SGreg Kroah-Hartman else 1237ab4382d2SGreg Kroah-Hartman mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow); 1238ab4382d2SGreg Kroah-Hartman 1239ab4382d2SGreg Kroah-Hartman pr_debug("Setting console parameters: %i %i%c1 flow=%c\n", 1240ab4382d2SGreg Kroah-Hartman baud, bits, parity, flow); 1241ab4382d2SGreg Kroah-Hartman 1242ab4382d2SGreg Kroah-Hartman return uart_set_options(port, co, baud, parity, bits, flow); 1243ab4382d2SGreg Kroah-Hartman } 1244ab4382d2SGreg Kroah-Hartman 1245ab4382d2SGreg Kroah-Hartman 1246ab4382d2SGreg Kroah-Hartman static struct uart_driver mpc52xx_uart_driver; 1247ab4382d2SGreg Kroah-Hartman 1248ab4382d2SGreg Kroah-Hartman static struct console mpc52xx_console = { 1249ab4382d2SGreg Kroah-Hartman .name = "ttyPSC", 1250ab4382d2SGreg Kroah-Hartman .write = mpc52xx_console_write, 1251ab4382d2SGreg Kroah-Hartman .device = uart_console_device, 1252ab4382d2SGreg Kroah-Hartman .setup = mpc52xx_console_setup, 1253ab4382d2SGreg Kroah-Hartman .flags = CON_PRINTBUFFER, 1254ab4382d2SGreg Kroah-Hartman .index = -1, /* Specified on the cmdline (e.g. console=ttyPSC0) */ 1255ab4382d2SGreg Kroah-Hartman .data = &mpc52xx_uart_driver, 1256ab4382d2SGreg Kroah-Hartman }; 1257ab4382d2SGreg Kroah-Hartman 1258ab4382d2SGreg Kroah-Hartman 1259ab4382d2SGreg Kroah-Hartman static int __init 1260ab4382d2SGreg Kroah-Hartman mpc52xx_console_init(void) 1261ab4382d2SGreg Kroah-Hartman { 1262ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_enumerate(); 1263ab4382d2SGreg Kroah-Hartman register_console(&mpc52xx_console); 1264ab4382d2SGreg Kroah-Hartman return 0; 1265ab4382d2SGreg Kroah-Hartman } 1266ab4382d2SGreg Kroah-Hartman 1267ab4382d2SGreg Kroah-Hartman console_initcall(mpc52xx_console_init); 1268ab4382d2SGreg Kroah-Hartman 1269ab4382d2SGreg Kroah-Hartman #define MPC52xx_PSC_CONSOLE &mpc52xx_console 1270ab4382d2SGreg Kroah-Hartman #else 1271ab4382d2SGreg Kroah-Hartman #define MPC52xx_PSC_CONSOLE NULL 1272ab4382d2SGreg Kroah-Hartman #endif 1273ab4382d2SGreg Kroah-Hartman 1274ab4382d2SGreg Kroah-Hartman 1275ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1276ab4382d2SGreg Kroah-Hartman /* UART Driver */ 1277ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1278ab4382d2SGreg Kroah-Hartman 1279ab4382d2SGreg Kroah-Hartman static struct uart_driver mpc52xx_uart_driver = { 1280ab4382d2SGreg Kroah-Hartman .driver_name = "mpc52xx_psc_uart", 1281ab4382d2SGreg Kroah-Hartman .dev_name = "ttyPSC", 1282ab4382d2SGreg Kroah-Hartman .major = SERIAL_PSC_MAJOR, 1283ab4382d2SGreg Kroah-Hartman .minor = SERIAL_PSC_MINOR, 1284ab4382d2SGreg Kroah-Hartman .nr = MPC52xx_PSC_MAXNUM, 1285ab4382d2SGreg Kroah-Hartman .cons = MPC52xx_PSC_CONSOLE, 1286ab4382d2SGreg Kroah-Hartman }; 1287ab4382d2SGreg Kroah-Hartman 1288ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1289ab4382d2SGreg Kroah-Hartman /* OF Platform Driver */ 1290ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1291ab4382d2SGreg Kroah-Hartman 1292ab4382d2SGreg Kroah-Hartman static struct of_device_id mpc52xx_uart_of_match[] = { 1293ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PPC_MPC52xx 1294ab4382d2SGreg Kroah-Hartman { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, }, 1295ab4382d2SGreg Kroah-Hartman { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, 1296ab4382d2SGreg Kroah-Hartman /* binding used by old lite5200 device trees: */ 1297ab4382d2SGreg Kroah-Hartman { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, 1298ab4382d2SGreg Kroah-Hartman /* binding used by efika: */ 1299ab4382d2SGreg Kroah-Hartman { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, }, 1300ab4382d2SGreg Kroah-Hartman #endif 1301ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PPC_MPC512x 1302ab4382d2SGreg Kroah-Hartman { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, }, 1303ab4382d2SGreg Kroah-Hartman #endif 1304ab4382d2SGreg Kroah-Hartman {}, 1305ab4382d2SGreg Kroah-Hartman }; 1306ab4382d2SGreg Kroah-Hartman 1307793218dfSGrant Likely static int __devinit mpc52xx_uart_of_probe(struct platform_device *op) 1308ab4382d2SGreg Kroah-Hartman { 1309ab4382d2SGreg Kroah-Hartman int idx = -1; 1310ab4382d2SGreg Kroah-Hartman unsigned int uartclk; 1311ab4382d2SGreg Kroah-Hartman struct uart_port *port = NULL; 1312ab4382d2SGreg Kroah-Hartman struct resource res; 1313ab4382d2SGreg Kroah-Hartman int ret; 1314ab4382d2SGreg Kroah-Hartman 1315ab4382d2SGreg Kroah-Hartman /* Check validity & presence */ 1316ab4382d2SGreg Kroah-Hartman for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++) 1317ab4382d2SGreg Kroah-Hartman if (mpc52xx_uart_nodes[idx] == op->dev.of_node) 1318ab4382d2SGreg Kroah-Hartman break; 1319ab4382d2SGreg Kroah-Hartman if (idx >= MPC52xx_PSC_MAXNUM) 1320ab4382d2SGreg Kroah-Hartman return -EINVAL; 1321ab4382d2SGreg Kroah-Hartman pr_debug("Found %s assigned to ttyPSC%x\n", 1322ab4382d2SGreg Kroah-Hartman mpc52xx_uart_nodes[idx]->full_name, idx); 1323ab4382d2SGreg Kroah-Hartman 1324ab4382d2SGreg Kroah-Hartman /* set the uart clock to the input clock of the psc, the different 1325ab4382d2SGreg Kroah-Hartman * prescalers are taken into account in the set_baudrate() methods 1326ab4382d2SGreg Kroah-Hartman * of the respective chip */ 1327ab4382d2SGreg Kroah-Hartman uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node); 1328ab4382d2SGreg Kroah-Hartman if (uartclk == 0) { 1329ab4382d2SGreg Kroah-Hartman dev_dbg(&op->dev, "Could not find uart clock frequency!\n"); 1330ab4382d2SGreg Kroah-Hartman return -EINVAL; 1331ab4382d2SGreg Kroah-Hartman } 1332ab4382d2SGreg Kroah-Hartman 1333ab4382d2SGreg Kroah-Hartman /* Init the port structure */ 1334ab4382d2SGreg Kroah-Hartman port = &mpc52xx_uart_ports[idx]; 1335ab4382d2SGreg Kroah-Hartman 1336ab4382d2SGreg Kroah-Hartman spin_lock_init(&port->lock); 1337ab4382d2SGreg Kroah-Hartman port->uartclk = uartclk; 1338ab4382d2SGreg Kroah-Hartman port->fifosize = 512; 1339ab4382d2SGreg Kroah-Hartman port->iotype = UPIO_MEM; 1340ab4382d2SGreg Kroah-Hartman port->flags = UPF_BOOT_AUTOCONF | 1341ab4382d2SGreg Kroah-Hartman (uart_console(port) ? 0 : UPF_IOREMAP); 1342ab4382d2SGreg Kroah-Hartman port->line = idx; 1343ab4382d2SGreg Kroah-Hartman port->ops = &mpc52xx_uart_ops; 1344ab4382d2SGreg Kroah-Hartman port->dev = &op->dev; 1345ab4382d2SGreg Kroah-Hartman 1346ab4382d2SGreg Kroah-Hartman /* Search for IRQ and mapbase */ 1347ab4382d2SGreg Kroah-Hartman ret = of_address_to_resource(op->dev.of_node, 0, &res); 1348ab4382d2SGreg Kroah-Hartman if (ret) 1349ab4382d2SGreg Kroah-Hartman return ret; 1350ab4382d2SGreg Kroah-Hartman 1351ab4382d2SGreg Kroah-Hartman port->mapbase = res.start; 1352ab4382d2SGreg Kroah-Hartman if (!port->mapbase) { 1353ab4382d2SGreg Kroah-Hartman dev_dbg(&op->dev, "Could not allocate resources for PSC\n"); 1354ab4382d2SGreg Kroah-Hartman return -EINVAL; 1355ab4382d2SGreg Kroah-Hartman } 1356ab4382d2SGreg Kroah-Hartman 1357ab4382d2SGreg Kroah-Hartman psc_ops->get_irq(port, op->dev.of_node); 1358d4e33facSAlan Cox if (port->irq == 0) { 1359ab4382d2SGreg Kroah-Hartman dev_dbg(&op->dev, "Could not get irq\n"); 1360ab4382d2SGreg Kroah-Hartman return -EINVAL; 1361ab4382d2SGreg Kroah-Hartman } 1362ab4382d2SGreg Kroah-Hartman 1363ab4382d2SGreg Kroah-Hartman dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n", 1364ab4382d2SGreg Kroah-Hartman (void *)port->mapbase, port->irq, port->uartclk); 1365ab4382d2SGreg Kroah-Hartman 1366ab4382d2SGreg Kroah-Hartman /* Add the port to the uart sub-system */ 1367ab4382d2SGreg Kroah-Hartman ret = uart_add_one_port(&mpc52xx_uart_driver, port); 1368ab4382d2SGreg Kroah-Hartman if (ret) 1369ab4382d2SGreg Kroah-Hartman return ret; 1370ab4382d2SGreg Kroah-Hartman 1371ab4382d2SGreg Kroah-Hartman dev_set_drvdata(&op->dev, (void *)port); 1372ab4382d2SGreg Kroah-Hartman return 0; 1373ab4382d2SGreg Kroah-Hartman } 1374ab4382d2SGreg Kroah-Hartman 1375ab4382d2SGreg Kroah-Hartman static int 1376ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_remove(struct platform_device *op) 1377ab4382d2SGreg Kroah-Hartman { 1378ab4382d2SGreg Kroah-Hartman struct uart_port *port = dev_get_drvdata(&op->dev); 1379ab4382d2SGreg Kroah-Hartman dev_set_drvdata(&op->dev, NULL); 1380ab4382d2SGreg Kroah-Hartman 1381ab4382d2SGreg Kroah-Hartman if (port) 1382ab4382d2SGreg Kroah-Hartman uart_remove_one_port(&mpc52xx_uart_driver, port); 1383ab4382d2SGreg Kroah-Hartman 1384ab4382d2SGreg Kroah-Hartman return 0; 1385ab4382d2SGreg Kroah-Hartman } 1386ab4382d2SGreg Kroah-Hartman 1387ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PM 1388ab4382d2SGreg Kroah-Hartman static int 1389ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) 1390ab4382d2SGreg Kroah-Hartman { 1391ab4382d2SGreg Kroah-Hartman struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); 1392ab4382d2SGreg Kroah-Hartman 1393ab4382d2SGreg Kroah-Hartman if (port) 1394ab4382d2SGreg Kroah-Hartman uart_suspend_port(&mpc52xx_uart_driver, port); 1395ab4382d2SGreg Kroah-Hartman 1396ab4382d2SGreg Kroah-Hartman return 0; 1397ab4382d2SGreg Kroah-Hartman } 1398ab4382d2SGreg Kroah-Hartman 1399ab4382d2SGreg Kroah-Hartman static int 1400ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_resume(struct platform_device *op) 1401ab4382d2SGreg Kroah-Hartman { 1402ab4382d2SGreg Kroah-Hartman struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); 1403ab4382d2SGreg Kroah-Hartman 1404ab4382d2SGreg Kroah-Hartman if (port) 1405ab4382d2SGreg Kroah-Hartman uart_resume_port(&mpc52xx_uart_driver, port); 1406ab4382d2SGreg Kroah-Hartman 1407ab4382d2SGreg Kroah-Hartman return 0; 1408ab4382d2SGreg Kroah-Hartman } 1409ab4382d2SGreg Kroah-Hartman #endif 1410ab4382d2SGreg Kroah-Hartman 1411ab4382d2SGreg Kroah-Hartman static void 1412ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_assign(struct device_node *np) 1413ab4382d2SGreg Kroah-Hartman { 1414ab4382d2SGreg Kroah-Hartman int i; 1415ab4382d2SGreg Kroah-Hartman 1416ab4382d2SGreg Kroah-Hartman /* Find the first free PSC number */ 1417ab4382d2SGreg Kroah-Hartman for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { 1418ab4382d2SGreg Kroah-Hartman if (mpc52xx_uart_nodes[i] == NULL) { 1419ab4382d2SGreg Kroah-Hartman of_node_get(np); 1420ab4382d2SGreg Kroah-Hartman mpc52xx_uart_nodes[i] = np; 1421ab4382d2SGreg Kroah-Hartman return; 1422ab4382d2SGreg Kroah-Hartman } 1423ab4382d2SGreg Kroah-Hartman } 1424ab4382d2SGreg Kroah-Hartman } 1425ab4382d2SGreg Kroah-Hartman 1426ab4382d2SGreg Kroah-Hartman static void 1427ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_enumerate(void) 1428ab4382d2SGreg Kroah-Hartman { 1429ab4382d2SGreg Kroah-Hartman static int enum_done; 1430ab4382d2SGreg Kroah-Hartman struct device_node *np; 1431ab4382d2SGreg Kroah-Hartman const struct of_device_id *match; 1432ab4382d2SGreg Kroah-Hartman int i; 1433ab4382d2SGreg Kroah-Hartman 1434ab4382d2SGreg Kroah-Hartman if (enum_done) 1435ab4382d2SGreg Kroah-Hartman return; 1436ab4382d2SGreg Kroah-Hartman 1437ab4382d2SGreg Kroah-Hartman /* Assign index to each PSC in device tree */ 1438ab4382d2SGreg Kroah-Hartman for_each_matching_node(np, mpc52xx_uart_of_match) { 1439ab4382d2SGreg Kroah-Hartman match = of_match_node(mpc52xx_uart_of_match, np); 1440ab4382d2SGreg Kroah-Hartman psc_ops = match->data; 1441ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_assign(np); 1442ab4382d2SGreg Kroah-Hartman } 1443ab4382d2SGreg Kroah-Hartman 1444ab4382d2SGreg Kroah-Hartman enum_done = 1; 1445ab4382d2SGreg Kroah-Hartman 1446ab4382d2SGreg Kroah-Hartman for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { 1447ab4382d2SGreg Kroah-Hartman if (mpc52xx_uart_nodes[i]) 1448ab4382d2SGreg Kroah-Hartman pr_debug("%s assigned to ttyPSC%x\n", 1449ab4382d2SGreg Kroah-Hartman mpc52xx_uart_nodes[i]->full_name, i); 1450ab4382d2SGreg Kroah-Hartman } 1451ab4382d2SGreg Kroah-Hartman } 1452ab4382d2SGreg Kroah-Hartman 1453ab4382d2SGreg Kroah-Hartman MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); 1454ab4382d2SGreg Kroah-Hartman 1455793218dfSGrant Likely static struct platform_driver mpc52xx_uart_of_driver = { 1456ab4382d2SGreg Kroah-Hartman .probe = mpc52xx_uart_of_probe, 1457ab4382d2SGreg Kroah-Hartman .remove = mpc52xx_uart_of_remove, 1458ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PM 1459ab4382d2SGreg Kroah-Hartman .suspend = mpc52xx_uart_of_suspend, 1460ab4382d2SGreg Kroah-Hartman .resume = mpc52xx_uart_of_resume, 1461ab4382d2SGreg Kroah-Hartman #endif 1462ab4382d2SGreg Kroah-Hartman .driver = { 1463ab4382d2SGreg Kroah-Hartman .name = "mpc52xx-psc-uart", 1464ab4382d2SGreg Kroah-Hartman .owner = THIS_MODULE, 1465ab4382d2SGreg Kroah-Hartman .of_match_table = mpc52xx_uart_of_match, 1466ab4382d2SGreg Kroah-Hartman }, 1467ab4382d2SGreg Kroah-Hartman }; 1468ab4382d2SGreg Kroah-Hartman 1469ab4382d2SGreg Kroah-Hartman 1470ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1471ab4382d2SGreg Kroah-Hartman /* Module */ 1472ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1473ab4382d2SGreg Kroah-Hartman 1474ab4382d2SGreg Kroah-Hartman static int __init 1475ab4382d2SGreg Kroah-Hartman mpc52xx_uart_init(void) 1476ab4382d2SGreg Kroah-Hartman { 1477ab4382d2SGreg Kroah-Hartman int ret; 1478ab4382d2SGreg Kroah-Hartman 1479ab4382d2SGreg Kroah-Hartman printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n"); 1480ab4382d2SGreg Kroah-Hartman 1481ab4382d2SGreg Kroah-Hartman ret = uart_register_driver(&mpc52xx_uart_driver); 1482ab4382d2SGreg Kroah-Hartman if (ret) { 1483ab4382d2SGreg Kroah-Hartman printk(KERN_ERR "%s: uart_register_driver failed (%i)\n", 1484ab4382d2SGreg Kroah-Hartman __FILE__, ret); 1485ab4382d2SGreg Kroah-Hartman return ret; 1486ab4382d2SGreg Kroah-Hartman } 1487ab4382d2SGreg Kroah-Hartman 1488ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_enumerate(); 1489ab4382d2SGreg Kroah-Hartman 1490ab4382d2SGreg Kroah-Hartman /* 1491ab4382d2SGreg Kroah-Hartman * Map the PSC FIFO Controller and init if on MPC512x. 1492ab4382d2SGreg Kroah-Hartman */ 1493ab4382d2SGreg Kroah-Hartman if (psc_ops && psc_ops->fifoc_init) { 1494ab4382d2SGreg Kroah-Hartman ret = psc_ops->fifoc_init(); 1495ab4382d2SGreg Kroah-Hartman if (ret) 1496ab4382d2SGreg Kroah-Hartman return ret; 1497ab4382d2SGreg Kroah-Hartman } 1498ab4382d2SGreg Kroah-Hartman 1499793218dfSGrant Likely ret = platform_driver_register(&mpc52xx_uart_of_driver); 1500ab4382d2SGreg Kroah-Hartman if (ret) { 1501793218dfSGrant Likely printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", 1502ab4382d2SGreg Kroah-Hartman __FILE__, ret); 1503ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&mpc52xx_uart_driver); 1504ab4382d2SGreg Kroah-Hartman return ret; 1505ab4382d2SGreg Kroah-Hartman } 1506ab4382d2SGreg Kroah-Hartman 1507ab4382d2SGreg Kroah-Hartman return 0; 1508ab4382d2SGreg Kroah-Hartman } 1509ab4382d2SGreg Kroah-Hartman 1510ab4382d2SGreg Kroah-Hartman static void __exit 1511ab4382d2SGreg Kroah-Hartman mpc52xx_uart_exit(void) 1512ab4382d2SGreg Kroah-Hartman { 1513ab4382d2SGreg Kroah-Hartman if (psc_ops->fifoc_uninit) 1514ab4382d2SGreg Kroah-Hartman psc_ops->fifoc_uninit(); 1515ab4382d2SGreg Kroah-Hartman 1516793218dfSGrant Likely platform_driver_unregister(&mpc52xx_uart_of_driver); 1517ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&mpc52xx_uart_driver); 1518ab4382d2SGreg Kroah-Hartman } 1519ab4382d2SGreg Kroah-Hartman 1520ab4382d2SGreg Kroah-Hartman 1521ab4382d2SGreg Kroah-Hartman module_init(mpc52xx_uart_init); 1522ab4382d2SGreg Kroah-Hartman module_exit(mpc52xx_uart_exit); 1523ab4382d2SGreg Kroah-Hartman 1524ab4382d2SGreg Kroah-Hartman MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>"); 1525ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("Freescale MPC52xx PSC UART"); 1526ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 1527