1*e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2ab4382d2SGreg Kroah-Hartman /* 3ab4382d2SGreg Kroah-Hartman * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs. 4ab4382d2SGreg Kroah-Hartman * 5ab4382d2SGreg Kroah-Hartman * FIXME According to the usermanual the status bits in the status register 6ab4382d2SGreg Kroah-Hartman * are only updated when the peripherals access the FIFO and not when the 7ab4382d2SGreg Kroah-Hartman * CPU access them. So since we use this bits to know when we stop writing 8ab4382d2SGreg Kroah-Hartman * and reading, they may not be updated in-time and a race condition may 9ab4382d2SGreg Kroah-Hartman * exists. But I haven't be able to prove this and I don't care. But if 10ab4382d2SGreg Kroah-Hartman * any problem arises, it might worth checking. The TX/RX FIFO Stats 11ab4382d2SGreg Kroah-Hartman * registers should be used in addition. 12ab4382d2SGreg Kroah-Hartman * Update: Actually, they seem updated ... At least the bits we use. 13ab4382d2SGreg Kroah-Hartman * 14ab4382d2SGreg Kroah-Hartman * 15ab4382d2SGreg Kroah-Hartman * Maintainer : Sylvain Munaut <tnt@246tNt.com> 16ab4382d2SGreg Kroah-Hartman * 17ab4382d2SGreg Kroah-Hartman * Some of the code has been inspired/copied from the 2.4 code written 18ab4382d2SGreg Kroah-Hartman * by Dale Farnsworth <dfarnsworth@mvista.com>. 19ab4382d2SGreg Kroah-Hartman * 20ab4382d2SGreg Kroah-Hartman * Copyright (C) 2008 Freescale Semiconductor Inc. 21ab4382d2SGreg Kroah-Hartman * John Rigby <jrigby@gmail.com> 22ab4382d2SGreg Kroah-Hartman * Added support for MPC5121 23ab4382d2SGreg Kroah-Hartman * Copyright (C) 2006 Secret Lab Technologies Ltd. 24ab4382d2SGreg Kroah-Hartman * Grant Likely <grant.likely@secretlab.ca> 25ab4382d2SGreg Kroah-Hartman * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com> 26ab4382d2SGreg Kroah-Hartman * Copyright (C) 2003 MontaVista, Software, Inc. 27ab4382d2SGreg Kroah-Hartman * 28ab4382d2SGreg Kroah-Hartman * This file is licensed under the terms of the GNU General Public License 29ab4382d2SGreg Kroah-Hartman * version 2. This program is licensed "as is" without any warranty of any 30ab4382d2SGreg Kroah-Hartman * kind, whether express or implied. 31ab4382d2SGreg Kroah-Hartman */ 32ab4382d2SGreg Kroah-Hartman 33ab4382d2SGreg Kroah-Hartman #undef DEBUG 34ab4382d2SGreg Kroah-Hartman 35ab4382d2SGreg Kroah-Hartman #include <linux/device.h> 36ab4382d2SGreg Kroah-Hartman #include <linux/module.h> 37ab4382d2SGreg Kroah-Hartman #include <linux/tty.h> 38ee160a38SJiri Slaby #include <linux/tty_flip.h> 39ab4382d2SGreg Kroah-Hartman #include <linux/serial.h> 40ab4382d2SGreg Kroah-Hartman #include <linux/sysrq.h> 41ab4382d2SGreg Kroah-Hartman #include <linux/console.h> 42ab4382d2SGreg Kroah-Hartman #include <linux/delay.h> 43ab4382d2SGreg Kroah-Hartman #include <linux/io.h> 44ab4382d2SGreg Kroah-Hartman #include <linux/of.h> 45ab4382d2SGreg Kroah-Hartman #include <linux/of_platform.h> 46ab4382d2SGreg Kroah-Hartman #include <linux/clk.h> 47ab4382d2SGreg Kroah-Hartman 48ab4382d2SGreg Kroah-Hartman #include <asm/mpc52xx.h> 49ab4382d2SGreg Kroah-Hartman #include <asm/mpc52xx_psc.h> 50ab4382d2SGreg Kroah-Hartman 51ab4382d2SGreg Kroah-Hartman #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) 52ab4382d2SGreg Kroah-Hartman #define SUPPORT_SYSRQ 53ab4382d2SGreg Kroah-Hartman #endif 54ab4382d2SGreg Kroah-Hartman 55ab4382d2SGreg Kroah-Hartman #include <linux/serial_core.h> 56ab4382d2SGreg Kroah-Hartman 57ab4382d2SGreg Kroah-Hartman 58ab4382d2SGreg Kroah-Hartman /* We've been assigned a range on the "Low-density serial ports" major */ 59ab4382d2SGreg Kroah-Hartman #define SERIAL_PSC_MAJOR 204 60ab4382d2SGreg Kroah-Hartman #define SERIAL_PSC_MINOR 148 61ab4382d2SGreg Kroah-Hartman 62ab4382d2SGreg Kroah-Hartman 63ab4382d2SGreg Kroah-Hartman #define ISR_PASS_LIMIT 256 /* Max number of iteration in the interrupt */ 64ab4382d2SGreg Kroah-Hartman 65ab4382d2SGreg Kroah-Hartman 66ab4382d2SGreg Kroah-Hartman static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM]; 67ab4382d2SGreg Kroah-Hartman /* Rem: - We use the read_status_mask as a shadow of 68ab4382d2SGreg Kroah-Hartman * psc->mpc52xx_psc_imr 69ab4382d2SGreg Kroah-Hartman * - It's important that is array is all zero on start as we 70ab4382d2SGreg Kroah-Hartman * use it to know if it's initialized or not ! If it's not sure 71ab4382d2SGreg Kroah-Hartman * it's cleared, then a memset(...,0,...) should be added to 72ab4382d2SGreg Kroah-Hartman * the console_init 73ab4382d2SGreg Kroah-Hartman */ 74ab4382d2SGreg Kroah-Hartman 75ab4382d2SGreg Kroah-Hartman /* lookup table for matching device nodes to index numbers */ 76ab4382d2SGreg Kroah-Hartman static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM]; 77ab4382d2SGreg Kroah-Hartman 78ab4382d2SGreg Kroah-Hartman static void mpc52xx_uart_of_enumerate(void); 79ab4382d2SGreg Kroah-Hartman 80ab4382d2SGreg Kroah-Hartman 81ab4382d2SGreg Kroah-Hartman #define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) 82ab4382d2SGreg Kroah-Hartman 83ab4382d2SGreg Kroah-Hartman 84ab4382d2SGreg Kroah-Hartman /* Forward declaration of the interruption handling routine */ 85ab4382d2SGreg Kroah-Hartman static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); 86ab4382d2SGreg Kroah-Hartman static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port); 87ab4382d2SGreg Kroah-Hartman 88ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 89ab4382d2SGreg Kroah-Hartman /* PSC fifo operations for isolating differences between 52xx and 512x */ 90ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 91ab4382d2SGreg Kroah-Hartman 92ab4382d2SGreg Kroah-Hartman struct psc_ops { 93ab4382d2SGreg Kroah-Hartman void (*fifo_init)(struct uart_port *port); 94ab4382d2SGreg Kroah-Hartman int (*raw_rx_rdy)(struct uart_port *port); 95ab4382d2SGreg Kroah-Hartman int (*raw_tx_rdy)(struct uart_port *port); 96ab4382d2SGreg Kroah-Hartman int (*rx_rdy)(struct uart_port *port); 97ab4382d2SGreg Kroah-Hartman int (*tx_rdy)(struct uart_port *port); 98ab4382d2SGreg Kroah-Hartman int (*tx_empty)(struct uart_port *port); 99ab4382d2SGreg Kroah-Hartman void (*stop_rx)(struct uart_port *port); 100ab4382d2SGreg Kroah-Hartman void (*start_tx)(struct uart_port *port); 101ab4382d2SGreg Kroah-Hartman void (*stop_tx)(struct uart_port *port); 102ab4382d2SGreg Kroah-Hartman void (*rx_clr_irq)(struct uart_port *port); 103ab4382d2SGreg Kroah-Hartman void (*tx_clr_irq)(struct uart_port *port); 104ab4382d2SGreg Kroah-Hartman void (*write_char)(struct uart_port *port, unsigned char c); 105ab4382d2SGreg Kroah-Hartman unsigned char (*read_char)(struct uart_port *port); 106ab4382d2SGreg Kroah-Hartman void (*cw_disable_ints)(struct uart_port *port); 107ab4382d2SGreg Kroah-Hartman void (*cw_restore_ints)(struct uart_port *port); 108ab4382d2SGreg Kroah-Hartman unsigned int (*set_baudrate)(struct uart_port *port, 109ab4382d2SGreg Kroah-Hartman struct ktermios *new, 110ab4382d2SGreg Kroah-Hartman struct ktermios *old); 1112d30ccacSGerhard Sittig int (*clock_alloc)(struct uart_port *port); 1122d30ccacSGerhard Sittig void (*clock_relse)(struct uart_port *port); 113ab4382d2SGreg Kroah-Hartman int (*clock)(struct uart_port *port, int enable); 114ab4382d2SGreg Kroah-Hartman int (*fifoc_init)(void); 115ab4382d2SGreg Kroah-Hartman void (*fifoc_uninit)(void); 116ab4382d2SGreg Kroah-Hartman void (*get_irq)(struct uart_port *, struct device_node *); 117ab4382d2SGreg Kroah-Hartman irqreturn_t (*handle_irq)(struct uart_port *port); 1182574b27eSMatteo Facchinetti u16 (*get_status)(struct uart_port *port); 1192574b27eSMatteo Facchinetti u8 (*get_ipcr)(struct uart_port *port); 1202574b27eSMatteo Facchinetti void (*command)(struct uart_port *port, u8 cmd); 1212574b27eSMatteo Facchinetti void (*set_mode)(struct uart_port *port, u8 mr1, u8 mr2); 1222574b27eSMatteo Facchinetti void (*set_rts)(struct uart_port *port, int state); 1232574b27eSMatteo Facchinetti void (*enable_ms)(struct uart_port *port); 1242574b27eSMatteo Facchinetti void (*set_sicr)(struct uart_port *port, u32 val); 1252574b27eSMatteo Facchinetti void (*set_imr)(struct uart_port *port, u16 val); 1262574b27eSMatteo Facchinetti u8 (*get_mr1)(struct uart_port *port); 127ab4382d2SGreg Kroah-Hartman }; 128ab4382d2SGreg Kroah-Hartman 129ab4382d2SGreg Kroah-Hartman /* setting the prescaler and divisor reg is common for all chips */ 130ab4382d2SGreg Kroah-Hartman static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc, 131ab4382d2SGreg Kroah-Hartman u16 prescaler, unsigned int divisor) 132ab4382d2SGreg Kroah-Hartman { 133ab4382d2SGreg Kroah-Hartman /* select prescaler */ 134ab4382d2SGreg Kroah-Hartman out_be16(&psc->mpc52xx_psc_clock_select, prescaler); 135ab4382d2SGreg Kroah-Hartman out_8(&psc->ctur, divisor >> 8); 136ab4382d2SGreg Kroah-Hartman out_8(&psc->ctlr, divisor & 0xff); 137ab4382d2SGreg Kroah-Hartman } 138ab4382d2SGreg Kroah-Hartman 1392574b27eSMatteo Facchinetti static u16 mpc52xx_psc_get_status(struct uart_port *port) 1402574b27eSMatteo Facchinetti { 1412574b27eSMatteo Facchinetti return in_be16(&PSC(port)->mpc52xx_psc_status); 1422574b27eSMatteo Facchinetti } 1432574b27eSMatteo Facchinetti 1442574b27eSMatteo Facchinetti static u8 mpc52xx_psc_get_ipcr(struct uart_port *port) 1452574b27eSMatteo Facchinetti { 1462574b27eSMatteo Facchinetti return in_8(&PSC(port)->mpc52xx_psc_ipcr); 1472574b27eSMatteo Facchinetti } 1482574b27eSMatteo Facchinetti 1492574b27eSMatteo Facchinetti static void mpc52xx_psc_command(struct uart_port *port, u8 cmd) 1502574b27eSMatteo Facchinetti { 1512574b27eSMatteo Facchinetti out_8(&PSC(port)->command, cmd); 1522574b27eSMatteo Facchinetti } 1532574b27eSMatteo Facchinetti 1542574b27eSMatteo Facchinetti static void mpc52xx_psc_set_mode(struct uart_port *port, u8 mr1, u8 mr2) 1552574b27eSMatteo Facchinetti { 1562574b27eSMatteo Facchinetti out_8(&PSC(port)->command, MPC52xx_PSC_SEL_MODE_REG_1); 1572574b27eSMatteo Facchinetti out_8(&PSC(port)->mode, mr1); 1582574b27eSMatteo Facchinetti out_8(&PSC(port)->mode, mr2); 1592574b27eSMatteo Facchinetti } 1602574b27eSMatteo Facchinetti 1612574b27eSMatteo Facchinetti static void mpc52xx_psc_set_rts(struct uart_port *port, int state) 1622574b27eSMatteo Facchinetti { 1632574b27eSMatteo Facchinetti if (state) 1642574b27eSMatteo Facchinetti out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS); 1652574b27eSMatteo Facchinetti else 1662574b27eSMatteo Facchinetti out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS); 1672574b27eSMatteo Facchinetti } 1682574b27eSMatteo Facchinetti 1692574b27eSMatteo Facchinetti static void mpc52xx_psc_enable_ms(struct uart_port *port) 1702574b27eSMatteo Facchinetti { 1712574b27eSMatteo Facchinetti struct mpc52xx_psc __iomem *psc = PSC(port); 1722574b27eSMatteo Facchinetti 1732574b27eSMatteo Facchinetti /* clear D_*-bits by reading them */ 1742574b27eSMatteo Facchinetti in_8(&psc->mpc52xx_psc_ipcr); 1752574b27eSMatteo Facchinetti /* enable CTS and DCD as IPC interrupts */ 1762574b27eSMatteo Facchinetti out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD); 1772574b27eSMatteo Facchinetti 1782574b27eSMatteo Facchinetti port->read_status_mask |= MPC52xx_PSC_IMR_IPC; 1792574b27eSMatteo Facchinetti out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); 1802574b27eSMatteo Facchinetti } 1812574b27eSMatteo Facchinetti 1822574b27eSMatteo Facchinetti static void mpc52xx_psc_set_sicr(struct uart_port *port, u32 val) 1832574b27eSMatteo Facchinetti { 1842574b27eSMatteo Facchinetti out_be32(&PSC(port)->sicr, val); 1852574b27eSMatteo Facchinetti } 1862574b27eSMatteo Facchinetti 1872574b27eSMatteo Facchinetti static void mpc52xx_psc_set_imr(struct uart_port *port, u16 val) 1882574b27eSMatteo Facchinetti { 1892574b27eSMatteo Facchinetti out_be16(&PSC(port)->mpc52xx_psc_imr, val); 1902574b27eSMatteo Facchinetti } 1912574b27eSMatteo Facchinetti 1922574b27eSMatteo Facchinetti static u8 mpc52xx_psc_get_mr1(struct uart_port *port) 1932574b27eSMatteo Facchinetti { 1942574b27eSMatteo Facchinetti out_8(&PSC(port)->command, MPC52xx_PSC_SEL_MODE_REG_1); 1952574b27eSMatteo Facchinetti return in_8(&PSC(port)->mode); 1962574b27eSMatteo Facchinetti } 1972574b27eSMatteo Facchinetti 198ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PPC_MPC52xx 199ab4382d2SGreg Kroah-Hartman #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) 200ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_fifo_init(struct uart_port *port) 201ab4382d2SGreg Kroah-Hartman { 202ab4382d2SGreg Kroah-Hartman struct mpc52xx_psc __iomem *psc = PSC(port); 203ab4382d2SGreg Kroah-Hartman struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port); 204ab4382d2SGreg Kroah-Hartman 205ab4382d2SGreg Kroah-Hartman out_8(&fifo->rfcntl, 0x00); 206ab4382d2SGreg Kroah-Hartman out_be16(&fifo->rfalarm, 0x1ff); 207ab4382d2SGreg Kroah-Hartman out_8(&fifo->tfcntl, 0x07); 208ab4382d2SGreg Kroah-Hartman out_be16(&fifo->tfalarm, 0x80); 209ab4382d2SGreg Kroah-Hartman 210ab4382d2SGreg Kroah-Hartman port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; 211ab4382d2SGreg Kroah-Hartman out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); 212ab4382d2SGreg Kroah-Hartman } 213ab4382d2SGreg Kroah-Hartman 214ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port) 215ab4382d2SGreg Kroah-Hartman { 216ab4382d2SGreg Kroah-Hartman return in_be16(&PSC(port)->mpc52xx_psc_status) 217ab4382d2SGreg Kroah-Hartman & MPC52xx_PSC_SR_RXRDY; 218ab4382d2SGreg Kroah-Hartman } 219ab4382d2SGreg Kroah-Hartman 220ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port) 221ab4382d2SGreg Kroah-Hartman { 222ab4382d2SGreg Kroah-Hartman return in_be16(&PSC(port)->mpc52xx_psc_status) 223ab4382d2SGreg Kroah-Hartman & MPC52xx_PSC_SR_TXRDY; 224ab4382d2SGreg Kroah-Hartman } 225ab4382d2SGreg Kroah-Hartman 226ab4382d2SGreg Kroah-Hartman 227ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_rx_rdy(struct uart_port *port) 228ab4382d2SGreg Kroah-Hartman { 229ab4382d2SGreg Kroah-Hartman return in_be16(&PSC(port)->mpc52xx_psc_isr) 230ab4382d2SGreg Kroah-Hartman & port->read_status_mask 231ab4382d2SGreg Kroah-Hartman & MPC52xx_PSC_IMR_RXRDY; 232ab4382d2SGreg Kroah-Hartman } 233ab4382d2SGreg Kroah-Hartman 234ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_tx_rdy(struct uart_port *port) 235ab4382d2SGreg Kroah-Hartman { 236ab4382d2SGreg Kroah-Hartman return in_be16(&PSC(port)->mpc52xx_psc_isr) 237ab4382d2SGreg Kroah-Hartman & port->read_status_mask 238ab4382d2SGreg Kroah-Hartman & MPC52xx_PSC_IMR_TXRDY; 239ab4382d2SGreg Kroah-Hartman } 240ab4382d2SGreg Kroah-Hartman 241ab4382d2SGreg Kroah-Hartman static int mpc52xx_psc_tx_empty(struct uart_port *port) 242ab4382d2SGreg Kroah-Hartman { 2437d07ada0SUwe Kleine-König u16 sts = in_be16(&PSC(port)->mpc52xx_psc_status); 2447d07ada0SUwe Kleine-König 2457d07ada0SUwe Kleine-König return (sts & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0; 246ab4382d2SGreg Kroah-Hartman } 247ab4382d2SGreg Kroah-Hartman 248ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_start_tx(struct uart_port *port) 249ab4382d2SGreg Kroah-Hartman { 250ab4382d2SGreg Kroah-Hartman port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; 251ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); 252ab4382d2SGreg Kroah-Hartman } 253ab4382d2SGreg Kroah-Hartman 254ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_stop_tx(struct uart_port *port) 255ab4382d2SGreg Kroah-Hartman { 256ab4382d2SGreg Kroah-Hartman port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; 257ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); 258ab4382d2SGreg Kroah-Hartman } 259ab4382d2SGreg Kroah-Hartman 260ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_stop_rx(struct uart_port *port) 261ab4382d2SGreg Kroah-Hartman { 262ab4382d2SGreg Kroah-Hartman port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; 263ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); 264ab4382d2SGreg Kroah-Hartman } 265ab4382d2SGreg Kroah-Hartman 266ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_rx_clr_irq(struct uart_port *port) 267ab4382d2SGreg Kroah-Hartman { 268ab4382d2SGreg Kroah-Hartman } 269ab4382d2SGreg Kroah-Hartman 270ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_tx_clr_irq(struct uart_port *port) 271ab4382d2SGreg Kroah-Hartman { 272ab4382d2SGreg Kroah-Hartman } 273ab4382d2SGreg Kroah-Hartman 274ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c) 275ab4382d2SGreg Kroah-Hartman { 276ab4382d2SGreg Kroah-Hartman out_8(&PSC(port)->mpc52xx_psc_buffer_8, c); 277ab4382d2SGreg Kroah-Hartman } 278ab4382d2SGreg Kroah-Hartman 279ab4382d2SGreg Kroah-Hartman static unsigned char mpc52xx_psc_read_char(struct uart_port *port) 280ab4382d2SGreg Kroah-Hartman { 281ab4382d2SGreg Kroah-Hartman return in_8(&PSC(port)->mpc52xx_psc_buffer_8); 282ab4382d2SGreg Kroah-Hartman } 283ab4382d2SGreg Kroah-Hartman 284ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_cw_disable_ints(struct uart_port *port) 285ab4382d2SGreg Kroah-Hartman { 286ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, 0); 287ab4382d2SGreg Kroah-Hartman } 288ab4382d2SGreg Kroah-Hartman 289ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_cw_restore_ints(struct uart_port *port) 290ab4382d2SGreg Kroah-Hartman { 291ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); 292ab4382d2SGreg Kroah-Hartman } 293ab4382d2SGreg Kroah-Hartman 294ab4382d2SGreg Kroah-Hartman static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port, 295ab4382d2SGreg Kroah-Hartman struct ktermios *new, 296ab4382d2SGreg Kroah-Hartman struct ktermios *old) 297ab4382d2SGreg Kroah-Hartman { 298ab4382d2SGreg Kroah-Hartman unsigned int baud; 299ab4382d2SGreg Kroah-Hartman unsigned int divisor; 300ab4382d2SGreg Kroah-Hartman 301ab4382d2SGreg Kroah-Hartman /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */ 302ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, new, old, 303ab4382d2SGreg Kroah-Hartman port->uartclk / (32 * 0xffff) + 1, 304ab4382d2SGreg Kroah-Hartman port->uartclk / 32); 305ab4382d2SGreg Kroah-Hartman divisor = (port->uartclk + 16 * baud) / (32 * baud); 306ab4382d2SGreg Kroah-Hartman 307ab4382d2SGreg Kroah-Hartman /* enable the /32 prescaler and set the divisor */ 308ab4382d2SGreg Kroah-Hartman mpc52xx_set_divisor(PSC(port), 0xdd00, divisor); 309ab4382d2SGreg Kroah-Hartman return baud; 310ab4382d2SGreg Kroah-Hartman } 311ab4382d2SGreg Kroah-Hartman 312ab4382d2SGreg Kroah-Hartman static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port, 313ab4382d2SGreg Kroah-Hartman struct ktermios *new, 314ab4382d2SGreg Kroah-Hartman struct ktermios *old) 315ab4382d2SGreg Kroah-Hartman { 316ab4382d2SGreg Kroah-Hartman unsigned int baud; 317ab4382d2SGreg Kroah-Hartman unsigned int divisor; 318ab4382d2SGreg Kroah-Hartman u16 prescaler; 319ab4382d2SGreg Kroah-Hartman 320ab4382d2SGreg Kroah-Hartman /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the 321ab4382d2SGreg Kroah-Hartman * ipb freq */ 322ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, new, old, 323ab4382d2SGreg Kroah-Hartman port->uartclk / (32 * 0xffff) + 1, 324ab4382d2SGreg Kroah-Hartman port->uartclk / 4); 325ab4382d2SGreg Kroah-Hartman divisor = (port->uartclk + 2 * baud) / (4 * baud); 326ab4382d2SGreg Kroah-Hartman 327e0955aceSFrank Benkert /* select the proper prescaler and set the divisor 328e0955aceSFrank Benkert * prefer high prescaler for more tolerance on low baudrates */ 329e0955aceSFrank Benkert if (divisor > 0xffff || baud <= 115200) { 330ab4382d2SGreg Kroah-Hartman divisor = (divisor + 4) / 8; 331ab4382d2SGreg Kroah-Hartman prescaler = 0xdd00; /* /32 */ 332ab4382d2SGreg Kroah-Hartman } else 333ab4382d2SGreg Kroah-Hartman prescaler = 0xff00; /* /4 */ 334ab4382d2SGreg Kroah-Hartman mpc52xx_set_divisor(PSC(port), prescaler, divisor); 335ab4382d2SGreg Kroah-Hartman return baud; 336ab4382d2SGreg Kroah-Hartman } 337ab4382d2SGreg Kroah-Hartman 338ab4382d2SGreg Kroah-Hartman static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np) 339ab4382d2SGreg Kroah-Hartman { 3409cfb5c05SYong Zhang port->irqflags = 0; 341ab4382d2SGreg Kroah-Hartman port->irq = irq_of_parse_and_map(np, 0); 342ab4382d2SGreg Kroah-Hartman } 343ab4382d2SGreg Kroah-Hartman 344ab4382d2SGreg Kroah-Hartman /* 52xx specific interrupt handler. The caller holds the port lock */ 345ab4382d2SGreg Kroah-Hartman static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port) 346ab4382d2SGreg Kroah-Hartman { 347ab4382d2SGreg Kroah-Hartman return mpc5xxx_uart_process_int(port); 348ab4382d2SGreg Kroah-Hartman } 349ab4382d2SGreg Kroah-Hartman 350cc74bd1dSAya Mahfouz static const struct psc_ops mpc52xx_psc_ops = { 351ab4382d2SGreg Kroah-Hartman .fifo_init = mpc52xx_psc_fifo_init, 352ab4382d2SGreg Kroah-Hartman .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, 353ab4382d2SGreg Kroah-Hartman .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, 354ab4382d2SGreg Kroah-Hartman .rx_rdy = mpc52xx_psc_rx_rdy, 355ab4382d2SGreg Kroah-Hartman .tx_rdy = mpc52xx_psc_tx_rdy, 356ab4382d2SGreg Kroah-Hartman .tx_empty = mpc52xx_psc_tx_empty, 357ab4382d2SGreg Kroah-Hartman .stop_rx = mpc52xx_psc_stop_rx, 358ab4382d2SGreg Kroah-Hartman .start_tx = mpc52xx_psc_start_tx, 359ab4382d2SGreg Kroah-Hartman .stop_tx = mpc52xx_psc_stop_tx, 360ab4382d2SGreg Kroah-Hartman .rx_clr_irq = mpc52xx_psc_rx_clr_irq, 361ab4382d2SGreg Kroah-Hartman .tx_clr_irq = mpc52xx_psc_tx_clr_irq, 362ab4382d2SGreg Kroah-Hartman .write_char = mpc52xx_psc_write_char, 363ab4382d2SGreg Kroah-Hartman .read_char = mpc52xx_psc_read_char, 364ab4382d2SGreg Kroah-Hartman .cw_disable_ints = mpc52xx_psc_cw_disable_ints, 365ab4382d2SGreg Kroah-Hartman .cw_restore_ints = mpc52xx_psc_cw_restore_ints, 366ab4382d2SGreg Kroah-Hartman .set_baudrate = mpc5200_psc_set_baudrate, 367ab4382d2SGreg Kroah-Hartman .get_irq = mpc52xx_psc_get_irq, 368ab4382d2SGreg Kroah-Hartman .handle_irq = mpc52xx_psc_handle_irq, 3692574b27eSMatteo Facchinetti .get_status = mpc52xx_psc_get_status, 3702574b27eSMatteo Facchinetti .get_ipcr = mpc52xx_psc_get_ipcr, 3712574b27eSMatteo Facchinetti .command = mpc52xx_psc_command, 3722574b27eSMatteo Facchinetti .set_mode = mpc52xx_psc_set_mode, 3732574b27eSMatteo Facchinetti .set_rts = mpc52xx_psc_set_rts, 3742574b27eSMatteo Facchinetti .enable_ms = mpc52xx_psc_enable_ms, 3752574b27eSMatteo Facchinetti .set_sicr = mpc52xx_psc_set_sicr, 3762574b27eSMatteo Facchinetti .set_imr = mpc52xx_psc_set_imr, 3772574b27eSMatteo Facchinetti .get_mr1 = mpc52xx_psc_get_mr1, 378ab4382d2SGreg Kroah-Hartman }; 379ab4382d2SGreg Kroah-Hartman 380cc74bd1dSAya Mahfouz static const struct psc_ops mpc5200b_psc_ops = { 381ab4382d2SGreg Kroah-Hartman .fifo_init = mpc52xx_psc_fifo_init, 382ab4382d2SGreg Kroah-Hartman .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, 383ab4382d2SGreg Kroah-Hartman .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, 384ab4382d2SGreg Kroah-Hartman .rx_rdy = mpc52xx_psc_rx_rdy, 385ab4382d2SGreg Kroah-Hartman .tx_rdy = mpc52xx_psc_tx_rdy, 386ab4382d2SGreg Kroah-Hartman .tx_empty = mpc52xx_psc_tx_empty, 387ab4382d2SGreg Kroah-Hartman .stop_rx = mpc52xx_psc_stop_rx, 388ab4382d2SGreg Kroah-Hartman .start_tx = mpc52xx_psc_start_tx, 389ab4382d2SGreg Kroah-Hartman .stop_tx = mpc52xx_psc_stop_tx, 390ab4382d2SGreg Kroah-Hartman .rx_clr_irq = mpc52xx_psc_rx_clr_irq, 391ab4382d2SGreg Kroah-Hartman .tx_clr_irq = mpc52xx_psc_tx_clr_irq, 392ab4382d2SGreg Kroah-Hartman .write_char = mpc52xx_psc_write_char, 393ab4382d2SGreg Kroah-Hartman .read_char = mpc52xx_psc_read_char, 394ab4382d2SGreg Kroah-Hartman .cw_disable_ints = mpc52xx_psc_cw_disable_ints, 395ab4382d2SGreg Kroah-Hartman .cw_restore_ints = mpc52xx_psc_cw_restore_ints, 396ab4382d2SGreg Kroah-Hartman .set_baudrate = mpc5200b_psc_set_baudrate, 397ab4382d2SGreg Kroah-Hartman .get_irq = mpc52xx_psc_get_irq, 398ab4382d2SGreg Kroah-Hartman .handle_irq = mpc52xx_psc_handle_irq, 3992574b27eSMatteo Facchinetti .get_status = mpc52xx_psc_get_status, 4002574b27eSMatteo Facchinetti .get_ipcr = mpc52xx_psc_get_ipcr, 4012574b27eSMatteo Facchinetti .command = mpc52xx_psc_command, 4022574b27eSMatteo Facchinetti .set_mode = mpc52xx_psc_set_mode, 4032574b27eSMatteo Facchinetti .set_rts = mpc52xx_psc_set_rts, 4042574b27eSMatteo Facchinetti .enable_ms = mpc52xx_psc_enable_ms, 4052574b27eSMatteo Facchinetti .set_sicr = mpc52xx_psc_set_sicr, 4062574b27eSMatteo Facchinetti .set_imr = mpc52xx_psc_set_imr, 4072574b27eSMatteo Facchinetti .get_mr1 = mpc52xx_psc_get_mr1, 408ab4382d2SGreg Kroah-Hartman }; 409ab4382d2SGreg Kroah-Hartman 4105b84c967SValentin Rothberg #endif /* CONFIG_PPC_MPC52xx */ 411ab4382d2SGreg Kroah-Hartman 412ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PPC_MPC512x 413ab4382d2SGreg Kroah-Hartman #define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) 414ab4382d2SGreg Kroah-Hartman 415ab4382d2SGreg Kroah-Hartman /* PSC FIFO Controller for mpc512x */ 416ab4382d2SGreg Kroah-Hartman struct psc_fifoc { 417ab4382d2SGreg Kroah-Hartman u32 fifoc_cmd; 418ab4382d2SGreg Kroah-Hartman u32 fifoc_int; 419ab4382d2SGreg Kroah-Hartman u32 fifoc_dma; 420ab4382d2SGreg Kroah-Hartman u32 fifoc_axe; 421ab4382d2SGreg Kroah-Hartman u32 fifoc_debug; 422ab4382d2SGreg Kroah-Hartman }; 423ab4382d2SGreg Kroah-Hartman 424ab4382d2SGreg Kroah-Hartman static struct psc_fifoc __iomem *psc_fifoc; 425ab4382d2SGreg Kroah-Hartman static unsigned int psc_fifoc_irq; 426cb1ea812SGerhard Sittig static struct clk *psc_fifoc_clk; 427ab4382d2SGreg Kroah-Hartman 428ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_fifo_init(struct uart_port *port) 429ab4382d2SGreg Kroah-Hartman { 430ab4382d2SGreg Kroah-Hartman /* /32 prescaler */ 431ab4382d2SGreg Kroah-Hartman out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00); 432ab4382d2SGreg Kroah-Hartman 433ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); 434ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); 435ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->txalarm, 1); 436ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, 0); 437ab4382d2SGreg Kroah-Hartman 438ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE); 439ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); 440ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rxalarm, 1); 441ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, 0); 442ab4382d2SGreg Kroah-Hartman 443ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM); 444ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM); 445ab4382d2SGreg Kroah-Hartman } 446ab4382d2SGreg Kroah-Hartman 447ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_raw_rx_rdy(struct uart_port *port) 448ab4382d2SGreg Kroah-Hartman { 449ab4382d2SGreg Kroah-Hartman return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); 450ab4382d2SGreg Kroah-Hartman } 451ab4382d2SGreg Kroah-Hartman 452ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_raw_tx_rdy(struct uart_port *port) 453ab4382d2SGreg Kroah-Hartman { 454ab4382d2SGreg Kroah-Hartman return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL); 455ab4382d2SGreg Kroah-Hartman } 456ab4382d2SGreg Kroah-Hartman 457ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_rx_rdy(struct uart_port *port) 458ab4382d2SGreg Kroah-Hartman { 459ab4382d2SGreg Kroah-Hartman return in_be32(&FIFO_512x(port)->rxsr) 460ab4382d2SGreg Kroah-Hartman & in_be32(&FIFO_512x(port)->rximr) 461ab4382d2SGreg Kroah-Hartman & MPC512x_PSC_FIFO_ALARM; 462ab4382d2SGreg Kroah-Hartman } 463ab4382d2SGreg Kroah-Hartman 464ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_tx_rdy(struct uart_port *port) 465ab4382d2SGreg Kroah-Hartman { 466ab4382d2SGreg Kroah-Hartman return in_be32(&FIFO_512x(port)->txsr) 467ab4382d2SGreg Kroah-Hartman & in_be32(&FIFO_512x(port)->tximr) 468ab4382d2SGreg Kroah-Hartman & MPC512x_PSC_FIFO_ALARM; 469ab4382d2SGreg Kroah-Hartman } 470ab4382d2SGreg Kroah-Hartman 471ab4382d2SGreg Kroah-Hartman static int mpc512x_psc_tx_empty(struct uart_port *port) 472ab4382d2SGreg Kroah-Hartman { 473ab4382d2SGreg Kroah-Hartman return in_be32(&FIFO_512x(port)->txsr) 474ab4382d2SGreg Kroah-Hartman & MPC512x_PSC_FIFO_EMPTY; 475ab4382d2SGreg Kroah-Hartman } 476ab4382d2SGreg Kroah-Hartman 477ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_stop_rx(struct uart_port *port) 478ab4382d2SGreg Kroah-Hartman { 479ab4382d2SGreg Kroah-Hartman unsigned long rx_fifo_imr; 480ab4382d2SGreg Kroah-Hartman 481ab4382d2SGreg Kroah-Hartman rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr); 482ab4382d2SGreg Kroah-Hartman rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; 483ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr); 484ab4382d2SGreg Kroah-Hartman } 485ab4382d2SGreg Kroah-Hartman 486ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_start_tx(struct uart_port *port) 487ab4382d2SGreg Kroah-Hartman { 488ab4382d2SGreg Kroah-Hartman unsigned long tx_fifo_imr; 489ab4382d2SGreg Kroah-Hartman 490ab4382d2SGreg Kroah-Hartman tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); 491ab4382d2SGreg Kroah-Hartman tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM; 492ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); 493ab4382d2SGreg Kroah-Hartman } 494ab4382d2SGreg Kroah-Hartman 495ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_stop_tx(struct uart_port *port) 496ab4382d2SGreg Kroah-Hartman { 497ab4382d2SGreg Kroah-Hartman unsigned long tx_fifo_imr; 498ab4382d2SGreg Kroah-Hartman 499ab4382d2SGreg Kroah-Hartman tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); 500ab4382d2SGreg Kroah-Hartman tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; 501ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); 502ab4382d2SGreg Kroah-Hartman } 503ab4382d2SGreg Kroah-Hartman 504ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_rx_clr_irq(struct uart_port *port) 505ab4382d2SGreg Kroah-Hartman { 506ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr)); 507ab4382d2SGreg Kroah-Hartman } 508ab4382d2SGreg Kroah-Hartman 509ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_tx_clr_irq(struct uart_port *port) 510ab4382d2SGreg Kroah-Hartman { 511ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr)); 512ab4382d2SGreg Kroah-Hartman } 513ab4382d2SGreg Kroah-Hartman 514ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c) 515ab4382d2SGreg Kroah-Hartman { 516ab4382d2SGreg Kroah-Hartman out_8(&FIFO_512x(port)->txdata_8, c); 517ab4382d2SGreg Kroah-Hartman } 518ab4382d2SGreg Kroah-Hartman 519ab4382d2SGreg Kroah-Hartman static unsigned char mpc512x_psc_read_char(struct uart_port *port) 520ab4382d2SGreg Kroah-Hartman { 521ab4382d2SGreg Kroah-Hartman return in_8(&FIFO_512x(port)->rxdata_8); 522ab4382d2SGreg Kroah-Hartman } 523ab4382d2SGreg Kroah-Hartman 524ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_cw_disable_ints(struct uart_port *port) 525ab4382d2SGreg Kroah-Hartman { 526ab4382d2SGreg Kroah-Hartman port->read_status_mask = 527ab4382d2SGreg Kroah-Hartman in_be32(&FIFO_512x(port)->tximr) << 16 | 528ab4382d2SGreg Kroah-Hartman in_be32(&FIFO_512x(port)->rximr); 529ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, 0); 530ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, 0); 531ab4382d2SGreg Kroah-Hartman } 532ab4382d2SGreg Kroah-Hartman 533ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_cw_restore_ints(struct uart_port *port) 534ab4382d2SGreg Kroah-Hartman { 535ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->tximr, 536ab4382d2SGreg Kroah-Hartman (port->read_status_mask >> 16) & 0x7f); 537ab4382d2SGreg Kroah-Hartman out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f); 538ab4382d2SGreg Kroah-Hartman } 539ab4382d2SGreg Kroah-Hartman 540ab4382d2SGreg Kroah-Hartman static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port, 541ab4382d2SGreg Kroah-Hartman struct ktermios *new, 542ab4382d2SGreg Kroah-Hartman struct ktermios *old) 543ab4382d2SGreg Kroah-Hartman { 544ab4382d2SGreg Kroah-Hartman unsigned int baud; 545ab4382d2SGreg Kroah-Hartman unsigned int divisor; 546ab4382d2SGreg Kroah-Hartman 547ab4382d2SGreg Kroah-Hartman /* 548ab4382d2SGreg Kroah-Hartman * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on 549ab4382d2SGreg Kroah-Hartman * pg. 30-10 that the chip supports a /32 and a /10 prescaler. 550ab4382d2SGreg Kroah-Hartman * Furthermore, it states that "After reset, the prescaler by 10 551ab4382d2SGreg Kroah-Hartman * for the UART mode is selected", but the reset register value is 552ab4382d2SGreg Kroah-Hartman * 0x0000 which means a /32 prescaler. This is wrong. 553ab4382d2SGreg Kroah-Hartman * 554ab4382d2SGreg Kroah-Hartman * In reality using /32 prescaler doesn't work, as it is not supported! 555ab4382d2SGreg Kroah-Hartman * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide", 556ab4382d2SGreg Kroah-Hartman * Chapter 4.1 PSC in UART Mode. 557ab4382d2SGreg Kroah-Hartman * Calculate with a /16 prescaler here. 558ab4382d2SGreg Kroah-Hartman */ 559ab4382d2SGreg Kroah-Hartman 560ab4382d2SGreg Kroah-Hartman /* uartclk contains the ips freq */ 561ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, new, old, 562ab4382d2SGreg Kroah-Hartman port->uartclk / (16 * 0xffff) + 1, 563ab4382d2SGreg Kroah-Hartman port->uartclk / 16); 564ab4382d2SGreg Kroah-Hartman divisor = (port->uartclk + 8 * baud) / (16 * baud); 565ab4382d2SGreg Kroah-Hartman 566ab4382d2SGreg Kroah-Hartman /* enable the /16 prescaler and set the divisor */ 567ab4382d2SGreg Kroah-Hartman mpc52xx_set_divisor(PSC(port), 0xdd00, divisor); 568ab4382d2SGreg Kroah-Hartman return baud; 569ab4382d2SGreg Kroah-Hartman } 570ab4382d2SGreg Kroah-Hartman 571ab4382d2SGreg Kroah-Hartman /* Init PSC FIFO Controller */ 572ab4382d2SGreg Kroah-Hartman static int __init mpc512x_psc_fifoc_init(void) 573ab4382d2SGreg Kroah-Hartman { 574cb1ea812SGerhard Sittig int err; 575ab4382d2SGreg Kroah-Hartman struct device_node *np; 576cb1ea812SGerhard Sittig struct clk *clk; 577cb1ea812SGerhard Sittig 578cb1ea812SGerhard Sittig /* default error code, potentially overwritten by clock calls */ 579cb1ea812SGerhard Sittig err = -ENODEV; 580ab4382d2SGreg Kroah-Hartman 581ab4382d2SGreg Kroah-Hartman np = of_find_compatible_node(NULL, NULL, 582ab4382d2SGreg Kroah-Hartman "fsl,mpc5121-psc-fifo"); 583ab4382d2SGreg Kroah-Hartman if (!np) { 584ab4382d2SGreg Kroah-Hartman pr_err("%s: Can't find FIFOC node\n", __func__); 585cb1ea812SGerhard Sittig goto out_err; 586ab4382d2SGreg Kroah-Hartman } 587ab4382d2SGreg Kroah-Hartman 588cb1ea812SGerhard Sittig clk = of_clk_get(np, 0); 589cb1ea812SGerhard Sittig if (IS_ERR(clk)) { 590cb1ea812SGerhard Sittig /* backwards compat with device trees that lack clock specs */ 591cb1ea812SGerhard Sittig clk = clk_get_sys(np->name, "ipg"); 592cb1ea812SGerhard Sittig } 593cb1ea812SGerhard Sittig if (IS_ERR(clk)) { 594cb1ea812SGerhard Sittig pr_err("%s: Can't lookup FIFO clock\n", __func__); 595cb1ea812SGerhard Sittig err = PTR_ERR(clk); 596cb1ea812SGerhard Sittig goto out_ofnode_put; 597cb1ea812SGerhard Sittig } 598cb1ea812SGerhard Sittig if (clk_prepare_enable(clk)) { 599cb1ea812SGerhard Sittig pr_err("%s: Can't enable FIFO clock\n", __func__); 600cb1ea812SGerhard Sittig clk_put(clk); 601cb1ea812SGerhard Sittig goto out_ofnode_put; 602cb1ea812SGerhard Sittig } 603cb1ea812SGerhard Sittig psc_fifoc_clk = clk; 604cb1ea812SGerhard Sittig 605ab4382d2SGreg Kroah-Hartman psc_fifoc = of_iomap(np, 0); 606ab4382d2SGreg Kroah-Hartman if (!psc_fifoc) { 607ab4382d2SGreg Kroah-Hartman pr_err("%s: Can't map FIFOC\n", __func__); 608cb1ea812SGerhard Sittig goto out_clk_disable; 609ab4382d2SGreg Kroah-Hartman } 610ab4382d2SGreg Kroah-Hartman 611ab4382d2SGreg Kroah-Hartman psc_fifoc_irq = irq_of_parse_and_map(np, 0); 612d4e33facSAlan Cox if (psc_fifoc_irq == 0) { 613ab4382d2SGreg Kroah-Hartman pr_err("%s: Can't get FIFOC irq\n", __func__); 614cb1ea812SGerhard Sittig goto out_unmap; 615ab4382d2SGreg Kroah-Hartman } 616ab4382d2SGreg Kroah-Hartman 617cb1ea812SGerhard Sittig of_node_put(np); 618ab4382d2SGreg Kroah-Hartman return 0; 619cb1ea812SGerhard Sittig 620cb1ea812SGerhard Sittig out_unmap: 621cb1ea812SGerhard Sittig iounmap(psc_fifoc); 622cb1ea812SGerhard Sittig out_clk_disable: 623cb1ea812SGerhard Sittig clk_disable_unprepare(psc_fifoc_clk); 624cb1ea812SGerhard Sittig clk_put(psc_fifoc_clk); 625cb1ea812SGerhard Sittig out_ofnode_put: 626cb1ea812SGerhard Sittig of_node_put(np); 627cb1ea812SGerhard Sittig out_err: 628cb1ea812SGerhard Sittig return err; 629ab4382d2SGreg Kroah-Hartman } 630ab4382d2SGreg Kroah-Hartman 631ab4382d2SGreg Kroah-Hartman static void __exit mpc512x_psc_fifoc_uninit(void) 632ab4382d2SGreg Kroah-Hartman { 633ab4382d2SGreg Kroah-Hartman iounmap(psc_fifoc); 634cb1ea812SGerhard Sittig 635cb1ea812SGerhard Sittig /* disable the clock, errors are not fatal */ 636cb1ea812SGerhard Sittig if (psc_fifoc_clk) { 637cb1ea812SGerhard Sittig clk_disable_unprepare(psc_fifoc_clk); 638cb1ea812SGerhard Sittig clk_put(psc_fifoc_clk); 639cb1ea812SGerhard Sittig psc_fifoc_clk = NULL; 640cb1ea812SGerhard Sittig } 641ab4382d2SGreg Kroah-Hartman } 642ab4382d2SGreg Kroah-Hartman 643ab4382d2SGreg Kroah-Hartman /* 512x specific interrupt handler. The caller holds the port lock */ 644ab4382d2SGreg Kroah-Hartman static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) 645ab4382d2SGreg Kroah-Hartman { 646ab4382d2SGreg Kroah-Hartman unsigned long fifoc_int; 647ab4382d2SGreg Kroah-Hartman int psc_num; 648ab4382d2SGreg Kroah-Hartman 649ab4382d2SGreg Kroah-Hartman /* Read pending PSC FIFOC interrupts */ 650ab4382d2SGreg Kroah-Hartman fifoc_int = in_be32(&psc_fifoc->fifoc_int); 651ab4382d2SGreg Kroah-Hartman 652ab4382d2SGreg Kroah-Hartman /* Check if it is an interrupt for this port */ 653ab4382d2SGreg Kroah-Hartman psc_num = (port->mapbase & 0xf00) >> 8; 654ab4382d2SGreg Kroah-Hartman if (test_bit(psc_num, &fifoc_int) || 655ab4382d2SGreg Kroah-Hartman test_bit(psc_num + 16, &fifoc_int)) 656ab4382d2SGreg Kroah-Hartman return mpc5xxx_uart_process_int(port); 657ab4382d2SGreg Kroah-Hartman 658ab4382d2SGreg Kroah-Hartman return IRQ_NONE; 659ab4382d2SGreg Kroah-Hartman } 660ab4382d2SGreg Kroah-Hartman 6612d30ccacSGerhard Sittig static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM]; 662e149b42bSGerhard Sittig static struct clk *psc_ipg_clk[MPC52xx_PSC_MAXNUM]; 6632d30ccacSGerhard Sittig 6642d30ccacSGerhard Sittig /* called from within the .request_port() callback (allocation) */ 6652d30ccacSGerhard Sittig static int mpc512x_psc_alloc_clock(struct uart_port *port) 666ab4382d2SGreg Kroah-Hartman { 667ab4382d2SGreg Kroah-Hartman int psc_num; 6682d30ccacSGerhard Sittig struct clk *clk; 6692d30ccacSGerhard Sittig int err; 6702d30ccacSGerhard Sittig 6712d30ccacSGerhard Sittig psc_num = (port->mapbase & 0xf00) >> 8; 672e149b42bSGerhard Sittig 673e149b42bSGerhard Sittig clk = devm_clk_get(port->dev, "mclk"); 6742d30ccacSGerhard Sittig if (IS_ERR(clk)) { 6752d30ccacSGerhard Sittig dev_err(port->dev, "Failed to get MCLK!\n"); 676e149b42bSGerhard Sittig err = PTR_ERR(clk); 677e149b42bSGerhard Sittig goto out_err; 6782d30ccacSGerhard Sittig } 6792d30ccacSGerhard Sittig err = clk_prepare_enable(clk); 6802d30ccacSGerhard Sittig if (err) { 6812d30ccacSGerhard Sittig dev_err(port->dev, "Failed to enable MCLK!\n"); 682e149b42bSGerhard Sittig goto out_err; 6832d30ccacSGerhard Sittig } 6842d30ccacSGerhard Sittig psc_mclk_clk[psc_num] = clk; 685e149b42bSGerhard Sittig 686e149b42bSGerhard Sittig clk = devm_clk_get(port->dev, "ipg"); 687e149b42bSGerhard Sittig if (IS_ERR(clk)) { 688e149b42bSGerhard Sittig dev_err(port->dev, "Failed to get IPG clock!\n"); 689e149b42bSGerhard Sittig err = PTR_ERR(clk); 690e149b42bSGerhard Sittig goto out_err; 691e149b42bSGerhard Sittig } 692e149b42bSGerhard Sittig err = clk_prepare_enable(clk); 693e149b42bSGerhard Sittig if (err) { 694e149b42bSGerhard Sittig dev_err(port->dev, "Failed to enable IPG clock!\n"); 695e149b42bSGerhard Sittig goto out_err; 696e149b42bSGerhard Sittig } 697e149b42bSGerhard Sittig psc_ipg_clk[psc_num] = clk; 698e149b42bSGerhard Sittig 6992d30ccacSGerhard Sittig return 0; 700e149b42bSGerhard Sittig 701e149b42bSGerhard Sittig out_err: 702e149b42bSGerhard Sittig if (psc_mclk_clk[psc_num]) { 703e149b42bSGerhard Sittig clk_disable_unprepare(psc_mclk_clk[psc_num]); 704e149b42bSGerhard Sittig psc_mclk_clk[psc_num] = NULL; 705e149b42bSGerhard Sittig } 706e149b42bSGerhard Sittig if (psc_ipg_clk[psc_num]) { 707e149b42bSGerhard Sittig clk_disable_unprepare(psc_ipg_clk[psc_num]); 708e149b42bSGerhard Sittig psc_ipg_clk[psc_num] = NULL; 709e149b42bSGerhard Sittig } 710e149b42bSGerhard Sittig return err; 7112d30ccacSGerhard Sittig } 7122d30ccacSGerhard Sittig 7132d30ccacSGerhard Sittig /* called from within the .release_port() callback (release) */ 7142d30ccacSGerhard Sittig static void mpc512x_psc_relse_clock(struct uart_port *port) 7152d30ccacSGerhard Sittig { 7162d30ccacSGerhard Sittig int psc_num; 7172d30ccacSGerhard Sittig struct clk *clk; 7182d30ccacSGerhard Sittig 7192d30ccacSGerhard Sittig psc_num = (port->mapbase & 0xf00) >> 8; 7202d30ccacSGerhard Sittig clk = psc_mclk_clk[psc_num]; 7212d30ccacSGerhard Sittig if (clk) { 7222d30ccacSGerhard Sittig clk_disable_unprepare(clk); 7232d30ccacSGerhard Sittig psc_mclk_clk[psc_num] = NULL; 7242d30ccacSGerhard Sittig } 725e149b42bSGerhard Sittig if (psc_ipg_clk[psc_num]) { 726e149b42bSGerhard Sittig clk_disable_unprepare(psc_ipg_clk[psc_num]); 727e149b42bSGerhard Sittig psc_ipg_clk[psc_num] = NULL; 728e149b42bSGerhard Sittig } 7292d30ccacSGerhard Sittig } 7302d30ccacSGerhard Sittig 7312d30ccacSGerhard Sittig /* implementation of the .clock() callback (enable/disable) */ 7322d30ccacSGerhard Sittig static int mpc512x_psc_endis_clock(struct uart_port *port, int enable) 7332d30ccacSGerhard Sittig { 7342d30ccacSGerhard Sittig int psc_num; 7352d30ccacSGerhard Sittig struct clk *psc_clk; 7362d30ccacSGerhard Sittig int ret; 737ab4382d2SGreg Kroah-Hartman 738ab4382d2SGreg Kroah-Hartman if (uart_console(port)) 739ab4382d2SGreg Kroah-Hartman return 0; 740ab4382d2SGreg Kroah-Hartman 741ab4382d2SGreg Kroah-Hartman psc_num = (port->mapbase & 0xf00) >> 8; 7422d30ccacSGerhard Sittig psc_clk = psc_mclk_clk[psc_num]; 7432d30ccacSGerhard Sittig if (!psc_clk) { 744ab4382d2SGreg Kroah-Hartman dev_err(port->dev, "Failed to get PSC clock entry!\n"); 745ab4382d2SGreg Kroah-Hartman return -ENODEV; 746ab4382d2SGreg Kroah-Hartman } 747ab4382d2SGreg Kroah-Hartman 7482d30ccacSGerhard Sittig dev_dbg(port->dev, "mclk %sable\n", enable ? "en" : "dis"); 7492d30ccacSGerhard Sittig if (enable) { 7502d30ccacSGerhard Sittig ret = clk_enable(psc_clk); 7512d30ccacSGerhard Sittig if (ret) 7522d30ccacSGerhard Sittig dev_err(port->dev, "Failed to enable MCLK!\n"); 7532d30ccacSGerhard Sittig return ret; 7542d30ccacSGerhard Sittig } else { 755ab4382d2SGreg Kroah-Hartman clk_disable(psc_clk); 756ab4382d2SGreg Kroah-Hartman return 0; 757ab4382d2SGreg Kroah-Hartman } 7582d30ccacSGerhard Sittig } 759ab4382d2SGreg Kroah-Hartman 760ab4382d2SGreg Kroah-Hartman static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np) 761ab4382d2SGreg Kroah-Hartman { 762ab4382d2SGreg Kroah-Hartman port->irqflags = IRQF_SHARED; 763ab4382d2SGreg Kroah-Hartman port->irq = psc_fifoc_irq; 764ab4382d2SGreg Kroah-Hartman } 7651f48c499SMatteo Facchinetti #endif 7661f48c499SMatteo Facchinetti 7671f48c499SMatteo Facchinetti #ifdef CONFIG_PPC_MPC512x 7681f48c499SMatteo Facchinetti 7691f48c499SMatteo Facchinetti #define PSC_5125(port) ((struct mpc5125_psc __iomem *)((port)->membase)) 7701f48c499SMatteo Facchinetti #define FIFO_5125(port) ((struct mpc512x_psc_fifo __iomem *)(PSC_5125(port)+1)) 7711f48c499SMatteo Facchinetti 7721f48c499SMatteo Facchinetti static void mpc5125_psc_fifo_init(struct uart_port *port) 7731f48c499SMatteo Facchinetti { 7741f48c499SMatteo Facchinetti /* /32 prescaler */ 7751f48c499SMatteo Facchinetti out_8(&PSC_5125(port)->mpc52xx_psc_clock_select, 0xdd); 7761f48c499SMatteo Facchinetti 7771f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); 7781f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); 7791f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->txalarm, 1); 7801f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->tximr, 0); 7811f48c499SMatteo Facchinetti 7821f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE); 7831f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); 7841f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->rxalarm, 1); 7851f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->rximr, 0); 7861f48c499SMatteo Facchinetti 7871f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->tximr, MPC512x_PSC_FIFO_ALARM); 7881f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->rximr, MPC512x_PSC_FIFO_ALARM); 7891f48c499SMatteo Facchinetti } 7901f48c499SMatteo Facchinetti 7911f48c499SMatteo Facchinetti static int mpc5125_psc_raw_rx_rdy(struct uart_port *port) 7921f48c499SMatteo Facchinetti { 7931f48c499SMatteo Facchinetti return !(in_be32(&FIFO_5125(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); 7941f48c499SMatteo Facchinetti } 7951f48c499SMatteo Facchinetti 7961f48c499SMatteo Facchinetti static int mpc5125_psc_raw_tx_rdy(struct uart_port *port) 7971f48c499SMatteo Facchinetti { 7981f48c499SMatteo Facchinetti return !(in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_FULL); 7991f48c499SMatteo Facchinetti } 8001f48c499SMatteo Facchinetti 8011f48c499SMatteo Facchinetti static int mpc5125_psc_rx_rdy(struct uart_port *port) 8021f48c499SMatteo Facchinetti { 8031f48c499SMatteo Facchinetti return in_be32(&FIFO_5125(port)->rxsr) & 8041f48c499SMatteo Facchinetti in_be32(&FIFO_5125(port)->rximr) & MPC512x_PSC_FIFO_ALARM; 8051f48c499SMatteo Facchinetti } 8061f48c499SMatteo Facchinetti 8071f48c499SMatteo Facchinetti static int mpc5125_psc_tx_rdy(struct uart_port *port) 8081f48c499SMatteo Facchinetti { 8091f48c499SMatteo Facchinetti return in_be32(&FIFO_5125(port)->txsr) & 8101f48c499SMatteo Facchinetti in_be32(&FIFO_5125(port)->tximr) & MPC512x_PSC_FIFO_ALARM; 8111f48c499SMatteo Facchinetti } 8121f48c499SMatteo Facchinetti 8131f48c499SMatteo Facchinetti static int mpc5125_psc_tx_empty(struct uart_port *port) 8141f48c499SMatteo Facchinetti { 8151f48c499SMatteo Facchinetti return in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_EMPTY; 8161f48c499SMatteo Facchinetti } 8171f48c499SMatteo Facchinetti 8181f48c499SMatteo Facchinetti static void mpc5125_psc_stop_rx(struct uart_port *port) 8191f48c499SMatteo Facchinetti { 8201f48c499SMatteo Facchinetti unsigned long rx_fifo_imr; 8211f48c499SMatteo Facchinetti 8221f48c499SMatteo Facchinetti rx_fifo_imr = in_be32(&FIFO_5125(port)->rximr); 8231f48c499SMatteo Facchinetti rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; 8241f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->rximr, rx_fifo_imr); 8251f48c499SMatteo Facchinetti } 8261f48c499SMatteo Facchinetti 8271f48c499SMatteo Facchinetti static void mpc5125_psc_start_tx(struct uart_port *port) 8281f48c499SMatteo Facchinetti { 8291f48c499SMatteo Facchinetti unsigned long tx_fifo_imr; 8301f48c499SMatteo Facchinetti 8311f48c499SMatteo Facchinetti tx_fifo_imr = in_be32(&FIFO_5125(port)->tximr); 8321f48c499SMatteo Facchinetti tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM; 8331f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->tximr, tx_fifo_imr); 8341f48c499SMatteo Facchinetti } 8351f48c499SMatteo Facchinetti 8361f48c499SMatteo Facchinetti static void mpc5125_psc_stop_tx(struct uart_port *port) 8371f48c499SMatteo Facchinetti { 8381f48c499SMatteo Facchinetti unsigned long tx_fifo_imr; 8391f48c499SMatteo Facchinetti 8401f48c499SMatteo Facchinetti tx_fifo_imr = in_be32(&FIFO_5125(port)->tximr); 8411f48c499SMatteo Facchinetti tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; 8421f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->tximr, tx_fifo_imr); 8431f48c499SMatteo Facchinetti } 8441f48c499SMatteo Facchinetti 8451f48c499SMatteo Facchinetti static void mpc5125_psc_rx_clr_irq(struct uart_port *port) 8461f48c499SMatteo Facchinetti { 8471f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->rxisr, in_be32(&FIFO_5125(port)->rxisr)); 8481f48c499SMatteo Facchinetti } 8491f48c499SMatteo Facchinetti 8501f48c499SMatteo Facchinetti static void mpc5125_psc_tx_clr_irq(struct uart_port *port) 8511f48c499SMatteo Facchinetti { 8521f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->txisr, in_be32(&FIFO_5125(port)->txisr)); 8531f48c499SMatteo Facchinetti } 8541f48c499SMatteo Facchinetti 8551f48c499SMatteo Facchinetti static void mpc5125_psc_write_char(struct uart_port *port, unsigned char c) 8561f48c499SMatteo Facchinetti { 8571f48c499SMatteo Facchinetti out_8(&FIFO_5125(port)->txdata_8, c); 8581f48c499SMatteo Facchinetti } 8591f48c499SMatteo Facchinetti 8601f48c499SMatteo Facchinetti static unsigned char mpc5125_psc_read_char(struct uart_port *port) 8611f48c499SMatteo Facchinetti { 8621f48c499SMatteo Facchinetti return in_8(&FIFO_5125(port)->rxdata_8); 8631f48c499SMatteo Facchinetti } 8641f48c499SMatteo Facchinetti 8651f48c499SMatteo Facchinetti static void mpc5125_psc_cw_disable_ints(struct uart_port *port) 8661f48c499SMatteo Facchinetti { 8671f48c499SMatteo Facchinetti port->read_status_mask = 8681f48c499SMatteo Facchinetti in_be32(&FIFO_5125(port)->tximr) << 16 | 8691f48c499SMatteo Facchinetti in_be32(&FIFO_5125(port)->rximr); 8701f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->tximr, 0); 8711f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->rximr, 0); 8721f48c499SMatteo Facchinetti } 8731f48c499SMatteo Facchinetti 8741f48c499SMatteo Facchinetti static void mpc5125_psc_cw_restore_ints(struct uart_port *port) 8751f48c499SMatteo Facchinetti { 8761f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->tximr, 8771f48c499SMatteo Facchinetti (port->read_status_mask >> 16) & 0x7f); 8781f48c499SMatteo Facchinetti out_be32(&FIFO_5125(port)->rximr, port->read_status_mask & 0x7f); 8791f48c499SMatteo Facchinetti } 8801f48c499SMatteo Facchinetti 8811f48c499SMatteo Facchinetti static inline void mpc5125_set_divisor(struct mpc5125_psc __iomem *psc, 8821f48c499SMatteo Facchinetti u8 prescaler, unsigned int divisor) 8831f48c499SMatteo Facchinetti { 8841f48c499SMatteo Facchinetti /* select prescaler */ 8851f48c499SMatteo Facchinetti out_8(&psc->mpc52xx_psc_clock_select, prescaler); 8861f48c499SMatteo Facchinetti out_8(&psc->ctur, divisor >> 8); 8871f48c499SMatteo Facchinetti out_8(&psc->ctlr, divisor & 0xff); 8881f48c499SMatteo Facchinetti } 8891f48c499SMatteo Facchinetti 8901f48c499SMatteo Facchinetti static unsigned int mpc5125_psc_set_baudrate(struct uart_port *port, 8911f48c499SMatteo Facchinetti struct ktermios *new, 8921f48c499SMatteo Facchinetti struct ktermios *old) 8931f48c499SMatteo Facchinetti { 8941f48c499SMatteo Facchinetti unsigned int baud; 8951f48c499SMatteo Facchinetti unsigned int divisor; 8961f48c499SMatteo Facchinetti 8971f48c499SMatteo Facchinetti /* 8981f48c499SMatteo Facchinetti * Calculate with a /16 prescaler here. 8991f48c499SMatteo Facchinetti */ 9001f48c499SMatteo Facchinetti 9011f48c499SMatteo Facchinetti /* uartclk contains the ips freq */ 9021f48c499SMatteo Facchinetti baud = uart_get_baud_rate(port, new, old, 9031f48c499SMatteo Facchinetti port->uartclk / (16 * 0xffff) + 1, 9041f48c499SMatteo Facchinetti port->uartclk / 16); 9051f48c499SMatteo Facchinetti divisor = (port->uartclk + 8 * baud) / (16 * baud); 9061f48c499SMatteo Facchinetti 9071f48c499SMatteo Facchinetti /* enable the /16 prescaler and set the divisor */ 9081f48c499SMatteo Facchinetti mpc5125_set_divisor(PSC_5125(port), 0xdd, divisor); 9091f48c499SMatteo Facchinetti return baud; 9101f48c499SMatteo Facchinetti } 9111f48c499SMatteo Facchinetti 9121f48c499SMatteo Facchinetti /* 9131f48c499SMatteo Facchinetti * MPC5125 have compatible PSC FIFO Controller. 9141f48c499SMatteo Facchinetti * Special init not needed. 9151f48c499SMatteo Facchinetti */ 9161f48c499SMatteo Facchinetti static u16 mpc5125_psc_get_status(struct uart_port *port) 9171f48c499SMatteo Facchinetti { 9181f48c499SMatteo Facchinetti return in_be16(&PSC_5125(port)->mpc52xx_psc_status); 9191f48c499SMatteo Facchinetti } 9201f48c499SMatteo Facchinetti 9211f48c499SMatteo Facchinetti static u8 mpc5125_psc_get_ipcr(struct uart_port *port) 9221f48c499SMatteo Facchinetti { 9231f48c499SMatteo Facchinetti return in_8(&PSC_5125(port)->mpc52xx_psc_ipcr); 9241f48c499SMatteo Facchinetti } 9251f48c499SMatteo Facchinetti 9261f48c499SMatteo Facchinetti static void mpc5125_psc_command(struct uart_port *port, u8 cmd) 9271f48c499SMatteo Facchinetti { 9281f48c499SMatteo Facchinetti out_8(&PSC_5125(port)->command, cmd); 9291f48c499SMatteo Facchinetti } 9301f48c499SMatteo Facchinetti 9311f48c499SMatteo Facchinetti static void mpc5125_psc_set_mode(struct uart_port *port, u8 mr1, u8 mr2) 9321f48c499SMatteo Facchinetti { 9331f48c499SMatteo Facchinetti out_8(&PSC_5125(port)->mr1, mr1); 9341f48c499SMatteo Facchinetti out_8(&PSC_5125(port)->mr2, mr2); 9351f48c499SMatteo Facchinetti } 9361f48c499SMatteo Facchinetti 9371f48c499SMatteo Facchinetti static void mpc5125_psc_set_rts(struct uart_port *port, int state) 9381f48c499SMatteo Facchinetti { 9391f48c499SMatteo Facchinetti if (state & TIOCM_RTS) 9401f48c499SMatteo Facchinetti out_8(&PSC_5125(port)->op1, MPC52xx_PSC_OP_RTS); 9411f48c499SMatteo Facchinetti else 9421f48c499SMatteo Facchinetti out_8(&PSC_5125(port)->op0, MPC52xx_PSC_OP_RTS); 9431f48c499SMatteo Facchinetti } 9441f48c499SMatteo Facchinetti 9451f48c499SMatteo Facchinetti static void mpc5125_psc_enable_ms(struct uart_port *port) 9461f48c499SMatteo Facchinetti { 9471f48c499SMatteo Facchinetti struct mpc5125_psc __iomem *psc = PSC_5125(port); 9481f48c499SMatteo Facchinetti 9491f48c499SMatteo Facchinetti /* clear D_*-bits by reading them */ 9501f48c499SMatteo Facchinetti in_8(&psc->mpc52xx_psc_ipcr); 9511f48c499SMatteo Facchinetti /* enable CTS and DCD as IPC interrupts */ 9521f48c499SMatteo Facchinetti out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD); 9531f48c499SMatteo Facchinetti 9541f48c499SMatteo Facchinetti port->read_status_mask |= MPC52xx_PSC_IMR_IPC; 9551f48c499SMatteo Facchinetti out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); 9561f48c499SMatteo Facchinetti } 9571f48c499SMatteo Facchinetti 9581f48c499SMatteo Facchinetti static void mpc5125_psc_set_sicr(struct uart_port *port, u32 val) 9591f48c499SMatteo Facchinetti { 9601f48c499SMatteo Facchinetti out_be32(&PSC_5125(port)->sicr, val); 9611f48c499SMatteo Facchinetti } 9621f48c499SMatteo Facchinetti 9631f48c499SMatteo Facchinetti static void mpc5125_psc_set_imr(struct uart_port *port, u16 val) 9641f48c499SMatteo Facchinetti { 9651f48c499SMatteo Facchinetti out_be16(&PSC_5125(port)->mpc52xx_psc_imr, val); 9661f48c499SMatteo Facchinetti } 9671f48c499SMatteo Facchinetti 9681f48c499SMatteo Facchinetti static u8 mpc5125_psc_get_mr1(struct uart_port *port) 9691f48c499SMatteo Facchinetti { 9701f48c499SMatteo Facchinetti return in_8(&PSC_5125(port)->mr1); 9711f48c499SMatteo Facchinetti } 9721f48c499SMatteo Facchinetti 973cc74bd1dSAya Mahfouz static const struct psc_ops mpc5125_psc_ops = { 9741f48c499SMatteo Facchinetti .fifo_init = mpc5125_psc_fifo_init, 9751f48c499SMatteo Facchinetti .raw_rx_rdy = mpc5125_psc_raw_rx_rdy, 9761f48c499SMatteo Facchinetti .raw_tx_rdy = mpc5125_psc_raw_tx_rdy, 9771f48c499SMatteo Facchinetti .rx_rdy = mpc5125_psc_rx_rdy, 9781f48c499SMatteo Facchinetti .tx_rdy = mpc5125_psc_tx_rdy, 9791f48c499SMatteo Facchinetti .tx_empty = mpc5125_psc_tx_empty, 9801f48c499SMatteo Facchinetti .stop_rx = mpc5125_psc_stop_rx, 9811f48c499SMatteo Facchinetti .start_tx = mpc5125_psc_start_tx, 9821f48c499SMatteo Facchinetti .stop_tx = mpc5125_psc_stop_tx, 9831f48c499SMatteo Facchinetti .rx_clr_irq = mpc5125_psc_rx_clr_irq, 9841f48c499SMatteo Facchinetti .tx_clr_irq = mpc5125_psc_tx_clr_irq, 9851f48c499SMatteo Facchinetti .write_char = mpc5125_psc_write_char, 9861f48c499SMatteo Facchinetti .read_char = mpc5125_psc_read_char, 9871f48c499SMatteo Facchinetti .cw_disable_ints = mpc5125_psc_cw_disable_ints, 9881f48c499SMatteo Facchinetti .cw_restore_ints = mpc5125_psc_cw_restore_ints, 9891f48c499SMatteo Facchinetti .set_baudrate = mpc5125_psc_set_baudrate, 9902d30ccacSGerhard Sittig .clock_alloc = mpc512x_psc_alloc_clock, 9912d30ccacSGerhard Sittig .clock_relse = mpc512x_psc_relse_clock, 9922d30ccacSGerhard Sittig .clock = mpc512x_psc_endis_clock, 9931f48c499SMatteo Facchinetti .fifoc_init = mpc512x_psc_fifoc_init, 9941f48c499SMatteo Facchinetti .fifoc_uninit = mpc512x_psc_fifoc_uninit, 9951f48c499SMatteo Facchinetti .get_irq = mpc512x_psc_get_irq, 9961f48c499SMatteo Facchinetti .handle_irq = mpc512x_psc_handle_irq, 9971f48c499SMatteo Facchinetti .get_status = mpc5125_psc_get_status, 9981f48c499SMatteo Facchinetti .get_ipcr = mpc5125_psc_get_ipcr, 9991f48c499SMatteo Facchinetti .command = mpc5125_psc_command, 10001f48c499SMatteo Facchinetti .set_mode = mpc5125_psc_set_mode, 10011f48c499SMatteo Facchinetti .set_rts = mpc5125_psc_set_rts, 10021f48c499SMatteo Facchinetti .enable_ms = mpc5125_psc_enable_ms, 10031f48c499SMatteo Facchinetti .set_sicr = mpc5125_psc_set_sicr, 10041f48c499SMatteo Facchinetti .set_imr = mpc5125_psc_set_imr, 10051f48c499SMatteo Facchinetti .get_mr1 = mpc5125_psc_get_mr1, 10061f48c499SMatteo Facchinetti }; 1007ab4382d2SGreg Kroah-Hartman 1008cc74bd1dSAya Mahfouz static const struct psc_ops mpc512x_psc_ops = { 1009ab4382d2SGreg Kroah-Hartman .fifo_init = mpc512x_psc_fifo_init, 1010ab4382d2SGreg Kroah-Hartman .raw_rx_rdy = mpc512x_psc_raw_rx_rdy, 1011ab4382d2SGreg Kroah-Hartman .raw_tx_rdy = mpc512x_psc_raw_tx_rdy, 1012ab4382d2SGreg Kroah-Hartman .rx_rdy = mpc512x_psc_rx_rdy, 1013ab4382d2SGreg Kroah-Hartman .tx_rdy = mpc512x_psc_tx_rdy, 1014ab4382d2SGreg Kroah-Hartman .tx_empty = mpc512x_psc_tx_empty, 1015ab4382d2SGreg Kroah-Hartman .stop_rx = mpc512x_psc_stop_rx, 1016ab4382d2SGreg Kroah-Hartman .start_tx = mpc512x_psc_start_tx, 1017ab4382d2SGreg Kroah-Hartman .stop_tx = mpc512x_psc_stop_tx, 1018ab4382d2SGreg Kroah-Hartman .rx_clr_irq = mpc512x_psc_rx_clr_irq, 1019ab4382d2SGreg Kroah-Hartman .tx_clr_irq = mpc512x_psc_tx_clr_irq, 1020ab4382d2SGreg Kroah-Hartman .write_char = mpc512x_psc_write_char, 1021ab4382d2SGreg Kroah-Hartman .read_char = mpc512x_psc_read_char, 1022ab4382d2SGreg Kroah-Hartman .cw_disable_ints = mpc512x_psc_cw_disable_ints, 1023ab4382d2SGreg Kroah-Hartman .cw_restore_ints = mpc512x_psc_cw_restore_ints, 1024ab4382d2SGreg Kroah-Hartman .set_baudrate = mpc512x_psc_set_baudrate, 10252d30ccacSGerhard Sittig .clock_alloc = mpc512x_psc_alloc_clock, 10262d30ccacSGerhard Sittig .clock_relse = mpc512x_psc_relse_clock, 10272d30ccacSGerhard Sittig .clock = mpc512x_psc_endis_clock, 1028ab4382d2SGreg Kroah-Hartman .fifoc_init = mpc512x_psc_fifoc_init, 1029ab4382d2SGreg Kroah-Hartman .fifoc_uninit = mpc512x_psc_fifoc_uninit, 1030ab4382d2SGreg Kroah-Hartman .get_irq = mpc512x_psc_get_irq, 1031ab4382d2SGreg Kroah-Hartman .handle_irq = mpc512x_psc_handle_irq, 10322574b27eSMatteo Facchinetti .get_status = mpc52xx_psc_get_status, 10332574b27eSMatteo Facchinetti .get_ipcr = mpc52xx_psc_get_ipcr, 10342574b27eSMatteo Facchinetti .command = mpc52xx_psc_command, 10352574b27eSMatteo Facchinetti .set_mode = mpc52xx_psc_set_mode, 10362574b27eSMatteo Facchinetti .set_rts = mpc52xx_psc_set_rts, 10372574b27eSMatteo Facchinetti .enable_ms = mpc52xx_psc_enable_ms, 10382574b27eSMatteo Facchinetti .set_sicr = mpc52xx_psc_set_sicr, 10392574b27eSMatteo Facchinetti .set_imr = mpc52xx_psc_set_imr, 10402574b27eSMatteo Facchinetti .get_mr1 = mpc52xx_psc_get_mr1, 1041ab4382d2SGreg Kroah-Hartman }; 10422574b27eSMatteo Facchinetti #endif /* CONFIG_PPC_MPC512x */ 10432574b27eSMatteo Facchinetti 1044ab4382d2SGreg Kroah-Hartman 104576d28e44SUwe Kleine-König static const struct psc_ops *psc_ops; 1046ab4382d2SGreg Kroah-Hartman 1047ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1048ab4382d2SGreg Kroah-Hartman /* UART operations */ 1049ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1050ab4382d2SGreg Kroah-Hartman 1051ab4382d2SGreg Kroah-Hartman static unsigned int 1052ab4382d2SGreg Kroah-Hartman mpc52xx_uart_tx_empty(struct uart_port *port) 1053ab4382d2SGreg Kroah-Hartman { 1054ab4382d2SGreg Kroah-Hartman return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0; 1055ab4382d2SGreg Kroah-Hartman } 1056ab4382d2SGreg Kroah-Hartman 1057ab4382d2SGreg Kroah-Hartman static void 1058ab4382d2SGreg Kroah-Hartman mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) 1059ab4382d2SGreg Kroah-Hartman { 10602574b27eSMatteo Facchinetti psc_ops->set_rts(port, mctrl & TIOCM_RTS); 1061ab4382d2SGreg Kroah-Hartman } 1062ab4382d2SGreg Kroah-Hartman 1063ab4382d2SGreg Kroah-Hartman static unsigned int 1064ab4382d2SGreg Kroah-Hartman mpc52xx_uart_get_mctrl(struct uart_port *port) 1065ab4382d2SGreg Kroah-Hartman { 1066ab4382d2SGreg Kroah-Hartman unsigned int ret = TIOCM_DSR; 10672574b27eSMatteo Facchinetti u8 status = psc_ops->get_ipcr(port); 1068ab4382d2SGreg Kroah-Hartman 1069ab4382d2SGreg Kroah-Hartman if (!(status & MPC52xx_PSC_CTS)) 1070ab4382d2SGreg Kroah-Hartman ret |= TIOCM_CTS; 1071ab4382d2SGreg Kroah-Hartman if (!(status & MPC52xx_PSC_DCD)) 1072ab4382d2SGreg Kroah-Hartman ret |= TIOCM_CAR; 1073ab4382d2SGreg Kroah-Hartman 1074ab4382d2SGreg Kroah-Hartman return ret; 1075ab4382d2SGreg Kroah-Hartman } 1076ab4382d2SGreg Kroah-Hartman 1077ab4382d2SGreg Kroah-Hartman static void 1078ab4382d2SGreg Kroah-Hartman mpc52xx_uart_stop_tx(struct uart_port *port) 1079ab4382d2SGreg Kroah-Hartman { 1080ab4382d2SGreg Kroah-Hartman /* port->lock taken by caller */ 1081ab4382d2SGreg Kroah-Hartman psc_ops->stop_tx(port); 1082ab4382d2SGreg Kroah-Hartman } 1083ab4382d2SGreg Kroah-Hartman 1084ab4382d2SGreg Kroah-Hartman static void 1085ab4382d2SGreg Kroah-Hartman mpc52xx_uart_start_tx(struct uart_port *port) 1086ab4382d2SGreg Kroah-Hartman { 1087ab4382d2SGreg Kroah-Hartman /* port->lock taken by caller */ 1088ab4382d2SGreg Kroah-Hartman psc_ops->start_tx(port); 1089ab4382d2SGreg Kroah-Hartman } 1090ab4382d2SGreg Kroah-Hartman 1091ab4382d2SGreg Kroah-Hartman static void 1092ab4382d2SGreg Kroah-Hartman mpc52xx_uart_stop_rx(struct uart_port *port) 1093ab4382d2SGreg Kroah-Hartman { 1094ab4382d2SGreg Kroah-Hartman /* port->lock taken by caller */ 1095ab4382d2SGreg Kroah-Hartman psc_ops->stop_rx(port); 1096ab4382d2SGreg Kroah-Hartman } 1097ab4382d2SGreg Kroah-Hartman 1098ab4382d2SGreg Kroah-Hartman static void 1099ab4382d2SGreg Kroah-Hartman mpc52xx_uart_enable_ms(struct uart_port *port) 1100ab4382d2SGreg Kroah-Hartman { 11012574b27eSMatteo Facchinetti psc_ops->enable_ms(port); 1102ab4382d2SGreg Kroah-Hartman } 1103ab4382d2SGreg Kroah-Hartman 1104ab4382d2SGreg Kroah-Hartman static void 1105ab4382d2SGreg Kroah-Hartman mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) 1106ab4382d2SGreg Kroah-Hartman { 1107ab4382d2SGreg Kroah-Hartman unsigned long flags; 1108ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, flags); 1109ab4382d2SGreg Kroah-Hartman 1110ab4382d2SGreg Kroah-Hartman if (ctl == -1) 11112574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_START_BRK); 1112ab4382d2SGreg Kroah-Hartman else 11132574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_STOP_BRK); 1114ab4382d2SGreg Kroah-Hartman 1115ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags); 1116ab4382d2SGreg Kroah-Hartman } 1117ab4382d2SGreg Kroah-Hartman 1118ab4382d2SGreg Kroah-Hartman static int 1119ab4382d2SGreg Kroah-Hartman mpc52xx_uart_startup(struct uart_port *port) 1120ab4382d2SGreg Kroah-Hartman { 1121ab4382d2SGreg Kroah-Hartman int ret; 1122ab4382d2SGreg Kroah-Hartman 1123ab4382d2SGreg Kroah-Hartman if (psc_ops->clock) { 1124ab4382d2SGreg Kroah-Hartman ret = psc_ops->clock(port, 1); 1125ab4382d2SGreg Kroah-Hartman if (ret) 1126ab4382d2SGreg Kroah-Hartman return ret; 1127ab4382d2SGreg Kroah-Hartman } 1128ab4382d2SGreg Kroah-Hartman 1129ab4382d2SGreg Kroah-Hartman /* Request IRQ */ 1130ab4382d2SGreg Kroah-Hartman ret = request_irq(port->irq, mpc52xx_uart_int, 1131ab4382d2SGreg Kroah-Hartman port->irqflags, "mpc52xx_psc_uart", port); 1132ab4382d2SGreg Kroah-Hartman if (ret) 1133ab4382d2SGreg Kroah-Hartman return ret; 1134ab4382d2SGreg Kroah-Hartman 1135ab4382d2SGreg Kroah-Hartman /* Reset/activate the port, clear and enable interrupts */ 11362574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_RST_RX); 11372574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_RST_TX); 1138ab4382d2SGreg Kroah-Hartman 1139e4b4e317SUwe Kleine-König /* 1140e4b4e317SUwe Kleine-König * According to Freescale's support the RST_TX command can produce a 1141e4b4e317SUwe Kleine-König * spike on the TX pin. So they recommend to delay "for one character". 1142e4b4e317SUwe Kleine-König * One millisecond should be enough for everyone. 1143e4b4e317SUwe Kleine-König */ 1144e4b4e317SUwe Kleine-König msleep(1); 1145e4b4e317SUwe Kleine-König 11462574b27eSMatteo Facchinetti psc_ops->set_sicr(port, 0); /* UART mode DCD ignored */ 1147ab4382d2SGreg Kroah-Hartman 1148ab4382d2SGreg Kroah-Hartman psc_ops->fifo_init(port); 1149ab4382d2SGreg Kroah-Hartman 11502574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_TX_ENABLE); 11512574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_RX_ENABLE); 1152ab4382d2SGreg Kroah-Hartman 1153ab4382d2SGreg Kroah-Hartman return 0; 1154ab4382d2SGreg Kroah-Hartman } 1155ab4382d2SGreg Kroah-Hartman 1156ab4382d2SGreg Kroah-Hartman static void 1157ab4382d2SGreg Kroah-Hartman mpc52xx_uart_shutdown(struct uart_port *port) 1158ab4382d2SGreg Kroah-Hartman { 1159ab4382d2SGreg Kroah-Hartman /* Shut down the port. Leave TX active if on a console port */ 11602574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_RST_RX); 1161ab4382d2SGreg Kroah-Hartman if (!uart_console(port)) 11622574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_RST_TX); 1163ab4382d2SGreg Kroah-Hartman 1164ab4382d2SGreg Kroah-Hartman port->read_status_mask = 0; 11652574b27eSMatteo Facchinetti psc_ops->set_imr(port, port->read_status_mask); 1166ab4382d2SGreg Kroah-Hartman 1167ab4382d2SGreg Kroah-Hartman if (psc_ops->clock) 1168ab4382d2SGreg Kroah-Hartman psc_ops->clock(port, 0); 1169ab4382d2SGreg Kroah-Hartman 11708a29dfb8SMatteo Facchinetti /* Disable interrupt */ 11718a29dfb8SMatteo Facchinetti psc_ops->cw_disable_ints(port); 11728a29dfb8SMatteo Facchinetti 1173ab4382d2SGreg Kroah-Hartman /* Release interrupt */ 1174ab4382d2SGreg Kroah-Hartman free_irq(port->irq, port); 1175ab4382d2SGreg Kroah-Hartman } 1176ab4382d2SGreg Kroah-Hartman 1177ab4382d2SGreg Kroah-Hartman static void 1178ab4382d2SGreg Kroah-Hartman mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, 1179ab4382d2SGreg Kroah-Hartman struct ktermios *old) 1180ab4382d2SGreg Kroah-Hartman { 1181ab4382d2SGreg Kroah-Hartman unsigned long flags; 1182ab4382d2SGreg Kroah-Hartman unsigned char mr1, mr2; 1183ab4382d2SGreg Kroah-Hartman unsigned int j; 1184ab4382d2SGreg Kroah-Hartman unsigned int baud; 1185ab4382d2SGreg Kroah-Hartman 1186ab4382d2SGreg Kroah-Hartman /* Prepare what we're gonna write */ 1187ab4382d2SGreg Kroah-Hartman mr1 = 0; 1188ab4382d2SGreg Kroah-Hartman 1189ab4382d2SGreg Kroah-Hartman switch (new->c_cflag & CSIZE) { 1190ab4382d2SGreg Kroah-Hartman case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS; 1191ab4382d2SGreg Kroah-Hartman break; 1192ab4382d2SGreg Kroah-Hartman case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS; 1193ab4382d2SGreg Kroah-Hartman break; 1194ab4382d2SGreg Kroah-Hartman case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS; 1195ab4382d2SGreg Kroah-Hartman break; 1196ab4382d2SGreg Kroah-Hartman case CS8: 1197ab4382d2SGreg Kroah-Hartman default: mr1 |= MPC52xx_PSC_MODE_8_BITS; 1198ab4382d2SGreg Kroah-Hartman } 1199ab4382d2SGreg Kroah-Hartman 1200ab4382d2SGreg Kroah-Hartman if (new->c_cflag & PARENB) { 1201d3dec96eSWolfram Sang if (new->c_cflag & CMSPAR) 1202d3dec96eSWolfram Sang mr1 |= MPC52xx_PSC_MODE_PARFORCE; 1203d3dec96eSWolfram Sang 1204d3dec96eSWolfram Sang /* With CMSPAR, PARODD also means high parity (same as termios) */ 1205ab4382d2SGreg Kroah-Hartman mr1 |= (new->c_cflag & PARODD) ? 1206ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN; 1207d3dec96eSWolfram Sang } else { 1208ab4382d2SGreg Kroah-Hartman mr1 |= MPC52xx_PSC_MODE_PARNONE; 1209d3dec96eSWolfram Sang } 1210ab4382d2SGreg Kroah-Hartman 1211ab4382d2SGreg Kroah-Hartman mr2 = 0; 1212ab4382d2SGreg Kroah-Hartman 1213ab4382d2SGreg Kroah-Hartman if (new->c_cflag & CSTOPB) 1214ab4382d2SGreg Kroah-Hartman mr2 |= MPC52xx_PSC_MODE_TWO_STOP; 1215ab4382d2SGreg Kroah-Hartman else 1216ab4382d2SGreg Kroah-Hartman mr2 |= ((new->c_cflag & CSIZE) == CS5) ? 1217ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_MODE_ONE_STOP_5_BITS : 1218ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_MODE_ONE_STOP; 1219ab4382d2SGreg Kroah-Hartman 1220ab4382d2SGreg Kroah-Hartman if (new->c_cflag & CRTSCTS) { 1221ab4382d2SGreg Kroah-Hartman mr1 |= MPC52xx_PSC_MODE_RXRTS; 1222ab4382d2SGreg Kroah-Hartman mr2 |= MPC52xx_PSC_MODE_TXCTS; 1223ab4382d2SGreg Kroah-Hartman } 1224ab4382d2SGreg Kroah-Hartman 1225ab4382d2SGreg Kroah-Hartman /* Get the lock */ 1226ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, flags); 1227ab4382d2SGreg Kroah-Hartman 1228ab4382d2SGreg Kroah-Hartman /* Do our best to flush TX & RX, so we don't lose anything */ 1229ab4382d2SGreg Kroah-Hartman /* But we don't wait indefinitely ! */ 1230ab4382d2SGreg Kroah-Hartman j = 5000000; /* Maximum wait */ 1231ab4382d2SGreg Kroah-Hartman /* FIXME Can't receive chars since set_termios might be called at early 1232ab4382d2SGreg Kroah-Hartman * boot for the console, all stuff is not yet ready to receive at that 1233ab4382d2SGreg Kroah-Hartman * time and that just makes the kernel oops */ 1234ab4382d2SGreg Kroah-Hartman /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ 1235ab4382d2SGreg Kroah-Hartman while (!mpc52xx_uart_tx_empty(port) && --j) 1236ab4382d2SGreg Kroah-Hartman udelay(1); 1237ab4382d2SGreg Kroah-Hartman 1238ab4382d2SGreg Kroah-Hartman if (!j) 1239ab4382d2SGreg Kroah-Hartman printk(KERN_ERR "mpc52xx_uart.c: " 1240ab4382d2SGreg Kroah-Hartman "Unable to flush RX & TX fifos in-time in set_termios." 1241ab4382d2SGreg Kroah-Hartman "Some chars may have been lost.\n"); 1242ab4382d2SGreg Kroah-Hartman 1243ab4382d2SGreg Kroah-Hartman /* Reset the TX & RX */ 12442574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_RST_RX); 12452574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_RST_TX); 1246ab4382d2SGreg Kroah-Hartman 1247ab4382d2SGreg Kroah-Hartman /* Send new mode settings */ 12482574b27eSMatteo Facchinetti psc_ops->set_mode(port, mr1, mr2); 1249ab4382d2SGreg Kroah-Hartman baud = psc_ops->set_baudrate(port, new, old); 1250ab4382d2SGreg Kroah-Hartman 1251ab4382d2SGreg Kroah-Hartman /* Update the per-port timeout */ 1252ab4382d2SGreg Kroah-Hartman uart_update_timeout(port, new->c_cflag, baud); 1253ab4382d2SGreg Kroah-Hartman 1254ab4382d2SGreg Kroah-Hartman if (UART_ENABLE_MS(port, new->c_cflag)) 1255ab4382d2SGreg Kroah-Hartman mpc52xx_uart_enable_ms(port); 1256ab4382d2SGreg Kroah-Hartman 1257ab4382d2SGreg Kroah-Hartman /* Reenable TX & RX */ 12582574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_TX_ENABLE); 12592574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_RX_ENABLE); 1260ab4382d2SGreg Kroah-Hartman 1261ab4382d2SGreg Kroah-Hartman /* We're all set, release the lock */ 1262ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags); 1263ab4382d2SGreg Kroah-Hartman } 1264ab4382d2SGreg Kroah-Hartman 1265ab4382d2SGreg Kroah-Hartman static const char * 1266ab4382d2SGreg Kroah-Hartman mpc52xx_uart_type(struct uart_port *port) 1267ab4382d2SGreg Kroah-Hartman { 1268ab4382d2SGreg Kroah-Hartman /* 1269ab4382d2SGreg Kroah-Hartman * We keep using PORT_MPC52xx for historic reasons although it applies 1270ab4382d2SGreg Kroah-Hartman * for MPC512x, too, but print "MPC5xxx" to not irritate users 1271ab4382d2SGreg Kroah-Hartman */ 1272ab4382d2SGreg Kroah-Hartman return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL; 1273ab4382d2SGreg Kroah-Hartman } 1274ab4382d2SGreg Kroah-Hartman 1275ab4382d2SGreg Kroah-Hartman static void 1276ab4382d2SGreg Kroah-Hartman mpc52xx_uart_release_port(struct uart_port *port) 1277ab4382d2SGreg Kroah-Hartman { 12782d30ccacSGerhard Sittig if (psc_ops->clock_relse) 12792d30ccacSGerhard Sittig psc_ops->clock_relse(port); 12802d30ccacSGerhard Sittig 1281ab4382d2SGreg Kroah-Hartman /* remapped by us ? */ 1282ab4382d2SGreg Kroah-Hartman if (port->flags & UPF_IOREMAP) { 1283ab4382d2SGreg Kroah-Hartman iounmap(port->membase); 1284ab4382d2SGreg Kroah-Hartman port->membase = NULL; 1285ab4382d2SGreg Kroah-Hartman } 1286ab4382d2SGreg Kroah-Hartman 1287ab4382d2SGreg Kroah-Hartman release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); 1288ab4382d2SGreg Kroah-Hartman } 1289ab4382d2SGreg Kroah-Hartman 1290ab4382d2SGreg Kroah-Hartman static int 1291ab4382d2SGreg Kroah-Hartman mpc52xx_uart_request_port(struct uart_port *port) 1292ab4382d2SGreg Kroah-Hartman { 1293ab4382d2SGreg Kroah-Hartman int err; 1294ab4382d2SGreg Kroah-Hartman 1295ab4382d2SGreg Kroah-Hartman if (port->flags & UPF_IOREMAP) /* Need to remap ? */ 1296ab4382d2SGreg Kroah-Hartman port->membase = ioremap(port->mapbase, 1297ab4382d2SGreg Kroah-Hartman sizeof(struct mpc52xx_psc)); 1298ab4382d2SGreg Kroah-Hartman 1299ab4382d2SGreg Kroah-Hartman if (!port->membase) 1300ab4382d2SGreg Kroah-Hartman return -EINVAL; 1301ab4382d2SGreg Kroah-Hartman 1302ab4382d2SGreg Kroah-Hartman err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc), 1303ab4382d2SGreg Kroah-Hartman "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY; 1304ab4382d2SGreg Kroah-Hartman 13052d30ccacSGerhard Sittig if (err) 13062d30ccacSGerhard Sittig goto out_membase; 13072d30ccacSGerhard Sittig 13082d30ccacSGerhard Sittig if (psc_ops->clock_alloc) { 13092d30ccacSGerhard Sittig err = psc_ops->clock_alloc(port); 13102d30ccacSGerhard Sittig if (err) 13112d30ccacSGerhard Sittig goto out_mapregion; 13122d30ccacSGerhard Sittig } 13132d30ccacSGerhard Sittig 13142d30ccacSGerhard Sittig return 0; 13152d30ccacSGerhard Sittig 13162d30ccacSGerhard Sittig out_mapregion: 13172d30ccacSGerhard Sittig release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); 13182d30ccacSGerhard Sittig out_membase: 13192d30ccacSGerhard Sittig if (port->flags & UPF_IOREMAP) { 1320ab4382d2SGreg Kroah-Hartman iounmap(port->membase); 1321ab4382d2SGreg Kroah-Hartman port->membase = NULL; 1322ab4382d2SGreg Kroah-Hartman } 1323ab4382d2SGreg Kroah-Hartman return err; 1324ab4382d2SGreg Kroah-Hartman } 1325ab4382d2SGreg Kroah-Hartman 1326ab4382d2SGreg Kroah-Hartman static void 1327ab4382d2SGreg Kroah-Hartman mpc52xx_uart_config_port(struct uart_port *port, int flags) 1328ab4382d2SGreg Kroah-Hartman { 1329ab4382d2SGreg Kroah-Hartman if ((flags & UART_CONFIG_TYPE) 1330ab4382d2SGreg Kroah-Hartman && (mpc52xx_uart_request_port(port) == 0)) 1331ab4382d2SGreg Kroah-Hartman port->type = PORT_MPC52xx; 1332ab4382d2SGreg Kroah-Hartman } 1333ab4382d2SGreg Kroah-Hartman 1334ab4382d2SGreg Kroah-Hartman static int 1335ab4382d2SGreg Kroah-Hartman mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) 1336ab4382d2SGreg Kroah-Hartman { 1337ab4382d2SGreg Kroah-Hartman if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx) 1338ab4382d2SGreg Kroah-Hartman return -EINVAL; 1339ab4382d2SGreg Kroah-Hartman 1340ab4382d2SGreg Kroah-Hartman if ((ser->irq != port->irq) || 1341ab4382d2SGreg Kroah-Hartman (ser->io_type != UPIO_MEM) || 1342ab4382d2SGreg Kroah-Hartman (ser->baud_base != port->uartclk) || 1343ab4382d2SGreg Kroah-Hartman (ser->iomem_base != (void *)port->mapbase) || 1344ab4382d2SGreg Kroah-Hartman (ser->hub6 != 0)) 1345ab4382d2SGreg Kroah-Hartman return -EINVAL; 1346ab4382d2SGreg Kroah-Hartman 1347ab4382d2SGreg Kroah-Hartman return 0; 1348ab4382d2SGreg Kroah-Hartman } 1349ab4382d2SGreg Kroah-Hartman 1350ab4382d2SGreg Kroah-Hartman 13516f137a75SJulia Lawall static const struct uart_ops mpc52xx_uart_ops = { 1352ab4382d2SGreg Kroah-Hartman .tx_empty = mpc52xx_uart_tx_empty, 1353ab4382d2SGreg Kroah-Hartman .set_mctrl = mpc52xx_uart_set_mctrl, 1354ab4382d2SGreg Kroah-Hartman .get_mctrl = mpc52xx_uart_get_mctrl, 1355ab4382d2SGreg Kroah-Hartman .stop_tx = mpc52xx_uart_stop_tx, 1356ab4382d2SGreg Kroah-Hartman .start_tx = mpc52xx_uart_start_tx, 1357ab4382d2SGreg Kroah-Hartman .stop_rx = mpc52xx_uart_stop_rx, 1358ab4382d2SGreg Kroah-Hartman .enable_ms = mpc52xx_uart_enable_ms, 1359ab4382d2SGreg Kroah-Hartman .break_ctl = mpc52xx_uart_break_ctl, 1360ab4382d2SGreg Kroah-Hartman .startup = mpc52xx_uart_startup, 1361ab4382d2SGreg Kroah-Hartman .shutdown = mpc52xx_uart_shutdown, 1362ab4382d2SGreg Kroah-Hartman .set_termios = mpc52xx_uart_set_termios, 1363ab4382d2SGreg Kroah-Hartman /* .pm = mpc52xx_uart_pm, Not supported yet */ 1364ab4382d2SGreg Kroah-Hartman .type = mpc52xx_uart_type, 1365ab4382d2SGreg Kroah-Hartman .release_port = mpc52xx_uart_release_port, 1366ab4382d2SGreg Kroah-Hartman .request_port = mpc52xx_uart_request_port, 1367ab4382d2SGreg Kroah-Hartman .config_port = mpc52xx_uart_config_port, 1368ab4382d2SGreg Kroah-Hartman .verify_port = mpc52xx_uart_verify_port 1369ab4382d2SGreg Kroah-Hartman }; 1370ab4382d2SGreg Kroah-Hartman 1371ab4382d2SGreg Kroah-Hartman 1372ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1373ab4382d2SGreg Kroah-Hartman /* Interrupt handling */ 1374ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1375ab4382d2SGreg Kroah-Hartman 1376ab4382d2SGreg Kroah-Hartman static inline int 1377ab4382d2SGreg Kroah-Hartman mpc52xx_uart_int_rx_chars(struct uart_port *port) 1378ab4382d2SGreg Kroah-Hartman { 137992a19f9cSJiri Slaby struct tty_port *tport = &port->state->port; 1380ab4382d2SGreg Kroah-Hartman unsigned char ch, flag; 1381ab4382d2SGreg Kroah-Hartman unsigned short status; 1382ab4382d2SGreg Kroah-Hartman 1383ab4382d2SGreg Kroah-Hartman /* While we can read, do so ! */ 1384ab4382d2SGreg Kroah-Hartman while (psc_ops->raw_rx_rdy(port)) { 1385ab4382d2SGreg Kroah-Hartman /* Get the char */ 1386ab4382d2SGreg Kroah-Hartman ch = psc_ops->read_char(port); 1387ab4382d2SGreg Kroah-Hartman 1388ab4382d2SGreg Kroah-Hartman /* Handle sysreq char */ 1389ab4382d2SGreg Kroah-Hartman #ifdef SUPPORT_SYSRQ 1390ab4382d2SGreg Kroah-Hartman if (uart_handle_sysrq_char(port, ch)) { 1391ab4382d2SGreg Kroah-Hartman port->sysrq = 0; 1392ab4382d2SGreg Kroah-Hartman continue; 1393ab4382d2SGreg Kroah-Hartman } 1394ab4382d2SGreg Kroah-Hartman #endif 1395ab4382d2SGreg Kroah-Hartman 1396ab4382d2SGreg Kroah-Hartman /* Store it */ 1397ab4382d2SGreg Kroah-Hartman 1398ab4382d2SGreg Kroah-Hartman flag = TTY_NORMAL; 1399ab4382d2SGreg Kroah-Hartman port->icount.rx++; 1400ab4382d2SGreg Kroah-Hartman 14012574b27eSMatteo Facchinetti status = psc_ops->get_status(port); 1402ab4382d2SGreg Kroah-Hartman 1403ab4382d2SGreg Kroah-Hartman if (status & (MPC52xx_PSC_SR_PE | 1404ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_SR_FE | 1405ab4382d2SGreg Kroah-Hartman MPC52xx_PSC_SR_RB)) { 1406ab4382d2SGreg Kroah-Hartman 1407ab4382d2SGreg Kroah-Hartman if (status & MPC52xx_PSC_SR_RB) { 1408ab4382d2SGreg Kroah-Hartman flag = TTY_BREAK; 1409ab4382d2SGreg Kroah-Hartman uart_handle_break(port); 1410ab4382d2SGreg Kroah-Hartman port->icount.brk++; 1411ab4382d2SGreg Kroah-Hartman } else if (status & MPC52xx_PSC_SR_PE) { 1412ab4382d2SGreg Kroah-Hartman flag = TTY_PARITY; 1413ab4382d2SGreg Kroah-Hartman port->icount.parity++; 1414ab4382d2SGreg Kroah-Hartman } 1415ab4382d2SGreg Kroah-Hartman else if (status & MPC52xx_PSC_SR_FE) { 1416ab4382d2SGreg Kroah-Hartman flag = TTY_FRAME; 1417ab4382d2SGreg Kroah-Hartman port->icount.frame++; 1418ab4382d2SGreg Kroah-Hartman } 1419ab4382d2SGreg Kroah-Hartman 1420ab4382d2SGreg Kroah-Hartman /* Clear error condition */ 14212574b27eSMatteo Facchinetti psc_ops->command(port, MPC52xx_PSC_RST_ERR_STAT); 1422ab4382d2SGreg Kroah-Hartman 1423ab4382d2SGreg Kroah-Hartman } 142492a19f9cSJiri Slaby tty_insert_flip_char(tport, ch, flag); 1425ab4382d2SGreg Kroah-Hartman if (status & MPC52xx_PSC_SR_OE) { 1426ab4382d2SGreg Kroah-Hartman /* 1427ab4382d2SGreg Kroah-Hartman * Overrun is special, since it's 1428ab4382d2SGreg Kroah-Hartman * reported immediately, and doesn't 1429ab4382d2SGreg Kroah-Hartman * affect the current character 1430ab4382d2SGreg Kroah-Hartman */ 143192a19f9cSJiri Slaby tty_insert_flip_char(tport, 0, TTY_OVERRUN); 1432ab4382d2SGreg Kroah-Hartman port->icount.overrun++; 1433ab4382d2SGreg Kroah-Hartman } 1434ab4382d2SGreg Kroah-Hartman } 1435ab4382d2SGreg Kroah-Hartman 1436ab4382d2SGreg Kroah-Hartman spin_unlock(&port->lock); 14372e124b4aSJiri Slaby tty_flip_buffer_push(tport); 1438ab4382d2SGreg Kroah-Hartman spin_lock(&port->lock); 1439ab4382d2SGreg Kroah-Hartman 1440ab4382d2SGreg Kroah-Hartman return psc_ops->raw_rx_rdy(port); 1441ab4382d2SGreg Kroah-Hartman } 1442ab4382d2SGreg Kroah-Hartman 1443ab4382d2SGreg Kroah-Hartman static inline int 1444ab4382d2SGreg Kroah-Hartman mpc52xx_uart_int_tx_chars(struct uart_port *port) 1445ab4382d2SGreg Kroah-Hartman { 1446ab4382d2SGreg Kroah-Hartman struct circ_buf *xmit = &port->state->xmit; 1447ab4382d2SGreg Kroah-Hartman 1448ab4382d2SGreg Kroah-Hartman /* Process out of band chars */ 1449ab4382d2SGreg Kroah-Hartman if (port->x_char) { 1450ab4382d2SGreg Kroah-Hartman psc_ops->write_char(port, port->x_char); 1451ab4382d2SGreg Kroah-Hartman port->icount.tx++; 1452ab4382d2SGreg Kroah-Hartman port->x_char = 0; 1453ab4382d2SGreg Kroah-Hartman return 1; 1454ab4382d2SGreg Kroah-Hartman } 1455ab4382d2SGreg Kroah-Hartman 1456ab4382d2SGreg Kroah-Hartman /* Nothing to do ? */ 1457ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { 1458ab4382d2SGreg Kroah-Hartman mpc52xx_uart_stop_tx(port); 1459ab4382d2SGreg Kroah-Hartman return 0; 1460ab4382d2SGreg Kroah-Hartman } 1461ab4382d2SGreg Kroah-Hartman 1462ab4382d2SGreg Kroah-Hartman /* Send chars */ 1463ab4382d2SGreg Kroah-Hartman while (psc_ops->raw_tx_rdy(port)) { 1464ab4382d2SGreg Kroah-Hartman psc_ops->write_char(port, xmit->buf[xmit->tail]); 1465ab4382d2SGreg Kroah-Hartman xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 1466ab4382d2SGreg Kroah-Hartman port->icount.tx++; 1467ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit)) 1468ab4382d2SGreg Kroah-Hartman break; 1469ab4382d2SGreg Kroah-Hartman } 1470ab4382d2SGreg Kroah-Hartman 1471ab4382d2SGreg Kroah-Hartman /* Wake up */ 1472ab4382d2SGreg Kroah-Hartman if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 1473ab4382d2SGreg Kroah-Hartman uart_write_wakeup(port); 1474ab4382d2SGreg Kroah-Hartman 1475ab4382d2SGreg Kroah-Hartman /* Maybe we're done after all */ 1476ab4382d2SGreg Kroah-Hartman if (uart_circ_empty(xmit)) { 1477ab4382d2SGreg Kroah-Hartman mpc52xx_uart_stop_tx(port); 1478ab4382d2SGreg Kroah-Hartman return 0; 1479ab4382d2SGreg Kroah-Hartman } 1480ab4382d2SGreg Kroah-Hartman 1481ab4382d2SGreg Kroah-Hartman return 1; 1482ab4382d2SGreg Kroah-Hartman } 1483ab4382d2SGreg Kroah-Hartman 1484ab4382d2SGreg Kroah-Hartman static irqreturn_t 1485ab4382d2SGreg Kroah-Hartman mpc5xxx_uart_process_int(struct uart_port *port) 1486ab4382d2SGreg Kroah-Hartman { 1487ab4382d2SGreg Kroah-Hartman unsigned long pass = ISR_PASS_LIMIT; 1488ab4382d2SGreg Kroah-Hartman unsigned int keepgoing; 1489ab4382d2SGreg Kroah-Hartman u8 status; 1490ab4382d2SGreg Kroah-Hartman 1491ab4382d2SGreg Kroah-Hartman /* While we have stuff to do, we continue */ 1492ab4382d2SGreg Kroah-Hartman do { 1493ab4382d2SGreg Kroah-Hartman /* If we don't find anything to do, we stop */ 1494ab4382d2SGreg Kroah-Hartman keepgoing = 0; 1495ab4382d2SGreg Kroah-Hartman 1496ab4382d2SGreg Kroah-Hartman psc_ops->rx_clr_irq(port); 1497ab4382d2SGreg Kroah-Hartman if (psc_ops->rx_rdy(port)) 1498ab4382d2SGreg Kroah-Hartman keepgoing |= mpc52xx_uart_int_rx_chars(port); 1499ab4382d2SGreg Kroah-Hartman 1500ab4382d2SGreg Kroah-Hartman psc_ops->tx_clr_irq(port); 1501ab4382d2SGreg Kroah-Hartman if (psc_ops->tx_rdy(port)) 1502ab4382d2SGreg Kroah-Hartman keepgoing |= mpc52xx_uart_int_tx_chars(port); 1503ab4382d2SGreg Kroah-Hartman 15042574b27eSMatteo Facchinetti status = psc_ops->get_ipcr(port); 1505ab4382d2SGreg Kroah-Hartman if (status & MPC52xx_PSC_D_DCD) 1506ab4382d2SGreg Kroah-Hartman uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD)); 1507ab4382d2SGreg Kroah-Hartman 1508ab4382d2SGreg Kroah-Hartman if (status & MPC52xx_PSC_D_CTS) 1509ab4382d2SGreg Kroah-Hartman uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS)); 1510ab4382d2SGreg Kroah-Hartman 1511ab4382d2SGreg Kroah-Hartman /* Limit number of iteration */ 1512ab4382d2SGreg Kroah-Hartman if (!(--pass)) 1513ab4382d2SGreg Kroah-Hartman keepgoing = 0; 1514ab4382d2SGreg Kroah-Hartman 1515ab4382d2SGreg Kroah-Hartman } while (keepgoing); 1516ab4382d2SGreg Kroah-Hartman 1517ab4382d2SGreg Kroah-Hartman return IRQ_HANDLED; 1518ab4382d2SGreg Kroah-Hartman } 1519ab4382d2SGreg Kroah-Hartman 1520ab4382d2SGreg Kroah-Hartman static irqreturn_t 1521ab4382d2SGreg Kroah-Hartman mpc52xx_uart_int(int irq, void *dev_id) 1522ab4382d2SGreg Kroah-Hartman { 1523ab4382d2SGreg Kroah-Hartman struct uart_port *port = dev_id; 1524ab4382d2SGreg Kroah-Hartman irqreturn_t ret; 1525ab4382d2SGreg Kroah-Hartman 1526ab4382d2SGreg Kroah-Hartman spin_lock(&port->lock); 1527ab4382d2SGreg Kroah-Hartman 1528ab4382d2SGreg Kroah-Hartman ret = psc_ops->handle_irq(port); 1529ab4382d2SGreg Kroah-Hartman 1530ab4382d2SGreg Kroah-Hartman spin_unlock(&port->lock); 1531ab4382d2SGreg Kroah-Hartman 1532ab4382d2SGreg Kroah-Hartman return ret; 1533ab4382d2SGreg Kroah-Hartman } 1534ab4382d2SGreg Kroah-Hartman 1535ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1536ab4382d2SGreg Kroah-Hartman /* Console ( if applicable ) */ 1537ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1538ab4382d2SGreg Kroah-Hartman 1539ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_MPC52xx_CONSOLE 1540ab4382d2SGreg Kroah-Hartman 1541ab4382d2SGreg Kroah-Hartman static void __init 1542ab4382d2SGreg Kroah-Hartman mpc52xx_console_get_options(struct uart_port *port, 1543ab4382d2SGreg Kroah-Hartman int *baud, int *parity, int *bits, int *flow) 1544ab4382d2SGreg Kroah-Hartman { 1545ab4382d2SGreg Kroah-Hartman unsigned char mr1; 1546ab4382d2SGreg Kroah-Hartman 1547ab4382d2SGreg Kroah-Hartman pr_debug("mpc52xx_console_get_options(port=%p)\n", port); 1548ab4382d2SGreg Kroah-Hartman 1549ab4382d2SGreg Kroah-Hartman /* Read the mode registers */ 15502574b27eSMatteo Facchinetti mr1 = psc_ops->get_mr1(port); 1551ab4382d2SGreg Kroah-Hartman 1552ab4382d2SGreg Kroah-Hartman /* CT{U,L}R are write-only ! */ 1553ab4382d2SGreg Kroah-Hartman *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; 1554ab4382d2SGreg Kroah-Hartman 1555ab4382d2SGreg Kroah-Hartman /* Parse them */ 1556ab4382d2SGreg Kroah-Hartman switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) { 1557ab4382d2SGreg Kroah-Hartman case MPC52xx_PSC_MODE_5_BITS: 1558ab4382d2SGreg Kroah-Hartman *bits = 5; 1559ab4382d2SGreg Kroah-Hartman break; 1560ab4382d2SGreg Kroah-Hartman case MPC52xx_PSC_MODE_6_BITS: 1561ab4382d2SGreg Kroah-Hartman *bits = 6; 1562ab4382d2SGreg Kroah-Hartman break; 1563ab4382d2SGreg Kroah-Hartman case MPC52xx_PSC_MODE_7_BITS: 1564ab4382d2SGreg Kroah-Hartman *bits = 7; 1565ab4382d2SGreg Kroah-Hartman break; 1566ab4382d2SGreg Kroah-Hartman case MPC52xx_PSC_MODE_8_BITS: 1567ab4382d2SGreg Kroah-Hartman default: 1568ab4382d2SGreg Kroah-Hartman *bits = 8; 1569ab4382d2SGreg Kroah-Hartman } 1570ab4382d2SGreg Kroah-Hartman 1571ab4382d2SGreg Kroah-Hartman if (mr1 & MPC52xx_PSC_MODE_PARNONE) 1572ab4382d2SGreg Kroah-Hartman *parity = 'n'; 1573ab4382d2SGreg Kroah-Hartman else 1574ab4382d2SGreg Kroah-Hartman *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e'; 1575ab4382d2SGreg Kroah-Hartman } 1576ab4382d2SGreg Kroah-Hartman 1577ab4382d2SGreg Kroah-Hartman static void 1578ab4382d2SGreg Kroah-Hartman mpc52xx_console_write(struct console *co, const char *s, unsigned int count) 1579ab4382d2SGreg Kroah-Hartman { 1580ab4382d2SGreg Kroah-Hartman struct uart_port *port = &mpc52xx_uart_ports[co->index]; 1581ab4382d2SGreg Kroah-Hartman unsigned int i, j; 1582ab4382d2SGreg Kroah-Hartman 1583ab4382d2SGreg Kroah-Hartman /* Disable interrupts */ 1584ab4382d2SGreg Kroah-Hartman psc_ops->cw_disable_ints(port); 1585ab4382d2SGreg Kroah-Hartman 1586ab4382d2SGreg Kroah-Hartman /* Wait the TX buffer to be empty */ 1587ab4382d2SGreg Kroah-Hartman j = 5000000; /* Maximum wait */ 1588ab4382d2SGreg Kroah-Hartman while (!mpc52xx_uart_tx_empty(port) && --j) 1589ab4382d2SGreg Kroah-Hartman udelay(1); 1590ab4382d2SGreg Kroah-Hartman 1591ab4382d2SGreg Kroah-Hartman /* Write all the chars */ 1592ab4382d2SGreg Kroah-Hartman for (i = 0; i < count; i++, s++) { 1593ab4382d2SGreg Kroah-Hartman /* Line return handling */ 1594ab4382d2SGreg Kroah-Hartman if (*s == '\n') 1595ab4382d2SGreg Kroah-Hartman psc_ops->write_char(port, '\r'); 1596ab4382d2SGreg Kroah-Hartman 1597ab4382d2SGreg Kroah-Hartman /* Send the char */ 1598ab4382d2SGreg Kroah-Hartman psc_ops->write_char(port, *s); 1599ab4382d2SGreg Kroah-Hartman 1600ab4382d2SGreg Kroah-Hartman /* Wait the TX buffer to be empty */ 1601ab4382d2SGreg Kroah-Hartman j = 20000; /* Maximum wait */ 1602ab4382d2SGreg Kroah-Hartman while (!mpc52xx_uart_tx_empty(port) && --j) 1603ab4382d2SGreg Kroah-Hartman udelay(1); 1604ab4382d2SGreg Kroah-Hartman } 1605ab4382d2SGreg Kroah-Hartman 1606ab4382d2SGreg Kroah-Hartman /* Restore interrupt state */ 1607ab4382d2SGreg Kroah-Hartman psc_ops->cw_restore_ints(port); 1608ab4382d2SGreg Kroah-Hartman } 1609ab4382d2SGreg Kroah-Hartman 1610ab4382d2SGreg Kroah-Hartman 1611ab4382d2SGreg Kroah-Hartman static int __init 1612ab4382d2SGreg Kroah-Hartman mpc52xx_console_setup(struct console *co, char *options) 1613ab4382d2SGreg Kroah-Hartman { 1614ab4382d2SGreg Kroah-Hartman struct uart_port *port = &mpc52xx_uart_ports[co->index]; 1615ab4382d2SGreg Kroah-Hartman struct device_node *np = mpc52xx_uart_nodes[co->index]; 1616ab4382d2SGreg Kroah-Hartman unsigned int uartclk; 1617ab4382d2SGreg Kroah-Hartman struct resource res; 1618ab4382d2SGreg Kroah-Hartman int ret; 1619ab4382d2SGreg Kroah-Hartman 1620ab4382d2SGreg Kroah-Hartman int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; 1621ab4382d2SGreg Kroah-Hartman int bits = 8; 1622ab4382d2SGreg Kroah-Hartman int parity = 'n'; 1623ab4382d2SGreg Kroah-Hartman int flow = 'n'; 1624ab4382d2SGreg Kroah-Hartman 1625ab4382d2SGreg Kroah-Hartman pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n", 1626ab4382d2SGreg Kroah-Hartman co, co->index, options); 1627ab4382d2SGreg Kroah-Hartman 1628ab4382d2SGreg Kroah-Hartman if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) { 1629ab4382d2SGreg Kroah-Hartman pr_debug("PSC%x out of range\n", co->index); 1630ab4382d2SGreg Kroah-Hartman return -EINVAL; 1631ab4382d2SGreg Kroah-Hartman } 1632ab4382d2SGreg Kroah-Hartman 1633ab4382d2SGreg Kroah-Hartman if (!np) { 1634ab4382d2SGreg Kroah-Hartman pr_debug("PSC%x not found in device tree\n", co->index); 1635ab4382d2SGreg Kroah-Hartman return -EINVAL; 1636ab4382d2SGreg Kroah-Hartman } 1637ab4382d2SGreg Kroah-Hartman 1638a73ee843SRob Herring pr_debug("Console on ttyPSC%x is %pOF\n", 1639a73ee843SRob Herring co->index, mpc52xx_uart_nodes[co->index]); 1640ab4382d2SGreg Kroah-Hartman 1641ab4382d2SGreg Kroah-Hartman /* Fetch register locations */ 1642ab4382d2SGreg Kroah-Hartman ret = of_address_to_resource(np, 0, &res); 1643ab4382d2SGreg Kroah-Hartman if (ret) { 1644ab4382d2SGreg Kroah-Hartman pr_debug("Could not get resources for PSC%x\n", co->index); 1645ab4382d2SGreg Kroah-Hartman return ret; 1646ab4382d2SGreg Kroah-Hartman } 1647ab4382d2SGreg Kroah-Hartman 1648ab4382d2SGreg Kroah-Hartman uartclk = mpc5xxx_get_bus_frequency(np); 1649ab4382d2SGreg Kroah-Hartman if (uartclk == 0) { 1650ab4382d2SGreg Kroah-Hartman pr_debug("Could not find uart clock frequency!\n"); 1651ab4382d2SGreg Kroah-Hartman return -EINVAL; 1652ab4382d2SGreg Kroah-Hartman } 1653ab4382d2SGreg Kroah-Hartman 1654ab4382d2SGreg Kroah-Hartman /* Basic port init. Needed since we use some uart_??? func before 1655ab4382d2SGreg Kroah-Hartman * real init for early access */ 1656ab4382d2SGreg Kroah-Hartman spin_lock_init(&port->lock); 1657ab4382d2SGreg Kroah-Hartman port->uartclk = uartclk; 1658ab4382d2SGreg Kroah-Hartman port->ops = &mpc52xx_uart_ops; 1659ab4382d2SGreg Kroah-Hartman port->mapbase = res.start; 1660ab4382d2SGreg Kroah-Hartman port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); 1661ab4382d2SGreg Kroah-Hartman port->irq = irq_of_parse_and_map(np, 0); 1662ab4382d2SGreg Kroah-Hartman 1663ab4382d2SGreg Kroah-Hartman if (port->membase == NULL) 1664ab4382d2SGreg Kroah-Hartman return -EINVAL; 1665ab4382d2SGreg Kroah-Hartman 1666ab4382d2SGreg Kroah-Hartman pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n", 1667ab4382d2SGreg Kroah-Hartman (void *)port->mapbase, port->membase, 1668ab4382d2SGreg Kroah-Hartman port->irq, port->uartclk); 1669ab4382d2SGreg Kroah-Hartman 1670ab4382d2SGreg Kroah-Hartman /* Setup the port parameters accoding to options */ 1671ab4382d2SGreg Kroah-Hartman if (options) 1672ab4382d2SGreg Kroah-Hartman uart_parse_options(options, &baud, &parity, &bits, &flow); 1673ab4382d2SGreg Kroah-Hartman else 1674ab4382d2SGreg Kroah-Hartman mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow); 1675ab4382d2SGreg Kroah-Hartman 1676ab4382d2SGreg Kroah-Hartman pr_debug("Setting console parameters: %i %i%c1 flow=%c\n", 1677ab4382d2SGreg Kroah-Hartman baud, bits, parity, flow); 1678ab4382d2SGreg Kroah-Hartman 1679ab4382d2SGreg Kroah-Hartman return uart_set_options(port, co, baud, parity, bits, flow); 1680ab4382d2SGreg Kroah-Hartman } 1681ab4382d2SGreg Kroah-Hartman 1682ab4382d2SGreg Kroah-Hartman 1683ab4382d2SGreg Kroah-Hartman static struct uart_driver mpc52xx_uart_driver; 1684ab4382d2SGreg Kroah-Hartman 1685ab4382d2SGreg Kroah-Hartman static struct console mpc52xx_console = { 1686ab4382d2SGreg Kroah-Hartman .name = "ttyPSC", 1687ab4382d2SGreg Kroah-Hartman .write = mpc52xx_console_write, 1688ab4382d2SGreg Kroah-Hartman .device = uart_console_device, 1689ab4382d2SGreg Kroah-Hartman .setup = mpc52xx_console_setup, 1690ab4382d2SGreg Kroah-Hartman .flags = CON_PRINTBUFFER, 1691ab4382d2SGreg Kroah-Hartman .index = -1, /* Specified on the cmdline (e.g. console=ttyPSC0) */ 1692ab4382d2SGreg Kroah-Hartman .data = &mpc52xx_uart_driver, 1693ab4382d2SGreg Kroah-Hartman }; 1694ab4382d2SGreg Kroah-Hartman 1695ab4382d2SGreg Kroah-Hartman 1696ab4382d2SGreg Kroah-Hartman static int __init 1697ab4382d2SGreg Kroah-Hartman mpc52xx_console_init(void) 1698ab4382d2SGreg Kroah-Hartman { 1699ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_enumerate(); 1700ab4382d2SGreg Kroah-Hartman register_console(&mpc52xx_console); 1701ab4382d2SGreg Kroah-Hartman return 0; 1702ab4382d2SGreg Kroah-Hartman } 1703ab4382d2SGreg Kroah-Hartman 1704ab4382d2SGreg Kroah-Hartman console_initcall(mpc52xx_console_init); 1705ab4382d2SGreg Kroah-Hartman 1706ab4382d2SGreg Kroah-Hartman #define MPC52xx_PSC_CONSOLE &mpc52xx_console 1707ab4382d2SGreg Kroah-Hartman #else 1708ab4382d2SGreg Kroah-Hartman #define MPC52xx_PSC_CONSOLE NULL 1709ab4382d2SGreg Kroah-Hartman #endif 1710ab4382d2SGreg Kroah-Hartman 1711ab4382d2SGreg Kroah-Hartman 1712ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1713ab4382d2SGreg Kroah-Hartman /* UART Driver */ 1714ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1715ab4382d2SGreg Kroah-Hartman 1716ab4382d2SGreg Kroah-Hartman static struct uart_driver mpc52xx_uart_driver = { 1717ab4382d2SGreg Kroah-Hartman .driver_name = "mpc52xx_psc_uart", 1718ab4382d2SGreg Kroah-Hartman .dev_name = "ttyPSC", 1719ab4382d2SGreg Kroah-Hartman .major = SERIAL_PSC_MAJOR, 1720ab4382d2SGreg Kroah-Hartman .minor = SERIAL_PSC_MINOR, 1721ab4382d2SGreg Kroah-Hartman .nr = MPC52xx_PSC_MAXNUM, 1722ab4382d2SGreg Kroah-Hartman .cons = MPC52xx_PSC_CONSOLE, 1723ab4382d2SGreg Kroah-Hartman }; 1724ab4382d2SGreg Kroah-Hartman 1725ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1726ab4382d2SGreg Kroah-Hartman /* OF Platform Driver */ 1727ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1728ab4382d2SGreg Kroah-Hartman 1729ed0bb232SFabian Frederick static const struct of_device_id mpc52xx_uart_of_match[] = { 1730ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PPC_MPC52xx 1731ab4382d2SGreg Kroah-Hartman { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, }, 1732ab4382d2SGreg Kroah-Hartman { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, 1733ab4382d2SGreg Kroah-Hartman /* binding used by old lite5200 device trees: */ 1734ab4382d2SGreg Kroah-Hartman { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, 1735ab4382d2SGreg Kroah-Hartman /* binding used by efika: */ 1736ab4382d2SGreg Kroah-Hartman { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, }, 1737ab4382d2SGreg Kroah-Hartman #endif 1738ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PPC_MPC512x 1739ab4382d2SGreg Kroah-Hartman { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, }, 17401f48c499SMatteo Facchinetti { .compatible = "fsl,mpc5125-psc-uart", .data = &mpc5125_psc_ops, }, 1741ab4382d2SGreg Kroah-Hartman #endif 1742ab4382d2SGreg Kroah-Hartman {}, 1743ab4382d2SGreg Kroah-Hartman }; 1744ab4382d2SGreg Kroah-Hartman 17459671f099SBill Pemberton static int mpc52xx_uart_of_probe(struct platform_device *op) 1746ab4382d2SGreg Kroah-Hartman { 1747ab4382d2SGreg Kroah-Hartman int idx = -1; 1748ab4382d2SGreg Kroah-Hartman unsigned int uartclk; 1749ab4382d2SGreg Kroah-Hartman struct uart_port *port = NULL; 1750ab4382d2SGreg Kroah-Hartman struct resource res; 1751ab4382d2SGreg Kroah-Hartman int ret; 1752ab4382d2SGreg Kroah-Hartman 1753ab4382d2SGreg Kroah-Hartman /* Check validity & presence */ 1754ab4382d2SGreg Kroah-Hartman for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++) 1755ab4382d2SGreg Kroah-Hartman if (mpc52xx_uart_nodes[idx] == op->dev.of_node) 1756ab4382d2SGreg Kroah-Hartman break; 1757ab4382d2SGreg Kroah-Hartman if (idx >= MPC52xx_PSC_MAXNUM) 1758ab4382d2SGreg Kroah-Hartman return -EINVAL; 1759a73ee843SRob Herring pr_debug("Found %pOF assigned to ttyPSC%x\n", 1760a73ee843SRob Herring mpc52xx_uart_nodes[idx], idx); 1761ab4382d2SGreg Kroah-Hartman 1762ab4382d2SGreg Kroah-Hartman /* set the uart clock to the input clock of the psc, the different 1763ab4382d2SGreg Kroah-Hartman * prescalers are taken into account in the set_baudrate() methods 1764ab4382d2SGreg Kroah-Hartman * of the respective chip */ 1765ab4382d2SGreg Kroah-Hartman uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node); 1766ab4382d2SGreg Kroah-Hartman if (uartclk == 0) { 1767ab4382d2SGreg Kroah-Hartman dev_dbg(&op->dev, "Could not find uart clock frequency!\n"); 1768ab4382d2SGreg Kroah-Hartman return -EINVAL; 1769ab4382d2SGreg Kroah-Hartman } 1770ab4382d2SGreg Kroah-Hartman 1771ab4382d2SGreg Kroah-Hartman /* Init the port structure */ 1772ab4382d2SGreg Kroah-Hartman port = &mpc52xx_uart_ports[idx]; 1773ab4382d2SGreg Kroah-Hartman 1774ab4382d2SGreg Kroah-Hartman spin_lock_init(&port->lock); 1775ab4382d2SGreg Kroah-Hartman port->uartclk = uartclk; 1776ab4382d2SGreg Kroah-Hartman port->fifosize = 512; 1777ab4382d2SGreg Kroah-Hartman port->iotype = UPIO_MEM; 1778ab4382d2SGreg Kroah-Hartman port->flags = UPF_BOOT_AUTOCONF | 1779ab4382d2SGreg Kroah-Hartman (uart_console(port) ? 0 : UPF_IOREMAP); 1780ab4382d2SGreg Kroah-Hartman port->line = idx; 1781ab4382d2SGreg Kroah-Hartman port->ops = &mpc52xx_uart_ops; 1782ab4382d2SGreg Kroah-Hartman port->dev = &op->dev; 1783ab4382d2SGreg Kroah-Hartman 1784ab4382d2SGreg Kroah-Hartman /* Search for IRQ and mapbase */ 1785ab4382d2SGreg Kroah-Hartman ret = of_address_to_resource(op->dev.of_node, 0, &res); 1786ab4382d2SGreg Kroah-Hartman if (ret) 1787ab4382d2SGreg Kroah-Hartman return ret; 1788ab4382d2SGreg Kroah-Hartman 1789ab4382d2SGreg Kroah-Hartman port->mapbase = res.start; 1790ab4382d2SGreg Kroah-Hartman if (!port->mapbase) { 1791ab4382d2SGreg Kroah-Hartman dev_dbg(&op->dev, "Could not allocate resources for PSC\n"); 1792ab4382d2SGreg Kroah-Hartman return -EINVAL; 1793ab4382d2SGreg Kroah-Hartman } 1794ab4382d2SGreg Kroah-Hartman 1795ab4382d2SGreg Kroah-Hartman psc_ops->get_irq(port, op->dev.of_node); 1796d4e33facSAlan Cox if (port->irq == 0) { 1797ab4382d2SGreg Kroah-Hartman dev_dbg(&op->dev, "Could not get irq\n"); 1798ab4382d2SGreg Kroah-Hartman return -EINVAL; 1799ab4382d2SGreg Kroah-Hartman } 1800ab4382d2SGreg Kroah-Hartman 1801ab4382d2SGreg Kroah-Hartman dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n", 1802ab4382d2SGreg Kroah-Hartman (void *)port->mapbase, port->irq, port->uartclk); 1803ab4382d2SGreg Kroah-Hartman 1804ab4382d2SGreg Kroah-Hartman /* Add the port to the uart sub-system */ 1805ab4382d2SGreg Kroah-Hartman ret = uart_add_one_port(&mpc52xx_uart_driver, port); 1806ab4382d2SGreg Kroah-Hartman if (ret) 1807ab4382d2SGreg Kroah-Hartman return ret; 1808ab4382d2SGreg Kroah-Hartman 1809696faeddSJingoo Han platform_set_drvdata(op, (void *)port); 1810ab4382d2SGreg Kroah-Hartman return 0; 1811ab4382d2SGreg Kroah-Hartman } 1812ab4382d2SGreg Kroah-Hartman 1813ab4382d2SGreg Kroah-Hartman static int 1814ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_remove(struct platform_device *op) 1815ab4382d2SGreg Kroah-Hartman { 1816696faeddSJingoo Han struct uart_port *port = platform_get_drvdata(op); 1817ab4382d2SGreg Kroah-Hartman 1818ab4382d2SGreg Kroah-Hartman if (port) 1819ab4382d2SGreg Kroah-Hartman uart_remove_one_port(&mpc52xx_uart_driver, port); 1820ab4382d2SGreg Kroah-Hartman 1821ab4382d2SGreg Kroah-Hartman return 0; 1822ab4382d2SGreg Kroah-Hartman } 1823ab4382d2SGreg Kroah-Hartman 1824ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PM 1825ab4382d2SGreg Kroah-Hartman static int 1826ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) 1827ab4382d2SGreg Kroah-Hartman { 18284190390aSJingoo Han struct uart_port *port = platform_get_drvdata(op); 1829ab4382d2SGreg Kroah-Hartman 1830ab4382d2SGreg Kroah-Hartman if (port) 1831ab4382d2SGreg Kroah-Hartman uart_suspend_port(&mpc52xx_uart_driver, port); 1832ab4382d2SGreg Kroah-Hartman 1833ab4382d2SGreg Kroah-Hartman return 0; 1834ab4382d2SGreg Kroah-Hartman } 1835ab4382d2SGreg Kroah-Hartman 1836ab4382d2SGreg Kroah-Hartman static int 1837ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_resume(struct platform_device *op) 1838ab4382d2SGreg Kroah-Hartman { 18394190390aSJingoo Han struct uart_port *port = platform_get_drvdata(op); 1840ab4382d2SGreg Kroah-Hartman 1841ab4382d2SGreg Kroah-Hartman if (port) 1842ab4382d2SGreg Kroah-Hartman uart_resume_port(&mpc52xx_uart_driver, port); 1843ab4382d2SGreg Kroah-Hartman 1844ab4382d2SGreg Kroah-Hartman return 0; 1845ab4382d2SGreg Kroah-Hartman } 1846ab4382d2SGreg Kroah-Hartman #endif 1847ab4382d2SGreg Kroah-Hartman 1848ab4382d2SGreg Kroah-Hartman static void 1849ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_assign(struct device_node *np) 1850ab4382d2SGreg Kroah-Hartman { 1851ab4382d2SGreg Kroah-Hartman int i; 1852ab4382d2SGreg Kroah-Hartman 1853ab4382d2SGreg Kroah-Hartman /* Find the first free PSC number */ 1854ab4382d2SGreg Kroah-Hartman for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { 1855ab4382d2SGreg Kroah-Hartman if (mpc52xx_uart_nodes[i] == NULL) { 1856ab4382d2SGreg Kroah-Hartman of_node_get(np); 1857ab4382d2SGreg Kroah-Hartman mpc52xx_uart_nodes[i] = np; 1858ab4382d2SGreg Kroah-Hartman return; 1859ab4382d2SGreg Kroah-Hartman } 1860ab4382d2SGreg Kroah-Hartman } 1861ab4382d2SGreg Kroah-Hartman } 1862ab4382d2SGreg Kroah-Hartman 1863ab4382d2SGreg Kroah-Hartman static void 1864ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_enumerate(void) 1865ab4382d2SGreg Kroah-Hartman { 1866ab4382d2SGreg Kroah-Hartman static int enum_done; 1867ab4382d2SGreg Kroah-Hartman struct device_node *np; 1868ab4382d2SGreg Kroah-Hartman const struct of_device_id *match; 1869ab4382d2SGreg Kroah-Hartman int i; 1870ab4382d2SGreg Kroah-Hartman 1871ab4382d2SGreg Kroah-Hartman if (enum_done) 1872ab4382d2SGreg Kroah-Hartman return; 1873ab4382d2SGreg Kroah-Hartman 1874ab4382d2SGreg Kroah-Hartman /* Assign index to each PSC in device tree */ 1875ab4382d2SGreg Kroah-Hartman for_each_matching_node(np, mpc52xx_uart_of_match) { 1876ab4382d2SGreg Kroah-Hartman match = of_match_node(mpc52xx_uart_of_match, np); 1877ab4382d2SGreg Kroah-Hartman psc_ops = match->data; 1878ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_assign(np); 1879ab4382d2SGreg Kroah-Hartman } 1880ab4382d2SGreg Kroah-Hartman 1881ab4382d2SGreg Kroah-Hartman enum_done = 1; 1882ab4382d2SGreg Kroah-Hartman 1883ab4382d2SGreg Kroah-Hartman for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { 1884ab4382d2SGreg Kroah-Hartman if (mpc52xx_uart_nodes[i]) 1885a73ee843SRob Herring pr_debug("%pOF assigned to ttyPSC%x\n", 1886a73ee843SRob Herring mpc52xx_uart_nodes[i], i); 1887ab4382d2SGreg Kroah-Hartman } 1888ab4382d2SGreg Kroah-Hartman } 1889ab4382d2SGreg Kroah-Hartman 1890ab4382d2SGreg Kroah-Hartman MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); 1891ab4382d2SGreg Kroah-Hartman 1892793218dfSGrant Likely static struct platform_driver mpc52xx_uart_of_driver = { 1893ab4382d2SGreg Kroah-Hartman .probe = mpc52xx_uart_of_probe, 1894ab4382d2SGreg Kroah-Hartman .remove = mpc52xx_uart_of_remove, 1895ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PM 1896ab4382d2SGreg Kroah-Hartman .suspend = mpc52xx_uart_of_suspend, 1897ab4382d2SGreg Kroah-Hartman .resume = mpc52xx_uart_of_resume, 1898ab4382d2SGreg Kroah-Hartman #endif 1899ab4382d2SGreg Kroah-Hartman .driver = { 1900ab4382d2SGreg Kroah-Hartman .name = "mpc52xx-psc-uart", 1901ab4382d2SGreg Kroah-Hartman .of_match_table = mpc52xx_uart_of_match, 1902ab4382d2SGreg Kroah-Hartman }, 1903ab4382d2SGreg Kroah-Hartman }; 1904ab4382d2SGreg Kroah-Hartman 1905ab4382d2SGreg Kroah-Hartman 1906ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1907ab4382d2SGreg Kroah-Hartman /* Module */ 1908ab4382d2SGreg Kroah-Hartman /* ======================================================================== */ 1909ab4382d2SGreg Kroah-Hartman 1910ab4382d2SGreg Kroah-Hartman static int __init 1911ab4382d2SGreg Kroah-Hartman mpc52xx_uart_init(void) 1912ab4382d2SGreg Kroah-Hartman { 1913ab4382d2SGreg Kroah-Hartman int ret; 1914ab4382d2SGreg Kroah-Hartman 1915ab4382d2SGreg Kroah-Hartman printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n"); 1916ab4382d2SGreg Kroah-Hartman 1917ab4382d2SGreg Kroah-Hartman ret = uart_register_driver(&mpc52xx_uart_driver); 1918ab4382d2SGreg Kroah-Hartman if (ret) { 1919ab4382d2SGreg Kroah-Hartman printk(KERN_ERR "%s: uart_register_driver failed (%i)\n", 1920ab4382d2SGreg Kroah-Hartman __FILE__, ret); 1921ab4382d2SGreg Kroah-Hartman return ret; 1922ab4382d2SGreg Kroah-Hartman } 1923ab4382d2SGreg Kroah-Hartman 1924ab4382d2SGreg Kroah-Hartman mpc52xx_uart_of_enumerate(); 1925ab4382d2SGreg Kroah-Hartman 1926ab4382d2SGreg Kroah-Hartman /* 1927ab4382d2SGreg Kroah-Hartman * Map the PSC FIFO Controller and init if on MPC512x. 1928ab4382d2SGreg Kroah-Hartman */ 1929ab4382d2SGreg Kroah-Hartman if (psc_ops && psc_ops->fifoc_init) { 1930ab4382d2SGreg Kroah-Hartman ret = psc_ops->fifoc_init(); 1931ab4382d2SGreg Kroah-Hartman if (ret) 19329bcc3278SWei Yongjun goto err_init; 1933ab4382d2SGreg Kroah-Hartman } 1934ab4382d2SGreg Kroah-Hartman 1935793218dfSGrant Likely ret = platform_driver_register(&mpc52xx_uart_of_driver); 1936ab4382d2SGreg Kroah-Hartman if (ret) { 1937793218dfSGrant Likely printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", 1938ab4382d2SGreg Kroah-Hartman __FILE__, ret); 19399bcc3278SWei Yongjun goto err_reg; 1940ab4382d2SGreg Kroah-Hartman } 1941ab4382d2SGreg Kroah-Hartman 1942ab4382d2SGreg Kroah-Hartman return 0; 19439bcc3278SWei Yongjun err_reg: 19449bcc3278SWei Yongjun if (psc_ops && psc_ops->fifoc_uninit) 19459bcc3278SWei Yongjun psc_ops->fifoc_uninit(); 19469bcc3278SWei Yongjun err_init: 19479bcc3278SWei Yongjun uart_unregister_driver(&mpc52xx_uart_driver); 19489bcc3278SWei Yongjun return ret; 1949ab4382d2SGreg Kroah-Hartman } 1950ab4382d2SGreg Kroah-Hartman 1951ab4382d2SGreg Kroah-Hartman static void __exit 1952ab4382d2SGreg Kroah-Hartman mpc52xx_uart_exit(void) 1953ab4382d2SGreg Kroah-Hartman { 1954ab4382d2SGreg Kroah-Hartman if (psc_ops->fifoc_uninit) 1955ab4382d2SGreg Kroah-Hartman psc_ops->fifoc_uninit(); 1956ab4382d2SGreg Kroah-Hartman 1957793218dfSGrant Likely platform_driver_unregister(&mpc52xx_uart_of_driver); 1958ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&mpc52xx_uart_driver); 1959ab4382d2SGreg Kroah-Hartman } 1960ab4382d2SGreg Kroah-Hartman 1961ab4382d2SGreg Kroah-Hartman 1962ab4382d2SGreg Kroah-Hartman module_init(mpc52xx_uart_init); 1963ab4382d2SGreg Kroah-Hartman module_exit(mpc52xx_uart_exit); 1964ab4382d2SGreg Kroah-Hartman 1965ab4382d2SGreg Kroah-Hartman MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>"); 1966ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("Freescale MPC52xx PSC UART"); 1967ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 1968