diff options
Diffstat (limited to 'drivers/tty')
120 files changed, 7478 insertions, 3759 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 978db344bda..b24aa010f68 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -366,7 +366,7 @@ config TRACE_SINK  	  "Trace data router for MIPI P1149.7 cJTAG standard".  config PPC_EPAPR_HV_BYTECHAN -	tristate "ePAPR hypervisor byte channel driver" +	bool "ePAPR hypervisor byte channel driver"  	depends on PPC  	select EPAPR_PARAVIRT  	help diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 2b86f8e0fb5..979e7c3ea2c 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1248,6 +1248,8 @@ static int rs_ioctl(struct tty_struct *tty,  	struct async_icount cprev, cnow;	/* kernel counter temps */  	void __user *argp = (void __user *)arg;  	unsigned long flags; +	DEFINE_WAIT(wait); +	int ret;  	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))  		return -ENODEV; @@ -1288,25 +1290,33 @@ static int rs_ioctl(struct tty_struct *tty,  			cprev = info->icount;  			local_irq_restore(flags);  			while (1) { -				interruptible_sleep_on(&info->tport.delta_msr_wait); -				/* see if a signal did it */ -				if (signal_pending(current)) -					return -ERESTARTSYS; +				prepare_to_wait(&info->tport.delta_msr_wait, +						&wait, TASK_INTERRUPTIBLE);  				local_irq_save(flags);  				cnow = info->icount; /* atomic copy */  				local_irq_restore(flags);  				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&  -				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) -					return -EIO; /* no change => error */ +				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { +					ret = -EIO; /* no change => error */ +					break; +				}  				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||  				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||  				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||  				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { -					return 0; +					ret = 0; +					break; +				} +				schedule(); +				/* see if a signal did it */ +				if (signal_pending(current)) { +					ret = -ERESTARTSYS; +					break;  				}  				cprev = cnow;  			} -			/* NOTREACHED */ +			finish_wait(&info->tport.delta_msr_wait, &wait); +			return ret;  		case TIOCSERGWILD:  		case TIOCSERSWILD: @@ -1855,6 +1865,9 @@ static struct console sercons = {   */  static int __init amiserial_console_init(void)  { +	if (!MACH_IS_AMIGA) +		return -ENODEV; +  	register_console(&sercons);  	return 0;  } diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index a93a424873f..8096fcbe2dc 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -349,7 +349,7 @@ bfin_jc_early_write(struct console *co, const char *buf, unsigned int count)  	bfin_jc_straight_buffer_write(buf, count);  } -static struct __initdata console bfin_jc_early_console = { +static struct console bfin_jc_early_console __initdata = {  	.name   = "early_BFJC",  	.write   = bfin_jc_early_write,  	.flags   = CON_ANYTIME | CON_PRINTBUFFER, diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 33f83fee9fa..a57bb5ab761 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -2709,6 +2709,8 @@ cy_ioctl(struct tty_struct *tty,  		break;  #ifndef CONFIG_CYZ_INTR  	case CYZSETPOLLCYCLE: +		if (arg > LONG_MAX / HZ) +			return -ENODEV;  		cyz_polling_cycle = (arg * HZ) / 1000;  		break;  	case CYZGETPOLLCYCLE: diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 9bffcec5ad8..0419b69e270 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -32,6 +32,7 @@  #include <linux/poll.h>  #include <asm/epapr_hcalls.h>  #include <linux/of.h> +#include <linux/of_irq.h>  #include <linux/platform_device.h>  #include <linux/cdev.h>  #include <linux/console.h> diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index f17d2e4ee2c..09495f515fa 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -14,7 +14,6 @@   */  #include <linux/console.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/platform_device.h>  #include <linux/tty.h> @@ -22,6 +21,7 @@  #include <linux/slab.h>  #include <linux/io.h>  #include <linux/module.h> +#include <linux/goldfish.h>  enum {  	GOLDFISH_TTY_PUT_CHAR       = 0x00, @@ -30,6 +30,7 @@ enum {  	GOLDFISH_TTY_DATA_PTR       = 0x10,  	GOLDFISH_TTY_DATA_LEN       = 0x14, +	GOLDFISH_TTY_DATA_PTR_HIGH  = 0x18,  	GOLDFISH_TTY_CMD_INT_DISABLE    = 0,  	GOLDFISH_TTY_CMD_INT_ENABLE     = 1, @@ -58,7 +59,8 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count)  	struct goldfish_tty *qtty = &goldfish_ttys[line];  	void __iomem *base = qtty->base;  	spin_lock_irqsave(&qtty->lock, irq_flags); -	writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR); +	gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR, +				base + GOLDFISH_TTY_DATA_PTR_HIGH);  	writel(count, base + GOLDFISH_TTY_DATA_LEN);  	writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);  	spin_unlock_irqrestore(&qtty->lock, irq_flags); @@ -74,12 +76,13 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)  	u32 count;  	count = readl(base + GOLDFISH_TTY_BYTES_READY); -	if(count == 0) +	if (count == 0)  		return IRQ_NONE;  	count = tty_prepare_flip_string(&qtty->port, &buf, count);  	spin_lock_irqsave(&qtty->lock, irq_flags); -	writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR); +	gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR, +				base + GOLDFISH_TTY_DATA_PTR_HIGH);  	writel(count, base + GOLDFISH_TTY_DATA_LEN);  	writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);  	spin_unlock_irqrestore(&qtty->lock, irq_flags); @@ -89,24 +92,26 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)  static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty)  { -	struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); +	struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, +									port);  	writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD);  	return 0;  }  static void goldfish_tty_shutdown(struct tty_port *port)  { -	struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); +	struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, +									port);  	writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD);  } -static int goldfish_tty_open(struct tty_struct * tty, struct file * filp) +static int goldfish_tty_open(struct tty_struct *tty, struct file *filp)  {  	struct goldfish_tty *qtty = &goldfish_ttys[tty->index];  	return tty_port_open(&qtty->port, tty, filp);  } -static void goldfish_tty_close(struct tty_struct * tty, struct file * filp) +static void goldfish_tty_close(struct tty_struct *tty, struct file *filp)  {  	tty_port_close(tty->port, tty, filp);  } @@ -116,7 +121,8 @@ static void goldfish_tty_hangup(struct tty_struct *tty)  	tty_port_hangup(tty->port);  } -static int goldfish_tty_write(struct tty_struct * tty, const unsigned char *buf, int count) +static int goldfish_tty_write(struct tty_struct *tty, const unsigned char *buf, +								int count)  {  	goldfish_tty_do_write(tty->index, buf, count);  	return count; @@ -134,12 +140,14 @@ static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)  	return readl(base + GOLDFISH_TTY_BYTES_READY);  } -static void goldfish_tty_console_write(struct console *co, const char *b, unsigned count) +static void goldfish_tty_console_write(struct console *co, const char *b, +								unsigned count)  {  	goldfish_tty_do_write(co->index, b, count);  } -static struct tty_driver *goldfish_tty_console_device(struct console *c, int *index) +static struct tty_driver *goldfish_tty_console_device(struct console *c, +								int *index)  {  	*index = c->index;  	return goldfish_tty_driver; @@ -147,9 +155,9 @@ static struct tty_driver *goldfish_tty_console_device(struct console *c, int *in  static int goldfish_tty_console_setup(struct console *co, char *options)  { -	if((unsigned)co->index > goldfish_tty_line_count) +	if ((unsigned)co->index > goldfish_tty_line_count)  		return -ENODEV; -	if(goldfish_ttys[co->index].base == 0) +	if (goldfish_ttys[co->index].base == 0)  		return -ENODEV;  	return 0;  } @@ -159,7 +167,7 @@ static struct tty_port_operations goldfish_port_ops = {  	.shutdown = goldfish_tty_shutdown  }; -static struct tty_operations goldfish_tty_ops = { +static const struct tty_operations goldfish_tty_ops = {  	.open = goldfish_tty_open,  	.close = goldfish_tty_close,  	.hangup = goldfish_tty_hangup, @@ -173,13 +181,14 @@ static int goldfish_tty_create_driver(void)  	int ret;  	struct tty_driver *tty; -	goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * goldfish_tty_line_count, GFP_KERNEL); -	if(goldfish_ttys == NULL) { +	goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * +				goldfish_tty_line_count, GFP_KERNEL); +	if (goldfish_ttys == NULL) {  		ret = -ENOMEM;  		goto err_alloc_goldfish_ttys_failed;  	}  	tty = alloc_tty_driver(goldfish_tty_line_count); -	if(tty == NULL) { +	if (tty == NULL) {  		ret = -ENOMEM;  		goto err_alloc_tty_driver_failed;  	} @@ -188,10 +197,11 @@ static int goldfish_tty_create_driver(void)  	tty->type = TTY_DRIVER_TYPE_SERIAL;  	tty->subtype = SERIAL_TYPE_NORMAL;  	tty->init_termios = tty_std_termios; -	tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; +	tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | +						TTY_DRIVER_DYNAMIC_DEV;  	tty_set_operations(tty, &goldfish_tty_ops);  	ret = tty_register_driver(tty); -	if(ret) +	if (ret)  		goto err_tty_register_driver_failed;  	goldfish_tty_driver = tty; @@ -226,7 +236,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)  	u32 irq;  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if(r == NULL) +	if (r == NULL)  		return -EINVAL;  	base = ioremap(r->start, 0x1000); @@ -234,18 +244,18 @@ static int goldfish_tty_probe(struct platform_device *pdev)  		pr_err("goldfish_tty: unable to remap base\n");  	r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -	if(r == NULL) +	if (r == NULL)  		goto err_unmap;  	irq = r->start; -	if(pdev->id >= goldfish_tty_line_count) +	if (pdev->id >= goldfish_tty_line_count)  		goto err_unmap;  	mutex_lock(&goldfish_tty_lock); -	if(goldfish_tty_current_line_count == 0) { +	if (goldfish_tty_current_line_count == 0) {  		ret = goldfish_tty_create_driver(); -		if(ret) +		if (ret)  			goto err_create_driver_failed;  	}  	goldfish_tty_current_line_count++; @@ -259,14 +269,15 @@ static int goldfish_tty_probe(struct platform_device *pdev)  	writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD); -	ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", pdev); -	if(ret) +	ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, +						"goldfish_tty", pdev); +	if (ret)  		goto err_request_irq_failed;  	ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,  							pdev->id, &pdev->dev); -	if(IS_ERR(ttydev)) { +	if (IS_ERR(ttydev)) {  		ret = PTR_ERR(ttydev);  		goto err_tty_register_device_failed;  	} @@ -287,7 +298,7 @@ err_tty_register_device_failed:  	free_irq(irq, pdev);  err_request_irq_failed:  	goldfish_tty_current_line_count--; -	if(goldfish_tty_current_line_count == 0) +	if (goldfish_tty_current_line_count == 0)  		goldfish_tty_delete_driver();  err_create_driver_failed:  	mutex_unlock(&goldfish_tty_lock); @@ -309,7 +320,7 @@ static int goldfish_tty_remove(struct platform_device *pdev)  	qtty->base = 0;  	free_irq(qtty->irq, pdev);  	goldfish_tty_current_line_count--; -	if(goldfish_tty_current_line_count == 0) +	if (goldfish_tty_current_line_count == 0)  		goldfish_tty_delete_driver();  	mutex_unlock(&goldfish_tty_lock);  	return 0; diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 9eba119bcdd..4fcec1d793a 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -31,6 +31,7 @@  #include <linux/list.h>  #include <linux/module.h>  #include <linux/major.h> +#include <linux/atomic.h>  #include <linux/sysrq.h>  #include <linux/tty.h>  #include <linux/tty_flip.h> @@ -70,6 +71,9 @@ static struct task_struct *hvc_task;  /* Picks up late kicks after list walk but before schedule() */  static int hvc_kicked; +/* hvc_init is triggered from hvc_alloc, i.e. only when actually used */ +static atomic_t hvc_needs_init __read_mostly = ATOMIC_INIT(-1); +  static int hvc_init(void);  #ifdef CONFIG_MAGIC_SYSRQ @@ -186,7 +190,7 @@ static struct tty_driver *hvc_console_device(struct console *c, int *index)  	return hvc_driver;  } -static int __init hvc_console_setup(struct console *co, char *options) +static int hvc_console_setup(struct console *co, char *options)  {	  	if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)  		return -ENODEV; @@ -756,10 +760,17 @@ static int khvcd(void *unused)  			if (poll_mask == 0)  				schedule();  			else { +				unsigned long j_timeout; +  				if (timeout < MAX_TIMEOUT)  					timeout += (timeout >> 6) + 1; -				msleep_interruptible(timeout); +				/* +				 * We don't use msleep_interruptible otherwise +				 * "kick" will fail to wake us up +				 */ +				j_timeout = msecs_to_jiffies(timeout) + 1; +				schedule_timeout_interruptible(j_timeout);  			}  		}  		__set_current_state(TASK_RUNNING); @@ -788,7 +799,7 @@ static int hvc_tiocmset(struct tty_struct *tty,  }  #ifdef CONFIG_CONSOLE_POLL -int hvc_poll_init(struct tty_driver *driver, int line, char *options) +static int hvc_poll_init(struct tty_driver *driver, int line, char *options)  {  	return 0;  } @@ -851,7 +862,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,  	int i;  	/* We wait until a driver actually comes along */ -	if (!hvc_driver) { +	if (atomic_inc_not_zero(&hvc_needs_init)) {  		int err = hvc_init();  		if (err)  			return ERR_PTR(err); diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c index 44fbebab507..809920d80a6 100644 --- a/drivers/tty/hvc/hvc_dcc.c +++ b/drivers/tty/hvc/hvc_dcc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 and @@ -8,20 +8,11 @@   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA.   */ -#include <linux/console.h> -#include <linux/delay.h> -#include <linux/err.h>  #include <linux/init.h> -#include <linux/moduleparam.h> -#include <linux/types.h> +#include <asm/dcc.h>  #include <asm/processor.h>  #include "hvc_console.h" @@ -30,35 +21,6 @@  #define DCC_STATUS_RX		(1 << 30)  #define DCC_STATUS_TX		(1 << 29) -static inline u32 __dcc_getstatus(void) -{ -	u32 __ret; -	asm volatile("mrc p14, 0, %0, c0, c1, 0	@ read comms ctrl reg" -		: "=r" (__ret) : : "cc"); - -	return __ret; -} - - -static inline char __dcc_getchar(void) -{ -	char __c; - -	asm volatile("mrc p14, 0, %0, c0, c5, 0	@ read comms data reg" -		: "=r" (__c)); -	isb(); - -	return __c; -} - -static inline void __dcc_putchar(char c) -{ -	asm volatile("mcr p14, 0, %0, c0, c5, 0	@ write a char" -		: /* no output register */ -		: "r" (c)); -	isb(); -} -  static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)  {  	int i; @@ -86,6 +48,21 @@ static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)  	return i;  } +static bool hvc_dcc_check(void) +{ +	unsigned long time = jiffies + (HZ / 10); + +	/* Write a test character to check if it is handled */ +	__dcc_putchar('\n'); + +	while (time_is_after_jiffies(time)) { +		if (!(__dcc_getstatus() & DCC_STATUS_TX)) +			return true; +	} + +	return false; +} +  static const struct hv_ops hvc_dcc_get_put_ops = {  	.get_chars = hvc_dcc_get_chars,  	.put_chars = hvc_dcc_put_chars, @@ -93,6 +70,9 @@ static const struct hv_ops hvc_dcc_get_put_ops = {  static int __init hvc_dcc_console_init(void)  { +	if (!hvc_dcc_check()) +		return -ENODEV; +  	hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);  	return 0;  } @@ -100,6 +80,9 @@ console_initcall(hvc_dcc_console_init);  static int __init hvc_dcc_init(void)  { +	if (!hvc_dcc_check()) +		return -ENODEV; +  	hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);  	return 0;  } diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index fd17a9b804b..ea74460f363 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -77,6 +77,7 @@ struct hvc_iucv_private {  	struct list_head	tty_outqueue;	/* outgoing IUCV messages */  	struct list_head	tty_inqueue;	/* incoming IUCV messages */  	struct device		*dev;		/* device structure */ +	u8			info_path[16];	/* IUCV path info (dev attr) */  };  struct iucv_tty_buffer { @@ -126,7 +127,7 @@ static struct iucv_handler hvc_iucv_handler = {   * This function returns the struct hvc_iucv_private instance that corresponds   * to the HVC virtual terminal number specified as parameter @num.   */ -struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) +static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)  {  	if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices))  		return NULL; @@ -772,18 +773,37 @@ static int hvc_iucv_filter_connreq(u8 ipvmid[8])  static	int hvc_iucv_path_pending(struct iucv_path *path,  				  u8 ipvmid[8], u8 ipuser[16])  { -	struct hvc_iucv_private *priv; +	struct hvc_iucv_private *priv, *tmp; +	u8 wildcard[9] = "lnxhvc  "; +	int i, rc, find_unused;  	u8 nuser_data[16];  	u8 vm_user_id[9]; -	int i, rc; +	ASCEBC(wildcard, sizeof(wildcard)); +	find_unused = !memcmp(wildcard, ipuser, 8); + +	/* First, check if the pending path request is managed by this +	 * IUCV handler: +	 * - find a disconnected device if ipuser contains the wildcard +	 * - find the device that matches the terminal ID in ipuser +	 */  	priv = NULL; -	for (i = 0; i < hvc_iucv_devices; i++) -		if (hvc_iucv_table[i] && -		    (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) { -			priv = hvc_iucv_table[i]; +	for (i = 0; i < hvc_iucv_devices; i++) { +		tmp = hvc_iucv_table[i]; +		if (!tmp) +			continue; + +		if (find_unused) { +			spin_lock(&tmp->lock); +			if (tmp->iucv_state == IUCV_DISCONN) +				priv = tmp; +			spin_unlock(&tmp->lock); + +		} else if (!memcmp(tmp->srv_name, ipuser, 8)) +				priv = tmp; +		if (priv)  			break; -		} +	}  	if (!priv)  		return -ENODEV; @@ -826,6 +846,10 @@ static	int hvc_iucv_path_pending(struct iucv_path *path,  	priv->path = path;  	priv->iucv_state = IUCV_CONNECTED; +	/* store path information */ +	memcpy(priv->info_path, ipvmid, 8); +	memcpy(priv->info_path + 8, ipuser + 8, 8); +  	/* flush buffered output data... */  	schedule_delayed_work(&priv->sndbuf_work, 5); @@ -960,6 +984,49 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev)  	return 0;  } +static ssize_t hvc_iucv_dev_termid_show(struct device *dev, +					struct device_attribute *attr, +					char *buf) +{ +	struct hvc_iucv_private *priv = dev_get_drvdata(dev); +	size_t len; + +	len = sizeof(priv->srv_name); +	memcpy(buf, priv->srv_name, len); +	EBCASC(buf, len); +	buf[len++] = '\n'; +	return len; +} + +static ssize_t hvc_iucv_dev_state_show(struct device *dev, +					struct device_attribute *attr, +					char *buf) +{ +	struct hvc_iucv_private *priv = dev_get_drvdata(dev); +	return sprintf(buf, "%u:%u\n", priv->iucv_state, priv->tty_state); +} + +static ssize_t hvc_iucv_dev_peer_show(struct device *dev, +				      struct device_attribute *attr, +				      char *buf) +{ +	struct hvc_iucv_private *priv = dev_get_drvdata(dev); +	char vmid[9], ipuser[9]; + +	memset(vmid, 0, sizeof(vmid)); +	memset(ipuser, 0, sizeof(ipuser)); + +	spin_lock_bh(&priv->lock); +	if (priv->iucv_state == IUCV_CONNECTED) { +		memcpy(vmid, priv->info_path, 8); +		memcpy(ipuser, priv->info_path + 8, 8); +	} +	spin_unlock_bh(&priv->lock); +	EBCASC(ipuser, 8); + +	return sprintf(buf, "%s:%s\n", vmid, ipuser); +} +  /* HVC operations */  static const struct hv_ops hvc_iucv_ops = { @@ -985,6 +1052,25 @@ static struct device_driver hvc_iucv_driver = {  	.pm   = &hvc_iucv_pm_ops,  }; +/* IUCV HVC device attributes */ +static DEVICE_ATTR(termid, 0640, hvc_iucv_dev_termid_show, NULL); +static DEVICE_ATTR(state, 0640, hvc_iucv_dev_state_show, NULL); +static DEVICE_ATTR(peer, 0640, hvc_iucv_dev_peer_show, NULL); +static struct attribute *hvc_iucv_dev_attrs[] = { +	&dev_attr_termid.attr, +	&dev_attr_state.attr, +	&dev_attr_peer.attr, +	NULL, +}; +static struct attribute_group hvc_iucv_dev_attr_group = { +	.attrs = hvc_iucv_dev_attrs, +}; +static const struct attribute_group *hvc_iucv_dev_attr_groups[] = { +	&hvc_iucv_dev_attr_group, +	NULL, +}; + +  /**   * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance   * @id:			hvc_iucv_table index @@ -1046,6 +1132,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)  	priv->dev->bus = &iucv_bus;  	priv->dev->parent = iucv_root;  	priv->dev->driver = &hvc_iucv_driver; +	priv->dev->groups = hvc_iucv_dev_attr_groups;  	priv->dev->release = (void (*)(struct device *)) kfree;  	rc = device_register(priv->dev);  	if (rc) { @@ -1354,8 +1441,7 @@ out_error_memory:  	mempool_destroy(hvc_iucv_mempool);  	kmem_cache_destroy(hvc_iucv_buffer_cache);  out_error: -	if (hvc_iucv_filter) -		kfree(hvc_iucv_filter); +	kfree(hvc_iucv_filter);  	hvc_iucv_devices = 0; /* ensure that we do not provide any device */  	return rc;  } diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index cd69b48f6df..a585079b4b3 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -61,6 +61,7 @@ static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES];  /* For early boot console */  static struct hvc_opal_priv hvc_opal_boot_priv;  static u32 hvc_opal_boot_termno; +static bool hvc_opal_event_registered;  static const struct hv_ops hvc_opal_raw_ops = {  	.get_chars = opal_get_chars, @@ -161,6 +162,18 @@ static const struct hv_ops hvc_opal_hvsi_ops = {  	.tiocmset = hvc_opal_hvsi_tiocmset,  }; +static int hvc_opal_console_event(struct notifier_block *nb, +				  unsigned long events, void *change) +{ +	if (events & OPAL_EVENT_CONSOLE_INPUT) +		hvc_kick(); +	return 0; +} + +static struct notifier_block hvc_opal_console_nb = { +	.notifier_call	= hvc_opal_console_event, +}; +  static int hvc_opal_probe(struct platform_device *dev)  {  	const struct hv_ops *ops; @@ -170,6 +183,7 @@ static int hvc_opal_probe(struct platform_device *dev)  	unsigned int termno, boot = 0;  	const __be32 *reg; +  	if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) {  		proto = HV_PROTOCOL_RAW;  		ops = &hvc_opal_raw_ops; @@ -213,12 +227,18 @@ static int hvc_opal_probe(struct platform_device *dev)  		dev->dev.of_node->full_name,  		boot ? " (boot console)" : ""); -	/* We don't do IRQ yet */ +	/* We don't do IRQ ... */  	hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS);  	if (IS_ERR(hp))  		return PTR_ERR(hp);  	dev_set_drvdata(&dev->dev, hp); +	/* ...  but we use OPAL event to kick the console */ +	if (!hvc_opal_event_registered) { +		opal_notifier_register(&hvc_opal_console_nb); +		hvc_opal_event_registered = true; +	} +  	return 0;  } @@ -255,13 +275,7 @@ static int __init hvc_opal_init(void)  	/* Register as a vio device to receive callbacks */  	return platform_driver_register(&hvc_opal_driver);  } -module_init(hvc_opal_init); - -static void __exit hvc_opal_exit(void) -{ -	platform_driver_unregister(&hvc_opal_driver); -} -module_exit(hvc_opal_exit); +device_initcall(hvc_opal_init);  static void udbg_opal_putc(char c)  { @@ -329,7 +343,7 @@ static void udbg_init_opal_common(void)  void __init hvc_opal_init_early(void)  {  	struct device_node *stdout_node = NULL; -	const u32 *termno; +	const __be32 *termno;  	const char *name = NULL;  	const struct hv_ops *ops;  	u32 index; @@ -371,7 +385,7 @@ void __init hvc_opal_init_early(void)  	if (!stdout_node)  		return;  	termno = of_get_property(stdout_node, "reg", NULL); -	index = termno ? *termno : 0; +	index = termno ? be32_to_cpup(termno) : 0;  	if (index >= MAX_NR_HVC_CONSOLES)  		return;  	hvc_opal_privs[index] = &hvc_opal_boot_priv; diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c index 0069bb86ba4..08c87920b74 100644 --- a/drivers/tty/hvc/hvc_rtas.c +++ b/drivers/tty/hvc/hvc_rtas.c @@ -102,17 +102,7 @@ static int __init hvc_rtas_init(void)  	return 0;  } -module_init(hvc_rtas_init); - -/* This will tear down the tty portion of the driver */ -static void __exit hvc_rtas_exit(void) -{ -	/* Really the fun isn't over until the worker thread breaks down and -	 * the tty cleans up */ -	if (hvc_rtas_dev) -		hvc_remove(hvc_rtas_dev); -} -module_exit(hvc_rtas_exit); +device_initcall(hvc_rtas_init);  /* This will happen prior to module init.  There is no tty at this time? */  static int __init hvc_rtas_console_init(void) diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c index af8cdaa1dcb..df374860037 100644 --- a/drivers/tty/hvc/hvc_tile.c +++ b/drivers/tty/hvc/hvc_tile.c @@ -133,14 +133,14 @@ static int hvc_tile_probe(struct platform_device *pdev)  	int tile_hvc_irq;  	/* Create our IRQ and register it. */ -	tile_hvc_irq = create_irq(); -	if (tile_hvc_irq < 0) +	tile_hvc_irq = irq_alloc_hwirq(-1); +	if (!tile_hvc_irq)  		return -ENXIO;  	tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU);  	hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128);  	if (IS_ERR(hp)) { -		destroy_irq(tile_hvc_irq); +		irq_free_hwirq(tile_hvc_irq);  		return PTR_ERR(hp);  	}  	dev_set_drvdata(&pdev->dev, hp); @@ -155,7 +155,7 @@ static int hvc_tile_remove(struct platform_device *pdev)  	rc = hvc_remove(hp);  	if (rc == 0) -		destroy_irq(hp->data); +		irq_free_hwirq(hp->data);  	return rc;  } @@ -196,7 +196,7 @@ static int __init hvc_tile_init(void)  #ifndef __tilegx__  	struct hvc_struct *hp;  	hp = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128); -	return IS_ERR(hp) ? PTR_ERR(hp) : 0; +	return PTR_ERR_OR_ZERO(hp);  #else  	platform_device_register(&hvc_tile_pdev);  	return platform_driver_register(&hvc_tile_driver); diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c index 72228276fe3..9cf573d06a2 100644 --- a/drivers/tty/hvc/hvc_udbg.c +++ b/drivers/tty/hvc/hvc_udbg.c @@ -80,14 +80,7 @@ static int __init hvc_udbg_init(void)  	return 0;  } -module_init(hvc_udbg_init); - -static void __exit hvc_udbg_exit(void) -{ -	if (hvc_udbg_dev) -		hvc_remove(hvc_udbg_dev); -} -module_exit(hvc_udbg_exit); +device_initcall(hvc_udbg_init);  static int __init hvc_udbg_console_init(void)  { diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index c791b18cdd0..b594abfbf21 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -48,6 +48,7 @@  #include <asm/prom.h>  #include <asm/hvsi.h>  #include <asm/udbg.h> +#include <asm/machdep.h>  #include "hvc_console.h" @@ -457,7 +458,9 @@ void __init hvc_vio_init_early(void)  	if (hvterm_priv0.proto == HV_PROTOCOL_HVSI)  		goto out;  #endif -	add_preferred_console("hvc", 0, NULL); +	/* Check whether the user has requested a different console. */ +	if (!strstr(cmd_line, "console=")) +		add_preferred_console("hvc", 0, NULL);  	hvc_instantiate(0, 0, ops);  out:  	of_node_put(stdout_node); diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index e61c36cbb86..2dc2831840c 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -183,7 +183,7 @@ static int dom0_write_console(uint32_t vtermno, const char *str, int len)  {  	int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);  	if (rc < 0) -		return 0; +		return rc;  	return len;  } @@ -561,18 +561,7 @@ static int __init xen_hvc_init(void)  #endif  	return r;  } - -static void __exit xen_hvc_fini(void) -{ -	struct xencons_info *entry, *next; - -	if (list_empty(&xenconsoles)) -			return; - -	list_for_each_entry_safe(entry, next, &xenconsoles, list) { -		xen_console_remove(entry); -	} -} +device_initcall(xen_hvc_init);  static int xen_cons_init(void)  { @@ -598,10 +587,6 @@ static int xen_cons_init(void)  	hvc_instantiate(HVC_COOKIE, 0, ops);  	return 0;  } - - -module_init(xen_hvc_init); -module_exit(xen_hvc_fini);  console_initcall(xen_cons_init);  #ifdef CONFIG_EARLY_PRINTK @@ -636,12 +621,28 @@ struct console xenboot_console = {  	.name		= "xenboot",  	.write		= xenboot_write_console,  	.flags		= CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME, +	.index		= -1,  };  #endif	/* CONFIG_EARLY_PRINTK */  void xen_raw_console_write(const char *str)  { -	dom0_write_console(0, str, strlen(str)); +	ssize_t len = strlen(str); +	int rc = 0; + +	if (xen_domain()) { +		rc = dom0_write_console(0, str, len); +#ifdef CONFIG_X86 +		if (rc == -ENOSYS && xen_hvm_domain()) +			goto outb_print; + +	} else if (xen_cpuid_base()) { +		int i; +outb_print: +		for (i = 0; i < len; i++) +			outb(str[i], 0xe9); +#endif +	}  }  void xen_raw_printk(const char *fmt, ...) diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index ac2767100df..7ae6c293e51 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -1,5 +1,4 @@  #include <linux/types.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/slab.h>  #include <linux/console.h> @@ -9,7 +8,7 @@  static int hvsi_send_packet(struct hvsi_priv *pv, struct hvsi_header *packet)  { -	packet->seqno = atomic_inc_return(&pv->seqno); +	packet->seqno = cpu_to_be16(atomic_inc_return(&pv->seqno));  	/* Assumes that always succeeds, works in practice */  	return pv->put_chars(pv->termno, (char *)packet, packet->len); @@ -28,7 +27,7 @@ static void hvsi_start_handshake(struct hvsi_priv *pv)  	/* Send version query */  	q.hdr.type = VS_QUERY_PACKET_HEADER;  	q.hdr.len = sizeof(struct hvsi_query); -	q.verb = VSV_SEND_VERSION_NUMBER; +	q.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER);  	hvsi_send_packet(pv, &q.hdr);  } @@ -40,7 +39,7 @@ static int hvsi_send_close(struct hvsi_priv *pv)  	ctrl.hdr.type = VS_CONTROL_PACKET_HEADER;  	ctrl.hdr.len = sizeof(struct hvsi_control); -	ctrl.verb = VSV_CLOSE_PROTOCOL; +	ctrl.verb = cpu_to_be16(VSV_CLOSE_PROTOCOL);  	return hvsi_send_packet(pv, &ctrl.hdr);  } @@ -69,14 +68,14 @@ static void hvsi_got_control(struct hvsi_priv *pv)  {  	struct hvsi_control *pkt = (struct hvsi_control *)pv->inbuf; -	switch (pkt->verb) { +	switch (be16_to_cpu(pkt->verb)) {  	case VSV_CLOSE_PROTOCOL:  		/* We restart the handshaking */  		hvsi_start_handshake(pv);  		break;  	case VSV_MODEM_CTL_UPDATE:  		/* Transition of carrier detect */ -		hvsi_cd_change(pv, pkt->word & HVSI_TSCD); +		hvsi_cd_change(pv, be32_to_cpu(pkt->word) & HVSI_TSCD);  		break;  	}  } @@ -87,7 +86,7 @@ static void hvsi_got_query(struct hvsi_priv *pv)  	struct hvsi_query_response r;  	/* We only handle version queries */ -	if (pkt->verb != VSV_SEND_VERSION_NUMBER) +	if (be16_to_cpu(pkt->verb) != VSV_SEND_VERSION_NUMBER)  		return;  	pr_devel("HVSI@%x: Got version query, sending response...\n", @@ -96,7 +95,7 @@ static void hvsi_got_query(struct hvsi_priv *pv)  	/* Send version response */  	r.hdr.type = VS_QUERY_RESPONSE_PACKET_HEADER;  	r.hdr.len = sizeof(struct hvsi_query_response); -	r.verb = VSV_SEND_VERSION_NUMBER; +	r.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER);  	r.u.version = HVSI_VERSION;  	r.query_seqno = pkt->hdr.seqno;  	hvsi_send_packet(pv, &r.hdr); @@ -112,7 +111,7 @@ static void hvsi_got_response(struct hvsi_priv *pv)  	switch(r->verb) {  	case VSV_SEND_MODEM_CTL_STATUS: -		hvsi_cd_change(pv, r->u.mctrl_word & HVSI_TSCD); +		hvsi_cd_change(pv, be32_to_cpu(r->u.mctrl_word) & HVSI_TSCD);  		pv->mctrl_update = 1;  		break;  	} @@ -265,8 +264,7 @@ int hvsilib_read_mctrl(struct hvsi_priv *pv)  	pv->mctrl_update = 0;  	q.hdr.type = VS_QUERY_PACKET_HEADER;  	q.hdr.len = sizeof(struct hvsi_query); -	q.hdr.seqno = atomic_inc_return(&pv->seqno); -	q.verb = VSV_SEND_MODEM_CTL_STATUS; +	q.verb = cpu_to_be16(VSV_SEND_MODEM_CTL_STATUS);  	rc = hvsi_send_packet(pv, &q.hdr);  	if (rc <= 0) {  		pr_devel("HVSI@%x: Error %d...\n", pv->termno, rc); @@ -304,9 +302,9 @@ int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr)  	ctrl.hdr.type = VS_CONTROL_PACKET_HEADER,  	ctrl.hdr.len = sizeof(struct hvsi_control); -	ctrl.verb = VSV_SET_MODEM_CTL; -	ctrl.mask = HVSI_TSDTR; -	ctrl.word = dtr ? HVSI_TSDTR : 0; +	ctrl.verb = cpu_to_be16(VSV_SET_MODEM_CTL); +	ctrl.mask = cpu_to_be32(HVSI_TSDTR); +	ctrl.word = cpu_to_be32(dtr ? HVSI_TSDTR : 0);  	return hvsi_send_packet(pv, &ctrl.hdr);  } diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 8fd72ff9436..17ee3bf0926 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -15,7 +15,6 @@   *   Copyright (C) 2007 David Sterba   */ -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/mutex.h> @@ -177,9 +176,6 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,  				": %d chars not inserted to flip buffer!\n",  				length - work); -	/* -	 * This may sleep if ->low_latency is set -	 */  	if (work)  		tty_flip_buffer_push(&tty->port);  } diff --git a/drivers/tty/metag_da.c b/drivers/tty/metag_da.c index 0e888621f48..7332e2ca461 100644 --- a/drivers/tty/metag_da.c +++ b/drivers/tty/metag_da.c @@ -495,7 +495,7 @@ static int dashtty_write(struct tty_struct *tty, const unsigned char *buf,  	count = dport->xmit_cnt;  	/* xmit buffer no longer empty? */  	if (count) -		INIT_COMPLETION(dport->xmit_empty); +		reinit_completion(&dport->xmit_empty);  	mutex_unlock(&dport->xmit_lock);  	if (total) { diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c0f76da5530..2ebe47b78a3 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -194,6 +194,7 @@ struct gsm_control {  struct gsm_mux {  	struct tty_struct *tty;		/* The tty our ldisc is bound to */  	spinlock_t lock; +	struct mutex mutex;  	unsigned int num;  	struct kref ref; @@ -1089,6 +1090,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)  {  	unsigned int addr = 0;  	unsigned int modem = 0; +	unsigned int brk = 0;  	struct gsm_dlci *dlci;  	int len = clen;  	u8 *dp = data; @@ -1115,6 +1117,16 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)  		if (len == 0)  			return;  	} +	len--; +	if (len > 0) { +		while (gsm_read_ea(&brk, *dp++) == 0) { +			len--; +			if (len == 0) +				return; +		} +		modem <<= 7; +		modem |= (brk & 0x7f); +	}  	tty = tty_port_tty_get(&dlci->port);  	gsm_process_modem(tty, dlci, modem, clen);  	if (tty) { @@ -1704,11 +1716,8 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)  		gsm_destroy_network(dlci);  		mutex_unlock(&dlci->mutex); -		/* tty_vhangup needs the tty_lock, so unlock and -		   relock after doing the hangup. */ -		tty_unlock(tty);  		tty_vhangup(tty); -		tty_lock(tty); +  		tty_port_tty_set(&dlci->port, NULL);  		tty_kref_put(tty);  	} @@ -2019,7 +2028,7 @@ static void gsm_error(struct gsm_mux *gsm,   *	and then shut down each device hanging up the channels as we go.   */ -void gsm_cleanup_mux(struct gsm_mux *gsm) +static void gsm_cleanup_mux(struct gsm_mux *gsm)  {  	int i;  	struct gsm_dlci *dlci = gsm->dlci[0]; @@ -2054,15 +2063,16 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)  					dlci->state == DLCI_CLOSED);  	}  	/* Free up any link layer users */ +	mutex_lock(&gsm->mutex);  	for (i = 0; i < NUM_DLCI; i++)  		if (gsm->dlci[i])  			gsm_dlci_release(gsm->dlci[i]); +	mutex_unlock(&gsm->mutex);  	/* Now wipe the queues */  	list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)  		kfree(txq);  	INIT_LIST_HEAD(&gsm->tx_list);  } -EXPORT_SYMBOL_GPL(gsm_cleanup_mux);  /**   *	gsm_activate_mux	-	generic GSM setup @@ -2073,7 +2083,7 @@ EXPORT_SYMBOL_GPL(gsm_cleanup_mux);   *	finally kick off connecting to DLCI 0 on the modem.   */ -int gsm_activate_mux(struct gsm_mux *gsm) +static int gsm_activate_mux(struct gsm_mux *gsm)  {  	struct gsm_dlci *dlci;  	int i = 0; @@ -2109,7 +2119,6 @@ int gsm_activate_mux(struct gsm_mux *gsm)  	gsm->dead = 0;		/* Tty opens are now permissible */  	return 0;  } -EXPORT_SYMBOL_GPL(gsm_activate_mux);  /**   *	gsm_free_mux		-	free up a mux @@ -2117,13 +2126,12 @@ EXPORT_SYMBOL_GPL(gsm_activate_mux);   *   *	Dispose of allocated resources for a dead mux   */ -void gsm_free_mux(struct gsm_mux *gsm) +static void gsm_free_mux(struct gsm_mux *gsm)  {  	kfree(gsm->txframe);  	kfree(gsm->buf);  	kfree(gsm);  } -EXPORT_SYMBOL_GPL(gsm_free_mux);  /**   *	gsm_free_muxr		-	free up a mux @@ -2153,7 +2161,7 @@ static inline void mux_put(struct gsm_mux *gsm)   *	Creates a new mux ready for activation.   */ -struct gsm_mux *gsm_alloc_mux(void) +static struct gsm_mux *gsm_alloc_mux(void)  {  	struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);  	if (gsm == NULL) @@ -2170,6 +2178,7 @@ struct gsm_mux *gsm_alloc_mux(void)  		return NULL;  	}  	spin_lock_init(&gsm->lock); +	mutex_init(&gsm->mutex);  	kref_init(&gsm->ref);  	INIT_LIST_HEAD(&gsm->tx_list); @@ -2185,7 +2194,6 @@ struct gsm_mux *gsm_alloc_mux(void)  	return gsm;  } -EXPORT_SYMBOL_GPL(gsm_alloc_mux);  /**   *	gsmld_output		-	write to link @@ -2269,14 +2277,15 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,  	char *f;  	int i;  	char buf[64]; -	char flags; +	char flags = TTY_NORMAL;  	if (debug & 4)  		print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET,  				     cp, count);  	for (i = count, dp = cp, f = fp; i; i--, dp++) { -		flags = *f++; +		if (f) +			flags = *f++;  		switch (flags) {  		case TTY_NORMAL:  			gsm->receive(gsm, *dp); @@ -2711,7 +2720,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,  	return;  } -int gsm_change_mtu(struct net_device *net, int new_mtu) +static int gsm_change_mtu(struct net_device *net, int new_mtu)  {  	struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);  	if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu)) @@ -2909,23 +2918,33 @@ static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)  	This is ok from a locking  	perspective as we don't have to worry about this  	if DLCI0 is lost */ -	if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) +	mutex_lock(&gsm->mutex); +	if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) { +		mutex_unlock(&gsm->mutex);  		return -EL2NSYNC; +	}  	dlci = gsm->dlci[line];  	if (dlci == NULL) {  		alloc = true;  		dlci = gsm_dlci_alloc(gsm, line);  	} -	if (dlci == NULL) +	if (dlci == NULL) { +		mutex_unlock(&gsm->mutex);  		return -ENOMEM; +	}  	ret = tty_port_install(&dlci->port, driver, tty);  	if (ret) {  		if (alloc)  			dlci_put(dlci); +		mutex_unlock(&gsm->mutex);  		return ret;  	} +	dlci_get(dlci); +	dlci_get(gsm->dlci[0]); +	mux_get(gsm);  	tty->driver_data = dlci; +	mutex_unlock(&gsm->mutex);  	return 0;  } @@ -2936,9 +2955,6 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)  	struct tty_port *port = &dlci->port;  	port->count++; -	dlci_get(dlci); -	dlci_get(dlci->gsm->dlci[0]); -	mux_get(dlci->gsm);  	tty_port_tty_set(port, tty);  	dlci->modem_rx = 0; @@ -2965,7 +2981,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)  	mutex_unlock(&dlci->mutex);  	gsm = dlci->gsm;  	if (tty_port_close_start(&dlci->port, tty, filp) == 0) -		goto out; +		return;  	gsm_dlci_begin_close(dlci);  	if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {  		if (C_HUPCL(tty)) @@ -2973,10 +2989,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)  	}  	tty_port_close_end(&dlci->port, tty);  	tty_port_tty_set(&dlci->port, NULL); -out: -	dlci_put(dlci); -	dlci_put(gsm->dlci[0]); -	mux_put(gsm); +	return;  }  static void gsmtty_hangup(struct tty_struct *tty) @@ -3153,6 +3166,16 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)  	return gsmtty_modem_update(dlci, encode);  } +static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty) +{ +	struct gsm_dlci *dlci = tty->driver_data; +	struct gsm_mux *gsm = dlci->gsm; + +	dlci_put(dlci); +	dlci_put(gsm->dlci[0]); +	mux_put(gsm); +	driver->ttys[tty->index] = NULL; +}  /* Virtual ttys for the demux */  static const struct tty_operations gsmtty_ops = { @@ -3172,6 +3195,7 @@ static const struct tty_operations gsmtty_ops = {  	.tiocmget		= gsmtty_tiocmget,  	.tiocmset		= gsmtty_tiocmset,  	.break_ctl		= gsmtty_break_ctl, +	.remove			= gsmtty_remove,  }; diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 1b2db9a3038..644ddb841d9 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -848,13 +848,11 @@ static struct n_hdlc *n_hdlc_alloc(void)  {  	struct n_hdlc_buf *buf;  	int i; -	struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL); +	struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);  	if (!n_hdlc)  		return NULL; -	memset(n_hdlc, 0, sizeof(*n_hdlc)); -  	n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);  	n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);  	n_hdlc_buf_list_init(&n_hdlc->rx_buf_list); @@ -952,8 +950,6 @@ static char hdlc_register_ok[] __initdata =  	KERN_INFO "N_HDLC line discipline registered.\n";  static char hdlc_register_fail[] __initdata =  	KERN_ERR "error registering line discipline: %d\n"; -static char hdlc_init_fail[] __initdata = -	KERN_INFO "N_HDLC: init failure %d\n";  static int __init n_hdlc_init(void)  { @@ -973,8 +969,6 @@ static int __init n_hdlc_init(void)  	else  		printk(hdlc_register_fail, status); -	if (status) -		printk(hdlc_init_fail, status);  	return status;  }	/* end of init_module() */ diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 1e6405070ce..8b157d68a03 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -1244,7 +1244,7 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,  {  	struct r3964_info *pInfo = tty->disc_data;  	const unsigned char *p; -	char *f, flags = 0; +	char *f, flags = TTY_NORMAL;  	int i;  	for (i = count, p = cp, f = fp; i; i--, p++) { diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index c9a9ddd1d0b..f44f1ba762c 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -93,6 +93,7 @@ struct n_tty_data {  	size_t canon_head;  	size_t echo_head;  	size_t echo_commit; +	size_t echo_mark;  	DECLARE_BITMAP(char_map, 256);  	/* private to n_tty_receive_overrun (single-threaded) */ @@ -104,6 +105,7 @@ struct n_tty_data {  	/* must hold exclusive termios_rwsem to reset these */  	unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1; +	unsigned char push:1;  	/* shared by producer and consumer */  	char read_buf[N_TTY_BUF_SIZE]; @@ -274,7 +276,8 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)  			return;  		n_tty_set_room(tty);  		n_tty_write_wakeup(tty->link); -		wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT); +		if (waitqueue_active(&tty->link->write_wait)) +			wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);  		return;  	} @@ -336,10 +339,12 @@ static void reset_buffer_flags(struct n_tty_data *ldata)  {  	ldata->read_head = ldata->canon_head = ldata->read_tail = 0;  	ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; +	ldata->echo_mark = 0;  	ldata->line_start = 0;  	ldata->erasing = 0;  	bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); +	ldata->push = 0;  }  static void n_tty_packet_mode_flush(struct tty_struct *tty) @@ -349,7 +354,8 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)  	spin_lock_irqsave(&tty->ctrl_lock, flags);  	if (tty->link->packet) {  		tty->ctrl_status |= TIOCPKT_FLUSHREAD; -		wake_up_interruptible(&tty->link->read_wait); +		if (waitqueue_active(&tty->link->read_wait)) +			wake_up_interruptible(&tty->link->read_wait);  	}  	spin_unlock_irqrestore(&tty->ctrl_lock, flags);  } @@ -767,8 +773,8 @@ static size_t __process_echoes(struct tty_struct *tty)  	 * of echo overrun before the next commit), then discard enough  	 * data at the tail to prevent a subsequent overrun */  	while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { -		if (echo_buf(ldata, tail == ECHO_OP_START)) { -			if (echo_buf(ldata, tail) == ECHO_OP_ERASE_TAB) +		if (echo_buf(ldata, tail) == ECHO_OP_START) { +			if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB)  				tail += 3;  			else  				tail += 2; @@ -787,6 +793,7 @@ static void commit_echoes(struct tty_struct *tty)  	size_t head;  	head = ldata->echo_head; +	ldata->echo_mark = head;  	old = ldata->echo_commit - ldata->echo_tail;  	/* Process committed echoes if the accumulated # of bytes @@ -810,10 +817,11 @@ static void process_echoes(struct tty_struct *tty)  	struct n_tty_data *ldata = tty->disc_data;  	size_t echoed; -	if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_tail) +	if (ldata->echo_mark == ldata->echo_tail)  		return;  	mutex_lock(&ldata->output_lock); +	ldata->echo_commit = ldata->echo_mark;  	echoed = __process_echoes(tty);  	mutex_unlock(&ldata->output_lock); @@ -821,11 +829,13 @@ static void process_echoes(struct tty_struct *tty)  		tty->ops->flush_chars(tty);  } +/* NB: echo_mark and echo_head should be equivalent here */  static void flush_echoes(struct tty_struct *tty)  {  	struct n_tty_data *ldata = tty->disc_data; -	if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_head) +	if ((!L_ECHO(tty) && !L_ECHONL(tty)) || +	    ldata->echo_commit == ldata->echo_head)  		return;  	mutex_lock(&ldata->output_lock); @@ -1155,7 +1165,8 @@ static void n_tty_receive_break(struct tty_struct *tty)  		put_tty_queue('\0', ldata);  	}  	put_tty_queue('\0', ldata); -	wake_up_interruptible(&tty->read_wait); +	if (waitqueue_active(&tty->read_wait)) +		wake_up_interruptible(&tty->read_wait);  }  /** @@ -1203,17 +1214,19 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)  {  	struct n_tty_data *ldata = tty->disc_data; -	if (I_IGNPAR(tty)) -		return; -	if (I_PARMRK(tty)) { -		put_tty_queue('\377', ldata); -		put_tty_queue('\0', ldata); -		put_tty_queue(c, ldata); -	} else	if (I_INPCK(tty)) -		put_tty_queue('\0', ldata); -	else +	if (I_INPCK(tty)) { +		if (I_IGNPAR(tty)) +			return; +		if (I_PARMRK(tty)) { +			put_tty_queue('\377', ldata); +			put_tty_queue('\0', ldata); +			put_tty_queue(c, ldata); +		} else +			put_tty_queue('\0', ldata); +	} else  		put_tty_queue(c, ldata); -	wake_up_interruptible(&tty->read_wait); +	if (waitqueue_active(&tty->read_wait)) +		wake_up_interruptible(&tty->read_wait);  }  static void @@ -1231,7 +1244,8 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)  	if (L_ECHO(tty)) {  		echo_char(c, tty);  		commit_echoes(tty); -	} +	} else +		process_echoes(tty);  	isig(signal, tty);  	return;  } @@ -1257,12 +1271,11 @@ static int  n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)  {  	struct n_tty_data *ldata = tty->disc_data; -	int parmrk;  	if (I_IXON(tty)) {  		if (c == START_CHAR(tty)) {  			start_tty(tty); -			commit_echoes(tty); +			process_echoes(tty);  			return 0;  		}  		if (c == STOP_CHAR(tty)) { @@ -1342,8 +1355,6 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)  		}  		if ((c == EOL_CHAR(tty)) ||  		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) { -			parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) -				 ? 1 : 0;  			/*  			 * XXX are EOL_CHAR and EOL2_CHAR echoed?!?  			 */ @@ -1358,7 +1369,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)  			 * XXX does PARMRK doubling happen for  			 * EOL_CHAR and EOL2_CHAR?  			 */ -			if (parmrk) +			if (c == (unsigned char) '\377' && I_PARMRK(tty))  				put_tty_queue(c, ldata);  handle_newline: @@ -1372,7 +1383,6 @@ handle_newline:  		}  	} -	parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;  	if (L_ECHO(tty)) {  		finish_erasing(ldata);  		if (c == '\n') @@ -1386,7 +1396,8 @@ handle_newline:  		commit_echoes(tty);  	} -	if (parmrk) +	/* PARMRK doubling check */ +	if (c == (unsigned char) '\377' && I_PARMRK(tty))  		put_tty_queue(c, ldata);  	put_tty_queue(c, ldata); @@ -1397,7 +1408,6 @@ static inline void  n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)  {  	struct n_tty_data *ldata = tty->disc_data; -	int parmrk;  	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {  		start_tty(tty); @@ -1411,13 +1421,13 @@ n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)  		echo_char(c, tty);  		commit_echoes(tty);  	} -	parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0; -	if (parmrk) +	/* PARMRK doubling check */ +	if (c == (unsigned char) '\377' && I_PARMRK(tty))  		put_tty_queue(c, ldata);  	put_tty_queue(c, ldata);  } -static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) +static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)  {  	n_tty_receive_char_inline(tty, c);  } @@ -1442,8 +1452,7 @@ n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)  	put_tty_queue(c, ldata);  } -static inline void -n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) +static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)  {  	if (I_ISTRIP(tty))  		c &= 0x7f; @@ -1674,32 +1683,9 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,  	}  } -static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, -			      char *fp, int count) -{ -	int room, n; - -	down_read(&tty->termios_rwsem); - -	while (1) { -		room = receive_room(tty); -		n = min(count, room); -		if (!n) -			break; -		__receive_buf(tty, cp, fp, n); -		cp += n; -		if (fp) -			fp += n; -		count -= n; -	} - -	tty->receive_room = room; -	n_tty_check_throttle(tty); -	up_read(&tty->termios_rwsem); -} - -static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp, -			      char *fp, int count) +static int +n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp, +			 char *fp, int count, int flow)  {  	struct n_tty_data *ldata = tty->disc_data;  	int room, n, rcvd = 0; @@ -1710,7 +1696,7 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,  		room = receive_room(tty);  		n = min(count, room);  		if (!n) { -			if (!room) +			if (flow && !room)  				ldata->no_room = 1;  			break;  		} @@ -1729,6 +1715,18 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,  	return rcvd;  } +static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, +			      char *fp, int count) +{ +	n_tty_receive_buf_common(tty, cp, fp, count, 0); +} + +static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp, +			      char *fp, int count) +{ +	return n_tty_receive_buf_common(tty, cp, fp, count, 1); +} +  int is_ignored(int sig)  {  	return (sigismember(¤t->blocked, sig) || @@ -1752,21 +1750,23 @@ int is_ignored(int sig)  static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)  {  	struct n_tty_data *ldata = tty->disc_data; -	int canon_change = 1; -	if (old) -		canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON; -	if (canon_change) { +	if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) {  		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); -		ldata->line_start = 0; -		ldata->canon_head = ldata->read_tail; +		ldata->line_start = ldata->read_tail; +		if (!L_ICANON(tty) || !read_cnt(ldata)) { +			ldata->canon_head = ldata->read_tail; +			ldata->push = 0; +		} else { +			set_bit((ldata->read_head - 1) & (N_TTY_BUF_SIZE - 1), +				ldata->read_flags); +			ldata->canon_head = ldata->read_head; +			ldata->push = 1; +		}  		ldata->erasing = 0;  		ldata->lnext = 0;  	} -	if (canon_change && !L_ICANON(tty) && read_cnt(ldata)) -		wake_up_interruptible(&tty->read_wait); -  	ldata->icanon = (L_ICANON(tty) != 0);  	if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || @@ -1823,11 +1823,14 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)  	 */  	if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {  		start_tty(tty); +		process_echoes(tty);  	}  	/* The termios change make the tty ready for I/O */ -	wake_up_interruptible(&tty->write_wait); -	wake_up_interruptible(&tty->read_wait); +	if (waitqueue_active(&tty->write_wait)) +		wake_up_interruptible(&tty->write_wait); +	if (waitqueue_active(&tty->read_wait)) +		wake_up_interruptible(&tty->read_wait);  }  /** @@ -1893,17 +1896,15 @@ err:  	return -ENOMEM;  } -static inline int input_available_p(struct tty_struct *tty, int amt) +static inline int input_available_p(struct tty_struct *tty, int poll)  {  	struct n_tty_data *ldata = tty->disc_data; +	int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1; -	if (ldata->icanon && !L_EXTPROC(tty)) { -		if (ldata->canon_head != ldata->read_tail) -			return 1; -	} else if (read_cnt(ldata) >= (amt ? amt : 1)) -		return 1; - -	return 0; +	if (ldata->icanon && !L_EXTPROC(tty)) +		return ldata->canon_head != ldata->read_tail; +	else +		return read_cnt(ldata) >= amt;  }  /** @@ -1966,6 +1967,12 @@ static int copy_from_read_buf(struct tty_struct *tty,   *	it copies one line of input up to and including the line-delimiting   *	character into the user-space buffer.   * + *	NB: When termios is changed from non-canonical to canonical mode and + *	the read buffer contains data, n_tty_set_termios() simulates an EOF + *	push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer. + *	This causes data already processed as input to be immediately available + *	as input although a newline has not been received. + *   *	Called under the atomic_read_lock mutex   *   *	n_tty_read()/consumer path: @@ -2006,10 +2013,13 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,  		found = 1;  	size = N_TTY_BUF_SIZE - tail; -	n = (found + eol + size) & (N_TTY_BUF_SIZE - 1); +	n = eol - tail; +	if (n > 4096) +		n += 4096; +	n += found;  	c = n; -	if (found && read_buf(ldata, eol) == __DISABLED_CHAR) { +	if (found && !ldata->push && read_buf(ldata, eol) == __DISABLED_CHAR) {  		n--;  		eof_push = !n && ldata->read_tail != ldata->line_start;  	} @@ -2032,11 +2042,14 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,  	if (found)  		clear_bit(eol, ldata->read_flags); -	smp_mb__after_clear_bit(); +	smp_mb__after_atomic();  	ldata->read_tail += c;  	if (found) { -		ldata->line_start = ldata->read_tail; +		if (!ldata->push) +			ldata->line_start = ldata->read_tail; +		else +			ldata->push = 0;  		tty_audit_push(tty);  	}  	return eof_push ? -EAGAIN : 0; @@ -2184,28 +2197,34 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,  		if (!input_available_p(tty, 0)) {  			if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { -				retval = -EIO; -				break; -			} -			if (tty_hung_up_p(file)) -				break; -			if (!timeout) -				break; -			if (file->f_flags & O_NONBLOCK) { -				retval = -EAGAIN; -				break; -			} -			if (signal_pending(current)) { -				retval = -ERESTARTSYS; -				break; -			} -			n_tty_set_room(tty); -			up_read(&tty->termios_rwsem); +				up_read(&tty->termios_rwsem); +				tty_flush_to_ldisc(tty); +				down_read(&tty->termios_rwsem); +				if (!input_available_p(tty, 0)) { +					retval = -EIO; +					break; +				} +			} else { +				if (tty_hung_up_p(file)) +					break; +				if (!timeout) +					break; +				if (file->f_flags & O_NONBLOCK) { +					retval = -EAGAIN; +					break; +				} +				if (signal_pending(current)) { +					retval = -ERESTARTSYS; +					break; +				} +				n_tty_set_room(tty); +				up_read(&tty->termios_rwsem); -			timeout = schedule_timeout(timeout); +				timeout = schedule_timeout(timeout); -			down_read(&tty->termios_rwsem); -			continue; +				down_read(&tty->termios_rwsem); +				continue; +			}  		}  		__set_current_state(TASK_RUNNING); @@ -2245,18 +2264,19 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,  		if (time)  			timeout = time;  	} -	mutex_unlock(&ldata->atomic_read_lock); -	remove_wait_queue(&tty->read_wait, &wait); +	n_tty_set_room(tty); +	up_read(&tty->termios_rwsem); +	remove_wait_queue(&tty->read_wait, &wait);  	if (!waitqueue_active(&tty->read_wait))  		ldata->minimum_to_wake = minimum; +	mutex_unlock(&ldata->atomic_read_lock); +  	__set_current_state(TASK_RUNNING);  	if (b - buf)  		retval = b - buf; -	n_tty_set_room(tty); -	up_read(&tty->termios_rwsem);  	return retval;  } @@ -2334,8 +2354,12 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,  			if (tty->ops->flush_chars)  				tty->ops->flush_chars(tty);  		} else { +			struct n_tty_data *ldata = tty->disc_data; +  			while (nr > 0) { +				mutex_lock(&ldata->output_lock);  				c = tty->ops->write(tty, b, nr); +				mutex_unlock(&ldata->output_lock);  				if (c < 0) {  					retval = c;  					goto break_out; @@ -2389,7 +2413,7 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,  	poll_wait(file, &tty->read_wait, wait);  	poll_wait(file, &tty->write_wait, wait); -	if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty))) +	if (input_available_p(tty, 1))  		mask |= POLLIN | POLLRDNORM;  	if (tty->packet && tty->link->ctrl_status)  		mask |= POLLPRI | POLLIN | POLLRDNORM; diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index d6080c3831e..cd042936955 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -959,7 +959,7 @@ static int receive_flow_control(struct nozomi *dc)  		dev_err(&dc->pdev->dev,  			"ERROR: flow control received for non-existing port\n");  		return 0; -	}; +	}  	DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl),  	   *((u16 *)&ctrl_dl)); @@ -1025,7 +1025,7 @@ static enum ctrl_port_type port2ctrl(enum port_type port,  		dev_err(&dc->pdev->dev,  			"ERROR: send flow control " \  			"received for non-existing port\n"); -	}; +	}  	return CTRL_ERROR;  } @@ -1805,7 +1805,7 @@ static int ntty_ioctl(struct tty_struct *tty,  	default:  		DBG1("ERR: 0x%08X, %d", cmd, cmd);  		break; -	}; +	}  	return rval;  } diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 354564ea47c..383c4c79663 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -1744,7 +1744,7 @@ static void rp_flush_buffer(struct tty_struct *tty)  #ifdef CONFIG_PCI -static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = { +static const struct pci_device_id rocket_pci_ids[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4QUAD) },  	{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA) },  	{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8OCTA) }, diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 570df9d2a5d..7a91c6d1eb7 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -555,7 +555,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)  	 */  	if ((p->port.type == PORT_XR17V35X) ||  	   (p->port.type == PORT_XR17D15X)) { -		serial_out(p, UART_EXAR_SLEEP, 0xff); +		serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0);  		return;  	} @@ -1520,7 +1520,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)  			status = serial8250_rx_chars(up, status);  	}  	serial8250_modem_status(up); -	if (status & UART_LSR_THRE) +	if (!up->dma && (status & UART_LSR_THRE))  		serial8250_tx_chars(up);  	spin_unlock_irqrestore(&port->lock, flags); @@ -1694,6 +1694,10 @@ static int serial_link_irq_chain(struct uart_8250_port *up)  static void serial_unlink_irq_chain(struct uart_8250_port *up)  { +	/* +	 * yes, some broken gcc emit "warning: 'i' may be used uninitialized" +	 * but no, we are not going to take a patch that assigns NULL below. +	 */  	struct irq_info *i;  	struct hlist_node *n;  	struct hlist_head *h; @@ -1922,13 +1926,8 @@ static void serial8250_put_poll_char(struct uart_port *port,  	wait_for_xmitr(up, BOTH_EMPTY);  	/*  	 *	Send the character out. -	 *	If a LF, also do CR...  	 */  	serial_port_out(port, UART_TX, c); -	if (c == 10) { -		wait_for_xmitr(up, BOTH_EMPTY); -		serial_port_out(port, UART_TX, 13); -	}  	/*  	 *	Finally, wait for transmitter to become empty @@ -2322,7 +2321,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,  	if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {  		fcr = uart_config[port->type].fcr; -		if (baud < 2400 || fifo_bug) { +		if ((baud < 2400 && !up->dma) || fifo_bug) {  			fcr &= ~UART_FCR_TRIGGER_MASK;  			fcr |= UART_FCR_TRIGGER_1;  		} @@ -2334,9 +2333,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,  	 * the trigger, or the MCR RTS bit is cleared.  In the case where  	 * the remote UART is not using CTS auto flow control, we must  	 * have sufficient FIFO entries for the latency of the remote -	 * UART to respond.  IOW, at least 32 bytes of FIFO. +	 * UART to respond.  IOW, at least 32 bytes of FIFO. Also enable +	 * AFE if hw flow control is supported  	 */ -	if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { +	if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) || +	    (port->flags & UPF_HARD_FLOW)) {  		up->mcr &= ~UART_MCR_AFE;  		if (termios->c_cflag & CRTSCTS)  			up->mcr |= UART_MCR_AFE; @@ -2356,7 +2357,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,  	port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= UART_LSR_BI;  	/* @@ -2433,6 +2434,24 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,  	serial_dl_write(up, quot);  	/* +	 * XR17V35x UARTs have an extra fractional divisor register (DLD) +	 * +	 * We need to recalculate all of the registers, because DLM and DLL +	 * are already rounded to a whole integer. +	 * +	 * When recalculating we use a 32x clock instead of a 16x clock to +	 * allow 1-bit for rounding in the fractional part. +	 */ +	if (up->port.type == PORT_XR17V35X) { +		unsigned int baud_x32 = (port->uartclk * 2) / baud; +		u16 quot = baud_x32 / 32; +		u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2); + +		serial_dl_write(up, quot); +		serial_port_out(port, 0x2, quot_frac & 0xf); +	} + +	/*  	 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR  	 * is written without DLAB set, this mode will be disabled.  	 */ @@ -2670,6 +2689,10 @@ static void serial8250_config_port(struct uart_port *port, int flags)  	if (port->type == PORT_16550A && port->iotype == UPIO_AU)  		up->bugs |= UART_BUG_NOMSR; +	/* HW bugs may trigger IRQ while IIR == NO_INT */ +	if (port->type == PORT_TEGRA) +		up->bugs |= UART_BUG_NOMSR; +  	if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)  		autoconfig_irq(up); @@ -2860,14 +2883,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)  	touch_nmi_watchdog(); -	local_irq_save(flags); -	if (port->sysrq) { -		/* serial8250_handle_irq() already took the lock */ -		locked = 0; -	} else if (oops_in_progress) { -		locked = spin_trylock(&port->lock); -	} else -		spin_lock(&port->lock); +	if (port->sysrq || oops_in_progress) +		locked = spin_trylock_irqsave(&port->lock, flags); +	else +		spin_lock_irqsave(&port->lock, flags);  	/*  	 *	First save the IER then disable the interrupts @@ -2899,8 +2918,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)  		serial8250_modem_status(up);  	if (locked) -		spin_unlock(&port->lock); -	local_irq_restore(flags); +		spin_unlock_irqrestore(&port->lock, flags);  }  static int __init serial8250_console_setup(struct console *co, char *options) diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 7046769608d..148ffe4c232 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -20,12 +20,15 @@ static void __dma_tx_complete(void *param)  	struct uart_8250_port	*p = param;  	struct uart_8250_dma	*dma = p->dma;  	struct circ_buf		*xmit = &p->port.state->xmit; - -	dma->tx_running = 0; +	unsigned long	flags;  	dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,  				UART_XMIT_SIZE, DMA_TO_DEVICE); +	spin_lock_irqsave(&p->port.lock, flags); + +	dma->tx_running = 0; +  	xmit->tail += dma->tx_size;  	xmit->tail &= UART_XMIT_SIZE - 1;  	p->port.icount.tx += dma->tx_size; @@ -35,6 +38,8 @@ static void __dma_tx_complete(void *param)  	if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port))  		serial8250_tx_dma(p); + +	spin_unlock_irqrestore(&p->port.lock, flags);  }  static void __dma_rx_complete(void *param) @@ -187,21 +192,28 @@ int serial8250_request_dma(struct uart_8250_port *p)  	dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,  					&dma->rx_addr, GFP_KERNEL); -	if (!dma->rx_buf) { -		dma_release_channel(dma->rxchan); -		dma_release_channel(dma->txchan); -		return -ENOMEM; -	} +	if (!dma->rx_buf) +		goto err;  	/* TX buffer */  	dma->tx_addr = dma_map_single(dma->txchan->device->dev,  					p->port.state->xmit.buf,  					UART_XMIT_SIZE,  					DMA_TO_DEVICE); +	if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) { +		dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, +				  dma->rx_buf, dma->rx_addr); +		goto err; +	}  	dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");  	return 0; +err: +	dma_release_channel(dma->rxchan); +	dma_release_channel(dma->txchan); + +	return -ENOMEM;  }  EXPORT_SYMBOL_GPL(serial8250_request_dma); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index daf710f5c3f..51b307aab75 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -14,7 +14,6 @@   * raised, the LCR needs to be rewritten and the uart status register read.   */  #include <linux/device.h> -#include <linux/init.h>  #include <linux/io.h>  #include <linux/module.h>  #include <linux/serial_8250.h> @@ -56,13 +55,77 @@  struct dw8250_data { -	int		last_lcr; -	int		last_mcr; -	int		line; -	struct clk	*clk; -	u8		usr_reg; +	u8			usr_reg; +	int			last_mcr; +	int			line; +	struct clk		*clk; +	struct uart_8250_dma	dma;  }; +struct dw8250_acpi_desc { +	void (*set_termios)(struct uart_port *p, struct ktermios *termios, +			    struct ktermios *old); +}; + +#define BYT_PRV_CLK			0x800 +#define BYT_PRV_CLK_EN			(1 << 0) +#define BYT_PRV_CLK_M_VAL_SHIFT		1 +#define BYT_PRV_CLK_N_VAL_SHIFT		16 +#define BYT_PRV_CLK_UPDATE		(1 << 31) + +static void byt_set_termios(struct uart_port *p, struct ktermios *termios, +			    struct ktermios *old) +{ +	unsigned int baud = tty_termios_baud_rate(termios); +	unsigned int m, n; +	u32 reg; + +	/* +	* For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the +	* dividers must be adjusted. +	* +	* uartclk = (m / n) * 100 MHz, where m <= n +	*/ +	switch (baud) { +	case 500000: +	case 1000000: +	case 2000000: +	case 4000000: +		m = 64; +		n = 100; +		p->uartclk = 64000000; +		break; +	case 3500000: +		m = 56; +		n = 100; +		p->uartclk = 56000000; +		break; +	case 1500000: +	case 3000000: +		m = 48; +		n = 100; +		p->uartclk = 48000000; +		break; +	case 2500000: +		m = 40; +		n = 100; +		p->uartclk = 40000000; +		break; +	default: +		m = 2304; +		n = 3125; +		p->uartclk = 73728000; +	} + +	/* Reset the clock */ +	reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); +	writel(reg, p->membase + BYT_PRV_CLK); +	reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; +	writel(reg, p->membase + BYT_PRV_CLK); + +	serial8250_do_set_termios(p, termios, old); +} +  static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)  {  	struct dw8250_data *d = p->private_data; @@ -76,17 +139,34 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)  	return value;  } +static void dw8250_force_idle(struct uart_port *p) +{ +	serial8250_clear_and_reinit_fifos(container_of +					  (p, struct uart_8250_port, port)); +	(void)p->serial_in(p, UART_RX); +} +  static void dw8250_serial_out(struct uart_port *p, int offset, int value)  {  	struct dw8250_data *d = p->private_data; -	if (offset == UART_LCR) -		d->last_lcr = value; -  	if (offset == UART_MCR)  		d->last_mcr = value;  	writeb(value, p->membase + (offset << p->regshift)); + +	/* Make sure LCR write wasn't ignored */ +	if (offset == UART_LCR) { +		int tries = 1000; +		while (tries--) { +			unsigned int lcr = p->serial_in(p, UART_LCR); +			if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) +				return; +			dw8250_force_idle(p); +			writeb(value, p->membase + (UART_LCR << p->regshift)); +		} +		dev_err(p->dev, "Couldn't set LCR to %d\n", value); +	}  }  static unsigned int dw8250_serial_in(struct uart_port *p, int offset) @@ -107,13 +187,23 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)  {  	struct dw8250_data *d = p->private_data; -	if (offset == UART_LCR) -		d->last_lcr = value; -  	if (offset == UART_MCR)  		d->last_mcr = value;  	writel(value, p->membase + (offset << p->regshift)); + +	/* Make sure LCR write wasn't ignored */ +	if (offset == UART_LCR) { +		int tries = 1000; +		while (tries--) { +			unsigned int lcr = p->serial_in(p, UART_LCR); +			if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) +				return; +			dw8250_force_idle(p); +			writel(value, p->membase + (UART_LCR << p->regshift)); +		} +		dev_err(p->dev, "Couldn't set LCR to %d\n", value); +	}  }  static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) @@ -131,9 +221,8 @@ static int dw8250_handle_irq(struct uart_port *p)  	if (serial8250_handle_irq(p, iir)) {  		return 1;  	} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { -		/* Clear the USR and write the LCR again. */ +		/* Clear the USR */  		(void)p->serial_in(p, d->usr_reg); -		p->serial_out(p, UART_LCR, d->last_lcr);  		return 1;  	} @@ -153,6 +242,14 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)  		pm_runtime_put_sync_suspend(port->dev);  } +static bool dw8250_dma_filter(struct dma_chan *chan, void *param) +{ +	struct dw8250_data *data = param; + +	return chan->chan_id == data->dma.tx_chan_id || +	       chan->chan_id == data->dma.rx_chan_id; +} +  static void dw8250_setup_port(struct uart_8250_port *up)  {  	struct uart_port	*p = &up->port; @@ -240,11 +337,12 @@ static int dw8250_probe_of(struct uart_port *p,  	return 0;  } -#ifdef CONFIG_ACPI -static int dw8250_probe_acpi(struct uart_8250_port *up) +static int dw8250_probe_acpi(struct uart_8250_port *up, +			     struct dw8250_data *data)  {  	const struct acpi_device_id *id;  	struct uart_port *p = &up->port; +	struct dw8250_acpi_desc *acpi_desc;  	dw8250_setup_port(up); @@ -257,24 +355,20 @@ static int dw8250_probe_acpi(struct uart_8250_port *up)  	p->serial_out = dw8250_serial_out32;  	p->regshift = 2; -	if (!p->uartclk) -		p->uartclk = (unsigned int)id->driver_data; - -	up->dma = devm_kzalloc(p->dev, sizeof(*up->dma), GFP_KERNEL); -	if (!up->dma) -		return -ENOMEM; +	up->dma = &data->dma;  	up->dma->rxconf.src_maxburst = p->fifosize / 4;  	up->dma->txconf.dst_maxburst = p->fifosize / 4; +	acpi_desc = (struct dw8250_acpi_desc *)id->driver_data; +	if (!acpi_desc) +		return 0; + +	if (acpi_desc->set_termios) +		p->set_termios = acpi_desc->set_termios; +  	return 0;  } -#else -static inline int dw8250_probe_acpi(struct uart_8250_port *up) -{ -	return -ENODEV; -} -#endif /* CONFIG_ACPI */  static int dw8250_probe(struct platform_device *pdev)  { @@ -314,6 +408,12 @@ static int dw8250_probe(struct platform_device *pdev)  		uart.port.uartclk = clk_get_rate(data->clk);  	} +	data->dma.rx_chan_id = -1; +	data->dma.tx_chan_id = -1; +	data->dma.rx_param = data; +	data->dma.tx_param = data; +	data->dma.fn = dw8250_dma_filter; +  	uart.port.iotype = UPIO_MEM;  	uart.port.serial_in = dw8250_serial_in;  	uart.port.serial_out = dw8250_serial_out; @@ -324,7 +424,7 @@ static int dw8250_probe(struct platform_device *pdev)  		if (err)  			return err;  	} else if (ACPI_HANDLE(&pdev->dev)) { -		err = dw8250_probe_acpi(&uart); +		err = dw8250_probe_acpi(&uart, data);  		if (err)  			return err;  	} else { @@ -360,7 +460,7 @@ static int dw8250_remove(struct platform_device *pdev)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int dw8250_suspend(struct device *dev)  {  	struct dw8250_data *data = dev_get_drvdata(dev); @@ -378,7 +478,7 @@ static int dw8250_resume(struct device *dev)  	return 0;  } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  #ifdef CONFIG_PM_RUNTIME  static int dw8250_runtime_suspend(struct device *dev) @@ -414,10 +514,16 @@ static const struct of_device_id dw8250_of_match[] = {  };  MODULE_DEVICE_TABLE(of, dw8250_of_match); +static struct dw8250_acpi_desc byt_8250_desc = { +	.set_termios = byt_set_termios, +}; +  static const struct acpi_device_id dw8250_acpi_match[] = {  	{ "INT33C4", 0 },  	{ "INT33C5", 0 }, -	{ "80860F0A", 0 }, +	{ "INT3434", 0 }, +	{ "INT3435", 0 }, +	{ "80860F0A", (kernel_ulong_t)&byt_8250_desc},  	{ },  };  MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index c100d6343d5..4858b8a99d3 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -35,18 +35,8 @@  #include <linux/serial_8250.h>  #include <asm/io.h>  #include <asm/serial.h> -#ifdef CONFIG_FIX_EARLYCON_MEM -#include <asm/pgtable.h> -#include <asm/fixmap.h> -#endif -struct early_serial8250_device { -	struct uart_port port; -	char options[16];		/* e.g., 115200n8 */ -	unsigned int baud; -}; - -static struct early_serial8250_device early_device; +static struct earlycon_device *early_device;  unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset)  { @@ -100,7 +90,7 @@ static void __init serial_putc(struct uart_port *port, int c)  static void __init early_serial8250_write(struct console *console,  					const char *s, unsigned int count)  { -	struct uart_port *port = &early_device.port; +	struct uart_port *port = &early_device->port;  	unsigned int ier;  	/* Save the IER and disable interrupts */ @@ -129,7 +119,7 @@ static unsigned int __init probe_baud(struct uart_port *port)  	return (port->uartclk / 16) / quot;  } -static void __init init_port(struct early_serial8250_device *device) +static void __init init_port(struct earlycon_device *device)  {  	struct uart_port *port = &device->port;  	unsigned int divisor; @@ -148,128 +138,45 @@ static void __init init_port(struct early_serial8250_device *device)  	serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);  } -static int __init parse_options(struct early_serial8250_device *device, -								char *options) +static int __init early_serial8250_setup(struct earlycon_device *device, +					 const char *options)  { -	struct uart_port *port = &device->port; -	int mmio, mmio32, length; - -	if (!options) -		return -ENODEV; - -	port->uartclk = BASE_BAUD * 16; - -	mmio = !strncmp(options, "mmio,", 5); -	mmio32 = !strncmp(options, "mmio32,", 7); -	if (mmio || mmio32) { -		port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); -		port->mapbase = simple_strtoul(options + (mmio ? 5 : 7), -					       &options, 0); -		if (mmio32) -			port->regshift = 2; -#ifdef CONFIG_FIX_EARLYCON_MEM -		set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, -					port->mapbase & PAGE_MASK); -		port->membase = -			(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); -		port->membase += port->mapbase & ~PAGE_MASK; -#else -		port->membase = ioremap_nocache(port->mapbase, 64); -		if (!port->membase) { -			printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n", -				__func__, -			       (unsigned long long) port->mapbase); -			return -ENOMEM; -		} -#endif -	} else if (!strncmp(options, "io,", 3)) { -		port->iotype = UPIO_PORT; -		port->iobase = simple_strtoul(options + 3, &options, 0); -		mmio = 0; -	} else -		return -EINVAL; +	if (!(device->port.membase || device->port.iobase)) +		return 0; -	options = strchr(options, ','); -	if (options) { -		options++; -		device->baud = simple_strtoul(options, NULL, 0); -		length = min(strcspn(options, " ") + 1, -			     (size_t)(sizeof(device->options))); -		strlcpy(device->options, options, length); -	} else { -		device->baud = probe_baud(port); +	if (!device->baud) { +		device->baud = probe_baud(&device->port);  		snprintf(device->options, sizeof(device->options), "%u", -			device->baud); +			 device->baud);  	} -	if (mmio || mmio32) -		printk(KERN_INFO -		       "Early serial console at MMIO%s 0x%llx (options '%s')\n", -			mmio32 ? "32" : "", -			(unsigned long long)port->mapbase, -			device->options); -	else -		printk(KERN_INFO -		      "Early serial console at I/O port 0x%lx (options '%s')\n", -			port->iobase, -			device->options); - -	return 0; -} - -static struct console early_serial8250_console __initdata = { -	.name	= "uart", -	.write	= early_serial8250_write, -	.flags	= CON_PRINTBUFFER | CON_BOOT, -	.index	= -1, -}; - -static int __init early_serial8250_setup(char *options) -{ -	struct early_serial8250_device *device = &early_device; -	int err; - -	if (device->port.membase || device->port.iobase) -		return 0; - -	err = parse_options(device, options); -	if (err < 0) -		return err; -  	init_port(device); + +	early_device = device; +	device->con->write = early_serial8250_write;  	return 0;  } +EARLYCON_DECLARE(uart8250, early_serial8250_setup); +EARLYCON_DECLARE(uart, early_serial8250_setup);  int __init setup_early_serial8250_console(char *cmdline)  { -	char *options; -	int err; +	char match[] = "uart8250"; -	options = strstr(cmdline, "uart8250,"); -	if (!options) { -		options = strstr(cmdline, "uart,"); -		if (!options) -			return 0; -	} - -	options = strchr(cmdline, ',') + 1; -	err = early_serial8250_setup(options); -	if (err < 0) -		return err; - -	register_console(&early_serial8250_console); +	if (cmdline && cmdline[4] == ',') +		match[4] = '\0'; -	return 0; +	return setup_earlycon(cmdline, match, early_serial8250_setup);  }  int serial8250_find_port_for_earlycon(void)  { -	struct early_serial8250_device *device = &early_device; -	struct uart_port *port = &device->port; +	struct earlycon_device *device = early_device; +	struct uart_port *port = device ? &device->port : NULL;  	int line;  	int ret; -	if (!device->port.membase && !device->port.iobase) +	if (!port || (!port->membase && !port->iobase))  		return -ENODEV;  	line = serial8250_find_port(port); @@ -284,5 +191,3 @@ int serial8250_find_port_for_earlycon(void)  	return ret;  } - -early_param("earlycon", setup_early_serial8250_console); diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index 5f3bba12c15..56c87232b6a 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -18,7 +18,6 @@   */  #include <linux/device.h> -#include <linux/init.h>  #include <linux/io.h>  #include <linux/module.h>  #include <linux/serial_8250.h> @@ -122,7 +121,7 @@ static int serial8250_em_probe(struct platform_device *pdev)  	up.port.dev = &pdev->dev;  	up.port.private_data = priv; -	clk_enable(priv->sclk); +	clk_prepare_enable(priv->sclk);  	up.port.uartclk = clk_get_rate(priv->sclk);  	up.port.iotype = UPIO_MEM32; @@ -134,7 +133,7 @@ static int serial8250_em_probe(struct platform_device *pdev)  	ret = serial8250_register_8250_port(&up);  	if (ret < 0) {  		dev_err(&pdev->dev, "unable to register 8250 port\n"); -		clk_disable(priv->sclk); +		clk_disable_unprepare(priv->sclk);  		return ret;  	} @@ -148,7 +147,7 @@ static int serial8250_em_remove(struct platform_device *pdev)  	struct serial8250_em_priv *priv = platform_get_drvdata(pdev);  	serial8250_unregister_port(priv->line); -	clk_disable(priv->sclk); +	clk_disable_unprepare(priv->sclk);  	return 0;  } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index c810da7c7a8..33137b3ba94 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -9,8 +9,8 @@   * it under the terms of the GNU General Public License as published by   * the Free Software Foundation; either version 2 of the License.   */ +#undef DEBUG  #include <linux/module.h> -#include <linux/init.h>  #include <linux/pci.h>  #include <linux/string.h>  #include <linux/kernel.h> @@ -27,8 +27,6 @@  #include "8250.h" -#undef SERIAL_DEBUG_PCI -  /*   * init function returns:   *  > 0 - number of ports @@ -63,7 +61,7 @@ static int pci_default_setup(struct serial_private*,  static void moan_device(const char *str, struct pci_dev *dev)  { -	printk(KERN_WARNING +	dev_err(&dev->dev,  	       "%s: %s\n"  	       "Please send the output of lspci -vv, this\n"  	       "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" @@ -233,7 +231,7 @@ static int pci_inteli960ni_init(struct pci_dev *dev)  	/* is firmware started? */  	pci_read_config_dword(dev, 0x44, (void *)&oldval);  	if (oldval == 0x00001000L) { /* RESET value */ -		printk(KERN_DEBUG "Local i960 firmware missing"); +		dev_dbg(&dev->dev, "Local i960 firmware missing\n");  		return -ENODEV;  	}  	return 0; @@ -785,7 +783,8 @@ static int pci_netmos_9900_setup(struct serial_private *priv,  {  	unsigned int bar; -	if ((priv->dev->subsystem_device & 0xff00) == 0x3000) { +	if ((priv->dev->device != PCI_DEVICE_ID_NETMOS_9865) && +	    (priv->dev->subsystem_device & 0xff00) == 0x3000) {  		/* netmos apparently orders BARs by datasheet layout, so serial  		 * ports get BARs 0 and 3 (or 1 and 4 for memmapped)  		 */ @@ -827,7 +826,7 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)  		if (sub_serports > 0) {  			return sub_serports;  		} else { -			printk(KERN_NOTICE "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); +			dev_err(&dev->dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");  			return 0;  		}  	} @@ -931,7 +930,7 @@ static int pci_ite887x_init(struct pci_dev *dev)  	}  	if (!inta_addr[i]) { -		printk(KERN_ERR "ite887x: could not find iobase\n"); +		dev_err(&dev->dev, "ite887x: could not find iobase\n");  		return -ENODEV;  	} @@ -1024,9 +1023,9 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev)  	/* Tornado device */  	if (deviceID == 0x07000200) {  		number_uarts = ioread8(p + 4); -		printk(KERN_DEBUG +		dev_dbg(&dev->dev,  			"%d ports detected on Oxford PCI Express device\n", -								number_uarts); +			number_uarts);  	}  	pci_iounmap(dev, p);  	return number_uarts; @@ -1260,10 +1259,10 @@ static int pci_quatech_init(struct pci_dev *dev)  		unsigned long base = pci_resource_start(dev, 0);  		if (base) {  			u32 tmp; -			outl(inl(base + 0x38), base + 0x38); +			outl(inl(base + 0x38) | 0x00002000, base + 0x38);  			tmp = inl(base + 0x3c);  			outl(tmp | 0x01000000, base + 0x3c); -			outl(tmp, base + 0x3c); +			outl(tmp &= ~0x01000000, base + 0x3c);  		}  	}  	return 0; @@ -1308,6 +1307,29 @@ static int pci_default_setup(struct serial_private *priv,  	return setup_port(priv, port, bar, offset, board->reg_shift);  } +static int pci_pericom_setup(struct serial_private *priv, +		  const struct pciserial_board *board, +		  struct uart_8250_port *port, int idx) +{ +	unsigned int bar, offset = board->first_offset, maxnr; + +	bar = FL_GET_BASE(board->flags); +	if (board->flags & FL_BASE_BARS) +		bar += idx; +	else +		offset += idx * board->uart_offset; + +	maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> +		(board->reg_shift + 3); + +	if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) +		return 1; + +	port->port.uartclk = 14745600; + +	return setup_port(priv, port, bar, offset, board->reg_shift); +} +  static int  ce4100_serial_setup(struct serial_private *priv,  		  const struct pciserial_board *board, @@ -1324,6 +1346,141 @@ ce4100_serial_setup(struct serial_private *priv,  	return ret;  } +#define PCI_DEVICE_ID_INTEL_BYT_UART1	0x0f0a +#define PCI_DEVICE_ID_INTEL_BYT_UART2	0x0f0c + +#define BYT_PRV_CLK			0x800 +#define BYT_PRV_CLK_EN			(1 << 0) +#define BYT_PRV_CLK_M_VAL_SHIFT		1 +#define BYT_PRV_CLK_N_VAL_SHIFT		16 +#define BYT_PRV_CLK_UPDATE		(1 << 31) + +#define BYT_GENERAL_REG			0x808 +#define BYT_GENERAL_DIS_RTS_N_OVERRIDE	(1 << 3) + +#define BYT_TX_OVF_INT			0x820 +#define BYT_TX_OVF_INT_MASK		(1 << 1) + +static void +byt_set_termios(struct uart_port *p, struct ktermios *termios, +		struct ktermios *old) +{ +	unsigned int baud = tty_termios_baud_rate(termios); +	unsigned int m, n; +	u32 reg; + +	/* +	 * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the +	 * dividers must be adjusted. +	 * +	 * uartclk = (m / n) * 100 MHz, where m <= n +	 */ +	switch (baud) { +	case 500000: +	case 1000000: +	case 2000000: +	case 4000000: +		m = 64; +		n = 100; +		p->uartclk = 64000000; +		break; +	case 3500000: +		m = 56; +		n = 100; +		p->uartclk = 56000000; +		break; +	case 1500000: +	case 3000000: +		m = 48; +		n = 100; +		p->uartclk = 48000000; +		break; +	case 2500000: +		m = 40; +		n = 100; +		p->uartclk = 40000000; +		break; +	default: +		m = 2304; +		n = 3125; +		p->uartclk = 73728000; +	} + +	/* Reset the clock */ +	reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); +	writel(reg, p->membase + BYT_PRV_CLK); +	reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; +	writel(reg, p->membase + BYT_PRV_CLK); + +	/* +	 * If auto-handshake mechanism is not enabled, +	 * disable rts_n override +	 */ +	reg = readl(p->membase + BYT_GENERAL_REG); +	reg &= ~BYT_GENERAL_DIS_RTS_N_OVERRIDE; +	if (termios->c_cflag & CRTSCTS) +		reg |= BYT_GENERAL_DIS_RTS_N_OVERRIDE; +	writel(reg, p->membase + BYT_GENERAL_REG); + +	serial8250_do_set_termios(p, termios, old); +} + +static bool byt_dma_filter(struct dma_chan *chan, void *param) +{ +	return chan->chan_id == *(int *)param; +} + +static int +byt_serial_setup(struct serial_private *priv, +		 const struct pciserial_board *board, +		 struct uart_8250_port *port, int idx) +{ +	struct uart_8250_dma *dma; +	int ret; + +	dma = devm_kzalloc(port->port.dev, sizeof(*dma), GFP_KERNEL); +	if (!dma) +		return -ENOMEM; + +	switch (priv->dev->device) { +	case PCI_DEVICE_ID_INTEL_BYT_UART1: +		dma->rx_chan_id = 3; +		dma->tx_chan_id = 2; +		break; +	case PCI_DEVICE_ID_INTEL_BYT_UART2: +		dma->rx_chan_id = 5; +		dma->tx_chan_id = 4; +		break; +	default: +		return -EINVAL; +	} + +	dma->rxconf.slave_id = dma->rx_chan_id; +	dma->rxconf.src_maxburst = 16; + +	dma->txconf.slave_id = dma->tx_chan_id; +	dma->txconf.dst_maxburst = 16; + +	dma->fn = byt_dma_filter; +	dma->rx_param = &dma->rx_chan_id; +	dma->tx_param = &dma->tx_chan_id; + +	ret = pci_default_setup(priv, board, port, idx); +	port->port.iotype = UPIO_MEM; +	port->port.type = PORT_16550A; +	port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); +	port->port.set_termios = byt_set_termios; +	port->port.fifosize = 64; +	port->tx_loadsz = 64; +	port->dma = dma; +	port->capabilities = UART_CAP_FIFO | UART_CAP_AFE; + +	/* Disable Tx counter interrupts */ +	writel(BYT_TX_OVF_INT_MASK, port->port.membase + BYT_TX_OVF_INT); + +	return ret; +} +  static int  pci_omegapci_setup(struct serial_private *priv,  		      const struct pciserial_board *board, @@ -1344,17 +1501,80 @@ pci_brcm_trumanage_setup(struct serial_private *priv,  	return ret;  } +static int pci_fintek_setup(struct serial_private *priv, +			    const struct pciserial_board *board, +			    struct uart_8250_port *port, int idx) +{ +	struct pci_dev *pdev = priv->dev; +	unsigned long base; +	unsigned long iobase; +	unsigned long ciobase = 0; +	u8 config_base; + +	/* +	 * We are supposed to be able to read these from the PCI config space, +	 * but the values there don't seem to match what we need to use, so +	 * just use these hard-coded values for now, as they are correct. +	 */ +	switch (idx) { +	case 0: iobase = 0xe000; config_base = 0x40; break; +	case 1: iobase = 0xe008; config_base = 0x48; break; +	case 2: iobase = 0xe010; config_base = 0x50; break; +	case 3: iobase = 0xe018; config_base = 0x58; break; +	case 4: iobase = 0xe020; config_base = 0x60; break; +	case 5: iobase = 0xe028; config_base = 0x68; break; +	case 6: iobase = 0xe030; config_base = 0x70; break; +	case 7: iobase = 0xe038; config_base = 0x78; break; +	case 8: iobase = 0xe040; config_base = 0x80; break; +	case 9: iobase = 0xe048; config_base = 0x88; break; +	case 10: iobase = 0xe050; config_base = 0x90; break; +	case 11: iobase = 0xe058; config_base = 0x98; break; +	default: +		/* Unknown number of ports, get out of here */ +		return -EINVAL; +	} + +	if (idx < 4) { +		base = pci_resource_start(priv->dev, 3); +		ciobase = (int)(base + (0x8 * idx)); +	} + +	dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n", +		__func__, idx, iobase, ciobase, config_base); + +	/* Enable UART I/O port */ +	pci_write_config_byte(pdev, config_base + 0x00, 0x01); + +	/* Select 128-byte FIFO and 8x FIFO threshold */ +	pci_write_config_byte(pdev, config_base + 0x01, 0x33); + +	/* LSB UART */ +	pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff)); + +	/* MSB UART */ +	pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8)); + +	/* irq number, this usually fails, but the spec says to do it anyway. */ +	pci_write_config_byte(pdev, config_base + 0x06, pdev->irq); + +	port->port.iotype = UPIO_PORT; +	port->port.iobase = iobase; +	port->port.mapbase = 0; +	port->port.membase = NULL; +	port->port.regshift = 0; + +	return 0; +} +  static int skip_tx_en_setup(struct serial_private *priv,  			const struct pciserial_board *board,  			struct uart_8250_port *port, int idx)  {  	port->port.flags |= UPF_NO_TXEN_TEST; -	printk(KERN_DEBUG "serial8250: skipping TxEn test for device " -			  "[%04x:%04x] subsystem [%04x:%04x]\n", -			  priv->dev->vendor, -			  priv->dev->device, -			  priv->dev->subsystem_vendor, -			  priv->dev->subsystem_device); +	dev_dbg(&priv->dev->dev, +		"serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n", +		priv->dev->vendor, priv->dev->device, +		priv->dev->subsystem_vendor, priv->dev->subsystem_device);  	return pci_default_setup(priv, board, port, idx);  } @@ -1533,6 +1753,8 @@ pci_wch_ch353_setup(struct serial_private *priv,  #define PCI_VENDOR_ID_ADVANTECH		0x13fe  #define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66  #define PCI_DEVICE_ID_ADVANTECH_PCI3620	0x3620 +#define PCI_DEVICE_ID_ADVANTECH_PCI3618	0x3618 +#define PCI_DEVICE_ID_ADVANTECH_PCIf618	0xf618  #define PCI_DEVICE_ID_TITAN_200I	0x8028  #define PCI_DEVICE_ID_TITAN_400I	0x8048  #define PCI_DEVICE_ID_TITAN_800I	0x8088 @@ -1545,6 +1767,7 @@ pci_wch_ch353_setup(struct serial_private *priv,  #define PCI_DEVICE_ID_TITAN_800E	0xA014  #define PCI_DEVICE_ID_TITAN_200EI	0xA016  #define PCI_DEVICE_ID_TITAN_200EISI	0xA017 +#define PCI_DEVICE_ID_TITAN_200V3	0xA306  #define PCI_DEVICE_ID_TITAN_400V3	0xA310  #define PCI_DEVICE_ID_TITAN_410V3	0xA312  #define PCI_DEVICE_ID_TITAN_800V3	0xA314 @@ -1557,6 +1780,7 @@ pci_wch_ch353_setup(struct serial_private *priv,  #define PCI_DEVICE_ID_WCH_CH352_2S	0x3253  #define PCI_DEVICE_ID_WCH_CH353_4S	0x3453  #define PCI_DEVICE_ID_WCH_CH353_2S1PF	0x5046 +#define PCI_DEVICE_ID_WCH_CH353_1S1P	0x5053  #define PCI_DEVICE_ID_WCH_CH353_2S1P	0x7053  #define PCI_VENDOR_ID_AGESTAR		0x5372  #define PCI_DEVICE_ID_AGESTAR_9375	0x6872 @@ -1662,6 +1886,20 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {  		.subdevice	= PCI_ANY_ID,  		.setup		= kt_serial_setup,  	}, +	{ +		.vendor		= PCI_VENDOR_ID_INTEL, +		.device		= PCI_DEVICE_ID_INTEL_BYT_UART1, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID, +		.setup		= byt_serial_setup, +	}, +	{ +		.vendor		= PCI_VENDOR_ID_INTEL, +		.device		= PCI_DEVICE_ID_INTEL_BYT_UART2, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID, +		.setup		= byt_serial_setup, +	},  	/*  	 * ITE  	 */ @@ -1826,6 +2064,31 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {  		.exit		= pci_plx9050_exit,  	},  	/* +	 * Pericom +	 */ +	{ +		.vendor		= 0x12d8, +		.device		= 0x7952, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID, +		.setup		= pci_pericom_setup, +	}, +	{ +		.vendor		= 0x12d8, +		.device		= 0x7954, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID, +		.setup		= pci_pericom_setup, +	}, +	{ +		.vendor		= 0x12d8, +		.device		= 0x7958, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID, +		.setup		= pci_pericom_setup, +	}, + +	/*  	 * PLX  	 */  	{ @@ -2150,6 +2413,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {  		.subdevice	= PCI_ANY_ID,  		.setup		= pci_omegapci_setup,  	}, +	/* WCH CH353 1S1P card (16550 clone) */ +	{ +		.vendor         = PCI_VENDOR_ID_WCH, +		.device         = PCI_DEVICE_ID_WCH_CH353_1S1P, +		.subvendor      = PCI_ANY_ID, +		.subdevice      = PCI_ANY_ID, +		.setup          = pci_wch_ch353_setup, +	},  	/* WCH CH353 2S1P card (16550 clone) */  	{  		.vendor         = PCI_VENDOR_ID_WCH, @@ -2255,6 +2526,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {  		.subdevice	= PCI_ANY_ID,  		.setup		= pci_brcm_trumanage_setup,  	}, +	{ +		.vendor		= 0x1c29, +		.device		= 0x1104, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID, +		.setup		= pci_fintek_setup, +	}, +	{ +		.vendor		= 0x1c29, +		.device		= 0x1108, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID, +		.setup		= pci_fintek_setup, +	}, +	{ +		.vendor		= 0x1c29, +		.device		= 0x1112, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID, +		.setup		= pci_fintek_setup, +	},  	/*  	 * Default "match everything" terminator entry @@ -2449,9 +2741,13 @@ enum pci_board_num_t {  	pbn_ADDIDATA_PCIe_4_3906250,  	pbn_ADDIDATA_PCIe_8_3906250,  	pbn_ce4100_1_115200, +	pbn_byt,  	pbn_omegapci,  	pbn_NETMOS9900_2s_115200,  	pbn_brcm_trumanage, +	pbn_fintek_4, +	pbn_fintek_8, +	pbn_fintek_12,  };  /* @@ -3185,6 +3481,17 @@ static struct pciserial_board pci_boards[] = {  		.base_baud	= 921600,  		.reg_shift      = 2,  	}, +	/* +	 * Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on, +	 * but is overridden by byt_set_termios. +	 */ +	[pbn_byt] = { +		.flags		= FL_BASE0, +		.num_ports	= 1, +		.base_baud	= 2764800, +		.uart_offset	= 0x80, +		.reg_shift      = 2, +	},  	[pbn_omegapci] = {  		.flags		= FL_BASE0,  		.num_ports	= 8, @@ -3202,6 +3509,24 @@ static struct pciserial_board pci_boards[] = {  		.reg_shift	= 2,  		.base_baud	= 115200,  	}, +	[pbn_fintek_4] = { +		.num_ports	= 4, +		.uart_offset	= 8, +		.base_baud	= 115200, +		.first_offset	= 0x40, +	}, +	[pbn_fintek_8] = { +		.num_ports	= 8, +		.uart_offset	= 8, +		.base_baud	= 115200, +		.first_offset	= 0x40, +	}, +	[pbn_fintek_12] = { +		.num_ports	= 12, +		.uart_offset	= 8, +		.base_baud	= 115200, +		.first_offset	= 0x40, +	},  };  static const struct pci_device_id blacklist[] = { @@ -3212,6 +3537,7 @@ static const struct pci_device_id blacklist[] = {  	/* multi-io cards handled by parport_serial */  	{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ +	{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */  };  /* @@ -3362,14 +3688,15 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)  		if (quirk->setup(priv, board, &uart, i))  			break; -#ifdef SERIAL_DEBUG_PCI -		printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n", -		       uart.port.iobase, uart.port.irq, uart.port.iotype); -#endif +		dev_dbg(&dev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", +			uart.port.iobase, uart.port.irq, uart.port.iotype);  		priv->line[i] = serial8250_register_8250_port(&uart);  		if (priv->line[i] < 0) { -			printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); +			dev_err(&dev->dev, +				"Couldn't register serial port %lx, irq %d, type %d, error %d\n", +				uart.port.iobase, uart.port.irq, +				uart.port.iotype, priv->line[i]);  			break;  		}  	} @@ -3462,7 +3789,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)  	}  	if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { -		printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", +		dev_err(&dev->dev, "invalid driver_data: %ld\n",  			ent->driver_data);  		return -EINVAL;  	} @@ -3520,8 +3847,6 @@ static void pciserial_remove_one(struct pci_dev *dev)  {  	struct serial_private *priv = pci_get_drvdata(dev); -	pci_set_drvdata(dev, NULL); -  	pciserial_remove_ports(priv);  	pci_disable_device(dev); @@ -3555,7 +3880,7 @@ static int pciserial_resume_one(struct pci_dev *dev)  		err = pci_enable_device(dev);  		/* FIXME: We cannot simply error out here */  		if (err) -			printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); +			dev_err(&dev->dev, "Unable to re-enable ports, trying to continue.\n");  		pciserial_resume_ports(priv);  	}  	return 0; @@ -3567,6 +3892,13 @@ static struct pci_device_id serial_pci_tbl[] = {  	{	PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,  		PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,  		pbn_b2_8_921600 }, +	/* Advantech also use 0x3618 and 0xf618 */ +	{	PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618, +		PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0, +		pbn_b0_4_921600 }, +	{	PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618, +		PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0, +		pbn_b0_4_921600 },  	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,  		PCI_SUBVENDOR_ID_CONNECT_TECH,  		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, @@ -4140,6 +4472,9 @@ static struct pci_device_id serial_pci_tbl[] = {  	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,  		PCI_ANY_ID, PCI_ANY_ID, 0, 0,  		pbn_oxsemi_2_4000000 }, +	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3, +		PCI_ANY_ID, PCI_ANY_ID, 0, 0, +		pbn_b0_bt_2_921600 },  	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3,  		PCI_ANY_ID, PCI_ANY_ID, 0, 0,  		pbn_b0_4_921600 }, @@ -4848,6 +5183,15 @@ static struct pci_device_id serial_pci_tbl[] = {  	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,  		PCI_ANY_ID,  PCI_ANY_ID, 0, 0,  		pbn_ce4100_1_115200 }, +	/* Intel BayTrail */ +	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART1, +		PCI_ANY_ID,  PCI_ANY_ID, +		PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, +		pbn_byt }, +	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART2, +		PCI_ANY_ID,  PCI_ANY_ID, +		PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, +		pbn_byt },  	/*  	 * Cronyx Omega PCI @@ -4918,6 +5262,11 @@ static struct pci_device_id serial_pci_tbl[] = {  		0,  		0, pbn_exar_XR17V358 }, +	/* Fintek PCI serial cards */ +	{ PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, +	{ PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, +	{ PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, +  	/*  	 * These entries match devices with class COMMUNICATION_SERIAL,  	 * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index 35d9ab95c5c..682a2fbe5c0 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -12,7 +12,6 @@   * the Free Software Foundation; either version 2 of the License.   */  #include <linux/module.h> -#include <linux/init.h>  #include <linux/pci.h>  #include <linux/pnp.h>  #include <linux/string.h> diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index f3b306efaa5..349ee598b34 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -41,7 +41,7 @@ config SERIAL_8250_DEPRECATED_OPTIONS  	  accept kernel parameters in both forms like 8250_core.nr_uarts=4 and  	  8250.nr_uarts=4. We now renamed the module back to 8250, but if  	  anybody noticed in 3.7 and changed their userspace we still have to -	  keep the 8350_core.* options around until they revert the changes +	  keep the 8250_core.* options around until they revert the changes  	  they already did.  	  If 8250 is built as a module, this adds 8250_core alias instead.  @@ -61,6 +61,7 @@ config SERIAL_8250_CONSOLE  	bool "Console on 8250/16550 and compatible serial port"  	depends on SERIAL_8250=y  	select SERIAL_CORE_CONSOLE +	select SERIAL_EARLYCON  	---help---  	  If you say Y here, it will be possible to use a serial port as the  	  system console (the system console is the device which receives all @@ -90,11 +91,6 @@ config SERIAL_8250_CONSOLE  	  If unsure, say N. -config FIX_EARLYCON_MEM -	bool -	depends on X86 -	default y -  config SERIAL_8250_GSC  	tristate  	depends on SERIAL_8250 && GSC diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 1b74b88e1e1..4d180c9423e 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -34,7 +34,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/ptrace.h>  #include <linux/slab.h>  #include <linux/string.h> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index febd45cd502..fb57159bad3 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -7,6 +7,13 @@ if TTY  menu "Serial drivers"  	depends on HAS_IOMEM +config SERIAL_EARLYCON +	bool +	help +	  Support for early consoles with the earlycon parameter. This enables +	  the console before standard serial driver is probed. The console is +	  enabled when early_param is processed. +  source "drivers/tty/serial/8250/Kconfig"  comment "Non-8250 serial port support" @@ -53,6 +60,7 @@ config SERIAL_AMBA_PL011_CONSOLE  	bool "Support for console on AMBA serial port"  	depends on SERIAL_AMBA_PL011=y  	select SERIAL_CORE_CONSOLE +	select SERIAL_EARLYCON  	---help---  	  Say Y here if you wish to use an AMBA PrimeCell UART as the system  	  console (the system console is the device which receives all kernel @@ -65,6 +73,18 @@ config SERIAL_AMBA_PL011_CONSOLE  	  your boot loader (lilo or loadlin) about how to pass options to the  	  kernel at boot time.) +config SERIAL_EARLYCON_ARM_SEMIHOST +	bool "Early console using ARM semihosting" +	depends on ARM64 || ARM +	select SERIAL_CORE +	select SERIAL_CORE_CONSOLE +	select SERIAL_EARLYCON +	help +	  Support for early debug console using ARM semihosting. This enables +	  the console before standard serial driver is probed. This is enabled +	  with "earlycon=smh" on the kernel command line. The console is +	  enabled when early_param is processed. +  config SERIAL_SB1250_DUART  	tristate "BCM1xxx on-chip DUART serial support"  	depends on SIBYTE_SB1xxx_SOC=y @@ -97,6 +117,7 @@ config SERIAL_ATMEL  	bool "AT91 / AT32 on-chip serial port support"  	depends on ARCH_AT91 || AVR32  	select SERIAL_CORE +	select SERIAL_MCTRL_GPIO  	help  	  This enables the driver for the on-chip UARTs of the Atmel  	  AT91 and AT32 processors. @@ -181,9 +202,8 @@ config SERIAL_KS8695_CONSOLE  config SERIAL_CLPS711X  	tristate "CLPS711X serial port support" -	depends on ARCH_CLPS711X +	depends on ARCH_CLPS711X || COMPILE_TEST  	select SERIAL_CORE -	default y  	help  	  This enables the driver for the on-chip UARTs of the Cirrus  	  Logic EP711x/EP721x/EP731x processors. @@ -290,7 +310,7 @@ config SERIAL_MAX3100  	  MAX3100 chip support  config SERIAL_MAX310X -	bool "MAX310X support" +	tristate "MAX310X support"  	depends on SPI_MASTER  	select SERIAL_CORE  	select REGMAP_SPI if SPI_MASTER @@ -709,7 +729,7 @@ config SERIAL_IP22_ZILOG_CONSOLE  config SERIAL_SH_SCI  	tristate "SuperH SCI(F) serial port support" -	depends on HAVE_CLK && (SUPERH || ARCH_SHMOBILE) +	depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST  	select SERIAL_CORE  config SERIAL_SH_SCI_NR_UARTS @@ -1025,7 +1045,7 @@ config SERIAL_SGI_IOC3  config SERIAL_MSM  	bool "MSM on-chip serial port support" -	depends on ARCH_MSM +	depends on ARCH_MSM || ARCH_QCOM  	select SERIAL_CORE  config SERIAL_MSM_CONSOLE @@ -1035,7 +1055,7 @@ config SERIAL_MSM_CONSOLE  config SERIAL_MSM_HS  	tristate "MSM UART High Speed: Serial Driver" -	depends on ARCH_MSM +	depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50  	select SERIAL_CORE  	help  	  If you have a machine based on MSM family of SoCs, you @@ -1146,31 +1166,13 @@ config SERIAL_QE  	  This driver supports the QE serial ports on Freescale embedded  	  PowerPC that contain a QUICC Engine. -config SERIAL_SC26XX -	tristate "SC2681/SC2692 serial port support" -	depends on SNI_RM -	select SERIAL_CORE -	help -	  This is a driver for the onboard serial ports of -	  older RM400 machines. - -config SERIAL_SC26XX_CONSOLE -	bool "Console on SC2681/SC2692 serial port" -	depends on SERIAL_SC26XX=y -	select SERIAL_CORE_CONSOLE -	help -	  Support for Console on SC2681/SC2692 serial ports. -  config SERIAL_SCCNXP  	tristate "SCCNXP serial port support" -	depends on !SERIAL_SC26XX  	select SERIAL_CORE -	default n  	help  	  This selects support for an advanced UART from NXP (Philips).  	  Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92,  	  SC28L202, SCC68681 and SCC68692. -	  Positioned as a replacement for the driver SC26XX.  config SERIAL_SCCNXP_CONSOLE  	bool "Console on SCCNXP serial port" @@ -1179,6 +1181,16 @@ config SERIAL_SCCNXP_CONSOLE  	help  	  Support for console on SCCNXP serial ports. +config SERIAL_SC16IS7XX +	tristate "SC16IS7xx serial support" +	depends on I2C +	select SERIAL_CORE +	select REGMAP_I2C if I2C +	help +	  This selects support for SC16IS7xx serial ports. +	  Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752, +	  SC16IS760 and SC16IS762. +  config SERIAL_BFIN_SPORT  	tristate "Blackfin SPORT emulate UART"  	depends on BLACKFIN @@ -1245,6 +1257,7 @@ config SERIAL_BFIN_SPORT3_UART_CTSRTS  config SERIAL_TIMBERDALE  	tristate "Support for timberdale UART"  	select SERIAL_CORE +	depends on X86_32 || COMPILE_TEST  	---help---  	Add support for UART controller on timberdale. @@ -1341,7 +1354,7 @@ config SERIAL_IFX6X60  config SERIAL_PCH_UART  	tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" -	depends on PCI +	depends on PCI && (X86_32 || COMPILE_TEST)  	select SERIAL_CORE  	help  	  This driver is for PCH(Platform controller Hub) UART of Intel EG20T @@ -1387,18 +1400,19 @@ config SERIAL_MXS_AUART_CONSOLE  	  Enable a MXS AUART port to be the system console.  config SERIAL_XILINX_PS_UART -	tristate "Xilinx PS UART support" +	tristate "Cadence (Xilinx Zynq) UART support"  	depends on OF  	select SERIAL_CORE  	help -	  This driver supports the Xilinx PS UART port. +	  This driver supports the Cadence UART. It is found e.g. in Xilinx +	  Zynq.  config SERIAL_XILINX_PS_UART_CONSOLE -	bool "Xilinx PS UART console support" +	bool "Cadence UART console support"  	depends on SERIAL_XILINX_PS_UART=y  	select SERIAL_CORE_CONSOLE  	help -	  Enable a Xilinx PS UART port to be the system console. +	  Enable a Cadence UART port to be the system console.  config SERIAL_AR933X  	tristate "AR933X serial port support" @@ -1497,6 +1511,7 @@ config SERIAL_RP2_NR_UARTS  config SERIAL_FSL_LPUART  	tristate "Freescale lpuart serial port support" +	depends on HAS_DMA  	select SERIAL_CORE  	help  	  Support for the on-chip lpuart on some Freescale SOCs. @@ -1512,6 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE  config SERIAL_ST_ASC  	tristate "ST ASC serial port support"  	select SERIAL_CORE +	depends on ARM || COMPILE_TEST  	help  	  This driver is for the on-chip Asychronous Serial Controller on  	  STMicroelectronics STi SoCs. @@ -1525,6 +1541,20 @@ config SERIAL_ST_ASC_CONSOLE  	depends on SERIAL_ST_ASC=y  	select SERIAL_CORE_CONSOLE +config SERIAL_MEN_Z135 +	tristate "MEN 16z135 Support" +	select SERIAL_CORE +	depends on MCB +	help +	  Say yes here to enable support for the MEN 16z135 High Speed UART IP-Core +	  on a MCB carrier. + +	  This driver can also be build as a module. If so, the module will be called +	  men_z135_uart.ko +  endmenu +config SERIAL_MCTRL_GPIO +	tristate +  endif # TTY diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 3068c772208..0080cc362e0 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -5,6 +5,9 @@  obj-$(CONFIG_SERIAL_CORE) += serial_core.o  obj-$(CONFIG_SERIAL_21285) += 21285.o +obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o +obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o +  # These Sparc drivers have to appear before others such as 8250  # which share ttySx minor node space.  Otherwise console device  # names change and other unplesantries. @@ -47,8 +50,8 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o  obj-$(CONFIG_SERIAL_MPSC) += mpsc.o  obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o  obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o -obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o  obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o +obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o  obj-$(CONFIG_SERIAL_JSM) += jsm/  obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o  obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o @@ -88,3 +91,7 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o  obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o  obj-$(CONFIG_SERIAL_RP2)	+= rp2.o  obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o +obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o + +# GPIOLIB helpers for modem control lines +obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 501667e3e3f..323376668b7 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -185,6 +185,12 @@ static void altera_uart_set_termios(struct uart_port *port,  	uart_update_timeout(port, termios->c_cflag, baud);  	altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);  	spin_unlock_irqrestore(&port->lock, flags); + +	/* +	 * FIXME: port->read_status_mask and port->ignore_status_mask +	 * need to be initialized based on termios settings for +	 * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT +	 */  }  static void altera_uart_rx_chars(struct altera_uart *pp) diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 8b90f0b6dfd..971af1e22d0 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -420,7 +420,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,  	uap->port.read_status_mask = UART01x_RSR_OE;  	if (termios->c_iflag & INPCK)  		uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		uap->port.read_status_mask |= UART01x_RSR_BE;  	/* @@ -728,7 +728,6 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id)  	amba_set_drvdata(dev, uap);  	ret = uart_add_one_port(&amba_reg, &uap->port);  	if (ret) { -		amba_set_drvdata(dev, NULL);  		amba_ports[i] = NULL;  		clk_put(uap->clk);   unmap: @@ -745,8 +744,6 @@ static int pl010_remove(struct amba_device *dev)  	struct uart_amba_port *uap = amba_get_drvdata(dev);  	int i; -	amba_set_drvdata(dev, NULL); -  	uart_remove_one_port(&amba_reg, &uap->port);  	for (i = 0; i < ARRAY_SIZE(amba_ports); i++) @@ -759,9 +756,10 @@ static int pl010_remove(struct amba_device *dev)  	return 0;  } -static int pl010_suspend(struct amba_device *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pl010_suspend(struct device *dev)  { -	struct uart_amba_port *uap = amba_get_drvdata(dev); +	struct uart_amba_port *uap = dev_get_drvdata(dev);  	if (uap)  		uart_suspend_port(&amba_reg, &uap->port); @@ -769,15 +767,18 @@ static int pl010_suspend(struct amba_device *dev, pm_message_t state)  	return 0;  } -static int pl010_resume(struct amba_device *dev) +static int pl010_resume(struct device *dev)  { -	struct uart_amba_port *uap = amba_get_drvdata(dev); +	struct uart_amba_port *uap = dev_get_drvdata(dev);  	if (uap)  		uart_resume_port(&amba_reg, &uap->port);  	return 0;  } +#endif + +static SIMPLE_DEV_PM_OPS(pl010_dev_pm_ops, pl010_suspend, pl010_resume);  static struct amba_id pl010_ids[] = {  	{ @@ -792,12 +793,11 @@ MODULE_DEVICE_TABLE(amba, pl010_ids);  static struct amba_driver pl010_driver = {  	.drv = {  		.name	= "uart-pl010", +		.pm	= &pl010_dev_pm_ops,  	},  	.id_table	= pl010_ids,  	.probe		= pl010_probe,  	.remove		= pl010_remove, -	.suspend	= pl010_suspend, -	.resume		= pl010_resume,  };  static int __init pl010_init(void) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index aaa22867e65..0e26dcbd5ea 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -112,8 +112,6 @@ static struct vendor_data vendor_st = {  	.get_fifosize		= get_fifosize_st,  }; -static struct uart_amba_port *amba_ports[UART_NR]; -  /* Deals with DMA transactions */  struct pl011_sgbuf { @@ -305,7 +303,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *  	/* Optionally make use of an RX channel as well */  	chan = dma_request_slave_channel(dev, "rx"); -	 +  	if (!chan && plat->dma_rx_param) {  		chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); @@ -320,7 +318,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *  			.src_addr = uap->port.mapbase + UART01x_DR,  			.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,  			.direction = DMA_DEV_TO_MEM, -			.src_maxburst = uap->fifosize >> 1, +			.src_maxburst = uap->fifosize >> 2,  			.device_fc = false,  		}; @@ -969,6 +967,8 @@ static void pl011_dma_rx_poll(unsigned long args)  		spin_lock_irqsave(&uap->port.lock, flags);  		pl011_dma_rx_stop(uap); +		uap->im |= UART011_RXIM; +		writew(uap->im, uap->port.membase + UART011_IMSC);  		spin_unlock_irqrestore(&uap->port.lock, flags);  		uap->dmarx.running = false; @@ -1216,8 +1216,8 @@ __acquires(&uap->port.lock)  			dev_dbg(uap->port.dev, "could not trigger RX DMA job "  				"fall back to interrupt mode again\n");  			uap->im |= UART011_RXIM; +			writew(uap->im, uap->port.membase + UART011_IMSC);  		} else { -			uap->im &= ~UART011_RXIM;  #ifdef CONFIG_DMA_ENGINE  			/* Start Rx DMA poll */  			if (uap->dmarx.poll_rate) { @@ -1229,8 +1229,6 @@ __acquires(&uap->port.lock)  			}  #endif  		} - -		writew(uap->im, uap->port.membase + UART011_IMSC);  	}  	spin_lock(&uap->port.lock);  } @@ -1513,10 +1511,25 @@ static int pl011_hwinit(struct uart_port *port)  	return retval;  } +static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) +{ +	writew(lcr_h, uap->port.membase + uap->lcrh_rx); +	if (uap->lcrh_rx != uap->lcrh_tx) { +		int i; +		/* +		 * Wait 10 PCLKs before writing LCRH_TX register, +		 * to get this delay write read only register 10 times +		 */ +		for (i = 0; i < 10; ++i) +			writew(0xff, uap->port.membase + UART011_MIS); +		writew(lcr_h, uap->port.membase + uap->lcrh_tx); +	} +} +  static int pl011_startup(struct uart_port *port)  {  	struct uart_amba_port *uap = (struct uart_amba_port *)port; -	unsigned int cr; +	unsigned int cr, lcr_h, fbrd, ibrd;  	int retval;  	retval = pl011_hwinit(port); @@ -1535,32 +1548,36 @@ static int pl011_startup(struct uart_port *port)  	writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);  	/* -	 * Provoke TX FIFO interrupt into asserting. +	 * Provoke TX FIFO interrupt into asserting. Taking care to preserve +	 * baud rate and data format specified by FBRD, IBRD and LCRH as the +	 * UART may already be in use as a console.  	 */ +	spin_lock_irq(&uap->port.lock); + +	fbrd = readw(uap->port.membase + UART011_FBRD); +	ibrd = readw(uap->port.membase + UART011_IBRD); +	lcr_h = readw(uap->port.membase + uap->lcrh_rx); +  	cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;  	writew(cr, uap->port.membase + UART011_CR);  	writew(0, uap->port.membase + UART011_FBRD);  	writew(1, uap->port.membase + UART011_IBRD); -	writew(0, uap->port.membase + uap->lcrh_rx); -	if (uap->lcrh_tx != uap->lcrh_rx) { -		int i; -		/* -		 * Wait 10 PCLKs before writing LCRH_TX register, -		 * to get this delay write read only register 10 times -		 */ -		for (i = 0; i < 10; ++i) -			writew(0xff, uap->port.membase + UART011_MIS); -		writew(0, uap->port.membase + uap->lcrh_tx); -	} +	pl011_write_lcr_h(uap, 0);  	writew(0, uap->port.membase + UART01x_DR);  	while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)  		barrier(); +	writew(fbrd, uap->port.membase + UART011_FBRD); +	writew(ibrd, uap->port.membase + UART011_IBRD); +	pl011_write_lcr_h(uap, lcr_h); +  	/* restore RTS and DTR */  	cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);  	cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;  	writew(cr, uap->port.membase + UART011_CR); +	spin_unlock_irq(&uap->port.lock); +  	/*  	 * initialise the old status of the modem signals  	 */ @@ -1629,11 +1646,13 @@ static void pl011_shutdown(struct uart_port *port)  	 * it during startup().  	 */  	uap->autorts = false; +	spin_lock_irq(&uap->port.lock);  	cr = readw(uap->port.membase + UART011_CR);  	uap->old_cr = cr;  	cr &= UART011_CR_RTS | UART011_CR_DTR;  	cr |= UART01x_CR_UARTEN | UART011_CR_TXE;  	writew(cr, uap->port.membase + UART011_CR); +	spin_unlock_irq(&uap->port.lock);  	/*  	 * disable break condition and fifos @@ -1725,7 +1744,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,  	port->read_status_mask = UART011_DR_OE | 255;  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= UART011_DR_BE;  	/* @@ -1797,17 +1816,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,  	 * UART011_FBRD & UART011_IBRD.  	 * ----------^----------^----------^----------^-----  	 */ -	writew(lcr_h, port->membase + uap->lcrh_rx); -	if (uap->lcrh_rx != uap->lcrh_tx) { -		int i; -		/* -		 * Wait 10 PCLKs before writing LCRH_TX register, -		 * to get this delay write read only register 10 times -		 */ -		for (i = 0; i < 10; ++i) -			writew(0xff, uap->port.membase + UART011_MIS); -		writew(lcr_h, port->membase + uap->lcrh_tx); -	} +	pl011_write_lcr_h(uap, lcr_h);  	writew(old_cr, port->membase + UART011_CR);  	spin_unlock_irqrestore(&port->lock, flags); @@ -2036,6 +2045,35 @@ static struct console amba_console = {  };  #define AMBA_CONSOLE	(&amba_console) + +static void pl011_putc(struct uart_port *port, int c) +{ +	while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) +		; +	writeb(c, port->membase + UART01x_DR); +	while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY) +		; +} + +static void pl011_early_write(struct console *con, const char *s, unsigned n) +{ +	struct earlycon_device *dev = con->data; + +	uart_console_write(&dev->port, s, n, pl011_putc); +} + +static int __init pl011_early_console_setup(struct earlycon_device *device, +					    const char *opt) +{ +	if (!device->port.membase) +		return -ENODEV; + +	device->con->write = pl011_early_write; +	return 0; +} +EARLYCON_DECLARE(pl011, pl011_early_console_setup); +OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); +  #else  #define AMBA_CONSOLE	NULL  #endif @@ -2145,10 +2183,19 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)  	amba_ports[i] = uap;  	amba_set_drvdata(dev, uap); + +	if (!amba_reg.state) { +		ret = uart_register_driver(&amba_reg); +		if (ret < 0) { +			pr_err("Failed to register AMBA-PL011 driver\n"); +			return ret; +		} +	} +  	ret = uart_add_one_port(&amba_reg, &uap->port);  	if (ret) { -		amba_set_drvdata(dev, NULL);  		amba_ports[i] = NULL; +		uart_unregister_driver(&amba_reg);  		pl011_dma_remove(uap);  	}   out: @@ -2158,24 +2205,27 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)  static int pl011_remove(struct amba_device *dev)  {  	struct uart_amba_port *uap = amba_get_drvdata(dev); +	bool busy = false;  	int i; -	amba_set_drvdata(dev, NULL); -  	uart_remove_one_port(&amba_reg, &uap->port);  	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)  		if (amba_ports[i] == uap)  			amba_ports[i] = NULL; +		else if (amba_ports[i]) +			busy = true;  	pl011_dma_remove(uap); +	if (!busy) +		uart_unregister_driver(&amba_reg);  	return 0;  } -#ifdef CONFIG_PM -static int pl011_suspend(struct amba_device *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pl011_suspend(struct device *dev)  { -	struct uart_amba_port *uap = amba_get_drvdata(dev); +	struct uart_amba_port *uap = dev_get_drvdata(dev);  	if (!uap)  		return -EINVAL; @@ -2183,9 +2233,9 @@ static int pl011_suspend(struct amba_device *dev, pm_message_t state)  	return uart_suspend_port(&amba_reg, &uap->port);  } -static int pl011_resume(struct amba_device *dev) +static int pl011_resume(struct device *dev)  { -	struct uart_amba_port *uap = amba_get_drvdata(dev); +	struct uart_amba_port *uap = dev_get_drvdata(dev);  	if (!uap)  		return -EINVAL; @@ -2194,6 +2244,8 @@ static int pl011_resume(struct amba_device *dev)  }  #endif +static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume); +  static struct amba_id pl011_ids[] = {  	{  		.id	= 0x00041011, @@ -2213,34 +2265,23 @@ MODULE_DEVICE_TABLE(amba, pl011_ids);  static struct amba_driver pl011_driver = {  	.drv = {  		.name	= "uart-pl011", +		.pm	= &pl011_dev_pm_ops,  	},  	.id_table	= pl011_ids,  	.probe		= pl011_probe,  	.remove		= pl011_remove, -#ifdef CONFIG_PM -	.suspend	= pl011_suspend, -	.resume		= pl011_resume, -#endif  };  static int __init pl011_init(void)  { -	int ret;  	printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); -	ret = uart_register_driver(&amba_reg); -	if (ret == 0) { -		ret = amba_driver_register(&pl011_driver); -		if (ret) -			uart_unregister_driver(&amba_reg); -	} -	return ret; +	return amba_driver_register(&pl011_driver);  }  static void __exit pl011_exit(void)  {  	amba_driver_unregister(&pl011_driver); -	uart_unregister_driver(&amba_reg);  }  /* diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 569872f4c9b..008c223eaf2 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -177,7 +177,7 @@ static void arc_serial_tx_chars(struct arc_uart_port *uart)  		uart->port.icount.tx++;  		uart->port.x_char = 0;  		sent = 1; -	} else if (xmit->tail != xmit->head) {	/* TODO: uart_circ_empty */ +	} else if (!uart_circ_empty(xmit)) {  		ch = xmit->buf[xmit->tail];  		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);  		uart->port.icount.tx++; @@ -533,7 +533,7 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id)  	unsigned long *plat_data;  	struct arc_uart_port *uart = &arc_uart_ports[dev_id]; -	plat_data = (unsigned long *)dev_get_platdata(&pdev->dev); +	plat_data = dev_get_platdata(&pdev->dev);  	if (!plat_data)  		return -ENODEV; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index d067285a2d2..c4f75031410 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -35,21 +35,21 @@  #include <linux/platform_device.h>  #include <linux/of.h>  #include <linux/of_device.h> +#include <linux/of_gpio.h>  #include <linux/dma-mapping.h>  #include <linux/atmel_pdc.h>  #include <linux/atmel_serial.h>  #include <linux/uaccess.h>  #include <linux/platform_data/atmel.h>  #include <linux/timer.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/err.h> +#include <linux/irq.h>  #include <asm/io.h>  #include <asm/ioctls.h> -#ifdef CONFIG_ARM -#include <mach/cpu.h> -#include <asm/gpio.h> -#endif -  #define PDC_BUFFER_SIZE		512  /* Revisit: We should calculate this based on the actual port settings */  #define PDC_RX_TIMEOUT		(3 * 10)		/* 3 bytes */ @@ -60,6 +60,8 @@  #include <linux/serial_core.h> +#include "serial_mctrl_gpio.h" +  static void atmel_start_rx(struct uart_port *port);  static void atmel_stop_rx(struct uart_port *port); @@ -99,6 +101,7 @@ static void atmel_stop_rx(struct uart_port *port);  #define UART_PUT_RTOR(port,v)	__raw_writel(v, (port)->membase + ATMEL_US_RTOR)  #define UART_PUT_TTGR(port, v)	__raw_writel(v, (port)->membase + ATMEL_US_TTGR)  #define UART_GET_IP_NAME(port)	__raw_readl((port)->membase + ATMEL_US_NAME) +#define UART_GET_IP_VERSION(port) __raw_readl((port)->membase + ATMEL_US_VERSION)   /* PDC registers */  #define UART_PUT_PTCR(port,v)	__raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) @@ -114,9 +117,6 @@ static void atmel_stop_rx(struct uart_port *port);  #define UART_PUT_TCR(port,v)	__raw_writel(v, (port)->membase + ATMEL_PDC_TCR)  #define UART_GET_TCR(port)	__raw_readl((port)->membase + ATMEL_PDC_TCR) -static int (*atmel_open_hook)(struct uart_port *); -static void (*atmel_close_hook)(struct uart_port *); -  struct atmel_dma_buffer {  	unsigned char	*buf;  	dma_addr_t	dma_addr; @@ -167,7 +167,10 @@ struct atmel_uart_port {  	struct circ_buf		rx_ring;  	struct serial_rs485	rs485;		/* rs485 settings */ +	struct mctrl_gpios	*gpios; +	int			gpio_irq[UART_GPIO_MAX];  	unsigned int		tx_done_mask; +	bool			ms_irq_enabled;  	bool			is_usart;	/* usart or uart */  	struct timer_list	uart_timer;	/* uart timer */  	int (*prepare_rx)(struct uart_port *port); @@ -241,6 +244,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)  	return atmel_port->use_dma_rx;  } +static unsigned int atmel_get_lines_status(struct uart_port *port) +{ +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); +	unsigned int status, ret = 0; + +	status = UART_GET_CSR(port); + +	mctrl_gpio_get(atmel_port->gpios, &ret); + +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, +						UART_GPIO_CTS))) { +		if (ret & TIOCM_CTS) +			status &= ~ATMEL_US_CTS; +		else +			status |= ATMEL_US_CTS; +	} + +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, +						UART_GPIO_DSR))) { +		if (ret & TIOCM_DSR) +			status &= ~ATMEL_US_DSR; +		else +			status |= ATMEL_US_DSR; +	} + +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, +						UART_GPIO_RI))) { +		if (ret & TIOCM_RI) +			status &= ~ATMEL_US_RI; +		else +			status |= ATMEL_US_RI; +	} + +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, +						UART_GPIO_DCD))) { +		if (ret & TIOCM_CD) +			status &= ~ATMEL_US_DCD; +		else +			status |= ATMEL_US_DCD; +	} + +	return status; +} +  /* Enable or disable the rs485 support */  void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)  { @@ -300,21 +347,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)  	unsigned int mode;  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -#ifdef CONFIG_ARCH_AT91RM9200 -	if (cpu_is_at91rm9200()) { -		/* -		 * AT91RM9200 Errata #39: RTS0 is not internally connected -		 * to PA21. We need to drive the pin manually. -		 */ -		if (port->mapbase == AT91RM9200_BASE_US0) { -			if (mctrl & TIOCM_RTS) -				at91_set_gpio_value(AT91_PIN_PA21, 0); -			else -				at91_set_gpio_value(AT91_PIN_PA21, 1); -		} -	} -#endif -  	if (mctrl & TIOCM_RTS)  		control |= ATMEL_US_RTSEN;  	else @@ -327,6 +359,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)  	UART_PUT_CR(port, control); +	mctrl_gpio_set(atmel_port->gpios, mctrl); +  	/* Local loopback mode? */  	mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;  	if (mctrl & TIOCM_LOOP) @@ -354,7 +388,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)   */  static u_int atmel_get_mctrl(struct uart_port *port)  { -	unsigned int status, ret = 0; +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); +	unsigned int ret = 0, status;  	status = UART_GET_CSR(port); @@ -370,7 +405,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)  	if (!(status & ATMEL_US_RI))  		ret |= TIOCM_RI; -	return ret; +	return mctrl_gpio_get(atmel_port->gpios, &ret);  }  /* @@ -457,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port)   */  static void atmel_enable_ms(struct uart_port *port)  { -	UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC -			| ATMEL_US_DCDIC | ATMEL_US_CTSIC); +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); +	uint32_t ier = 0; + +	/* +	 * Interrupt should not be enabled twice +	 */ +	if (atmel_port->ms_irq_enabled) +		return; + +	atmel_port->ms_irq_enabled = true; + +	if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0) +		enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]); +	else +		ier |= ATMEL_US_CTSIC; + +	if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0) +		enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]); +	else +		ier |= ATMEL_US_DSRIC; + +	if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0) +		enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]); +	else +		ier |= ATMEL_US_RIIC; + +	if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0) +		enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]); +	else +		ier |= ATMEL_US_DCDIC; + +	UART_PUT_IER(port, ier);  }  /* @@ -824,9 +889,6 @@ static void atmel_release_rx_dma(struct uart_port *port)  	atmel_port->desc_rx = NULL;  	atmel_port->chan_rx = NULL;  	atmel_port->cookie_rx = -EINVAL; - -	if (!atmel_port->is_usart) -		del_timer_sync(&atmel_port->uart_timer);  }  static void atmel_rx_from_dma(struct uart_port *port) @@ -1050,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,  static irqreturn_t atmel_interrupt(int irq, void *dev_id)  {  	struct uart_port *port = dev_id; +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);  	unsigned int status, pending, pass_counter = 0; +	bool gpio_handled = false;  	do { -		status = UART_GET_CSR(port); +		status = atmel_get_lines_status(port);  		pending = status & UART_GET_IMR(port); +		if (!gpio_handled) { +			/* +			 * Dealing with GPIO interrupt +			 */ +			if (irq == atmel_port->gpio_irq[UART_GPIO_CTS]) +				pending |= ATMEL_US_CTSIC; + +			if (irq == atmel_port->gpio_irq[UART_GPIO_DSR]) +				pending |= ATMEL_US_DSRIC; + +			if (irq == atmel_port->gpio_irq[UART_GPIO_RI]) +				pending |= ATMEL_US_RIIC; + +			if (irq == atmel_port->gpio_irq[UART_GPIO_DCD]) +				pending |= ATMEL_US_DCDIC; + +			gpio_handled = true; +		}  		if (!pending)  			break; @@ -1228,9 +1310,6 @@ static void atmel_release_rx_pdc(struct uart_port *port)  				 DMA_FROM_DEVICE);  		kfree(pdc->buf);  	} - -	if (!atmel_port->is_usart) -		del_timer_sync(&atmel_port->uart_timer);  }  static void atmel_rx_from_pdc(struct uart_port *port) @@ -1499,10 +1578,11 @@ static void atmel_set_ops(struct uart_port *port)  /*   * Get ip name usart or uart   */ -static int atmel_get_ip_name(struct uart_port *port) +static void atmel_get_ip_name(struct uart_port *port)  {  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);  	int name = UART_GET_IP_NAME(port); +	u32 version;  	int usart, uart;  	/* usart and uart ascii */  	usart = 0x55534152; @@ -1517,11 +1597,62 @@ static int atmel_get_ip_name(struct uart_port *port)  		dev_dbg(port->dev, "This is uart\n");  		atmel_port->is_usart = false;  	} else { -		dev_err(port->dev, "Not supported ip name, set to uart\n"); -		return -EINVAL; +		/* fallback for older SoCs: use version field */ +		version = UART_GET_IP_VERSION(port); +		switch (version) { +		case 0x302: +		case 0x10213: +			dev_dbg(port->dev, "This version is usart\n"); +			atmel_port->is_usart = true; +			break; +		case 0x203: +		case 0x10202: +			dev_dbg(port->dev, "This version is uart\n"); +			atmel_port->is_usart = false; +			break; +		default: +			dev_err(port->dev, "Not supported ip name nor version, set to uart\n"); +		}  	} +} -	return 0; +static void atmel_free_gpio_irq(struct uart_port *port) +{ +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); +	enum mctrl_gpio_idx i; + +	for (i = 0; i < UART_GPIO_MAX; i++) +		if (atmel_port->gpio_irq[i] >= 0) +			free_irq(atmel_port->gpio_irq[i], port); +} + +static int atmel_request_gpio_irq(struct uart_port *port) +{ +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); +	int *irq = atmel_port->gpio_irq; +	enum mctrl_gpio_idx i; +	int err = 0; + +	for (i = 0; (i < UART_GPIO_MAX) && !err; i++) { +		if (irq[i] < 0) +			continue; + +		irq_set_status_flags(irq[i], IRQ_NOAUTOEN); +		err = request_irq(irq[i], atmel_interrupt, IRQ_TYPE_EDGE_BOTH, +				  "atmel_serial", port); +		if (err) +			dev_err(port->dev, "atmel_startup - Can't get %d irq\n", +				irq[i]); +	} + +	/* +	 * If something went wrong, rollback. +	 */ +	while (err && (--i >= 0)) +		if (irq[i] >= 0) +			free_irq(irq[i], port); + +	return err;  }  /* @@ -1540,6 +1671,7 @@ static int atmel_startup(struct uart_port *port)  	 * handle an unexpected interrupt  	 */  	UART_PUT_IDR(port, -1); +	atmel_port->ms_irq_enabled = false;  	/*  	 * Allocate the IRQ @@ -1547,11 +1679,18 @@ static int atmel_startup(struct uart_port *port)  	retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,  			tty ? tty->name : "atmel_serial", port);  	if (retval) { -		printk("atmel_serial: atmel_startup - Can't get irq\n"); +		dev_err(port->dev, "atmel_startup - Can't get irq\n");  		return retval;  	}  	/* +	 * Get the GPIO lines IRQ +	 */ +	retval = atmel_request_gpio_irq(port); +	if (retval) +		goto free_irq; + +	/*  	 * Initialize DMA (if necessary)  	 */  	atmel_init_property(atmel_port, pdev); @@ -1567,20 +1706,9 @@ static int atmel_startup(struct uart_port *port)  		if (retval < 0)  			atmel_set_ops(port);  	} -	/* -	 * If there is a specific "open" function (to register -	 * control line interrupts) -	 */ -	if (atmel_open_hook) { -		retval = atmel_open_hook(port); -		if (retval) { -			free_irq(port->irq, port); -			return retval; -		} -	}  	/* Save current CSR for comparison in atmel_tasklet_func() */ -	atmel_port->irq_status_prev = UART_GET_CSR(port); +	atmel_port->irq_status_prev = atmel_get_lines_status(port);  	atmel_port->irq_status = atmel_port->irq_status_prev;  	/* @@ -1590,12 +1718,13 @@ static int atmel_startup(struct uart_port *port)  	/* enable xmit & rcvr */  	UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); +	setup_timer(&atmel_port->uart_timer, +			atmel_uart_timer_callback, +			(unsigned long)port); +  	if (atmel_use_pdc_rx(port)) {  		/* set UART timeout */  		if (!atmel_port->is_usart) { -			setup_timer(&atmel_port->uart_timer, -					atmel_uart_timer_callback, -					(unsigned long)port);  			mod_timer(&atmel_port->uart_timer,  					jiffies + uart_poll_timeout(port));  		/* set USART timeout */ @@ -1610,9 +1739,6 @@ static int atmel_startup(struct uart_port *port)  	} else if (atmel_use_dma_rx(port)) {  		/* set UART timeout */  		if (!atmel_port->is_usart) { -			setup_timer(&atmel_port->uart_timer, -					atmel_uart_timer_callback, -					(unsigned long)port);  			mod_timer(&atmel_port->uart_timer,  					jiffies + uart_poll_timeout(port));  		/* set USART timeout */ @@ -1628,6 +1754,11 @@ static int atmel_startup(struct uart_port *port)  	}  	return 0; + +free_irq: +	free_irq(port->irq, port); + +	return retval;  }  /* @@ -1636,12 +1767,30 @@ static int atmel_startup(struct uart_port *port)  static void atmel_shutdown(struct uart_port *port)  {  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + +	/* +	 * Prevent any tasklets being scheduled during +	 * cleanup +	 */ +	del_timer_sync(&atmel_port->uart_timer); + +	/* +	 * Clear out any scheduled tasklets before +	 * we destroy the buffers +	 */ +	tasklet_kill(&atmel_port->tasklet); +  	/* -	 * Ensure everything is stopped. +	 * Ensure everything is stopped and +	 * disable all interrupts, port and break condition.  	 */  	atmel_stop_rx(port);  	atmel_stop_tx(port); +	UART_PUT_CR(port, ATMEL_US_RSTSTA); +	UART_PUT_IDR(port, -1); + +  	/*  	 * Shut-down the DMA.  	 */ @@ -1651,22 +1800,18 @@ static void atmel_shutdown(struct uart_port *port)  		atmel_port->release_tx(port);  	/* -	 * Disable all interrupts, port and break condition. +	 * Reset ring buffer pointers  	 */ -	UART_PUT_CR(port, ATMEL_US_RSTSTA); -	UART_PUT_IDR(port, -1); +	atmel_port->rx_ring.head = 0; +	atmel_port->rx_ring.tail = 0;  	/* -	 * Free the interrupt +	 * Free the interrupts  	 */  	free_irq(port->irq, port); +	atmel_free_gpio_irq(port); -	/* -	 * If there is a specific "close" function (to unregister -	 * control line interrupts) -	 */ -	if (atmel_close_hook) -		atmel_close_hook(port); +	atmel_port->ms_irq_enabled = false;  }  /* @@ -1714,7 +1859,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,  		clk_disable_unprepare(atmel_port->clk);  		break;  	default: -		printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); +		dev_err(port->dev, "atmel_serial: unknown pm %d\n", state);  	}  } @@ -1787,7 +1932,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,  	port->read_status_mask = ATMEL_US_OVRE;  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= ATMEL_US_RXBRK;  	if (atmel_use_pdc_rx(port)) @@ -1829,13 +1974,10 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,  	mode &= ~ATMEL_US_USMODE;  	if (atmel_port->rs485.flags & SER_RS485_ENABLED) { -		dev_dbg(port->dev, "Setting UART to RS485\n");  		if ((atmel_port->rs485.delay_rts_after_send) > 0)  			UART_PUT_TTGR(port,  					atmel_port->rs485.delay_rts_after_send);  		mode |= ATMEL_US_USMODE_RS485; -	} else { -		dev_dbg(port->dev, "Setting UART to RS232\n");  	}  	/* set the parity, stop bits and data size */ @@ -2330,6 +2472,26 @@ static int atmel_serial_resume(struct platform_device *pdev)  #define atmel_serial_resume NULL  #endif +static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev) +{ +	enum mctrl_gpio_idx i; +	struct gpio_desc *gpiod; + +	p->gpios = mctrl_gpio_init(dev, 0); +	if (IS_ERR_OR_NULL(p->gpios)) +		return -1; + +	for (i = 0; i < UART_GPIO_MAX; i++) { +		gpiod = mctrl_gpio_to_gpiod(p->gpios, i); +		if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN)) +			p->gpio_irq[i] = gpiod_to_irq(gpiod); +		else +			p->gpio_irq[i] = -EINVAL; +	} + +	return 0; +} +  static int atmel_serial_probe(struct platform_device *pdev)  {  	struct atmel_uart_port *port; @@ -2366,6 +2528,11 @@ static int atmel_serial_probe(struct platform_device *pdev)  	port->backup_imr = 0;  	port->uart.line = ret; +	ret = atmel_init_gpios(port, &pdev->dev); +	if (ret < 0) +		dev_err(&pdev->dev, "%s", +			"Failed to initialize GPIOs. The serial port may not work as expected"); +  	ret = atmel_init_port(port, pdev);  	if (ret)  		goto err; @@ -2405,9 +2572,7 @@ static int atmel_serial_probe(struct platform_device *pdev)  	/*  	 * Get port name of usart or uart  	 */ -	ret = atmel_get_ip_name(&port->uart); -	if (ret < 0) -		goto err_add_port; +	atmel_get_ip_name(&port->uart);  	return 0; @@ -2429,11 +2594,12 @@ static int atmel_serial_remove(struct platform_device *pdev)  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);  	int ret = 0; +	tasklet_kill(&atmel_port->tasklet); +  	device_init_wakeup(&pdev->dev, 0);  	ret = uart_remove_one_port(&atmel_uart, port); -	tasklet_kill(&atmel_port->tasklet);  	kfree(atmel_port->rx_ring.buf);  	/* "port" is allocated statically, so we shouldn't free it */ diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 649d5129c4b..231519022b7 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -29,10 +29,9 @@  #include <linux/sysrq.h>  #include <linux/serial.h>  #include <linux/serial_core.h> - -#include <bcm63xx_irq.h> -#include <bcm63xx_regs.h> -#include <bcm63xx_io.h> +#include <linux/serial_bcm63xx.h> +#include <linux/io.h> +#include <linux/of.h>  #define BCM63XX_NR_UARTS	2 @@ -81,13 +80,13 @@ static struct uart_port ports[BCM63XX_NR_UARTS];  static inline unsigned int bcm_uart_readl(struct uart_port *port,  					 unsigned int offset)  { -	return bcm_readl(port->membase + offset); +	return __raw_readl(port->membase + offset);  }  static inline void bcm_uart_writel(struct uart_port *port,  				  unsigned int value, unsigned int offset)  { -	bcm_writel(value, port->membase + offset); +	__raw_writel(value, port->membase + offset);  }  /* @@ -568,7 +567,7 @@ static void bcm_uart_set_termios(struct uart_port *port,  		port->read_status_mask |= UART_FIFO_FRAMEERR_MASK;  		port->read_status_mask |= UART_FIFO_PARERR_MASK;  	} -	if (new->c_iflag & (BRKINT)) +	if (new->c_iflag & (IGNBRK | BRKINT))  		port->read_status_mask |= UART_FIFO_BRKDET_MASK;  	port->ignore_status_mask = 0; @@ -591,7 +590,7 @@ static int bcm_uart_request_port(struct uart_port *port)  {  	unsigned int size; -	size = RSET_UART_SIZE; +	size = UART_REG_SIZE;  	if (!request_mem_region(port->mapbase, size, "bcm63xx")) {  		dev_err(port->dev, "Memory region busy\n");  		return -EBUSY; @@ -611,7 +610,7 @@ static int bcm_uart_request_port(struct uart_port *port)   */  static void bcm_uart_release_port(struct uart_port *port)  { -	release_mem_region(port->mapbase, RSET_UART_SIZE); +	release_mem_region(port->mapbase, UART_REG_SIZE);  	iounmap(port->membase);  } @@ -808,6 +807,9 @@ static int bcm_uart_probe(struct platform_device *pdev)  	struct clk *clk;  	int ret; +	if (pdev->dev.of_node) +		pdev->id = of_alias_get_id(pdev->dev.of_node, "uart"); +  	if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)  		return -EINVAL; @@ -859,6 +861,12 @@ static int bcm_uart_remove(struct platform_device *pdev)  	return 0;  } +static const struct of_device_id bcm63xx_of_match[] = { +	{ .compatible = "brcm,bcm6345-uart" }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bcm63xx_of_match); +  /*   * platform driver stuff   */ @@ -868,6 +876,7 @@ static struct platform_driver bcm_uart_platform_driver = {  	.driver	= {  		.owner = THIS_MODULE,  		.name  = "bcm63xx_uart", +		.of_match_table = bcm63xx_of_match,  	},  }; diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c index 87636cc61a2..4f229703328 100644 --- a/drivers/tty/serial/bfin_sport_uart.c +++ b/drivers/tty/serial/bfin_sport_uart.c @@ -766,9 +766,8 @@ static int sport_uart_probe(struct platform_device *pdev)  			return -ENOMEM;  		} -		ret = peripheral_request_list( -			(unsigned short *)dev_get_platdata(&pdev->dev), -			DRV_NAME); +		ret = peripheral_request_list(dev_get_platdata(&pdev->dev), +						DRV_NAME);  		if (ret) {  			dev_err(&pdev->dev,  				"Fail to request SPORT peripherals\n"); @@ -844,8 +843,7 @@ static int sport_uart_probe(struct platform_device *pdev)  out_error_unmap:  		iounmap(sport->port.membase);  out_error_free_peripherals: -		peripheral_free_list( -			(unsigned short *)dev_get_platdata(&pdev->dev)); +		peripheral_free_list(dev_get_platdata(&pdev->dev));  out_error_free_mem:  		kfree(sport);  		bfin_sport_uart_ports[pdev->id] = NULL; @@ -864,8 +862,7 @@ static int sport_uart_remove(struct platform_device *pdev)  	if (sport) {  		uart_remove_one_port(&sport_uart_reg, &sport->port);  		iounmap(sport->port.membase); -		peripheral_free_list( -			(unsigned short *)dev_get_platdata(&pdev->dev)); +		peripheral_free_list(dev_get_platdata(&pdev->dev));  		kfree(sport);  		bfin_sport_uart_ports[pdev->id] = NULL;  	} diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 3c75e8e0402..ac86a20992e 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -680,7 +680,7 @@ static int bfin_serial_startup(struct uart_port *port)  		default:  			uart_dma_ch_rx = uart_dma_ch_tx = 0;  			break; -		}; +		}  		if (uart_dma_ch_rx &&  			request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { @@ -726,7 +726,7 @@ static int bfin_serial_startup(struct uart_port *port)  #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS  	if (uart->cts_pin >= 0) {  		if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int, -			IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) { +			0, "BFIN_UART_MODEM_STATUS", uart)) {  			uart->cts_pin = -1;  			dev_info(port->dev, "Unable to attach BlackFin UART Modem Status interrupt.\n");  		} @@ -765,7 +765,7 @@ static void bfin_serial_shutdown(struct uart_port *port)  		break;  	default:  		break; -	}; +	}  #endif  	free_irq(uart->rx_irq, uart);  	free_irq(uart->tx_irq, uart); @@ -833,7 +833,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,  	port->read_status_mask = OE;  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= (FE | PE); -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= BI;  	/* @@ -1240,7 +1240,7 @@ static int bfin_serial_probe(struct platform_device *pdev)  			 */  #endif  		ret = peripheral_request_list( -			(unsigned short *)dev_get_platdata(&pdev->dev), +			dev_get_platdata(&pdev->dev),  			DRIVER_NAME);  		if (ret) {  			dev_err(&pdev->dev, @@ -1358,8 +1358,7 @@ static int bfin_serial_probe(struct platform_device *pdev)  out_error_unmap:  		iounmap(uart->port.membase);  out_error_free_peripherals: -		peripheral_free_list( -			(unsigned short *)dev_get_platdata(&pdev->dev)); +		peripheral_free_list(dev_get_platdata(&pdev->dev));  out_error_free_mem:  		kfree(uart);  		bfin_serial_ports[pdev->id] = NULL; @@ -1377,8 +1376,7 @@ static int bfin_serial_remove(struct platform_device *pdev)  	if (uart) {  		uart_remove_one_port(&bfin_serial_reg, &uart->port);  		iounmap(uart->port.membase); -		peripheral_free_list( -			(unsigned short *)dev_get_platdata(&pdev->dev)); +		peripheral_free_list(dev_get_platdata(&pdev->dev));  		kfree(uart);  		bfin_serial_ports[pdev->id] = NULL;  	} @@ -1432,8 +1430,8 @@ static int bfin_earlyprintk_probe(struct platform_device *pdev)  		return -ENOENT;  	} -	ret = peripheral_request_list( -		(unsigned short *)dev_get_platdata(&pdev->dev), DRIVER_NAME); +	ret = peripheral_request_list(dev_get_platdata(&pdev->dev), +					DRIVER_NAME);  	if (ret) {  		dev_err(&pdev->dev,  				"fail to request bfin serial peripherals\n"); @@ -1463,8 +1461,7 @@ static int bfin_earlyprintk_probe(struct platform_device *pdev)  	return 0;  out_error_free_peripherals: -	peripheral_free_list( -		(unsigned short *)dev_get_platdata(&pdev->dev)); +	peripheral_free_list(dev_get_platdata(&pdev->dev));  	return ret;  } diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 7e4e4088471..14aaea0d413 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -21,44 +21,66 @@  #include <linux/console.h>  #include <linux/serial_core.h>  #include <linux/serial.h> -#include <linux/io.h>  #include <linux/clk.h> +#include <linux/io.h>  #include <linux/tty.h>  #include <linux/tty_flip.h>  #include <linux/ioport.h> +#include <linux/of.h>  #include <linux/platform_device.h> +#include <linux/regmap.h> -#include <mach/hardware.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/clps711x.h> -#define UART_CLPS711X_NAME	"uart-clps711x" +#define UART_CLPS711X_DEVNAME	"ttyCL"  #define UART_CLPS711X_NR	2  #define UART_CLPS711X_MAJOR	204  #define UART_CLPS711X_MINOR	40 -#define UBRLCR(port)		((port)->line ? UBRLCR2 : UBRLCR1) -#define UARTDR(port)		((port)->line ? UARTDR2 : UARTDR1) -#define SYSFLG(port)		((port)->line ? SYSFLG2 : SYSFLG1) -#define SYSCON(port)		((port)->line ? SYSCON2 : SYSCON1) -#define TX_IRQ(port)		((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1) -#define RX_IRQ(port)		((port)->line ? IRQ_URXINT2 : IRQ_URXINT1) +#define UARTDR_OFFSET		(0x00) +#define UBRLCR_OFFSET		(0x40) + +#define UARTDR_FRMERR		(1 << 8) +#define UARTDR_PARERR		(1 << 9) +#define UARTDR_OVERR		(1 << 10) + +#define UBRLCR_BAUD_MASK	((1 << 12) - 1) +#define UBRLCR_BREAK		(1 << 12) +#define UBRLCR_PRTEN		(1 << 13) +#define UBRLCR_EVENPRT		(1 << 14) +#define UBRLCR_XSTOP		(1 << 15) +#define UBRLCR_FIFOEN		(1 << 16) +#define UBRLCR_WRDLEN5		(0 << 17) +#define UBRLCR_WRDLEN6		(1 << 17) +#define UBRLCR_WRDLEN7		(2 << 17) +#define UBRLCR_WRDLEN8		(3 << 17) +#define UBRLCR_WRDLEN_MASK	(3 << 17)  struct clps711x_port { -	struct uart_driver	uart; -	struct clk		*uart_clk; -	struct uart_port	port[UART_CLPS711X_NR]; -	int			tx_enabled[UART_CLPS711X_NR]; -#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE -	struct console		console; -#endif +	struct uart_port	port; +	unsigned int		tx_enabled; +	int			rx_irq; +	struct regmap		*syscon; +	bool			use_ms; +}; + +static struct uart_driver clps711x_uart = { +	.owner		= THIS_MODULE, +	.driver_name	= UART_CLPS711X_DEVNAME, +	.dev_name	= UART_CLPS711X_DEVNAME, +	.major		= UART_CLPS711X_MAJOR, +	.minor		= UART_CLPS711X_MINOR, +	.nr		= UART_CLPS711X_NR,  };  static void uart_clps711x_stop_tx(struct uart_port *port)  {  	struct clps711x_port *s = dev_get_drvdata(port->dev); -	if (s->tx_enabled[port->line]) { -		disable_irq(TX_IRQ(port)); -		s->tx_enabled[port->line] = 0; +	if (s->tx_enabled) { +		disable_irq(port->irq); +		s->tx_enabled = 0;  	}  } @@ -66,33 +88,27 @@ static void uart_clps711x_start_tx(struct uart_port *port)  {  	struct clps711x_port *s = dev_get_drvdata(port->dev); -	if (!s->tx_enabled[port->line]) { -		enable_irq(TX_IRQ(port)); -		s->tx_enabled[port->line] = 1; +	if (!s->tx_enabled) { +		s->tx_enabled = 1; +		enable_irq(port->irq);  	}  } -static void uart_clps711x_stop_rx(struct uart_port *port) -{ -	disable_irq(RX_IRQ(port)); -} - -static void uart_clps711x_enable_ms(struct uart_port *port) -{ -	/* Do nothing */ -} -  static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)  {  	struct uart_port *port = dev_id; -	unsigned int status, ch, flg; +	struct clps711x_port *s = dev_get_drvdata(port->dev); +	unsigned int status, flg; +	u16 ch;  	for (;;) { -		status = clps_readl(SYSFLG(port)); -		if (status & SYSFLG_URXFE) +		u32 sysflg = 0; + +		regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); +		if (sysflg & SYSFLG_URXFE)  			break; -		ch = clps_readw(UARTDR(port)); +		ch = readw(port->membase + UARTDR_OFFSET);  		status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR);  		ch &= 0xff; @@ -138,23 +154,29 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)  	struct circ_buf *xmit = &port->state->xmit;  	if (port->x_char) { -		clps_writew(port->x_char, UARTDR(port)); +		writew(port->x_char, port->membase + UARTDR_OFFSET);  		port->icount.tx++;  		port->x_char = 0;  		return IRQ_HANDLED;  	}  	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -		disable_irq_nosync(TX_IRQ(port)); -		s->tx_enabled[port->line] = 0; +		if (s->tx_enabled) { +			disable_irq_nosync(port->irq); +			s->tx_enabled = 0; +		}  		return IRQ_HANDLED;  	}  	while (!uart_circ_empty(xmit)) { -		clps_writew(xmit->buf[xmit->tail], UARTDR(port)); +		u32 sysflg = 0; + +		writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET);  		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);  		port->icount.tx++; -		if (clps_readl(SYSFLG(port) & SYSFLG_UTXFF)) + +		regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); +		if (sysflg & SYSFLG_UTXFF)  			break;  	} @@ -166,20 +188,28 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)  static unsigned int uart_clps711x_tx_empty(struct uart_port *port)  { -	return (clps_readl(SYSFLG(port) & SYSFLG_UBUSY)) ? 0 : TIOCSER_TEMT; +	struct clps711x_port *s = dev_get_drvdata(port->dev); +	u32 sysflg = 0; + +	regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); + +	return (sysflg & SYSFLG_UBUSY) ? 0 : TIOCSER_TEMT;  }  static unsigned int uart_clps711x_get_mctrl(struct uart_port *port)  { -	unsigned int status, result = 0; +	struct clps711x_port *s = dev_get_drvdata(port->dev); +	unsigned int result = 0; + +	if (s->use_ms) { +		u32 sysflg = 0; -	if (port->line == 0) { -		status = clps_readl(SYSFLG1); -		if (status & SYSFLG1_DCD) +		regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); +		if (sysflg & SYSFLG1_DCD)  			result |= TIOCM_CAR; -		if (status & SYSFLG1_DSR) +		if (sysflg & SYSFLG1_DSR)  			result |= TIOCM_DSR; -		if (status & SYSFLG1_CTS) +		if (sysflg & SYSFLG1_CTS)  			result |= TIOCM_CTS;  	} else  		result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; @@ -194,65 +224,53 @@ static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl)  static void uart_clps711x_break_ctl(struct uart_port *port, int break_state)  { -	unsigned long flags;  	unsigned int ubrlcr; -	spin_lock_irqsave(&port->lock, flags); - -	ubrlcr = clps_readl(UBRLCR(port)); +	ubrlcr = readl(port->membase + UBRLCR_OFFSET);  	if (break_state)  		ubrlcr |= UBRLCR_BREAK;  	else  		ubrlcr &= ~UBRLCR_BREAK; -	clps_writel(ubrlcr, UBRLCR(port)); +	writel(ubrlcr, port->membase + UBRLCR_OFFSET); +} + +static void uart_clps711x_set_ldisc(struct uart_port *port, int ld) +{ +	if (!port->line) { +		struct clps711x_port *s = dev_get_drvdata(port->dev); -	spin_unlock_irqrestore(&port->lock, flags); +		regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON1_SIREN, +				   (ld == N_IRDA) ? SYSCON1_SIREN : 0); +	}  }  static int uart_clps711x_startup(struct uart_port *port)  {  	struct clps711x_port *s = dev_get_drvdata(port->dev); -	int ret; - -	s->tx_enabled[port->line] = 1; -	/* Allocate the IRQs */ -	ret = devm_request_irq(port->dev, TX_IRQ(port), uart_clps711x_int_tx, -			       0, UART_CLPS711X_NAME " TX", port); -	if (ret) -		return ret; - -	ret = devm_request_irq(port->dev, RX_IRQ(port), uart_clps711x_int_rx, -			       0, UART_CLPS711X_NAME " RX", port); -	if (ret) { -		devm_free_irq(port->dev, TX_IRQ(port), port); -		return ret; -	}  	/* Disable break */ -	clps_writel(clps_readl(UBRLCR(port)) & ~UBRLCR_BREAK, UBRLCR(port)); +	writel(readl(port->membase + UBRLCR_OFFSET) & ~UBRLCR_BREAK, +	       port->membase + UBRLCR_OFFSET);  	/* Enable the port */ -	clps_writel(clps_readl(SYSCON(port)) | SYSCON_UARTEN, SYSCON(port)); - -	return 0; +	return regmap_update_bits(s->syscon, SYSCON_OFFSET, +				  SYSCON_UARTEN, SYSCON_UARTEN);  }  static void uart_clps711x_shutdown(struct uart_port *port)  { -	/* Free the interrupts */ -	devm_free_irq(port->dev, TX_IRQ(port), port); -	devm_free_irq(port->dev, RX_IRQ(port), port); +	struct clps711x_port *s = dev_get_drvdata(port->dev);  	/* Disable the port */ -	clps_writel(clps_readl(SYSCON(port)) & ~SYSCON_UARTEN, SYSCON(port)); +	regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0);  }  static void uart_clps711x_set_termios(struct uart_port *port,  				      struct ktermios *termios,  				      struct ktermios *old)  { -	unsigned int ubrlcr, baud, quot; -	unsigned long flags; +	u32 ubrlcr; +	unsigned int baud, quot;  	/* Mask termios capabilities we don't support */  	termios->c_cflag &= ~CMSPAR; @@ -291,8 +309,6 @@ static void uart_clps711x_set_termios(struct uart_port *port,  	/* Enable FIFO */  	ubrlcr |= UBRLCR_FIFOEN; -	spin_lock_irqsave(&port->lock, flags); -  	/* Set read status mask */  	port->read_status_mask = UARTDR_OVERR;  	if (termios->c_iflag & INPCK) @@ -306,9 +322,7 @@ static void uart_clps711x_set_termios(struct uart_port *port,  	uart_update_timeout(port, termios->c_cflag, baud); -	clps_writel(ubrlcr | (quot - 1), UBRLCR(port)); - -	spin_unlock_irqrestore(&port->lock, flags); +	writel(ubrlcr | (quot - 1), port->membase + UBRLCR_OFFSET);  }  static const char *uart_clps711x_type(struct uart_port *port) @@ -322,14 +336,12 @@ static void uart_clps711x_config_port(struct uart_port *port, int flags)  		port->type = PORT_CLPS711X;  } -static void uart_clps711x_release_port(struct uart_port *port) +static void uart_clps711x_nop_void(struct uart_port *port)  { -	/* Do nothing */  } -static int uart_clps711x_request_port(struct uart_port *port) +static int uart_clps711x_nop_int(struct uart_port *port)  { -	/* Do nothing */  	return 0;  } @@ -339,183 +351,238 @@ static const struct uart_ops uart_clps711x_ops = {  	.get_mctrl	= uart_clps711x_get_mctrl,  	.stop_tx	= uart_clps711x_stop_tx,  	.start_tx	= uart_clps711x_start_tx, -	.stop_rx	= uart_clps711x_stop_rx, -	.enable_ms	= uart_clps711x_enable_ms, +	.stop_rx	= uart_clps711x_nop_void, +	.enable_ms	= uart_clps711x_nop_void,  	.break_ctl	= uart_clps711x_break_ctl, +	.set_ldisc	= uart_clps711x_set_ldisc,  	.startup	= uart_clps711x_startup,  	.shutdown	= uart_clps711x_shutdown,  	.set_termios	= uart_clps711x_set_termios,  	.type		= uart_clps711x_type,  	.config_port	= uart_clps711x_config_port, -	.release_port	= uart_clps711x_release_port, -	.request_port	= uart_clps711x_request_port, +	.release_port	= uart_clps711x_nop_void, +	.request_port	= uart_clps711x_nop_int,  };  #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE  static void uart_clps711x_console_putchar(struct uart_port *port, int ch)  { -	while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF) -		barrier(); +	struct clps711x_port *s = dev_get_drvdata(port->dev); +	u32 sysflg = 0; + +	/* Wait for FIFO is not full */ +	do { +		regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); +	} while (sysflg & SYSFLG_UTXFF); -	clps_writew(ch, UARTDR(port)); +	writew(ch, port->membase + UARTDR_OFFSET);  }  static void uart_clps711x_console_write(struct console *co, const char *c,  					unsigned n)  { -	struct clps711x_port *s = (struct clps711x_port *)co->data; -	struct uart_port *port = &s->port[co->index]; -	u32 syscon; - -	/* Ensure that the port is enabled */ -	syscon = clps_readl(SYSCON(port)); -	clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); +	struct uart_port *port = clps711x_uart.state[co->index].uart_port; +	struct clps711x_port *s = dev_get_drvdata(port->dev); +	u32 sysflg = 0;  	uart_console_write(port, c, n, uart_clps711x_console_putchar);  	/* Wait for transmitter to become empty */ -	while (clps_readl(SYSFLG(port)) & SYSFLG_UBUSY) -		barrier(); - -	/* Restore the uart state */ -	clps_writel(syscon, SYSCON(port)); +	do { +		regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); +	} while (sysflg & SYSFLG_UBUSY);  } -static void uart_clps711x_console_get_options(struct uart_port *port, -					      int *baud, int *parity, -					      int *bits) +static int uart_clps711x_console_setup(struct console *co, char *options)  { -	if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) { -		unsigned int ubrlcr, quot; +	int baud = 38400, bits = 8, parity = 'n', flow = 'n'; +	int ret, index = co->index; +	struct clps711x_port *s; +	struct uart_port *port; +	unsigned int quot; +	u32 ubrlcr; -		ubrlcr = clps_readl(UBRLCR(port)); +	if (index < 0 || index >= UART_CLPS711X_NR) +		return -EINVAL; -		*parity = 'n'; -		if (ubrlcr & UBRLCR_PRTEN) { -			if (ubrlcr & UBRLCR_EVENPRT) -				*parity = 'e'; -			else -				*parity = 'o'; -		} +	port = clps711x_uart.state[index].uart_port; +	if (!port) +		return -ENODEV; -		if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) -			*bits = 7; -		else -			*bits = 8; +	s = dev_get_drvdata(port->dev); -		quot = ubrlcr & UBRLCR_BAUD_MASK; -		*baud = port->uartclk / (16 * (quot + 1)); -	} -} +	if (!options) { +		u32 syscon = 0; -static int uart_clps711x_console_setup(struct console *co, char *options) -{ -	int baud = 38400, bits = 8, parity = 'n', flow = 'n'; -	struct clps711x_port *s = (struct clps711x_port *)co->data; -	struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0]; +		regmap_read(s->syscon, SYSCON_OFFSET, &syscon); +		if (syscon & SYSCON_UARTEN) { +			ubrlcr = readl(port->membase + UBRLCR_OFFSET); + +			if (ubrlcr & UBRLCR_PRTEN) { +				if (ubrlcr & UBRLCR_EVENPRT) +					parity = 'e'; +				else +					parity = 'o'; +			} + +			if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) +				bits = 7; -	if (options) +			quot = ubrlcr & UBRLCR_BAUD_MASK; +			baud = port->uartclk / (16 * (quot + 1)); +		} +	} else  		uart_parse_options(options, &baud, &parity, &bits, &flow); -	else -		uart_clps711x_console_get_options(port, &baud, &parity, &bits); -	return uart_set_options(port, co, baud, parity, bits, flow); +	ret = uart_set_options(port, co, baud, parity, bits, flow); +	if (ret) +		return ret; + +	return regmap_update_bits(s->syscon, SYSCON_OFFSET, +				  SYSCON_UARTEN, SYSCON_UARTEN);  } + +static struct console clps711x_console = { +	.name	= UART_CLPS711X_DEVNAME, +	.device	= uart_console_device, +	.write	= uart_clps711x_console_write, +	.setup	= uart_clps711x_console_setup, +	.flags	= CON_PRINTBUFFER, +	.index	= -1, +};  #endif  static int uart_clps711x_probe(struct platform_device *pdev)  { +	struct device_node *np = pdev->dev.of_node; +	int ret, index = np ? of_alias_get_id(np, "serial") : pdev->id;  	struct clps711x_port *s; -	int ret, i; +	struct resource *res; +	struct clk *uart_clk; -	s = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_port), GFP_KERNEL); -	if (!s) { -		dev_err(&pdev->dev, "Error allocating port structure\n"); +	if (index < 0 || index >= UART_CLPS711X_NR) +		return -EINVAL; + +	s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); +	if (!s)  		return -ENOMEM; + +	uart_clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(uart_clk)) +		return PTR_ERR(uart_clk); + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	s->port.membase = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(s->port.membase)) +		return PTR_ERR(s->port.membase); + +	s->port.irq = platform_get_irq(pdev, 0); +	if (IS_ERR_VALUE(s->port.irq)) +		return s->port.irq; + +	s->rx_irq = platform_get_irq(pdev, 1); +	if (IS_ERR_VALUE(s->rx_irq)) +		return s->rx_irq; + +	if (!np) { +		char syscon_name[9]; + +		sprintf(syscon_name, "syscon.%i", index + 1); +		s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name); +		if (IS_ERR(s->syscon)) +			return PTR_ERR(s->syscon); + +		s->use_ms = !index; +	} else { +		s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); +		if (IS_ERR(s->syscon)) +			return PTR_ERR(s->syscon); + +		if (!index) +			s->use_ms = of_property_read_bool(np, "uart-use-ms");  	} + +	s->port.line		= index; +	s->port.dev		= &pdev->dev; +	s->port.iotype		= UPIO_MEM32; +	s->port.mapbase		= res->start; +	s->port.type		= PORT_CLPS711X; +	s->port.fifosize	= 16; +	s->port.flags		= UPF_SKIP_TEST | UPF_FIXED_TYPE; +	s->port.uartclk		= clk_get_rate(uart_clk); +	s->port.ops		= &uart_clps711x_ops; +  	platform_set_drvdata(pdev, s); -	s->uart_clk = devm_clk_get(&pdev->dev, "uart"); -	if (IS_ERR(s->uart_clk)) { -		dev_err(&pdev->dev, "Can't get UART clocks\n"); -		return PTR_ERR(s->uart_clk); -	} +	ret = uart_add_one_port(&clps711x_uart, &s->port); +	if (ret) +		return ret; -	s->uart.owner		= THIS_MODULE; -	s->uart.dev_name	= "ttyCL"; -	s->uart.major		= UART_CLPS711X_MAJOR; -	s->uart.minor		= UART_CLPS711X_MINOR; -	s->uart.nr		= UART_CLPS711X_NR; -#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE -	s->uart.cons		= &s->console; -	s->uart.cons->device	= uart_console_device; -	s->uart.cons->write	= uart_clps711x_console_write; -	s->uart.cons->setup	= uart_clps711x_console_setup; -	s->uart.cons->flags	= CON_PRINTBUFFER; -	s->uart.cons->index	= -1; -	s->uart.cons->data	= s; -	strcpy(s->uart.cons->name, "ttyCL"); -#endif -	ret = uart_register_driver(&s->uart); +	/* Disable port */ +	if (!uart_console(&s->port)) +		regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0); + +	s->tx_enabled = 1; + +	ret = devm_request_irq(&pdev->dev, s->port.irq, uart_clps711x_int_tx, 0, +			       dev_name(&pdev->dev), &s->port);  	if (ret) { -		dev_err(&pdev->dev, "Registering UART driver failed\n"); -		devm_clk_put(&pdev->dev, s->uart_clk); +		uart_remove_one_port(&clps711x_uart, &s->port);  		return ret;  	} -	for (i = 0; i < UART_CLPS711X_NR; i++) { -		s->port[i].line		= i; -		s->port[i].dev		= &pdev->dev; -		s->port[i].irq		= TX_IRQ(&s->port[i]); -		s->port[i].iobase	= SYSCON(&s->port[i]); -		s->port[i].type		= PORT_CLPS711X; -		s->port[i].fifosize	= 16; -		s->port[i].flags	= UPF_SKIP_TEST | UPF_FIXED_TYPE; -		s->port[i].uartclk	= clk_get_rate(s->uart_clk); -		s->port[i].ops		= &uart_clps711x_ops; -		WARN_ON(uart_add_one_port(&s->uart, &s->port[i])); -	} +	ret = devm_request_irq(&pdev->dev, s->rx_irq, uart_clps711x_int_rx, 0, +			       dev_name(&pdev->dev), &s->port); +	if (ret) +		uart_remove_one_port(&clps711x_uart, &s->port); -	return 0; +	return ret;  }  static int uart_clps711x_remove(struct platform_device *pdev)  {  	struct clps711x_port *s = platform_get_drvdata(pdev); -	int i; -	for (i = 0; i < UART_CLPS711X_NR; i++) -		uart_remove_one_port(&s->uart, &s->port[i]); - -	devm_clk_put(&pdev->dev, s->uart_clk); -	uart_unregister_driver(&s->uart); - -	return 0; +	return uart_remove_one_port(&clps711x_uart, &s->port);  } -static struct platform_driver clps711x_uart_driver = { +static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = { +	{ .compatible = "cirrus,clps711x-uart", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids); + +static struct platform_driver clps711x_uart_platform = {  	.driver = { -		.name	= UART_CLPS711X_NAME, -		.owner	= THIS_MODULE, +		.name		= "clps711x-uart", +		.owner		= THIS_MODULE, +		.of_match_table	= of_match_ptr(clps711x_uart_dt_ids),  	},  	.probe	= uart_clps711x_probe,  	.remove	= uart_clps711x_remove,  }; -module_platform_driver(clps711x_uart_driver); - -static struct platform_device clps711x_uart_device = { -	.name	= UART_CLPS711X_NAME, -};  static int __init uart_clps711x_init(void)  { -	return platform_device_register(&clps711x_uart_device); +	int ret; + +#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE +	clps711x_uart.cons = &clps711x_console; +	clps711x_console.data = &clps711x_uart; +#endif + +	ret = uart_register_driver(&clps711x_uart); +	if (ret) +		return ret; + +	return platform_driver_register(&clps711x_uart_platform);  }  module_init(uart_clps711x_init);  static void __exit uart_clps711x_exit(void)  { -	platform_device_unregister(&clps711x_uart_device); +	platform_driver_unregister(&clps711x_uart_platform); +	uart_unregister_driver(&clps711x_uart);  }  module_exit(uart_clps711x_exit); diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 1a535f70dc4..aa60e6d13ec 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -41,6 +41,8 @@  #include <linux/bootmem.h>  #include <linux/dma-mapping.h>  #include <linux/fs_uart_pd.h> +#include <linux/of_address.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h>  #include <linux/gpio.h>  #include <linux/of_gpio.h> @@ -969,7 +971,7 @@ static void cpm_uart_config_port(struct uart_port *port, int flags)   * Note that this is called with interrupts already disabled   */  static void cpm_uart_early_write(struct uart_cpm_port *pinfo, -		const char *string, u_int count) +		const char *string, u_int count, bool handle_linefeed)  {  	unsigned int i;  	cbd_t __iomem *bdp, *bdbase; @@ -1011,7 +1013,7 @@ static void cpm_uart_early_write(struct uart_cpm_port *pinfo,  			bdp++;  		/* if a LF, also do CR... */ -		if (*string == 10) { +		if (handle_linefeed && *string == 10) {  			while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)  				; @@ -1109,7 +1111,7 @@ static void cpm_put_poll_char(struct uart_port *port,  	static char ch[2];  	ch[0] = (char)c; -	cpm_uart_early_write(pinfo, ch, 1); +	cpm_uart_early_write(pinfo, ch, 1, false);  }  #endif /* CONFIG_CONSOLE_POLL */ @@ -1207,7 +1209,7 @@ static int cpm_uart_init_port(struct device_node *np,  	pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize;  	spin_lock_init(&pinfo->port.lock); -	pinfo->port.irq = of_irq_to_resource(np, 0, NULL); +	pinfo->port.irq = irq_of_parse_and_map(np, 0);  	if (pinfo->port.irq == NO_IRQ) {  		ret = -EINVAL;  		goto out_pram; @@ -1273,7 +1275,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,  		spin_lock_irqsave(&pinfo->port.lock, flags);  	} -	cpm_uart_early_write(pinfo, s, count); +	cpm_uart_early_write(pinfo, s, count, true);  	if (unlikely(nolock)) {  		local_irq_restore(flags); diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c index 18f79575894..6d3b22e9324 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c @@ -29,7 +29,6 @@  #include <linux/tty.h>  #include <linux/gfp.h>  #include <linux/ioport.h> -#include <linux/init.h>  #include <linux/serial.h>  #include <linux/console.h>  #include <linux/sysrq.h> @@ -45,6 +44,7 @@  #include <linux/kernel.h>  #include <linux/of.h> +#include <linux/of_address.h>  #include "cpm_uart.h" diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c index a4927e66e74..f46d2ca8720 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c @@ -29,7 +29,6 @@  #include <linux/tty.h>  #include <linux/ioport.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/serial.h>  #include <linux/console.h>  #include <linux/sysrq.h> diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 477f22f773f..d567ac5d3af 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -286,7 +286,6 @@ static struct e100_serial rs_table[] = {  #endif  },  /* ttyS0 */ -#ifndef CONFIG_SVINTO_SIM  	{ .baud        = DEF_BAUD,  	  .ioport        = (unsigned char *)R_SERIAL1_CTRL,  	  .irq         = 1U << 16, /* uses DMA 8 and 9 */ @@ -447,7 +446,6 @@ static struct e100_serial rs_table[] = {  	  .dma_in_enabled = 0  #endif   }   /* ttyS3 */ -#endif  }; @@ -1035,7 +1033,6 @@ cflag_to_etrax_baud(unsigned int cflag)  static inline void  e100_dtr(struct e100_serial *info, int set)  { -#ifndef CONFIG_SVINTO_SIM  	unsigned char mask = e100_modem_pins[info->line].dtr_mask;  #ifdef SERIAL_DEBUG_IO @@ -1060,7 +1057,6 @@ e100_dtr(struct e100_serial *info, int set)  	       info->line, *e100_modem_pins[info->line].dtr_shadow,  	       E100_DTR_GET(info));  #endif -#endif  }  /* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive @@ -1069,7 +1065,6 @@ e100_dtr(struct e100_serial *info, int set)  static inline void  e100_rts(struct e100_serial *info, int set)  { -#ifndef CONFIG_SVINTO_SIM  	unsigned long flags;  	local_irq_save(flags);  	info->rx_ctrl &= ~E100_RTS_MASK; @@ -1079,7 +1074,6 @@ e100_rts(struct e100_serial *info, int set)  #ifdef SERIAL_DEBUG_IO  	printk("ser%i rts %i\n", info->line, set);  #endif -#endif  } @@ -1087,7 +1081,6 @@ e100_rts(struct e100_serial *info, int set)  static inline void  e100_ri_out(struct e100_serial *info, int set)  { -#ifndef CONFIG_SVINTO_SIM  	/* RI is active low */  	{  		unsigned char mask = e100_modem_pins[info->line].ri_mask; @@ -1099,12 +1092,10 @@ e100_ri_out(struct e100_serial *info, int set)  		*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;  		local_irq_restore(flags);  	} -#endif  }  static inline void  e100_cd_out(struct e100_serial *info, int set)  { -#ifndef CONFIG_SVINTO_SIM  	/* CD is active low */  	{  		unsigned char mask = e100_modem_pins[info->line].cd_mask; @@ -1116,27 +1107,22 @@ e100_cd_out(struct e100_serial *info, int set)  		*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;  		local_irq_restore(flags);  	} -#endif  }  static inline void  e100_disable_rx(struct e100_serial *info)  { -#ifndef CONFIG_SVINTO_SIM  	/* disable the receiver */  	info->ioport[REG_REC_CTRL] =  		(info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -#endif  }  static inline void  e100_enable_rx(struct e100_serial *info)  { -#ifndef CONFIG_SVINTO_SIM  	/* enable the receiver */  	info->ioport[REG_REC_CTRL] =  		(info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -#endif  }  /* the rx DMA uses both the dma_descr and the dma_eop interrupts */ @@ -1554,24 +1540,6 @@ transmit_chars_dma(struct e100_serial *info)  	unsigned int c, sentl;  	struct etrax_dma_descr *descr; -#ifdef CONFIG_SVINTO_SIM -	/* This will output too little if tail is not 0 always since -	 * we don't reloop to send the other part. Anyway this SHOULD be a -	 * no-op - transmit_chars_dma would never really be called during sim -	 * since rs_write does not write into the xmit buffer then. -	 */ -	if (info->xmit.tail) -		printk("Error in serial.c:transmit_chars-dma(), tail!=0\n"); -	if (info->xmit.head != info->xmit.tail) { -		SIMCOUT(info->xmit.buf + info->xmit.tail, -			CIRC_CNT(info->xmit.head, -				 info->xmit.tail, -				 SERIAL_XMIT_SIZE)); -		info->xmit.head = info->xmit.tail;  /* move back head */ -		info->tr_running = 0; -	} -	return; -#endif  	/* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */  	*info->oclrintradr =  		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | @@ -1842,13 +1810,6 @@ static void receive_chars_dma(struct e100_serial *info)  	struct tty_struct *tty;  	unsigned char rstat; -#ifdef CONFIG_SVINTO_SIM -	/* No receive in the simulator.  Will probably be when the rest of -	 * the serial interface works, and this piece will just be removed. -	 */ -	return; -#endif -  	/* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */  	*info->iclrintradr =  		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | @@ -1934,12 +1895,6 @@ static int start_recv_dma(struct e100_serial *info)  static void  start_receive(struct e100_serial *info)  { -#ifdef CONFIG_SVINTO_SIM -	/* No receive in the simulator.  Will probably be when the rest of -	 * the serial interface works, and this piece will just be removed. -	 */ -	return; -#endif  	if (info->uses_dma_in) {  		/* reset the input dma channel to be sure it works */ @@ -1972,17 +1927,6 @@ tr_interrupt(int irq, void *dev_id)  	int i;  	int handled = 0; -#ifdef CONFIG_SVINTO_SIM -	/* No receive in the simulator.  Will probably be when the rest of -	 * the serial interface works, and this piece will just be removed. -	 */ -	{ -		const char *s = "What? tr_interrupt in simulator??\n"; -		SIMCOUT(s,strlen(s)); -	} -	return IRQ_HANDLED; -#endif -  	/* find out the line that caused this irq and get it from rs_table */  	ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */ @@ -2021,17 +1965,6 @@ rec_interrupt(int irq, void *dev_id)  	int i;  	int handled = 0; -#ifdef CONFIG_SVINTO_SIM -	/* No receive in the simulator.  Will probably be when the rest of -	 * the serial interface works, and this piece will just be removed. -	 */ -	{ -		const char *s = "What? rec_interrupt in simulator??\n"; -		SIMCOUT(s,strlen(s)); -	} -	return IRQ_HANDLED; -#endif -  	/* find out the line that caused this irq and get it from rs_table */  	ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */ @@ -2153,7 +2086,7 @@ static void flush_timeout_function(unsigned long data)  	fast_timers[info->line].function = NULL;  	serial_fast_timer_expired++; -	TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line)); +	TIMERD(DEBUG_LOG(info->line, "flush_timeout %i ", info->line));  	TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired));  	check_flush_timeout(info);  } @@ -2173,10 +2106,6 @@ timed_flush_handler(unsigned long ptr)  	struct e100_serial *info;  	int i; -#ifdef CONFIG_SVINTO_SIM -	return; -#endif -  	for (i = 0; i < NR_PORTS; i++) {  		info = rs_table + i;  		if (info->uses_dma_in) @@ -2729,25 +2658,6 @@ startup(struct e100_serial * info)  	printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);  #endif -#ifdef CONFIG_SVINTO_SIM -	/* Bits and pieces collected from below.  Better to have them -	   in one ifdef:ed clause than to mix in a lot of ifdefs, -	   right? */ -	if (info->port.tty) -		clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - -	info->xmit.head = info->xmit.tail = 0; -	info->first_recv_buffer = info->last_recv_buffer = NULL; -	info->recv_cnt = info->max_recv_cnt = 0; - -	for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) -		info->rec_descr[i].buf = NULL; - -	/* No real action in the simulator, but may set info important -	   to ioctl. */ -	change_speed(info); -#else -  	/*  	 * Clear the FIFO buffers and disable them  	 * (they will be reenabled in change_speed()) @@ -2837,8 +2747,6 @@ startup(struct e100_serial * info)  	e100_rts(info, 1);  	e100_dtr(info, 1); -#endif /* CONFIG_SVINTO_SIM */ -  	info->port.flags |= ASYNC_INITIALIZED;  	local_irq_restore(flags); @@ -2857,7 +2765,6 @@ shutdown(struct e100_serial * info)  	struct etrax_recv_buffer *buffer;  	int i; -#ifndef CONFIG_SVINTO_SIM  	/* shut down the transmitter and receiver */  	DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));  	e100_disable_rx(info); @@ -2882,8 +2789,6 @@ shutdown(struct e100_serial * info)  		info->tr_running = 0;  	} -#endif /* CONFIG_SVINTO_SIM */ -  	if (!(info->port.flags & ASYNC_INITIALIZED))  		return; @@ -2995,17 +2900,12 @@ change_speed(struct e100_serial *info)  			IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);  		r_alt_ser_baudrate_shadow &= ~mask;  		r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); -#ifndef CONFIG_SVINTO_SIM  		*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; -#endif /* CONFIG_SVINTO_SIM */  		info->baud = cflag_to_baud(cflag); -#ifndef CONFIG_SVINTO_SIM  		info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag); -#endif /* CONFIG_SVINTO_SIM */  	} -#ifndef CONFIG_SVINTO_SIM  	/* start with default settings and then fill in changes */  	local_irq_save(flags);  	/* 8 bit, no/even parity */ @@ -3073,7 +2973,6 @@ change_speed(struct e100_serial *info)  	*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;  	local_irq_restore(flags); -#endif /* !CONFIG_SVINTO_SIM */  	update_char_time(info); @@ -3122,11 +3021,6 @@ static int rs_raw_write(struct tty_struct *tty,  		       count, info->ioport[REG_STATUS]);  #endif -#ifdef CONFIG_SVINTO_SIM -	/* Really simple.  The output is here and now. */ -	SIMCOUT(buf, count); -	return count; -#endif  	local_save_flags(flags);  	DFLOW(DEBUG_LOG(info->line, "write count %i ", count));  	DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty))); @@ -3463,7 +3357,6 @@ static int  get_lsr_info(struct e100_serial * info, unsigned int *value)  {  	unsigned int result = TIOCSER_TEMT; -#ifndef CONFIG_SVINTO_SIM  	unsigned long curr_time = jiffies;  	unsigned long curr_time_usec = GET_JIFFIES_USEC();  	unsigned long elapsed_usec = @@ -3474,7 +3367,6 @@ get_lsr_info(struct e100_serial * info, unsigned int *value)  	    elapsed_usec < 2*info->char_time_usec) {  		result = 0;  	} -#endif  	if (copy_to_user(value, &result, sizeof(int)))  		return -EFAULT; @@ -3804,7 +3696,6 @@ rs_close(struct tty_struct *tty, struct file * filp)  	e100_disable_serial_data_irq(info);  #endif -#ifndef CONFIG_SVINTO_SIM  	e100_disable_rx(info);  	e100_disable_rx_irq(info); @@ -3816,7 +3707,6 @@ rs_close(struct tty_struct *tty, struct file * filp)  		 */  		rs_wait_until_sent(tty, HZ);  	} -#endif  	shutdown(info);  	rs_flush_buffer(tty); @@ -4479,7 +4369,6 @@ static int __init rs_init(void)  	fast_timer_init();  #endif -#ifndef CONFIG_SVINTO_SIM  #ifndef CONFIG_ETRAX_KGDB  	/* Not needed in simulator.  May only complicate stuff. */  	/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ @@ -4489,7 +4378,6 @@ static int __init rs_init(void)  		panic("%s: Failed to request irq8", __func__);  #endif -#endif /* CONFIG_SVINTO_SIM */  	return 0;  } diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index 2f2b2e538a5..cdbbc788230 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -625,7 +625,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,  	dport->port.read_status_mask = DZ_OERR;  	if (termios->c_iflag & INPCK)  		dport->port.read_status_mask |= DZ_FERR | DZ_PERR; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		dport->port.read_status_mask |= DZ_BREAK;  	/* characters to ignore */ diff --git a/drivers/tty/serial/earlycon-arm-semihost.c b/drivers/tty/serial/earlycon-arm-semihost.c new file mode 100644 index 00000000000..383db10fbb4 --- /dev/null +++ b/drivers/tty/serial/earlycon-arm-semihost.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * Author: Marc Zyngier <marc.zyngier@arm.com> + * + * Adapted for ARM and earlycon: + * Copyright (C) 2014 Linaro Ltd. + * Author: Rob Herring <robh@kernel.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#include <linux/kernel.h> +#include <linux/console.h> +#include <linux/init.h> +#include <linux/serial_core.h> + +#ifdef CONFIG_THUMB2_KERNEL +#define SEMIHOST_SWI	"0xab" +#else +#define SEMIHOST_SWI	"0x123456" +#endif + +/* + * Semihosting-based debug console + */ +static void smh_putc(struct uart_port *port, int c) +{ +#ifdef CONFIG_ARM64 +	asm volatile("mov  x1, %0\n" +		     "mov  x0, #3\n" +		     "hlt  0xf000\n" +		     : : "r" (&c) : "x0", "x1", "memory"); +#else +	asm volatile("mov  r1, %0\n" +		     "mov  r0, #3\n" +		     "svc  " SEMIHOST_SWI "\n" +		     : : "r" (&c) : "r0", "r1", "memory"); +#endif +} + +static void smh_write(struct console *con, const char *s, unsigned n) +{ +	struct earlycon_device *dev = con->data; +	uart_console_write(&dev->port, s, n, smh_putc); +} + +int __init early_smh_setup(struct earlycon_device *device, const char *opt) +{ +	device->con->write = smh_write; +	return 0; +} +EARLYCON_DECLARE(smh, early_smh_setup); diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c new file mode 100644 index 00000000000..a514ee6f540 --- /dev/null +++ b/drivers/tty/serial/earlycon.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * Author: Rob Herring <robh@kernel.org> + * + * Based on 8250 earlycon: + * (c) Copyright 2004 Hewlett-Packard Development Company, L.P. + *	Bjorn Helgaas <bjorn.helgaas@hp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/console.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/serial_core.h> +#include <linux/sizes.h> +#include <linux/mod_devicetable.h> + +#ifdef CONFIG_FIX_EARLYCON_MEM +#include <asm/fixmap.h> +#endif + +#include <asm/serial.h> + +static struct console early_con = { +	.name =		"uart", /* 8250 console switch requires this name */ +	.flags =	CON_PRINTBUFFER | CON_BOOT, +	.index =	-1, +}; + +static struct earlycon_device early_console_dev = { +	.con = &early_con, +}; + +static const struct of_device_id __earlycon_of_table_sentinel +	__used __section(__earlycon_of_table_end); + +static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) +{ +	void __iomem *base; +#ifdef CONFIG_FIX_EARLYCON_MEM +	set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK); +	base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); +	base += paddr & ~PAGE_MASK; +#else +	base = ioremap(paddr, size); +#endif +	if (!base) +		pr_err("%s: Couldn't map 0x%llx\n", __func__, +		       (unsigned long long)paddr); + +	return base; +} + +static int __init parse_options(struct earlycon_device *device, +				char *options) +{ +	struct uart_port *port = &device->port; +	int mmio, mmio32, length; +	unsigned long addr; + +	if (!options) +		return -ENODEV; + +	mmio = !strncmp(options, "mmio,", 5); +	mmio32 = !strncmp(options, "mmio32,", 7); +	if (mmio || mmio32) { +		port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); +		options += mmio ? 5 : 7; +		addr = simple_strtoul(options, NULL, 0); +		port->mapbase = addr; +		if (mmio32) +			port->regshift = 2; +	} else if (!strncmp(options, "io,", 3)) { +		port->iotype = UPIO_PORT; +		options += 3; +		addr = simple_strtoul(options, NULL, 0); +		port->iobase = addr; +		mmio = 0; +	} else if (!strncmp(options, "0x", 2)) { +		port->iotype = UPIO_MEM; +		addr = simple_strtoul(options, NULL, 0); +		port->mapbase = addr; +	} else { +		return -EINVAL; +	} + +	port->uartclk = BASE_BAUD * 16; + +	options = strchr(options, ','); +	if (options) { +		options++; +		device->baud = simple_strtoul(options, NULL, 0); +		length = min(strcspn(options, " ") + 1, +			     (size_t)(sizeof(device->options))); +		strlcpy(device->options, options, length); +	} + +	if (mmio || mmio32) +		pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", +			mmio32 ? "32" : "", +			(unsigned long long)port->mapbase, +			device->options); +	else +		pr_info("Early serial console at I/O port 0x%lx (options '%s')\n", +			port->iobase, +			device->options); + +	return 0; +} + +int __init setup_earlycon(char *buf, const char *match, +			  int (*setup)(struct earlycon_device *, const char *)) +{ +	int err; +	size_t len; +	struct uart_port *port = &early_console_dev.port; + +	if (!buf || !match || !setup) +		return 0; + +	len = strlen(match); +	if (strncmp(buf, match, len)) +		return 0; +	if (buf[len] && (buf[len] != ',')) +		return 0; + +	buf += len + 1; + +	err = parse_options(&early_console_dev, buf); +	/* On parsing error, pass the options buf to the setup function */ +	if (!err) +		buf = NULL; + +	if (port->mapbase) +		port->membase = earlycon_map(port->mapbase, 64); + +	early_console_dev.con->data = &early_console_dev; +	err = setup(&early_console_dev, buf); +	if (err < 0) +		return err; +	if (!early_console_dev.con->write) +		return -ENODEV; + +	register_console(early_console_dev.con); +	return 0; +} + +int __init of_setup_earlycon(unsigned long addr, +			     int (*setup)(struct earlycon_device *, const char *)) +{ +	int err; +	struct uart_port *port = &early_console_dev.port; + +	port->iotype = UPIO_MEM; +	port->mapbase = addr; +	port->uartclk = BASE_BAUD * 16; +	port->membase = earlycon_map(addr, SZ_4K); + +	early_console_dev.con->data = &early_console_dev; +	err = setup(&early_console_dev, NULL); +	if (err < 0) +		return err; +	if (!early_console_dev.con->write) +		return -ENODEV; + + +	register_console(early_console_dev.con); +	return 0; +} diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 0eb5b5673ed..3b0ee9afd76 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -407,7 +407,7 @@ static void efm32_uart_set_termios(struct uart_port *port,  	if (new->c_iflag & INPCK)  		port->read_status_mask |=  			UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; -	if (new->c_iflag & (BRKINT | PARMRK)) +	if (new->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= SW_UARTn_RXDATAX_BERR;  	port->ignore_status_mask = 0; @@ -671,7 +671,10 @@ static int efm32_uart_probe_dt(struct platform_device *pdev,  	if (!np)  		return 1; -	ret = of_property_read_u32(np, "location", &location); +	ret = of_property_read_u32(np, "efm32,location", &location); +	if (ret) +		/* fall back to old and (wrongly) generic property "location" */ +		ret = of_property_read_u32(np, "location", &location);  	if (!ret) {  		if (location > 5) {  			dev_err(&pdev->dev, "invalid location\n"); @@ -795,6 +798,9 @@ static int efm32_uart_remove(struct platform_device *pdev)  static const struct of_device_id efm32_uart_dt_ids[] = {  	{ +		.compatible = "energymicro,efm32-uart", +	}, { +		/* doesn't follow the "vendor,device" scheme, don't use */  		.compatible = "efm32,uart",  	}, {  		/* sentinel */ @@ -836,6 +842,7 @@ static void __exit efm32_uart_exit(void)  	platform_driver_unregister(&efm32_uart_driver);  	uart_unregister_driver(&efm32_uart_reg);  } +module_exit(efm32_uart_exit);  MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");  MODULE_DESCRIPTION("EFM32 UART/USART driver"); diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 8978dc9a58b..49385c86cfb 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -13,14 +13,19 @@  #define SUPPORT_SYSRQ  #endif -#include <linux/module.h> +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/dmapool.h>  #include <linux/io.h>  #include <linux/irq.h> -#include <linux/clk.h> +#include <linux/module.h>  #include <linux/of.h>  #include <linux/of_device.h> -#include <linux/console.h> +#include <linux/of_dma.h>  #include <linux/serial_core.h> +#include <linux/slab.h>  #include <linux/tty_flip.h>  /* All registers are 8-bit width */ @@ -112,6 +117,10 @@  #define UARTSFIFO_TXOF		0x02  #define UARTSFIFO_RXUF		0x01 +#define DMA_MAXBURST		16 +#define DMA_MAXBURST_MASK	(DMA_MAXBURST - 1) +#define FSL_UART_RX_DMA_BUFFER_SIZE	64 +  #define DRIVER_NAME	"fsl-lpuart"  #define DEV_NAME	"ttyLP"  #define UART_NR		6 @@ -121,6 +130,24 @@ struct lpuart_port {  	struct clk		*clk;  	unsigned int		txfifo_size;  	unsigned int		rxfifo_size; + +	bool			lpuart_dma_use; +	struct dma_chan		*dma_tx_chan; +	struct dma_chan		*dma_rx_chan; +	struct dma_async_tx_descriptor  *dma_tx_desc; +	struct dma_async_tx_descriptor  *dma_rx_desc; +	dma_addr_t		dma_tx_buf_bus; +	dma_addr_t		dma_rx_buf_bus; +	dma_cookie_t		dma_tx_cookie; +	dma_cookie_t		dma_rx_cookie; +	unsigned char		*dma_tx_buf_virt; +	unsigned char		*dma_rx_buf_virt; +	unsigned int		dma_tx_bytes; +	unsigned int		dma_rx_bytes; +	int			dma_tx_in_progress; +	int			dma_rx_in_progress; +	unsigned int		dma_rx_timeout; +	struct timer_list	lpuart_timer;  };  static struct of_device_id lpuart_dt_ids[] = { @@ -131,6 +158,10 @@ static struct of_device_id lpuart_dt_ids[] = {  };  MODULE_DEVICE_TABLE(of, lpuart_dt_ids); +/* Forward declare this for the dma callbacks*/ +static void lpuart_dma_tx_complete(void *arg); +static void lpuart_dma_rx_complete(void *arg); +  static void lpuart_stop_tx(struct uart_port *port)  {  	unsigned char temp; @@ -152,6 +183,210 @@ static void lpuart_enable_ms(struct uart_port *port)  {  } +static void lpuart_copy_rx_to_tty(struct lpuart_port *sport, +		struct tty_port *tty, int count) +{ +	int copied; + +	sport->port.icount.rx += count; + +	if (!tty) { +		dev_err(sport->port.dev, "No tty port\n"); +		return; +	} + +	dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus, +			FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); +	copied = tty_insert_flip_string(tty, +			((unsigned char *)(sport->dma_rx_buf_virt)), count); + +	if (copied != count) { +		WARN_ON(1); +		dev_err(sport->port.dev, "RxData copy to tty layer failed\n"); +	} + +	dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus, +			FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); +} + +static void lpuart_pio_tx(struct lpuart_port *sport) +{ +	struct circ_buf *xmit = &sport->port.state->xmit; +	unsigned long flags; + +	spin_lock_irqsave(&sport->port.lock, flags); + +	while (!uart_circ_empty(xmit) && +		readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) { +		writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR); +		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); +		sport->port.icount.tx++; +	} + +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) +		uart_write_wakeup(&sport->port); + +	if (uart_circ_empty(xmit)) +		writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, +			sport->port.membase + UARTCR5); + +	spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count) +{ +	struct circ_buf *xmit = &sport->port.state->xmit; +	dma_addr_t tx_bus_addr; + +	dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus, +				UART_XMIT_SIZE, DMA_TO_DEVICE); +	sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK); +	tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail; +	sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan, +					tx_bus_addr, sport->dma_tx_bytes, +					DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); + +	if (!sport->dma_tx_desc) { +		dev_err(sport->port.dev, "Not able to get desc for tx\n"); +		return -EIO; +	} + +	sport->dma_tx_desc->callback = lpuart_dma_tx_complete; +	sport->dma_tx_desc->callback_param = sport; +	sport->dma_tx_in_progress = 1; +	sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc); +	dma_async_issue_pending(sport->dma_tx_chan); + +	return 0; +} + +static void lpuart_prepare_tx(struct lpuart_port *sport) +{ +	struct circ_buf *xmit = &sport->port.state->xmit; +	unsigned long count =  CIRC_CNT_TO_END(xmit->head, +					xmit->tail, UART_XMIT_SIZE); + +	if (!count) +		return; + +	if (count < DMA_MAXBURST) +		writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS, +				sport->port.membase + UARTCR5); +	else { +		writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, +				sport->port.membase + UARTCR5); +		lpuart_dma_tx(sport, count); +	} +} + +static void lpuart_dma_tx_complete(void *arg) +{ +	struct lpuart_port *sport = arg; +	struct circ_buf *xmit = &sport->port.state->xmit; +	unsigned long flags; + +	async_tx_ack(sport->dma_tx_desc); + +	spin_lock_irqsave(&sport->port.lock, flags); + +	xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1); +	sport->dma_tx_in_progress = 0; + +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) +		uart_write_wakeup(&sport->port); + +	lpuart_prepare_tx(sport); + +	spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int lpuart_dma_rx(struct lpuart_port *sport) +{ +	dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus, +			FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); +	sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan, +			sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE, +			DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + +	if (!sport->dma_rx_desc) { +		dev_err(sport->port.dev, "Not able to get desc for rx\n"); +		return -EIO; +	} + +	sport->dma_rx_desc->callback = lpuart_dma_rx_complete; +	sport->dma_rx_desc->callback_param = sport; +	sport->dma_rx_in_progress = 1; +	sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc); +	dma_async_issue_pending(sport->dma_rx_chan); + +	return 0; +} + +static void lpuart_dma_rx_complete(void *arg) +{ +	struct lpuart_port *sport = arg; +	struct tty_port *port = &sport->port.state->port; +	unsigned long flags; + +	async_tx_ack(sport->dma_rx_desc); + +	spin_lock_irqsave(&sport->port.lock, flags); + +	sport->dma_rx_in_progress = 0; +	lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE); +	tty_flip_buffer_push(port); +	lpuart_dma_rx(sport); + +	spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static void lpuart_timer_func(unsigned long data) +{ +	struct lpuart_port *sport = (struct lpuart_port *)data; +	struct tty_port *port = &sport->port.state->port; +	struct dma_tx_state state; +	unsigned long flags; +	unsigned char temp; +	int count; + +	del_timer(&sport->lpuart_timer); +	dmaengine_pause(sport->dma_rx_chan); +	dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state); +	dmaengine_terminate_all(sport->dma_rx_chan); +	count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue; +	async_tx_ack(sport->dma_rx_desc); + +	spin_lock_irqsave(&sport->port.lock, flags); + +	sport->dma_rx_in_progress = 0; +	lpuart_copy_rx_to_tty(sport, port, count); +	tty_flip_buffer_push(port); +	temp = readb(sport->port.membase + UARTCR5); +	writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); + +	spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static inline void lpuart_prepare_rx(struct lpuart_port *sport) +{ +	unsigned long flags; +	unsigned char temp; + +	spin_lock_irqsave(&sport->port.lock, flags); + +	init_timer(&sport->lpuart_timer); +	sport->lpuart_timer.function = lpuart_timer_func; +	sport->lpuart_timer.data = (unsigned long)sport; +	sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; +	add_timer(&sport->lpuart_timer); + +	lpuart_dma_rx(sport); +	temp = readb(sport->port.membase + UARTCR5); +	writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5); + +	spin_unlock_irqrestore(&sport->port.lock, flags); +} +  static inline void lpuart_transmit_buffer(struct lpuart_port *sport)  {  	struct circ_buf *xmit = &sport->port.state->xmit; @@ -172,14 +407,21 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)  static void lpuart_start_tx(struct uart_port *port)  { -	struct lpuart_port *sport = container_of(port, struct lpuart_port, port); +	struct lpuart_port *sport = container_of(port, +			struct lpuart_port, port); +	struct circ_buf *xmit = &sport->port.state->xmit;  	unsigned char temp;  	temp = readb(port->membase + UARTCR2);  	writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); -	if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) -		lpuart_transmit_buffer(sport); +	if (sport->lpuart_dma_use) { +		if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress) +			lpuart_prepare_tx(sport); +	} else { +		if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) +			lpuart_transmit_buffer(sport); +	}  }  static irqreturn_t lpuart_txint(int irq, void *dev_id) @@ -279,12 +521,19 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)  	sts = readb(sport->port.membase + UARTSR1); -	if (sts & UARTSR1_RDRF) -		lpuart_rxint(irq, dev_id); - +	if (sts & UARTSR1_RDRF) { +		if (sport->lpuart_dma_use) +			lpuart_prepare_rx(sport); +		else +			lpuart_rxint(irq, dev_id); +	}  	if (sts & UARTSR1_TDRE && -		!(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) -		lpuart_txint(irq, dev_id); +		!(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) { +		if (sport->lpuart_dma_use) +			lpuart_pio_tx(sport); +		else +			lpuart_txint(irq, dev_id); +	}  	return IRQ_HANDLED;  } @@ -366,13 +615,156 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)  	writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,  			sport->port.membase + UARTCFIFO); -	writeb(2, sport->port.membase + UARTTWFIFO); +	writeb(0, sport->port.membase + UARTTWFIFO);  	writeb(1, sport->port.membase + UARTRWFIFO);  	/* Restore cr2 */  	writeb(cr2_saved, sport->port.membase + UARTCR2);  } +static int lpuart_dma_tx_request(struct uart_port *port) +{ +	struct lpuart_port *sport = container_of(port, +					struct lpuart_port, port); +	struct dma_chan *tx_chan; +	struct dma_slave_config dma_tx_sconfig; +	dma_addr_t dma_bus; +	unsigned char *dma_buf; +	int ret; + +	tx_chan  = dma_request_slave_channel(sport->port.dev, "tx"); + +	if (!tx_chan) { +		dev_err(sport->port.dev, "Dma tx channel request failed!\n"); +		return -ENODEV; +	} + +	dma_bus = dma_map_single(tx_chan->device->dev, +				sport->port.state->xmit.buf, +				UART_XMIT_SIZE, DMA_TO_DEVICE); + +	if (dma_mapping_error(tx_chan->device->dev, dma_bus)) { +		dev_err(sport->port.dev, "dma_map_single tx failed\n"); +		dma_release_channel(tx_chan); +		return -ENOMEM; +	} + +	dma_buf = sport->port.state->xmit.buf; +	dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; +	dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; +	dma_tx_sconfig.dst_maxburst = DMA_MAXBURST; +	dma_tx_sconfig.direction = DMA_MEM_TO_DEV; +	ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig); + +	if (ret < 0) { +		dev_err(sport->port.dev, +				"Dma slave config failed, err = %d\n", ret); +		dma_release_channel(tx_chan); +		return ret; +	} + +	sport->dma_tx_chan = tx_chan; +	sport->dma_tx_buf_virt = dma_buf; +	sport->dma_tx_buf_bus = dma_bus; +	sport->dma_tx_in_progress = 0; + +	return 0; +} + +static int lpuart_dma_rx_request(struct uart_port *port) +{ +	struct lpuart_port *sport = container_of(port, +					struct lpuart_port, port); +	struct dma_chan *rx_chan; +	struct dma_slave_config dma_rx_sconfig; +	dma_addr_t dma_bus; +	unsigned char *dma_buf; +	int ret; + +	rx_chan  = dma_request_slave_channel(sport->port.dev, "rx"); + +	if (!rx_chan) { +		dev_err(sport->port.dev, "Dma rx channel request failed!\n"); +		return -ENODEV; +	} + +	dma_buf = devm_kzalloc(sport->port.dev, +				FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL); + +	if (!dma_buf) { +		dev_err(sport->port.dev, "Dma rx alloc failed\n"); +		dma_release_channel(rx_chan); +		return -ENOMEM; +	} + +	dma_bus = dma_map_single(rx_chan->device->dev, dma_buf, +				FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); + +	if (dma_mapping_error(rx_chan->device->dev, dma_bus)) { +		dev_err(sport->port.dev, "dma_map_single rx failed\n"); +		dma_release_channel(rx_chan); +		return -ENOMEM; +	} + +	dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR; +	dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; +	dma_rx_sconfig.src_maxburst = 1; +	dma_rx_sconfig.direction = DMA_DEV_TO_MEM; +	ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig); + +	if (ret < 0) { +		dev_err(sport->port.dev, +				"Dma slave config failed, err = %d\n", ret); +		dma_release_channel(rx_chan); +		return ret; +	} + +	sport->dma_rx_chan = rx_chan; +	sport->dma_rx_buf_virt = dma_buf; +	sport->dma_rx_buf_bus = dma_bus; +	sport->dma_rx_in_progress = 0; + +	sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) * +				FSL_UART_RX_DMA_BUFFER_SIZE * 3 / +				sport->rxfifo_size / 2; + +	if (sport->dma_rx_timeout < msecs_to_jiffies(20)) +		sport->dma_rx_timeout = msecs_to_jiffies(20); + +	return 0; +} + +static void lpuart_dma_tx_free(struct uart_port *port) +{ +	struct lpuart_port *sport = container_of(port, +					struct lpuart_port, port); +	struct dma_chan *dma_chan; + +	dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus, +			UART_XMIT_SIZE, DMA_TO_DEVICE); +	dma_chan = sport->dma_tx_chan; +	sport->dma_tx_chan = NULL; +	sport->dma_tx_buf_bus = 0; +	sport->dma_tx_buf_virt = NULL; +	dma_release_channel(dma_chan); +} + +static void lpuart_dma_rx_free(struct uart_port *port) +{ +	struct lpuart_port *sport = container_of(port, +					struct lpuart_port, port); +	struct dma_chan *dma_chan; + +	dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus, +			FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); + +	dma_chan = sport->dma_rx_chan; +	sport->dma_rx_chan = NULL; +	sport->dma_rx_buf_bus = 0; +	sport->dma_rx_buf_virt = NULL; +	dma_release_channel(dma_chan); +} +  static int lpuart_startup(struct uart_port *port)  {  	struct lpuart_port *sport = container_of(port, struct lpuart_port, port); @@ -380,6 +772,15 @@ static int lpuart_startup(struct uart_port *port)  	unsigned long flags;  	unsigned char temp; +	/*whether use dma support by dma request results*/ +	if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) { +		sport->lpuart_dma_use = false; +	} else { +		sport->lpuart_dma_use = true; +		temp = readb(port->membase + UARTCR5); +		writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5); +	} +  	ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,  				DRIVER_NAME, sport);  	if (ret) @@ -414,6 +815,11 @@ static void lpuart_shutdown(struct uart_port *port)  	spin_unlock_irqrestore(&port->lock, flags);  	devm_free_irq(port->dev, port->irq, sport); + +	if (sport->lpuart_dma_use) { +		lpuart_dma_tx_free(port); +		lpuart_dma_rx_free(port); +	}  }  static void @@ -496,7 +902,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,  	sport->port.read_status_mask = 0;  	if (termios->c_iflag & INPCK)  		sport->port.read_status_mask |=	(UARTSR1_FE | UARTSR1_PE); -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		sport->port.read_status_mask |= UARTSR1_FE;  	/* characters to ignore */ diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index d98e4334897..67423805e6d 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -455,11 +455,11 @@ static void load_code(struct icom_port *icom_port)  	for (index = 0; index < fw->size; index++)  		new_page[index] = fw->data[index]; -	release_firmware(fw); -  	writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length);  	writel(temp_pci, &icom_port->dram->mac_load_addr); +	release_firmware(fw); +  	/*Setting the syncReg to 0x80 causes adapter to start downloading  	   the personality code into adapter instruction RAM.  	   Once code is loaded, it will begin executing and, based on diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index af286e6713e..59039097099 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -1008,7 +1008,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)  		return -ENODEV;  	} -	pl_data = (struct ifx_modem_platform_data *)dev_get_platdata(&spi->dev); +	pl_data = dev_get_platdata(&spi->dev);  	if (!pl_data) {  		dev_err(&spi->dev, "missing platform data!");  		return -ENODEV; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index a0ebbc9ce5c..044e86d528a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -116,7 +116,7 @@  #define UCR3_DSR	(1<<10) /* Data set ready */  #define UCR3_DCD	(1<<9)	/* Data carrier detect */  #define UCR3_RI		(1<<8)	/* Ring indicator */ -#define UCR3_TIMEOUTEN	(1<<7)	/* Timeout interrupt enable */ +#define UCR3_ADNIMP	(1<<7)	/* Autobaud Detection Not Improved */  #define UCR3_RXDSEN	(1<<6)	/* Receive status interrupt enable */  #define UCR3_AIRINTEN	(1<<5)	/* Async IR wake interrupt enable */  #define UCR3_AWAKEN	(1<<4)	/* Async wake interrupt enable */ @@ -223,8 +223,7 @@ struct imx_port {  	struct dma_chan		*dma_chan_rx, *dma_chan_tx;  	struct scatterlist	rx_sgl, tx_sgl[2];  	void			*rx_buf; -	unsigned int		rx_bytes, tx_bytes; -	struct work_struct	tsk_dma_rx, tsk_dma_tx; +	unsigned int		tx_bytes;  	unsigned int		dma_tx_nents;  	wait_queue_head_t	dma_wait;  }; @@ -445,6 +444,10 @@ static void imx_stop_rx(struct uart_port *port)  	temp = readl(sport->port.membase + UCR2);  	writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); + +	/* disable the `Receiver Ready Interrrupt` */ +	temp = readl(sport->port.membase + UCR1); +	writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1);  }  /* @@ -497,42 +500,32 @@ static void dma_tx_callback(void *data)  	dev_dbg(sport->port.dev, "we finish the TX DMA.\n"); -	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -		uart_write_wakeup(&sport->port); +	uart_write_wakeup(&sport->port);  	if (waitqueue_active(&sport->dma_wait)) {  		wake_up(&sport->dma_wait);  		dev_dbg(sport->port.dev, "exit in %s.\n", __func__);  		return;  	} - -	schedule_work(&sport->tsk_dma_tx);  } -static void dma_tx_work(struct work_struct *w) +static void imx_dma_tx(struct imx_port *sport)  { -	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx);  	struct circ_buf *xmit = &sport->port.state->xmit;  	struct scatterlist *sgl = sport->tx_sgl;  	struct dma_async_tx_descriptor *desc;  	struct dma_chan	*chan = sport->dma_chan_tx;  	struct device *dev = sport->port.dev;  	enum dma_status status; -	unsigned long flags;  	int ret; -	status = chan->device->device_tx_status(chan, (dma_cookie_t)0, NULL); +	status = dmaengine_tx_status(chan, (dma_cookie_t)0, NULL);  	if (DMA_IN_PROGRESS == status)  		return; -	spin_lock_irqsave(&sport->port.lock, flags);  	sport->tx_bytes = uart_circ_chars_pending(xmit); -	if (sport->tx_bytes == 0) { -		spin_unlock_irqrestore(&sport->port.lock, flags); -		return; -	} -	if (xmit->tail > xmit->head) { +	if (xmit->tail > xmit->head && xmit->head > 0) {  		sport->dma_tx_nents = 2;  		sg_init_table(sgl, 2);  		sg_set_buf(sgl, xmit->buf + xmit->tail, @@ -542,7 +535,6 @@ static void dma_tx_work(struct work_struct *w)  		sport->dma_tx_nents = 1;  		sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);  	} -	spin_unlock_irqrestore(&sport->port.lock, flags);  	ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);  	if (ret == 0) { @@ -575,6 +567,9 @@ static void imx_start_tx(struct uart_port *port)  	struct imx_port *sport = (struct imx_port *)port;  	unsigned long temp; +	if (uart_circ_empty(&port->state->xmit)) +		return; +  	if (USE_IRDA(sport)) {  		/* half duplex in IrDA mode; have to disable receive mode */  		temp = readl(sport->port.membase + UCR4); @@ -609,11 +604,7 @@ static void imx_start_tx(struct uart_port *port)  	}  	if (sport->dma_is_enabled) { -		/* -		 * We may in the interrupt context, so arise a work_struct to -		 * do the real job. -		 */ -		schedule_work(&sport->tsk_dma_tx); +		imx_dma_tx(sport);  		return;  	} @@ -732,6 +723,7 @@ out:  	return IRQ_HANDLED;  } +static int start_rx_dma(struct imx_port *sport);  /*   * If the RXFIFO is filled with some data, and then we   * arise a DMA operation to receive them. @@ -750,7 +742,7 @@ static void imx_dma_rxint(struct imx_port *sport)  		writel(temp, sport->port.membase + UCR1);  		/* tell the DMA to receive the data. */ -		schedule_work(&sport->tsk_dma_rx); +		start_rx_dma(sport);  	}  } @@ -795,8 +787,15 @@ static irqreturn_t imx_int(int irq, void *dev_id)  static unsigned int imx_tx_empty(struct uart_port *port)  {  	struct imx_port *sport = (struct imx_port *)port; +	unsigned int ret; -	return (readl(sport->port.membase + USR2) & USR2_TXDC) ?  TIOCSER_TEMT : 0; +	ret = (readl(sport->port.membase + USR2) & USR2_TXDC) ?  TIOCSER_TEMT : 0; + +	/* If the TX DMA is working, return 0. */ +	if (sport->dma_is_enabled && sport->dma_is_txing) +		ret = 0; + +	return ret;  }  /* @@ -813,6 +812,9 @@ static unsigned int imx_get_mctrl(struct uart_port *port)  	if (readl(sport->port.membase + UCR2) & UCR2_CTS)  		tmp |= TIOCM_RTS; +	if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP) +		tmp |= TIOCM_LOOP; +  	return tmp;  } @@ -828,6 +830,11 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)  			temp |= UCR2_CTS;  	writel(temp, sport->port.membase + UCR2); + +	temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP; +	if (mctrl & TIOCM_LOOP) +		temp |= UTS_LOOP; +	writel(temp, sport->port.membase + uts_reg(sport));  }  /* @@ -865,22 +872,6 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)  }  #define RX_BUF_SIZE	(PAGE_SIZE) -static int start_rx_dma(struct imx_port *sport); -static void dma_rx_work(struct work_struct *w) -{ -	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_rx); -	struct tty_port *port = &sport->port.state->port; - -	if (sport->rx_bytes) { -		tty_insert_flip_string(port, sport->rx_buf, sport->rx_bytes); -		tty_flip_buffer_push(port); -		sport->rx_bytes = 0; -	} - -	if (sport->dma_is_rxing) -		start_rx_dma(sport); -} -  static void imx_rx_dma_done(struct imx_port *sport)  {  	unsigned long temp; @@ -912,6 +903,7 @@ static void dma_rx_callback(void *data)  	struct imx_port *sport = data;  	struct dma_chan	*chan = sport->dma_chan_rx;  	struct scatterlist *sgl = &sport->rx_sgl; +	struct tty_port *port = &sport->port.state->port;  	struct dma_tx_state state;  	enum dma_status status;  	unsigned int count; @@ -919,13 +911,15 @@ static void dma_rx_callback(void *data)  	/* unmap it first */  	dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE); -	status = chan->device->device_tx_status(chan, (dma_cookie_t)0, &state); +	status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);  	count = RX_BUF_SIZE - state.residue;  	dev_dbg(sport->port.dev, "We get %d bytes.\n", count);  	if (count) { -		sport->rx_bytes = count; -		schedule_work(&sport->tsk_dma_rx); +		tty_insert_flip_string(port, sport->rx_buf, count); +		tty_flip_buffer_push(port); + +		start_rx_dma(sport);  	} else  		imx_rx_dma_done(sport);  } @@ -1007,7 +1001,6 @@ static int imx_uart_dma_init(struct imx_port *sport)  		ret = -ENOMEM;  		goto err;  	} -	sport->rx_bytes = 0;  	/* Prepare for TX : */  	sport->dma_chan_tx = dma_request_slave_channel(dev, "tx"); @@ -1038,11 +1031,7 @@ err:  static void imx_enable_dma(struct imx_port *sport)  {  	unsigned long temp; -	struct tty_port *port = &sport->port.state->port; -	port->low_latency = 1; -	INIT_WORK(&sport->tsk_dma_tx, dma_tx_work); -	INIT_WORK(&sport->tsk_dma_rx, dma_rx_work);  	init_waitqueue_head(&sport->dma_wait);  	/* set UCR1 */ @@ -1063,7 +1052,6 @@ static void imx_enable_dma(struct imx_port *sport)  static void imx_disable_dma(struct imx_port *sport)  {  	unsigned long temp; -	struct tty_port *port = &sport->port.state->port;  	/* clear UCR1 */  	temp = readl(sport->port.membase + UCR1); @@ -1081,7 +1069,6 @@ static void imx_disable_dma(struct imx_port *sport)  	writel(temp, sport->port.membase + UCR4);  	sport->dma_is_enabled = 0; -	port->low_latency = 0;  }  /* half the RX buffer size */ @@ -1090,7 +1077,7 @@ static void imx_disable_dma(struct imx_port *sport)  static int imx_startup(struct uart_port *port)  {  	struct imx_port *sport = (struct imx_port *)port; -	int retval; +	int retval, i;  	unsigned long flags, temp;  	retval = clk_prepare_enable(sport->clk_per); @@ -1118,17 +1105,15 @@ static int imx_startup(struct uart_port *port)  	writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); -	if (USE_IRDA(sport)) { -		/* reset fifo's and state machines */ -		int i = 100; -		temp = readl(sport->port.membase + UCR2); -		temp &= ~UCR2_SRST; -		writel(temp, sport->port.membase + UCR2); -		while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && -		    (--i > 0)) { -			udelay(1); -		} -	} +	/* Reset fifo's and state machines */ +	i = 100; + +	temp = readl(sport->port.membase + UCR2); +	temp &= ~UCR2_SRST; +	writel(temp, sport->port.membase + UCR2); + +	while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) +		udelay(1);  	/*  	 * Allocate the IRQ(s) i.MX1 has three interrupts whereas later @@ -1136,25 +1121,25 @@ static int imx_startup(struct uart_port *port)  	 */  	if (sport->txirq > 0) {  		retval = request_irq(sport->rxirq, imx_rxint, 0, -				DRIVER_NAME, sport); +				     dev_name(port->dev), sport);  		if (retval)  			goto error_out1;  		retval = request_irq(sport->txirq, imx_txint, 0, -				DRIVER_NAME, sport); +				     dev_name(port->dev), sport);  		if (retval)  			goto error_out2;  		/* do not use RTS IRQ on IrDA */  		if (!USE_IRDA(sport)) {  			retval = request_irq(sport->rtsirq, imx_rtsint, 0, -					DRIVER_NAME, sport); +					     dev_name(port->dev), sport);  			if (retval)  				goto error_out3;  		}  	} else {  		retval = request_irq(sport->port.irq, imx_int, 0, -				DRIVER_NAME, sport); +				     dev_name(port->dev), sport);  		if (retval) {  			free_irq(sport->port.irq, sport);  			goto error_out1; @@ -1183,18 +1168,9 @@ static int imx_startup(struct uart_port *port)  		temp |= UCR2_IRTS;  	writel(temp, sport->port.membase + UCR2); -	if (USE_IRDA(sport)) { -		/* clear RX-FIFO */ -		int i = 64; -		while ((--i > 0) && -			(readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { -			barrier(); -		} -	} -  	if (!is_imx1_uart(sport)) {  		temp = readl(sport->port.membase + UCR3); -		temp |= IMX21_UCR3_RXDMUXSEL; +		temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP;  		writel(temp, sport->port.membase + UCR3);  	} @@ -1303,6 +1279,16 @@ static void imx_shutdown(struct uart_port *port)  	clk_disable_unprepare(sport->clk_ipg);  } +static void imx_flush_buffer(struct uart_port *port) +{ +	struct imx_port *sport = (struct imx_port *)port; + +	if (sport->dma_is_enabled) { +		sport->tx_bytes = 0; +		dmaengine_terminate_all(sport->dma_chan_tx); +	} +} +  static void  imx_set_termios(struct uart_port *port, struct ktermios *termios,  		   struct ktermios *old) @@ -1479,44 +1465,13 @@ static const char *imx_type(struct uart_port *port)  }  /* - * Release the memory region(s) being used by 'port'. - */ -static void imx_release_port(struct uart_port *port) -{ -	struct platform_device *pdev = to_platform_device(port->dev); -	struct resource *mmres; - -	mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	release_mem_region(mmres->start, resource_size(mmres)); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int imx_request_port(struct uart_port *port) -{ -	struct platform_device *pdev = to_platform_device(port->dev); -	struct resource *mmres; -	void *ret; - -	mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!mmres) -		return -ENODEV; - -	ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart"); - -	return  ret ? 0 : -EBUSY; -} - -/*   * Configure/autoconfigure the port.   */  static void imx_config_port(struct uart_port *port, int flags)  {  	struct imx_port *sport = (struct imx_port *)port; -	if (flags & UART_CONFIG_TYPE && -	    imx_request_port(&sport->port) == 0) +	if (flags & UART_CONFIG_TYPE)  		sport->port.type = PORT_IMX;  } @@ -1539,7 +1494,7 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)  		ret = -EINVAL;  	if (sport->port.uartclk / 16 != ser->baud_base)  		ret = -EINVAL; -	if ((void *)sport->port.mapbase != ser->iomem_base) +	if (sport->port.mapbase != (unsigned long)ser->iomem_base)  		ret = -EINVAL;  	if (sport->port.iobase != ser->port)  		ret = -EINVAL; @@ -1623,10 +1578,9 @@ static struct uart_ops imx_pops = {  	.break_ctl	= imx_break_ctl,  	.startup	= imx_startup,  	.shutdown	= imx_shutdown, +	.flush_buffer	= imx_flush_buffer,  	.set_termios	= imx_set_termios,  	.type		= imx_type, -	.release_port	= imx_release_port, -	.request_port	= imx_request_port,  	.config_port	= imx_config_port,  	.verify_port	= imx_verify_port,  #if defined(CONFIG_CONSOLE_POLL) @@ -1912,9 +1866,6 @@ static int serial_imx_probe_dt(struct imx_port *sport,  	sport->devdata = of_id->data; -	if (of_device_is_stdout_path(np)) -		add_preferred_console(imx_reg.cons->name, sport->port.line, 0); -  	return 0;  }  #else @@ -1946,7 +1897,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport,  static int serial_imx_probe(struct platform_device *pdev)  {  	struct imx_port *sport; -	struct imxuart_platform_data *pdata;  	void __iomem *base;  	int ret = 0;  	struct resource *res; @@ -1962,12 +1912,9 @@ static int serial_imx_probe(struct platform_device *pdev)  		return ret;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) -		return -ENODEV; - -	base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE); -	if (!base) -		return -ENOMEM; +	base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(base)) +		return PTR_ERR(base);  	sport->port.dev = &pdev->dev;  	sport->port.mapbase = res->start; @@ -2003,38 +1950,16 @@ static int serial_imx_probe(struct platform_device *pdev)  	imx_ports[sport->port.line] = sport; -	pdata = dev_get_platdata(&pdev->dev); -	if (pdata && pdata->init) { -		ret = pdata->init(pdev); -		if (ret) -			return ret; -	} - -	ret = uart_add_one_port(&imx_reg, &sport->port); -	if (ret) -		goto deinit;  	platform_set_drvdata(pdev, sport); -	return 0; -deinit: -	if (pdata && pdata->exit) -		pdata->exit(pdev); -	return ret; +	return uart_add_one_port(&imx_reg, &sport->port);  }  static int serial_imx_remove(struct platform_device *pdev)  { -	struct imxuart_platform_data *pdata;  	struct imx_port *sport = platform_get_drvdata(pdev); -	pdata = dev_get_platdata(&pdev->dev); - -	uart_remove_one_port(&imx_reg, &sport->port); - -	if (pdata && pdata->exit) -		pdata->exit(pdev); - -	return 0; +	return uart_remove_one_port(&imx_reg, &sport->port);  }  static struct platform_driver serial_imx_driver = { diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index cb3c81eb099..99b7b869786 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -603,6 +603,8 @@ static void ip22zilog_start_tx(struct uart_port *port)  	} else {  		struct circ_buf *xmit = &port->state->xmit; +		if (uart_circ_empty(xmit)) +			return;  		writeb(xmit->buf[xmit->tail], &channel->data);  		ZSDELAY();  		ZS_WSYNC(channel); @@ -832,7 +834,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,  		up->curregs[5] |= Tx8;  		up->parity_mask = 0xff;  		break; -	}; +	}  	up->curregs[4] &= ~0x0c;  	if (cflag & CSTOPB)  		up->curregs[4] |= SB2; @@ -850,7 +852,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag,  	up->port.read_status_mask = Rx_OVR;  	if (iflag & INPCK)  		up->port.read_status_mask |= CRC_ERR | PAR_ERR; -	if (iflag & (BRKINT | PARMRK)) +	if (iflag & (IGNBRK | BRKINT | PARMRK))  		up->port.read_status_mask |= BRK_ABRT;  	up->port.ignore_status_mask = 0; diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index 5dafcf1c227..cfadf2971b1 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -15,7 +15,6 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/compiler.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/errno.h>  #include <linux/atomic.h> @@ -45,13 +44,22 @@ MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");  static bool kgdb_nmi_tty_enabled; +static int kgdb_nmi_console_setup(struct console *co, char *options) +{ +	/* The NMI console uses the dbg_io_ops to issue console messages. To +	 * avoid duplicate messages during kdb sessions we must inform kdb's +	 * I/O utilities that messages sent to the console will automatically +	 * be displayed on the dbg_io. +	 */ +	dbg_io_ops->is_console = true; + +	return 0; +} +  static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)  {  	int i; -	if (!kgdb_nmi_tty_enabled || atomic_read(&kgdb_active) >= 0) -		return; -  	for (i = 0; i < c; i++)  		dbg_io_ops->write_char(s[i]);  } @@ -66,6 +74,7 @@ static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)  static struct console kgdb_nmi_console = {  	.name	= "ttyNMI", +	.setup  = kgdb_nmi_console_setup,  	.write	= kgdb_nmi_console_write,  	.device	= kgdb_nmi_console_device,  	.flags	= CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, @@ -81,29 +90,10 @@ static struct console kgdb_nmi_console = {  struct kgdb_nmi_tty_priv {  	struct tty_port port; -	struct tasklet_struct tlet; +	struct timer_list timer;  	STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;  }; -static struct kgdb_nmi_tty_priv *kgdb_nmi_port_to_priv(struct tty_port *port) -{ -	return container_of(port, struct kgdb_nmi_tty_priv, port); -} - -/* - * Our debugging console is polled in a tasklet, so we'll check for input - * every tick. In HZ-less mode, we should program the next tick.  We have - * to use the lowlevel stuff as no locks should be grabbed. - */ -#ifdef CONFIG_HIGH_RES_TIMERS -static void kgdb_tty_poke(void) -{ -	tick_program_event(ktime_get(), 0); -} -#else -static inline void kgdb_tty_poke(void) {} -#endif -  static struct tty_port *kgdb_nmi_port;  static void kgdb_tty_recv(int ch) @@ -114,14 +104,13 @@ static void kgdb_tty_recv(int ch)  	if (!kgdb_nmi_port || ch < 0)  		return;  	/* -	 * Can't use port->tty->driver_data as tty might be not there. Tasklet +	 * Can't use port->tty->driver_data as tty might be not there. Timer  	 * will check for tty and will get the ref, but here we don't have to  	 * do that, and actually, we can't: we're in NMI context, no locks are  	 * possible.  	 */ -	priv = kgdb_nmi_port_to_priv(kgdb_nmi_port); +	priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port);  	kfifo_in(&priv->fifo, &c, 1); -	kgdb_tty_poke();  }  static int kgdb_nmi_poll_one_knock(void) @@ -205,7 +194,8 @@ static void kgdb_nmi_tty_receiver(unsigned long data)  	struct kgdb_nmi_tty_priv *priv = (void *)data;  	char ch; -	tasklet_schedule(&priv->tlet); +	priv->timer.expires = jiffies + (HZ/100); +	add_timer(&priv->timer);  	if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo)))  		return; @@ -217,18 +207,22 @@ static void kgdb_nmi_tty_receiver(unsigned long data)  static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)  { -	struct kgdb_nmi_tty_priv *priv = tty->driver_data; +	struct kgdb_nmi_tty_priv *priv = +	    container_of(port, struct kgdb_nmi_tty_priv, port);  	kgdb_nmi_port = port; -	tasklet_schedule(&priv->tlet); +	priv->timer.expires = jiffies + (HZ/100); +	add_timer(&priv->timer); +  	return 0;  }  static void kgdb_nmi_tty_shutdown(struct tty_port *port)  { -	struct kgdb_nmi_tty_priv *priv = port->tty->driver_data; +	struct kgdb_nmi_tty_priv *priv = +	    container_of(port, struct kgdb_nmi_tty_priv, port); -	tasklet_kill(&priv->tlet); +	del_timer(&priv->timer);  	kgdb_nmi_port = NULL;  } @@ -247,7 +241,7 @@ static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)  		return -ENOMEM;  	INIT_KFIFO(priv->fifo); -	tasklet_init(&priv->tlet, kgdb_nmi_tty_receiver, (unsigned long)priv); +	setup_timer(&priv->timer, kgdb_nmi_tty_receiver, (unsigned long)priv);  	tty_port_init(&priv->port);  	priv->port.ops = &kgdb_nmi_tty_port_ops;  	tty->driver_data = priv; diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 9cd9b4eba9f..5702828fb62 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -266,9 +266,11 @@ static void m32r_sio_start_tx(struct uart_port *port)  	if (!(up->ier & UART_IER_THRI)) {  		up->ier |= UART_IER_THRI;  		serial_out(up, UART_IER, up->ier); -		serial_out(up, UART_TX, xmit->buf[xmit->tail]); -		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -		up->port.icount.tx++; +		if (!uart_circ_empty(xmit)) { +			serial_out(up, UART_TX, xmit->buf[xmit->tail]); +			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); +			up->port.icount.tx++; +		}  	}  	while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY);  #else @@ -737,7 +739,7 @@ static void m32r_sio_set_termios(struct uart_port *port,  	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;  	if (termios->c_iflag & INPCK)  		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		up->port.read_status_mask |= UART_LSR_BI;  	/* diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index b2e707aa603..ba285cd45b5 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1,7 +1,7 @@  /*   *  Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver   * - *  Copyright (C) 2012-2013 Alexander Shiyan <shc_work@mail.ru> + *  Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru>   *   *  Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>   *  Based on max3110.c, by Feng Tang <feng.tang@intel.com> @@ -13,19 +13,21 @@   *  (at your option) any later version.   */ -#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/clk.h>  #include <linux/delay.h>  #include <linux/device.h> -#include <linux/bitops.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h>  #include <linux/serial_core.h>  #include <linux/serial.h>  #include <linux/tty.h>  #include <linux/tty_flip.h> -#include <linux/regmap.h> -#include <linux/gpio.h>  #include <linux/spi/spi.h> - -#include <linux/platform_data/max310x.h> +#include <linux/uaccess.h>  #define MAX310X_NAME			"max310x"  #define MAX310X_MAJOR			204 @@ -161,10 +163,6 @@  /* IRDA register bits */  #define MAX310X_IRDA_IRDAEN_BIT		(1 << 0) /* IRDA mode enable */  #define MAX310X_IRDA_SIR_BIT		(1 << 1) /* SIR mode enable */ -#define MAX310X_IRDA_SHORTIR_BIT	(1 << 2) /* Short SIR mode enable */ -#define MAX310X_IRDA_MIR_BIT		(1 << 3) /* MIR mode enable */ -#define MAX310X_IRDA_RXINV_BIT		(1 << 4) /* RX logic inversion enable */ -#define MAX310X_IRDA_TXINV_BIT		(1 << 5) /* TX logic inversion enable */  /* Flow control trigger level register masks */  #define MAX310X_FLOWLVL_HALT_MASK	(0x000f) /* Flow control halt level */ @@ -220,26 +218,6 @@  						  *       XOFF2  						  */ -/* GPIO configuration register bits */ -#define MAX310X_GPIOCFG_GP0OUT_BIT	(1 << 0) /* GPIO 0 output enable */ -#define MAX310X_GPIOCFG_GP1OUT_BIT	(1 << 1) /* GPIO 1 output enable */ -#define MAX310X_GPIOCFG_GP2OUT_BIT	(1 << 2) /* GPIO 2 output enable */ -#define MAX310X_GPIOCFG_GP3OUT_BIT	(1 << 3) /* GPIO 3 output enable */ -#define MAX310X_GPIOCFG_GP0OD_BIT	(1 << 4) /* GPIO 0 open-drain enable */ -#define MAX310X_GPIOCFG_GP1OD_BIT	(1 << 5) /* GPIO 1 open-drain enable */ -#define MAX310X_GPIOCFG_GP2OD_BIT	(1 << 6) /* GPIO 2 open-drain enable */ -#define MAX310X_GPIOCFG_GP3OD_BIT	(1 << 7) /* GPIO 3 open-drain enable */ - -/* GPIO DATA register bits */ -#define MAX310X_GPIODATA_GP0OUT_BIT	(1 << 0) /* GPIO 0 output value */ -#define MAX310X_GPIODATA_GP1OUT_BIT	(1 << 1) /* GPIO 1 output value */ -#define MAX310X_GPIODATA_GP2OUT_BIT	(1 << 2) /* GPIO 2 output value */ -#define MAX310X_GPIODATA_GP3OUT_BIT	(1 << 3) /* GPIO 3 output value */ -#define MAX310X_GPIODATA_GP0IN_BIT	(1 << 4) /* GPIO 0 input value */ -#define MAX310X_GPIODATA_GP1IN_BIT	(1 << 5) /* GPIO 1 input value */ -#define MAX310X_GPIODATA_GP2IN_BIT	(1 << 6) /* GPIO 2 input value */ -#define MAX310X_GPIODATA_GP3IN_BIT	(1 << 7) /* GPIO 3 input value */ -  /* PLL configuration register masks */  #define MAX310X_PLLCFG_PREDIV_MASK	(0x3f) /* PLL predivision value */  #define MAX310X_PLLCFG_PLLFACTOR_MASK	(0xc0) /* PLL multiplication factor */ @@ -283,16 +261,15 @@ struct max310x_devtype {  struct max310x_one {  	struct uart_port	port;  	struct work_struct	tx_work; +	struct work_struct	md_work;  };  struct max310x_port {  	struct uart_driver	uart;  	struct max310x_devtype	*devtype;  	struct regmap		*regmap; -	struct regmap_config	regcfg;  	struct mutex		mutex; -	struct max310x_pdata	*pdata; -	int			gpio_used; +	struct clk		*clk;  #ifdef CONFIG_GPIOLIB  	struct gpio_chip	gpio;  #endif @@ -504,25 +481,33 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)  	return false;  } -static void max310x_set_baud(struct uart_port *port, int baud) +static int max310x_set_baud(struct uart_port *port, int baud)  { -	unsigned int mode = 0, div = port->uartclk / baud; +	unsigned int mode = 0, clk = port->uartclk, div = clk / baud; -	if (!(div / 16)) { +	/* Check for minimal value for divider */ +	if (div < 16) +		div = 16; + +	if (clk % baud && (div / 16) < 0x8000) {  		/* Mode x2 */  		mode = MAX310X_BRGCFG_2XMODE_BIT; -		div = (port->uartclk * 2) / baud; -	} - -	if (!(div / 16)) { -		/* Mode x4 */ -		mode = MAX310X_BRGCFG_4XMODE_BIT; -		div = (port->uartclk * 4) / baud; +		clk = port->uartclk * 2; +		div = clk / baud; + +		if (clk % baud && (div / 16) < 0x8000) { +			/* Mode x4 */ +			mode = MAX310X_BRGCFG_4XMODE_BIT; +			clk = port->uartclk * 4; +			div = clk / baud; +		}  	}  	max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);  	max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);  	max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode); + +	return DIV_ROUND_CLOSEST(clk, div);  }  static int max310x_update_best_err(unsigned long f, long *besterr) @@ -538,18 +523,19 @@ static int max310x_update_best_err(unsigned long f, long *besterr)  	return 1;  } -static int max310x_set_ref_clk(struct max310x_port *s) +static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq, +			       bool xtal)  {  	unsigned int div, clksrc, pllcfg = 0;  	long besterr = -1; -	unsigned long fdiv, fmul, bestfreq = s->pdata->frequency; +	unsigned long fdiv, fmul, bestfreq = freq;  	/* First, update error without PLL */ -	max310x_update_best_err(s->pdata->frequency, &besterr); +	max310x_update_best_err(freq, &besterr);  	/* Try all possible PLL dividers */  	for (div = 1; (div <= 63) && besterr; div++) { -		fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div); +		fdiv = DIV_ROUND_CLOSEST(freq, div);  		/* Try multiplier 6 */  		fmul = fdiv * 6; @@ -582,10 +568,7 @@ static int max310x_set_ref_clk(struct max310x_port *s)  	}  	/* Configure clock source */ -	if (s->pdata->driver_flags & MAX310X_EXT_CLK) -		clksrc = MAX310X_CLKSRC_EXTCLK_BIT; -	else -		clksrc = MAX310X_CLKSRC_CRYST_BIT; +	clksrc = xtal ? MAX310X_CLKSRC_CRYST_BIT : MAX310X_CLKSRC_EXTCLK_BIT;  	/* Configure PLL */  	if (pllcfg) { @@ -597,7 +580,7 @@ static int max310x_set_ref_clk(struct max310x_port *s)  	regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc);  	/* Wait for crystal */ -	if (pllcfg && !(s->pdata->driver_flags & MAX310X_EXT_CLK)) +	if (pllcfg && xtal)  		msleep(10);  	return (int)bestfreq; @@ -690,7 +673,7 @@ static void max310x_handle_tx(struct uart_port *port)  			max310x_port_write(port, MAX310X_THR_REG,  					   xmit->buf[xmit->tail]);  			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -		}; +		}  	}  	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -782,11 +765,21 @@ static unsigned int max310x_get_mctrl(struct uart_port *port)  	return TIOCM_DSR | TIOCM_CAR;  } +static void max310x_md_proc(struct work_struct *ws) +{ +	struct max310x_one *one = container_of(ws, struct max310x_one, md_work); + +	max310x_port_update(&one->port, MAX310X_MODE2_REG, +			    MAX310X_MODE2_LOOPBACK_BIT, +			    (one->port.mctrl & TIOCM_LOOP) ? +			    MAX310X_MODE2_LOOPBACK_BIT : 0); +} +  static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)  { -	/* DCD and DSR are not wired and CTS/RTS is hadnled automatically -	 * so do nothing -	 */ +	struct max310x_one *one = container_of(port, struct max310x_one, port); + +	schedule_work(&one->md_work);  }  static void max310x_break_ctl(struct uart_port *port, int break_state) @@ -842,7 +835,7 @@ static void max310x_set_termios(struct uart_port *port,  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= MAX310X_LSR_RXPAR_BIT |  					  MAX310X_LSR_FRERR_BIT; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= MAX310X_LSR_RXBRK_BIT;  	/* Set status ignore mask */ @@ -875,40 +868,76 @@ static void max310x_set_termios(struct uart_port *port,  				  port->uartclk / 4);  	/* Setup baudrate generator */ -	max310x_set_baud(port, baud); +	baud = max310x_set_baud(port, baud);  	/* Update timeout according to new baud rate */  	uart_update_timeout(port, termios->c_cflag, baud);  } +static int max310x_ioctl(struct uart_port *port, unsigned int cmd, +			 unsigned long arg) +{ +#if defined(TIOCSRS485) && defined(TIOCGRS485) +	struct serial_rs485 rs485; +	unsigned int val; + +	switch (cmd) { +	case TIOCSRS485: +		if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485))) +			return -EFAULT; +		if (rs485.delay_rts_before_send > 0x0f || +		    rs485.delay_rts_after_send > 0x0f) +			return -ERANGE; +		val = (rs485.delay_rts_before_send << 4) | +		      rs485.delay_rts_after_send; +		max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val); +		if (rs485.flags & SER_RS485_ENABLED) { +			max310x_port_update(port, MAX310X_MODE1_REG, +					    MAX310X_MODE1_TRNSCVCTRL_BIT, +					    MAX310X_MODE1_TRNSCVCTRL_BIT); +			max310x_port_update(port, MAX310X_MODE2_REG, +					    MAX310X_MODE2_ECHOSUPR_BIT, +					    MAX310X_MODE2_ECHOSUPR_BIT); +		} else { +			max310x_port_update(port, MAX310X_MODE1_REG, +					    MAX310X_MODE1_TRNSCVCTRL_BIT, 0); +			max310x_port_update(port, MAX310X_MODE2_REG, +					    MAX310X_MODE2_ECHOSUPR_BIT, 0); +		} +		return 0; +	case TIOCGRS485: +		memset(&rs485, 0, sizeof(rs485)); +		val = max310x_port_read(port, MAX310X_MODE1_REG); +		rs485.flags = (val & MAX310X_MODE1_TRNSCVCTRL_BIT) ? +			      SER_RS485_ENABLED : 0; +		rs485.flags |= SER_RS485_RTS_ON_SEND; +		val = max310x_port_read(port, MAX310X_HDPIXDELAY_REG); +		rs485.delay_rts_before_send = val >> 4; +		rs485.delay_rts_after_send = val & 0x0f; +		if (copy_to_user((void __user *)arg, &rs485, sizeof(rs485))) +			return -EFAULT; +		return 0; +	default: +		break; +	} +#endif + +	return -ENOIOCTLCMD; +} +  static int max310x_startup(struct uart_port *port)  { -	unsigned int val, line = port->line;  	struct max310x_port *s = dev_get_drvdata(port->dev); +	unsigned int val;  	s->devtype->power(port, 1); -	/* Configure baud rate, 9600 as default */ -	max310x_set_baud(port, 9600); - -	/* Configure LCR register, 8N1 mode by default */ -	max310x_port_write(port, MAX310X_LCR_REG, MAX310X_LCR_WORD_LEN_8); -  	/* Configure MODE1 register */  	max310x_port_update(port, MAX310X_MODE1_REG, -			    MAX310X_MODE1_TRNSCVCTRL_BIT, -			    (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL) -			    ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0); - -	/* Configure MODE2 register */ -	val = MAX310X_MODE2_RXEMPTINV_BIT; -	if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK) -		val |= MAX310X_MODE2_LOOPBACK_BIT; -	if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS) -		val |= MAX310X_MODE2_ECHOSUPR_BIT; - -	/* Reset FIFOs */ -	val |= MAX310X_MODE2_FIFORST_BIT; +			    MAX310X_MODE1_TRNSCVCTRL_BIT, 0); + +	/* Configure MODE2 register & Reset FIFOs*/ +	val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT;  	max310x_port_write(port, MAX310X_MODE2_REG, val);  	max310x_port_update(port, MAX310X_MODE2_REG,  			    MAX310X_MODE2_FIFORST_BIT, 0); @@ -989,6 +1018,7 @@ static const struct uart_ops max310x_ops = {  	.release_port	= max310x_null_void,  	.config_port	= max310x_config_port,  	.verify_port	= max310x_verify_port, +	.ioctl		= max310x_ioctl,  };  static int __maybe_unused max310x_suspend(struct device *dev) @@ -1017,6 +1047,8 @@ static int __maybe_unused max310x_resume(struct device *dev)  	return 0;  } +static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); +  #ifdef CONFIG_GPIOLIB  static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)  { @@ -1063,23 +1095,16 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip,  }  #endif -static int max310x_probe(struct device *dev, int is_spi, -			 struct max310x_devtype *devtype, int irq) +static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, +			 struct regmap *regmap, int irq, unsigned long flags)  { +	int i, ret, fmin, fmax, freq, uartclk; +	struct clk *clk_osc, *clk_xtal;  	struct max310x_port *s; -	struct max310x_pdata *pdata = dev_get_platdata(dev); -	int i, ret, uartclk; +	bool xtal = false; -	/* Check for IRQ */ -	if (irq <= 0) { -		dev_err(dev, "No IRQ specified\n"); -		return -ENOTSUPP; -	} - -	if (!pdata) { -		dev_err(dev, "No platform data supplied\n"); -		return -EINVAL; -	} +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap);  	/* Alloc port structure */  	s = devm_kzalloc(dev, sizeof(*s) + @@ -1089,52 +1114,44 @@ static int max310x_probe(struct device *dev, int is_spi,  		return -ENOMEM;  	} -	/* Check input frequency */ -	if ((pdata->driver_flags & MAX310X_EXT_CLK) && -	   ((pdata->frequency < 500000) || (pdata->frequency > 35000000))) -		goto err_freq; -	/* Check frequency for quartz */ -	if (!(pdata->driver_flags & MAX310X_EXT_CLK) && -	   ((pdata->frequency < 1000000) || (pdata->frequency > 4000000))) -		goto err_freq; - -	s->pdata = pdata; -	s->devtype = devtype; -	dev_set_drvdata(dev, s); - -	mutex_init(&s->mutex); +	clk_osc = devm_clk_get(dev, "osc"); +	clk_xtal = devm_clk_get(dev, "xtal"); +	if (!IS_ERR(clk_osc)) { +		s->clk = clk_osc; +		fmin = 500000; +		fmax = 35000000; +	} else if (!IS_ERR(clk_xtal)) { +		s->clk = clk_xtal; +		fmin = 1000000; +		fmax = 4000000; +		xtal = true; +	} else if (PTR_ERR(clk_osc) == -EPROBE_DEFER || +		   PTR_ERR(clk_xtal) == -EPROBE_DEFER) { +		return -EPROBE_DEFER; +	} else { +		dev_err(dev, "Cannot get clock\n"); +		return -EINVAL; +	} -	/* Setup regmap */ -	s->regcfg.reg_bits		= 8; -	s->regcfg.val_bits		= 8; -	s->regcfg.read_flag_mask	= 0x00; -	s->regcfg.write_flag_mask	= 0x80; -	s->regcfg.cache_type		= REGCACHE_RBTREE; -	s->regcfg.writeable_reg		= max310x_reg_writeable; -	s->regcfg.volatile_reg		= max310x_reg_volatile; -	s->regcfg.precious_reg		= max310x_reg_precious; -	s->regcfg.max_register		= devtype->nr * 0x20 - 1; - -	if (IS_ENABLED(CONFIG_SPI_MASTER) && is_spi) { -		struct spi_device *spi = to_spi_device(dev); - -		s->regmap = devm_regmap_init_spi(spi, &s->regcfg); -	} else -		return -ENOTSUPP; +	ret = clk_prepare_enable(s->clk); +	if (ret) +		return ret; -	if (IS_ERR(s->regmap)) { -		dev_err(dev, "Failed to initialize register map\n"); -		return PTR_ERR(s->regmap); +	freq = clk_get_rate(s->clk); +	/* Check frequency limits */ +	if (freq < fmin || freq > fmax) { +		ret = -ERANGE; +		goto out_clk;  	} -	/* Board specific configure */ -	if (s->pdata->init) -		s->pdata->init(); +	s->regmap = regmap; +	s->devtype = devtype; +	dev_set_drvdata(dev, s);  	/* Check device to ensure we are talking to what we expect */  	ret = devtype->detect(dev);  	if (ret) -		return ret; +		goto out_clk;  	for (i = 0; i < devtype->nr; i++) {  		unsigned int offs = i << 5; @@ -1156,7 +1173,7 @@ static int max310x_probe(struct device *dev, int is_spi,  				   MAX310X_MODE1_AUTOSLEEP_BIT);  	} -	uartclk = max310x_set_ref_clk(s); +	uartclk = max310x_set_ref_clk(s, freq, xtal);  	dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);  	/* Register UART driver */ @@ -1168,9 +1185,28 @@ static int max310x_probe(struct device *dev, int is_spi,  	ret = uart_register_driver(&s->uart);  	if (ret) {  		dev_err(dev, "Registering UART driver failed\n"); -		return ret; +		goto out_clk;  	} +#ifdef CONFIG_GPIOLIB +	/* Setup GPIO cotroller */ +	s->gpio.owner		= THIS_MODULE; +	s->gpio.dev		= dev; +	s->gpio.label		= dev_name(dev); +	s->gpio.direction_input	= max310x_gpio_direction_input; +	s->gpio.get		= max310x_gpio_get; +	s->gpio.direction_output= max310x_gpio_direction_output; +	s->gpio.set		= max310x_gpio_set; +	s->gpio.base		= -1; +	s->gpio.ngpio		= devtype->nr * 4; +	s->gpio.can_sleep	= 1; +	ret = gpiochip_add(&s->gpio); +	if (ret) +		goto out_uart; +#endif + +	mutex_init(&s->mutex); +  	for (i = 0; i < devtype->nr; i++) {  		/* Initialize port data */  		s->p[i].port.line	= i; @@ -1178,8 +1214,7 @@ static int max310x_probe(struct device *dev, int is_spi,  		s->p[i].port.irq	= irq;  		s->p[i].port.type	= PORT_MAX310X;  		s->p[i].port.fifosize	= MAX310X_FIFO_SIZE; -		s->p[i].port.flags	= UPF_SKIP_TEST | UPF_FIXED_TYPE | -					  UPF_LOW_LATENCY; +		s->p[i].port.flags	= UPF_FIXED_TYPE | UPF_LOW_LATENCY;  		s->p[i].port.iotype	= UPIO_PORT;  		s->p[i].port.iobase	= i * 0x20;  		s->p[i].port.membase	= (void __iomem *)~0; @@ -1195,48 +1230,35 @@ static int max310x_probe(struct device *dev, int is_spi,  				    MAX310X_MODE1_IRQSEL_BIT);  		/* Initialize queue for start TX */  		INIT_WORK(&s->p[i].tx_work, max310x_wq_proc); +		/* Initialize queue for changing mode */ +		INIT_WORK(&s->p[i].md_work, max310x_md_proc);  		/* Register port */  		uart_add_one_port(&s->uart, &s->p[i].port);  		/* Go to suspend mode */  		devtype->power(&s->p[i].port, 0);  	} -#ifdef CONFIG_GPIOLIB -	/* Setup GPIO cotroller */ -	if (s->pdata->gpio_base) { -		s->gpio.owner		= THIS_MODULE; -		s->gpio.dev		= dev; -		s->gpio.label		= dev_name(dev); -		s->gpio.direction_input	= max310x_gpio_direction_input; -		s->gpio.get		= max310x_gpio_get; -		s->gpio.direction_output= max310x_gpio_direction_output; -		s->gpio.set		= max310x_gpio_set; -		s->gpio.base		= s->pdata->gpio_base; -		s->gpio.ngpio		= devtype->nr * 4; -		s->gpio.can_sleep	= 1; -		if (!gpiochip_add(&s->gpio)) -			s->gpio_used = 1; -	} else -		dev_info(dev, "GPIO support not enabled\n"); -#endif -  	/* Setup interrupt */  	ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, -					IRQF_TRIGGER_FALLING | IRQF_ONESHOT, -					dev_name(dev), s); -	if (ret) { -		dev_err(dev, "Unable to reguest IRQ %i\n", irq); +					IRQF_ONESHOT | flags, dev_name(dev), s); +	if (!ret) +		return 0; + +	dev_err(dev, "Unable to reguest IRQ %i\n", irq); + +	mutex_destroy(&s->mutex); +  #ifdef CONFIG_GPIOLIB -		if (s->gpio_used) -			WARN_ON(gpiochip_remove(&s->gpio)); +	WARN_ON(gpiochip_remove(&s->gpio)); + +out_uart:  #endif -	} +	uart_unregister_driver(&s->uart); -	return ret; +out_clk: +	clk_disable_unprepare(s->clk); -err_freq: -	dev_err(dev, "Frequency parameter incorrect\n"); -	return -EINVAL; +	return ret;  }  static int max310x_remove(struct device *dev) @@ -1244,30 +1266,51 @@ static int max310x_remove(struct device *dev)  	struct max310x_port *s = dev_get_drvdata(dev);  	int i, ret = 0; +#ifdef CONFIG_GPIOLIB +	ret = gpiochip_remove(&s->gpio); +	if (ret) +		return ret; +#endif +  	for (i = 0; i < s->uart.nr; i++) {  		cancel_work_sync(&s->p[i].tx_work); +		cancel_work_sync(&s->p[i].md_work);  		uart_remove_one_port(&s->uart, &s->p[i].port);  		s->devtype->power(&s->p[i].port, 0);  	} +	mutex_destroy(&s->mutex);  	uart_unregister_driver(&s->uart); - -#ifdef CONFIG_GPIOLIB -	if (s->gpio_used) -		ret = gpiochip_remove(&s->gpio); -#endif - -	if (s->pdata->exit) -		s->pdata->exit(); +	clk_disable_unprepare(s->clk);  	return ret;  } +static const struct of_device_id __maybe_unused max310x_dt_ids[] = { +	{ .compatible = "maxim,max3107",	.data = &max3107_devtype, }, +	{ .compatible = "maxim,max3108",	.data = &max3108_devtype, }, +	{ .compatible = "maxim,max3109",	.data = &max3109_devtype, }, +	{ .compatible = "maxim,max14830",	.data = &max14830_devtype }, +	{ } +}; +MODULE_DEVICE_TABLE(of, max310x_dt_ids); + +static struct regmap_config regcfg = { +	.reg_bits = 8, +	.val_bits = 8, +	.write_flag_mask = 0x80, +	.cache_type = REGCACHE_RBTREE, +	.writeable_reg = max310x_reg_writeable, +	.volatile_reg = max310x_reg_volatile, +	.precious_reg = max310x_reg_precious, +}; +  #ifdef CONFIG_SPI_MASTER  static int max310x_spi_probe(struct spi_device *spi)  { -	struct max310x_devtype *devtype = -		(struct max310x_devtype *)spi_get_device_id(spi)->driver_data; +	struct max310x_devtype *devtype; +	unsigned long flags = 0; +	struct regmap *regmap;  	int ret;  	/* Setup SPI bus */ @@ -1275,12 +1318,25 @@ static int max310x_spi_probe(struct spi_device *spi)  	spi->mode		= spi->mode ? : SPI_MODE_0;  	spi->max_speed_hz	= spi->max_speed_hz ? : 26000000;  	ret = spi_setup(spi); -	if (ret) { -		dev_err(&spi->dev, "SPI setup failed\n"); +	if (ret)  		return ret; + +	if (spi->dev.of_node) { +		const struct of_device_id *of_id = +			of_match_device(max310x_dt_ids, &spi->dev); + +		devtype = (struct max310x_devtype *)of_id->data; +	} else { +		const struct spi_device_id *id_entry = spi_get_device_id(spi); + +		devtype = (struct max310x_devtype *)id_entry->driver_data; +		flags = IRQF_TRIGGER_FALLING;  	} -	return max310x_probe(&spi->dev, 1, devtype, spi->irq); +	regcfg.max_register = devtype->nr * 0x20 - 1; +	regmap = devm_regmap_init_spi(spi, ®cfg); + +	return max310x_probe(&spi->dev, devtype, regmap, spi->irq, flags);  }  static int max310x_spi_remove(struct spi_device *spi) @@ -1288,8 +1344,6 @@ static int max310x_spi_remove(struct spi_device *spi)  	return max310x_remove(&spi->dev);  } -static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); -  static const struct spi_device_id max310x_id_table[] = {  	{ "max3107",	(kernel_ulong_t)&max3107_devtype, },  	{ "max3108",	(kernel_ulong_t)&max3108_devtype, }, @@ -1301,9 +1355,10 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table);  static struct spi_driver max310x_uart_driver = {  	.driver = { -		.name	= MAX310X_NAME, -		.owner	= THIS_MODULE, -		.pm	= &max310x_pm_ops, +		.name		= MAX310X_NAME, +		.owner		= THIS_MODULE, +		.of_match_table	= of_match_ptr(max310x_dt_ids), +		.pm		= &max310x_pm_ops,  	},  	.probe		= max310x_spi_probe,  	.remove		= max310x_spi_remove, diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 0edfaf8cd26..a6f085717f9 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -248,6 +248,12 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,  		mr1 |= MCFUART_MR1_PARITYNONE;  	} +	/* +	 * FIXME: port->read_status_mask and port->ignore_status_mask +	 * need to be initialized based on termios settings for +	 * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT +	 */ +  	if (termios->c_cflag & CSTOPB)  		mr2 |= MCFUART_MR2_STOP2;  	else diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c new file mode 100644 index 00000000000..c9d18548783 --- /dev/null +++ b/drivers/tty/serial/men_z135_uart.c @@ -0,0 +1,867 @@ +/* + * MEN 16z135 High Speed UART + * + * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de) + * Author: Johannes Thumshirn <johannes.thumshirn@men.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2 of the License. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/serial_core.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/tty_flip.h> +#include <linux/bitops.h> +#include <linux/mcb.h> + +#define MEN_Z135_MAX_PORTS		12 +#define MEN_Z135_BASECLK		29491200 +#define MEN_Z135_FIFO_SIZE		1024 +#define MEN_Z135_NUM_MSI_VECTORS	2 +#define MEN_Z135_FIFO_WATERMARK		1020 + +#define MEN_Z135_STAT_REG		0x0 +#define MEN_Z135_RX_RAM			0x4 +#define MEN_Z135_TX_RAM			0x400 +#define MEN_Z135_RX_CTRL		0x800 +#define MEN_Z135_TX_CTRL		0x804 +#define MEN_Z135_CONF_REG		0x808 +#define MEN_Z135_UART_FREQ		0x80c +#define MEN_Z135_BAUD_REG		0x810 +#define MENZ135_TIMEOUT			0x814 + +#define MEN_Z135_MEM_SIZE		0x818 + +#define IS_IRQ(x) ((x) & 1) +#define IRQ_ID(x) (((x) >> 1) & 7) + +#define MEN_Z135_IER_RXCIEN BIT(0)		/* RX Space IRQ */ +#define MEN_Z135_IER_TXCIEN BIT(1)		/* TX Space IRQ */ +#define MEN_Z135_IER_RLSIEN BIT(2)		/* Receiver Line Status IRQ */ +#define MEN_Z135_IER_MSIEN  BIT(3)		/* Modem Status IRQ */ +#define MEN_Z135_ALL_IRQS (MEN_Z135_IER_RXCIEN		\ +				| MEN_Z135_IER_RLSIEN	\ +				| MEN_Z135_IER_MSIEN	\ +				| MEN_Z135_IER_TXCIEN) + +#define MEN_Z135_MCR_DTR	BIT(24) +#define MEN_Z135_MCR_RTS	BIT(25) +#define MEN_Z135_MCR_OUT1	BIT(26) +#define MEN_Z135_MCR_OUT2	BIT(27) +#define MEN_Z135_MCR_LOOP	BIT(28) +#define MEN_Z135_MCR_RCFC	BIT(29) + +#define MEN_Z135_MSR_DCTS	BIT(0) +#define MEN_Z135_MSR_DDSR	BIT(1) +#define MEN_Z135_MSR_DRI	BIT(2) +#define MEN_Z135_MSR_DDCD	BIT(3) +#define MEN_Z135_MSR_CTS	BIT(4) +#define MEN_Z135_MSR_DSR	BIT(5) +#define MEN_Z135_MSR_RI		BIT(6) +#define MEN_Z135_MSR_DCD	BIT(7) + +#define MEN_Z135_LCR_SHIFT 8	/* LCR shift mask */ + +#define MEN_Z135_WL5 0		/* CS5 */ +#define MEN_Z135_WL6 1		/* CS6 */ +#define MEN_Z135_WL7 2		/* CS7 */ +#define MEN_Z135_WL8 3		/* CS8 */ + +#define MEN_Z135_STB_SHIFT 2	/* Stopbits */ +#define MEN_Z135_NSTB1 0 +#define MEN_Z135_NSTB2 1 + +#define MEN_Z135_PEN_SHIFT 3	/* Parity enable */ +#define MEN_Z135_PAR_DIS 0 +#define MEN_Z135_PAR_ENA 1 + +#define MEN_Z135_PTY_SHIFT 4	/* Parity type */ +#define MEN_Z135_PTY_ODD 0 +#define MEN_Z135_PTY_EVN 1 + +#define MEN_Z135_LSR_DR BIT(0) +#define MEN_Z135_LSR_OE BIT(1) +#define MEN_Z135_LSR_PE BIT(2) +#define MEN_Z135_LSR_FE BIT(3) +#define MEN_Z135_LSR_BI BIT(4) +#define MEN_Z135_LSR_THEP BIT(5) +#define MEN_Z135_LSR_TEXP BIT(6) +#define MEN_Z135_LSR_RXFIFOERR BIT(7) + +#define MEN_Z135_IRQ_ID_MST 0 +#define MEN_Z135_IRQ_ID_TSA 1 +#define MEN_Z135_IRQ_ID_RDA 2 +#define MEN_Z135_IRQ_ID_RLS 3 +#define MEN_Z135_IRQ_ID_CTI 6 + +#define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff) + +#define BYTES_TO_ALIGN(x) ((x) & 0x3) + +static int line; + +static int txlvl = 5; +module_param(txlvl, int, S_IRUGO); +MODULE_PARM_DESC(txlvl, "TX IRQ trigger level 0-7, default 5 (128 byte)"); + +static int rxlvl = 6; +module_param(rxlvl, int, S_IRUGO); +MODULE_PARM_DESC(rxlvl, "RX IRQ trigger level 0-7, default 6 (256 byte)"); + +static int align; +module_param(align, int, S_IRUGO); +MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0"); + +struct men_z135_port { +	struct uart_port port; +	struct mcb_device *mdev; +	unsigned char *rxbuf; +	u32 stat_reg; +	spinlock_t lock; +}; +#define to_men_z135(port) container_of((port), struct men_z135_port, port) + +/** + * men_z135_reg_set() - Set value in register + * @uart: The UART port + * @addr: Register address + * @val: value to set + */ +static inline void men_z135_reg_set(struct men_z135_port *uart, +				u32 addr, u32 val) +{ +	struct uart_port *port = &uart->port; +	unsigned long flags; +	u32 reg; + +	spin_lock_irqsave(&uart->lock, flags); + +	reg = ioread32(port->membase + addr); +	reg |= val; +	iowrite32(reg, port->membase + addr); + +	spin_unlock_irqrestore(&uart->lock, flags); +} + +/** + * men_z135_reg_clr() - Unset value in register + * @uart: The UART port + * @addr: Register address + * @val: value to clear + */ +static inline void men_z135_reg_clr(struct men_z135_port *uart, +				u32 addr, u32 val) +{ +	struct uart_port *port = &uart->port; +	unsigned long flags; +	u32 reg; + +	spin_lock_irqsave(&uart->lock, flags); + +	reg = ioread32(port->membase + addr); +	reg &= ~val; +	iowrite32(reg, port->membase + addr); + +	spin_unlock_irqrestore(&uart->lock, flags); +} + +/** + * men_z135_handle_modem_status() - Handle change of modem status + * @port: The UART port + * + * Handle change of modem status register. This is done by reading the "delta" + * versions of DCD (Data Carrier Detect) and CTS (Clear To Send). + */ +static void men_z135_handle_modem_status(struct men_z135_port *uart) +{ +	if (uart->stat_reg & MEN_Z135_MSR_DDCD) +		uart_handle_dcd_change(&uart->port, +				uart->stat_reg & ~MEN_Z135_MSR_DCD); +	if (uart->stat_reg & MEN_Z135_MSR_DCTS) +		uart_handle_cts_change(&uart->port, +				uart->stat_reg & ~MEN_Z135_MSR_CTS); +} + +static void men_z135_handle_lsr(struct men_z135_port *uart) +{ +	struct uart_port *port = &uart->port; +	u8 lsr; + +	lsr = (uart->stat_reg >> 16) & 0xff; + +	if (lsr & MEN_Z135_LSR_OE) +		port->icount.overrun++; +	if (lsr & MEN_Z135_LSR_PE) +		port->icount.parity++; +	if (lsr & MEN_Z135_LSR_FE) +		port->icount.frame++; +	if (lsr & MEN_Z135_LSR_BI) { +		port->icount.brk++; +		uart_handle_break(port); +	} +} + +/** + * get_rx_fifo_content() - Get the number of bytes in RX FIFO + * @uart: The UART port + * + * Read RXC register from hardware and return current FIFO fill size. + */ +static u16 get_rx_fifo_content(struct men_z135_port *uart) +{ +	struct uart_port *port = &uart->port; +	u32 stat_reg; +	u16 rxc; +	u8 rxc_lo; +	u8 rxc_hi; + +	stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); +	rxc_lo = stat_reg >> 24; +	rxc_hi = (stat_reg & 0xC0) >> 6; + +	rxc = rxc_lo | (rxc_hi << 8); + +	return rxc; +} + +/** + * men_z135_handle_rx() - RX tasklet routine + * @arg: Pointer to struct men_z135_port + * + * Copy from RX FIFO and acknowledge number of bytes copied. + */ +static void men_z135_handle_rx(struct men_z135_port *uart) +{ +	struct uart_port *port = &uart->port; +	struct tty_port *tport = &port->state->port; +	int copied; +	u16 size; +	int room; + +	size = get_rx_fifo_content(uart); + +	if (size == 0) +		return; + +	/* Avoid accidently accessing TX FIFO instead of RX FIFO. Last +	 * longword in RX FIFO cannot be read.(0x004-0x3FF) +	 */ +	if (size > MEN_Z135_FIFO_WATERMARK) +		size = MEN_Z135_FIFO_WATERMARK; + +	room = tty_buffer_request_room(tport, size); +	if (room != size) +		dev_warn(&uart->mdev->dev, +			"Not enough room in flip buffer, truncating to %d\n", +			room); + +	if (room == 0) +		return; + +	memcpy_fromio(uart->rxbuf, port->membase + MEN_Z135_RX_RAM, room); +	/* Be sure to first copy all data and then acknowledge it */ +	mb(); +	iowrite32(room, port->membase +  MEN_Z135_RX_CTRL); + +	copied = tty_insert_flip_string(tport, uart->rxbuf, room); +	if (copied != room) +		dev_warn(&uart->mdev->dev, +			"Only copied %d instead of %d bytes\n", +			copied, room); + +	port->icount.rx += copied; + +	tty_flip_buffer_push(tport); + +} + +/** + * men_z135_handle_tx() - TX tasklet routine + * @arg: Pointer to struct men_z135_port + * + */ +static void men_z135_handle_tx(struct men_z135_port *uart) +{ +	struct uart_port *port = &uart->port; +	struct circ_buf *xmit = &port->state->xmit; +	u32 txc; +	u32 wptr; +	int qlen; +	int n; +	int txfree; +	int head; +	int tail; +	int s; + +	if (uart_circ_empty(xmit)) +		goto out; + +	if (uart_tx_stopped(port)) +		goto out; + +	if (port->x_char) +		goto out; + +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) +		uart_write_wakeup(port); + +	/* calculate bytes to copy */ +	qlen = uart_circ_chars_pending(xmit); +	if (qlen <= 0) +		goto out; + +	wptr = ioread32(port->membase + MEN_Z135_TX_CTRL); +	txc = (wptr >> 16) & 0x3ff; +	wptr &= 0x3ff; + +	if (txc > MEN_Z135_FIFO_WATERMARK) +		txc = MEN_Z135_FIFO_WATERMARK; + +	txfree = MEN_Z135_FIFO_WATERMARK - txc; +	if (txfree <= 0) { +		pr_err("Not enough room in TX FIFO have %d, need %d\n", +			txfree, qlen); +		goto irq_en; +	} + +	/* if we're not aligned, it's better to copy only 1 or 2 bytes and +	 * then the rest. +	 */ +	if (align && qlen >= 3 && BYTES_TO_ALIGN(wptr)) +		n = 4 - BYTES_TO_ALIGN(wptr); +	else if (qlen > txfree) +		n = txfree; +	else +		n = qlen; + +	if (n <= 0) +		goto irq_en; + +	head = xmit->head & (UART_XMIT_SIZE - 1); +	tail = xmit->tail & (UART_XMIT_SIZE - 1); + +	s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; +	n = min(n, s); + +	memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n); +	xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1); +	mmiowb(); + +	iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL); + +	port->icount.tx += n; + +irq_en: +	if (!uart_circ_empty(xmit)) +		men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); +	else +		men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); + +out: +	return; + +} + +/** + * men_z135_intr() - Handle legacy IRQs + * @irq: The IRQ number + * @data: Pointer to UART port + * + * Check IIR register to see which tasklet to start. + */ +static irqreturn_t men_z135_intr(int irq, void *data) +{ +	struct men_z135_port *uart = (struct men_z135_port *)data; +	struct uart_port *port = &uart->port; +	int irq_id; + +	uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); +	/* IRQ pending is low active */ +	if (IS_IRQ(uart->stat_reg)) +		return IRQ_NONE; + +	irq_id = IRQ_ID(uart->stat_reg); +	switch (irq_id) { +	case MEN_Z135_IRQ_ID_MST: +		men_z135_handle_modem_status(uart); +		break; +	case MEN_Z135_IRQ_ID_TSA: +		men_z135_handle_tx(uart); +		break; +	case MEN_Z135_IRQ_ID_CTI: +		dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n"); +		/* Fallthrough */ +	case MEN_Z135_IRQ_ID_RDA: +		/* Reading data clears RX IRQ */ +		men_z135_handle_rx(uart); +		break; +	case MEN_Z135_IRQ_ID_RLS: +		men_z135_handle_lsr(uart); +		break; +	default: +		dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id); +		return IRQ_NONE; +	} + +	return IRQ_HANDLED; +} + +/** + * men_z135_request_irq() - Request IRQ for 16z135 core + * @uart: z135 private uart port structure + * + * Request an IRQ for 16z135 to use. First try using MSI, if it fails + * fall back to using legacy interrupts. + */ +static int men_z135_request_irq(struct men_z135_port *uart) +{ +	struct device *dev = &uart->mdev->dev; +	struct uart_port *port = &uart->port; +	int err = 0; + +	err = request_irq(port->irq, men_z135_intr, IRQF_SHARED, +			"men_z135_intr", uart); +	if (err) +		dev_err(dev, "Error %d getting interrupt\n", err); + +	return err; +} + +/** + * men_z135_tx_empty() - Handle tx_empty call + * @port: The UART port + * + * This function tests whether the TX FIFO and shifter for the port + * described by @port is empty. + */ +static unsigned int men_z135_tx_empty(struct uart_port *port) +{ +	u32 wptr; +	u16 txc; + +	wptr = ioread32(port->membase + MEN_Z135_TX_CTRL); +	txc = (wptr >> 16) & 0x3ff; + +	if (txc == 0) +		return TIOCSER_TEMT; +	else +		return 0; +} + +/** + * men_z135_set_mctrl() - Set modem control lines + * @port: The UART port + * @mctrl: The modem control lines + * + * This function sets the modem control lines for a port described by @port + * to the state described by @mctrl + */ +static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +	struct men_z135_port *uart = to_men_z135(port); +	u32 conf_reg = 0; + +	if (mctrl & TIOCM_RTS) +		conf_reg |= MEN_Z135_MCR_RTS; +	if (mctrl & TIOCM_DTR) +		conf_reg |= MEN_Z135_MCR_DTR; +	if (mctrl & TIOCM_OUT1) +		conf_reg |= MEN_Z135_MCR_OUT1; +	if (mctrl & TIOCM_OUT2) +		conf_reg |= MEN_Z135_MCR_OUT2; +	if (mctrl & TIOCM_LOOP) +		conf_reg |= MEN_Z135_MCR_LOOP; + +	men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg); +} + +/** + * men_z135_get_mctrl() - Get modem control lines + * @port: The UART port + * + * Retruns the current state of modem control inputs. + */ +static unsigned int men_z135_get_mctrl(struct uart_port *port) +{ +	unsigned int mctrl = 0; +	u32 stat_reg; +	u8 msr; + +	stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); + +	msr = ~((stat_reg >> 8) & 0xff); + +	if (msr & MEN_Z135_MSR_CTS) +		mctrl |= TIOCM_CTS; +	if (msr & MEN_Z135_MSR_DSR) +		mctrl |= TIOCM_DSR; +	if (msr & MEN_Z135_MSR_RI) +		mctrl |= TIOCM_RI; +	if (msr & MEN_Z135_MSR_DCD) +		mctrl |= TIOCM_CAR; + +	return mctrl; +} + +/** + * men_z135_stop_tx() - Stop transmitting characters + * @port: The UART port + * + * Stop transmitting characters. This might be due to CTS line becomming + * inactive or the tty layer indicating we want to stop transmission due to + * an XOFF character. + */ +static void men_z135_stop_tx(struct uart_port *port) +{ +	struct men_z135_port *uart = to_men_z135(port); + +	men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); +} + +/** + * men_z135_start_tx() - Start transmitting characters + * @port: The UART port + * + * Start transmitting character. This actually doesn't transmit anything, but + * fires off the TX tasklet. + */ +static void men_z135_start_tx(struct uart_port *port) +{ +	struct men_z135_port *uart = to_men_z135(port); + +	men_z135_handle_tx(uart); +} + +/** + * men_z135_stop_rx() - Stop receiving characters + * @port: The UART port + * + * Stop receiving characters; the port is in the process of being closed. + */ +static void men_z135_stop_rx(struct uart_port *port) +{ +	struct men_z135_port *uart = to_men_z135(port); + +	men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_RXCIEN); +} + +/** + * men_z135_enable_ms() - Enable Modem Status + * port: + * + * Enable Modem Status IRQ. + */ +static void men_z135_enable_ms(struct uart_port *port) +{ +	struct men_z135_port *uart = to_men_z135(port); + +	men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN); +} + +static int men_z135_startup(struct uart_port *port) +{ +	struct men_z135_port *uart = to_men_z135(port); +	int err; +	u32 conf_reg = 0; + +	err = men_z135_request_irq(uart); +	if (err) +		return -ENODEV; + +	conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG); + +	/* Activate all but TX space available IRQ */ +	conf_reg |= MEN_Z135_ALL_IRQS & ~MEN_Z135_IER_TXCIEN; +	conf_reg &= ~(0xff << 16); +	conf_reg |= (txlvl << 16); +	conf_reg |= (rxlvl << 20); + +	iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG); + +	return 0; +} + +static void men_z135_shutdown(struct uart_port *port) +{ +	struct men_z135_port *uart = to_men_z135(port); +	u32 conf_reg = 0; + +	conf_reg |= MEN_Z135_ALL_IRQS; + +	men_z135_reg_clr(uart, MEN_Z135_CONF_REG, conf_reg); + +	free_irq(uart->port.irq, uart); +} + +static void men_z135_set_termios(struct uart_port *port, +				struct ktermios *termios, +				struct ktermios *old) +{ +	unsigned int baud; +	u32 conf_reg; +	u32 bd_reg; +	u32 uart_freq; +	u8 lcr; + +	conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG); +	lcr = LCR(conf_reg); + +	/* byte size */ +	switch (termios->c_cflag & CSIZE) { +	case CS5: +		lcr |= MEN_Z135_WL5; +		break; +	case CS6: +		lcr |= MEN_Z135_WL6; +		break; +	case CS7: +		lcr |= MEN_Z135_WL7; +		break; +	case CS8: +		lcr |= MEN_Z135_WL8; +		break; +	} + +	/* stop bits */ +	if (termios->c_cflag & CSTOPB) +		lcr |= MEN_Z135_NSTB2 << MEN_Z135_STB_SHIFT; + +	/* parity */ +	if (termios->c_cflag & PARENB) { +		lcr |= MEN_Z135_PAR_ENA << MEN_Z135_PEN_SHIFT; + +		if (termios->c_cflag & PARODD) +			lcr |= MEN_Z135_PTY_ODD << MEN_Z135_PTY_SHIFT; +		else +			lcr |= MEN_Z135_PTY_EVN << MEN_Z135_PTY_SHIFT; +	} else +		lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT; + +	termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ + +	conf_reg |= lcr << MEN_Z135_LCR_SHIFT; +	iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG); + +	uart_freq = ioread32(port->membase + MEN_Z135_UART_FREQ); +	if (uart_freq == 0) +		uart_freq = MEN_Z135_BASECLK; + +	baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16); + +	spin_lock(&port->lock); +	if (tty_termios_baud_rate(termios)) +		tty_termios_encode_baud_rate(termios, baud, baud); + +	bd_reg = uart_freq / (4 * baud); +	iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG); + +	uart_update_timeout(port, termios->c_cflag, baud); +	spin_unlock(&port->lock); +} + +static const char *men_z135_type(struct uart_port *port) +{ +	return KBUILD_MODNAME; +} + +static void men_z135_release_port(struct uart_port *port) +{ +	iounmap(port->membase); +	port->membase = NULL; + +	release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE); +} + +static int men_z135_request_port(struct uart_port *port) +{ +	int size = MEN_Z135_MEM_SIZE; + +	if (!request_mem_region(port->mapbase, size, "men_z135_port")) +		return -EBUSY; + +	port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE); +	if (port->membase == NULL) { +		release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE); +		return -ENOMEM; +	} + +	return 0; +} + +static void men_z135_config_port(struct uart_port *port, int type) +{ +	port->type = PORT_MEN_Z135; +	men_z135_request_port(port); +} + +static int men_z135_verify_port(struct uart_port *port, +				struct serial_struct *serinfo) +{ +	return -EINVAL; +} + +static struct uart_ops men_z135_ops = { +	.tx_empty = men_z135_tx_empty, +	.set_mctrl = men_z135_set_mctrl, +	.get_mctrl = men_z135_get_mctrl, +	.stop_tx = men_z135_stop_tx, +	.start_tx = men_z135_start_tx, +	.stop_rx = men_z135_stop_rx, +	.enable_ms = men_z135_enable_ms, +	.startup = men_z135_startup, +	.shutdown = men_z135_shutdown, +	.set_termios = men_z135_set_termios, +	.type = men_z135_type, +	.release_port = men_z135_release_port, +	.request_port = men_z135_request_port, +	.config_port = men_z135_config_port, +	.verify_port = men_z135_verify_port, +}; + +static struct uart_driver men_z135_driver = { +	.owner = THIS_MODULE, +	.driver_name = KBUILD_MODNAME, +	.dev_name = "ttyHSU", +	.major = 0, +	.minor = 0, +	.nr = MEN_Z135_MAX_PORTS, +}; + +/** + * men_z135_probe() - Probe a z135 instance + * @mdev: The MCB device + * @id: The MCB device ID + * + * men_z135_probe does the basic setup of hardware resources and registers the + * new uart port to the tty layer. + */ +static int men_z135_probe(struct mcb_device *mdev, +			const struct mcb_device_id *id) +{ +	struct men_z135_port *uart; +	struct resource *mem; +	struct device *dev; +	int err; + +	dev = &mdev->dev; + +	uart = devm_kzalloc(dev, sizeof(struct men_z135_port), GFP_KERNEL); +	if (!uart) +		return -ENOMEM; + +	uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL); +	if (!uart->rxbuf) +		return -ENOMEM; + +	mem = &mdev->mem; + +	mcb_set_drvdata(mdev, uart); + +	uart->port.uartclk = MEN_Z135_BASECLK * 16; +	uart->port.fifosize = MEN_Z135_FIFO_SIZE; +	uart->port.iotype = UPIO_MEM; +	uart->port.ops = &men_z135_ops; +	uart->port.irq = mcb_get_irq(mdev); +	uart->port.iotype = UPIO_MEM; +	uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; +	uart->port.line = line++; +	uart->port.dev = dev; +	uart->port.type = PORT_MEN_Z135; +	uart->port.mapbase = mem->start; +	uart->port.membase = NULL; +	uart->mdev = mdev; + +	spin_lock_init(&uart->port.lock); +	spin_lock_init(&uart->lock); + +	err = uart_add_one_port(&men_z135_driver, &uart->port); +	if (err) +		goto err; + +	return 0; + +err: +	free_page((unsigned long) uart->rxbuf); +	dev_err(dev, "Failed to add UART: %d\n", err); + +	return err; +} + +/** + * men_z135_remove() - Remove a z135 instance from the system + * + * @mdev: The MCB device + */ +static void men_z135_remove(struct mcb_device *mdev) +{ +	struct men_z135_port *uart = mcb_get_drvdata(mdev); + +	line--; +	uart_remove_one_port(&men_z135_driver, &uart->port); +	free_page((unsigned long) uart->rxbuf); +} + +static const struct mcb_device_id men_z135_ids[] = { +	{ .device = 0x87 }, +}; +MODULE_DEVICE_TABLE(mcb, men_z135_ids); + +static struct mcb_driver mcb_driver = { +	.driver = { +		.name = "z135-uart", +		.owner = THIS_MODULE, +	}, +	.probe = men_z135_probe, +	.remove = men_z135_remove, +	.id_table = men_z135_ids, +}; + +/** + * men_z135_init() - Driver Registration Routine + * + * men_z135_init is the first routine called when the driver is loaded. All it + * does is register with the legacy MEN Chameleon subsystem. + */ +static int __init men_z135_init(void) +{ +	int err; + +	err = uart_register_driver(&men_z135_driver); +	if (err) { +		pr_err("Failed to register UART: %d\n", err); +		return err; +	} + +	err = mcb_register_driver(&mcb_driver); +	if  (err) { +		pr_err("Failed to register MCB driver: %d\n", err); +		uart_unregister_driver(&men_z135_driver); +		return err; +	} + +	return 0; +} +module_init(men_z135_init); + +/** + * men_z135_exit() - Driver Exit Routine + * + * men_z135_exit is called just before the driver is removed from memory. + */ +static void __exit men_z135_exit(void) +{ +	mcb_unregister_driver(&mcb_driver); +	uart_unregister_driver(&men_z135_driver); +} +module_exit(men_z135_exit); + +MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MEN 16z135 High Speed UART"); +MODULE_ALIAS("mcb:16z135"); diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index d3db042f649..445799dc984 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -293,7 +293,7 @@ static void serial_hsu_enable_ms(struct uart_port *port)  	serial_out(up, UART_IER, up->ier);  } -void hsu_dma_tx(struct uart_hsu_port *up) +static void hsu_dma_tx(struct uart_hsu_port *up)  {  	struct circ_buf *xmit = &up->port.state->xmit;  	struct hsu_dma_buffer *dbuf = &up->txbuf; @@ -340,7 +340,8 @@ void hsu_dma_tx(struct uart_hsu_port *up)  }  /* The buffer is already cache coherent */ -void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf) +static void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, +					struct hsu_dma_buffer *dbuf)  {  	dbuf->ofs = 0; @@ -386,7 +387,8 @@ static void serial_hsu_stop_tx(struct uart_port *port)  /* This is always called in spinlock protected mode, so   * modify timeout timer is safe here */ -void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, unsigned long *flags) +static void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, +			unsigned long *flags)  {  	struct hsu_dma_buffer *dbuf = &up->rxbuf;  	struct hsu_dma_chan *chan = up->rxc; @@ -975,7 +977,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,  	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;  	if (termios->c_iflag & INPCK)  		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		up->port.read_status_mask |= UART_LSR_BI;  	/* Characters to ignore */ @@ -1183,7 +1185,7 @@ static struct console serial_hsu_console = {  #define SERIAL_HSU_CONSOLE	NULL  #endif -struct uart_ops serial_hsu_pops = { +static struct uart_ops serial_hsu_pops = {  	.tx_empty	= serial_hsu_tx_empty,  	.set_mctrl	= serial_hsu_set_mctrl,  	.get_mctrl	= serial_hsu_get_mctrl, @@ -1451,7 +1453,6 @@ static void serial_hsu_remove(struct pci_dev *pdev)  		uart_remove_one_port(&serial_hsu_reg, &up->port);  	} -	pci_set_drvdata(pdev, NULL);  	free_irq(pdev->irq, priv);  	pci_disable_device(pdev);  } @@ -1504,4 +1505,4 @@ module_init(hsu_pci_init);  module_exit(hsu_pci_exit);  MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:medfield-hsu"); +MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 5be1df39f9f..97888f4900e 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -421,6 +421,7 @@ struct psc_fifoc {  static struct psc_fifoc __iomem *psc_fifoc;  static unsigned int psc_fifoc_irq; +static struct clk *psc_fifoc_clk;  static void mpc512x_psc_fifo_init(struct uart_port *port)  { @@ -568,36 +569,73 @@ static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,  /* Init PSC FIFO Controller */  static int __init mpc512x_psc_fifoc_init(void)  { +	int err;  	struct device_node *np; +	struct clk *clk; + +	/* default error code, potentially overwritten by clock calls */ +	err = -ENODEV;  	np = of_find_compatible_node(NULL, NULL,  				     "fsl,mpc5121-psc-fifo");  	if (!np) {  		pr_err("%s: Can't find FIFOC node\n", __func__); -		return -ENODEV; +		goto out_err; +	} + +	clk = of_clk_get(np, 0); +	if (IS_ERR(clk)) { +		/* backwards compat with device trees that lack clock specs */ +		clk = clk_get_sys(np->name, "ipg"); +	} +	if (IS_ERR(clk)) { +		pr_err("%s: Can't lookup FIFO clock\n", __func__); +		err = PTR_ERR(clk); +		goto out_ofnode_put;  	} +	if (clk_prepare_enable(clk)) { +		pr_err("%s: Can't enable FIFO clock\n", __func__); +		clk_put(clk); +		goto out_ofnode_put; +	} +	psc_fifoc_clk = clk;  	psc_fifoc = of_iomap(np, 0);  	if (!psc_fifoc) {  		pr_err("%s: Can't map FIFOC\n", __func__); -		of_node_put(np); -		return -ENODEV; +		goto out_clk_disable;  	}  	psc_fifoc_irq = irq_of_parse_and_map(np, 0); -	of_node_put(np);  	if (psc_fifoc_irq == 0) {  		pr_err("%s: Can't get FIFOC irq\n", __func__); -		iounmap(psc_fifoc); -		return -ENODEV; +		goto out_unmap;  	} +	of_node_put(np);  	return 0; + +out_unmap: +	iounmap(psc_fifoc); +out_clk_disable: +	clk_disable_unprepare(psc_fifoc_clk); +	clk_put(psc_fifoc_clk); +out_ofnode_put: +	of_node_put(np); +out_err: +	return err;  }  static void __exit mpc512x_psc_fifoc_uninit(void)  {  	iounmap(psc_fifoc); + +	/* disable the clock, errors are not fatal */ +	if (psc_fifoc_clk) { +		clk_disable_unprepare(psc_fifoc_clk); +		clk_put(psc_fifoc_clk); +		psc_fifoc_clk = NULL; +	}  }  /* 512x specific interrupt handler. The caller holds the port lock */ @@ -619,29 +657,55 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)  }  static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM]; +static struct clk *psc_ipg_clk[MPC52xx_PSC_MAXNUM];  /* called from within the .request_port() callback (allocation) */  static int mpc512x_psc_alloc_clock(struct uart_port *port)  {  	int psc_num; -	char clk_name[16];  	struct clk *clk;  	int err;  	psc_num = (port->mapbase & 0xf00) >> 8; -	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num); -	clk = devm_clk_get(port->dev, clk_name); + +	clk = devm_clk_get(port->dev, "mclk");  	if (IS_ERR(clk)) {  		dev_err(port->dev, "Failed to get MCLK!\n"); -		return PTR_ERR(clk); +		err = PTR_ERR(clk); +		goto out_err;  	}  	err = clk_prepare_enable(clk);  	if (err) {  		dev_err(port->dev, "Failed to enable MCLK!\n"); -		return err; +		goto out_err;  	}  	psc_mclk_clk[psc_num] = clk; + +	clk = devm_clk_get(port->dev, "ipg"); +	if (IS_ERR(clk)) { +		dev_err(port->dev, "Failed to get IPG clock!\n"); +		err = PTR_ERR(clk); +		goto out_err; +	} +	err = clk_prepare_enable(clk); +	if (err) { +		dev_err(port->dev, "Failed to enable IPG clock!\n"); +		goto out_err; +	} +	psc_ipg_clk[psc_num] = clk; +  	return 0; + +out_err: +	if (psc_mclk_clk[psc_num]) { +		clk_disable_unprepare(psc_mclk_clk[psc_num]); +		psc_mclk_clk[psc_num] = NULL; +	} +	if (psc_ipg_clk[psc_num]) { +		clk_disable_unprepare(psc_ipg_clk[psc_num]); +		psc_ipg_clk[psc_num] = NULL; +	} +	return err;  }  /* called from within the .release_port() callback (release) */ @@ -656,6 +720,10 @@ static void mpc512x_psc_relse_clock(struct uart_port *port)  		clk_disable_unprepare(clk);  		psc_mclk_clk[psc_num] = NULL;  	} +	if (psc_ipg_clk[psc_num]) { +		clk_disable_unprepare(psc_ipg_clk[psc_num]); +		psc_ipg_clk[psc_num] = NULL; +	}  }  /* implementation of the .clock() callback (enable/disable) */ @@ -1301,7 +1369,6 @@ static struct uart_ops mpc52xx_uart_ops = {  	.shutdown	= mpc52xx_uart_shutdown,  	.set_termios	= mpc52xx_uart_set_termios,  /*	.pm		= mpc52xx_uart_pm,		Not supported yet */ -/*	.set_wake	= mpc52xx_uart_set_wake,	Not supported yet */  	.type		= mpc52xx_uart_type,  	.release_port	= mpc52xx_uart_release_port,  	.request_port	= mpc52xx_uart_request_port, @@ -1766,7 +1833,7 @@ mpc52xx_uart_of_remove(struct platform_device *op)  static int  mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)  { -	struct uart_port *port = (struct uart_port *) platform_get_drvdata(op); +	struct uart_port *port = platform_get_drvdata(op);  	if (port)  		uart_suspend_port(&mpc52xx_uart_driver, port); @@ -1777,7 +1844,7 @@ mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)  static int  mpc52xx_uart_of_resume(struct platform_device *op)  { -	struct uart_port *port = (struct uart_port *) platform_get_drvdata(op); +	struct uart_port *port = platform_get_drvdata(op);  	if (port)  		uart_resume_port(&mpc52xx_uart_driver, port); diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index 8d702677acc..759c6a6fa74 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -1458,7 +1458,7 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,  		pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE  			| SDMA_DESC_CMDSTAT_FR; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;  	/* Characters/events to ignore */ @@ -2030,7 +2030,7 @@ static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,  {  	struct mpsc_pdata	*pdata; -	pdata = (struct mpsc_pdata *)dev_get_platdata(&pd->dev); +	pdata = dev_get_platdata(&pd->dev);  	pi->port.uartclk = pdata->brg_clk_freq;  	pi->port.iotype = UPIO_MEM; diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index a67e7081f00..db0448ae59d 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -43,6 +43,7 @@  #include <linux/kthread.h>  #include <linux/spi/spi.h> +#include <linux/pm.h>  #include "mrst_max3110.h" @@ -61,6 +62,7 @@ struct uart_max3110 {  	struct task_struct *main_thread;  	struct task_struct *read_thread;  	struct mutex thread_mutex; +	struct mutex io_mutex;  	u32 baud;  	u16 cur_conf; @@ -90,6 +92,7 @@ static int max3110_write_then_read(struct uart_max3110 *max,  	struct spi_transfer	x;  	int ret; +	mutex_lock(&max->io_mutex);  	spi_message_init(&message);  	memset(&x, 0, sizeof x);  	x.len = len; @@ -104,6 +107,7 @@ static int max3110_write_then_read(struct uart_max3110 *max,  	/* Do the i/o */  	ret = spi_sync(spi, &message); +	mutex_unlock(&max->io_mutex);  	return ret;  } @@ -491,19 +495,9 @@ static int serial_m3110_startup(struct uart_port *port)  	port->state->port.low_latency = 1;  	if (max->irq) { -		max->read_thread = NULL; -		ret = request_irq(max->irq, serial_m3110_irq, -				IRQ_TYPE_EDGE_FALLING, "max3110", max); -		if (ret) { -			max->irq = 0; -			pr_err(PR_FMT "unable to allocate IRQ, polling\n"); -		}  else { -			/* Enable RX IRQ only */ -			config |= WC_RXA_IRQ_ENABLE; -		} -	} - -	if (max->irq == 0) { +		/* Enable RX IRQ only */ +		config |= WC_RXA_IRQ_ENABLE; +	} else {  		/* If IRQ is disabled, start a read thread for input data */  		max->read_thread =  			kthread_run(max3110_read_thread, max, "max3110_read"); @@ -517,8 +511,6 @@ static int serial_m3110_startup(struct uart_port *port)  	ret = max3110_out(max, config);  	if (ret) { -		if (max->irq) -			free_irq(max->irq, max);  		if (max->read_thread)  			kthread_stop(max->read_thread);  		max->read_thread = NULL; @@ -540,9 +532,6 @@ static void serial_m3110_shutdown(struct uart_port *port)  		max->read_thread = NULL;  	} -	if (max->irq) -		free_irq(max->irq, max); -  	/* Disable interrupts from this port */  	config = WC_TAG | WC_SW_SHDI;  	max3110_out(max, config); @@ -749,7 +738,8 @@ static int serial_m3110_suspend(struct device *dev)  	struct spi_device *spi = to_spi_device(dev);  	struct uart_max3110 *max = spi_get_drvdata(spi); -	disable_irq(max->irq); +	if (max->irq > 0) +		disable_irq(max->irq);  	uart_suspend_port(&serial_m3110_reg, &max->port);  	max3110_out(max, max->cur_conf | WC_SW_SHDI);  	return 0; @@ -762,7 +752,8 @@ static int serial_m3110_resume(struct device *dev)  	max3110_out(max, max->cur_conf);  	uart_resume_port(&serial_m3110_reg, &max->port); -	enable_irq(max->irq); +	if (max->irq > 0) +		enable_irq(max->irq);  	return 0;  } @@ -803,6 +794,7 @@ static int serial_m3110_probe(struct spi_device *spi)  	max->irq = (u16)spi->irq;  	mutex_init(&max->thread_mutex); +	mutex_init(&max->io_mutex);  	max->word_7bits = 0;  	max->parity = 0; @@ -840,6 +832,16 @@ static int serial_m3110_probe(struct spi_device *spi)  		goto err_kthread;  	} +	if (max->irq) { +		ret = request_irq(max->irq, serial_m3110_irq, +				IRQ_TYPE_EDGE_FALLING, "max3110", max); +		if (ret) { +			max->irq = 0; +			dev_warn(&spi->dev, +			"unable to allocate IRQ, will use polling method\n"); +		} +	} +  	spi_set_drvdata(spi, max);  	pmax = max; @@ -867,6 +869,9 @@ static int serial_m3110_remove(struct spi_device *dev)  	free_page((unsigned long)max->con_xmit.buf); +	if (max->irq) +		free_irq(max->irq, max); +  	if (max->main_thread)  		kthread_stop(max->main_thread); diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index b5d779cd3c2..72000a6d5af 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -39,13 +39,19 @@  #include "msm_serial.h" +enum { +	UARTDM_1P1 = 1, +	UARTDM_1P2, +	UARTDM_1P3, +	UARTDM_1P4, +}; +  struct msm_port {  	struct uart_port	uart;  	char			name[16];  	struct clk		*clk;  	struct clk		*pclk;  	unsigned int		imr; -	void __iomem		*gsbi_base;  	int			is_uartdm;  	unsigned int		old_snap_state;  }; @@ -309,6 +315,8 @@ static unsigned int msm_get_mctrl(struct uart_port *port)  static void msm_reset(struct uart_port *port)  { +	struct msm_port *msm_port = UART_TO_MSM(port); +  	/* reset everything */  	msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);  	msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); @@ -316,6 +324,10 @@ static void msm_reset(struct uart_port *port)  	msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);  	msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);  	msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); + +	/* Disable DM modes */ +	if (msm_port->is_uartdm) +		msm_write(port, 0, UARTDM_DMEN);  }  static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -570,7 +582,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,  	port->read_status_mask = 0;  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= UART_SR_PAR_FRAME_ERR; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= UART_SR_RX_BREAK;  	uart_update_timeout(port, termios->c_cflag, baud); @@ -586,9 +598,7 @@ static const char *msm_type(struct uart_port *port)  static void msm_release_port(struct uart_port *port)  {  	struct platform_device *pdev = to_platform_device(port->dev); -	struct msm_port *msm_port = UART_TO_MSM(port);  	struct resource *uart_resource; -	struct resource *gsbi_resource;  	resource_size_t size;  	uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -599,28 +609,12 @@ static void msm_release_port(struct uart_port *port)  	release_mem_region(port->mapbase, size);  	iounmap(port->membase);  	port->membase = NULL; - -	if (msm_port->gsbi_base) { -		writel_relaxed(GSBI_PROTOCOL_IDLE, -				msm_port->gsbi_base + GSBI_CONTROL); - -		gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1); -		if (unlikely(!gsbi_resource)) -			return; - -		size = resource_size(gsbi_resource); -		release_mem_region(gsbi_resource->start, size); -		iounmap(msm_port->gsbi_base); -		msm_port->gsbi_base = NULL; -	}  }  static int msm_request_port(struct uart_port *port)  { -	struct msm_port *msm_port = UART_TO_MSM(port);  	struct platform_device *pdev = to_platform_device(port->dev);  	struct resource *uart_resource; -	struct resource *gsbi_resource;  	resource_size_t size;  	int ret; @@ -639,30 +633,8 @@ static int msm_request_port(struct uart_port *port)  		goto fail_release_port;  	} -	gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1); -	/* Is this a GSBI-based port? */ -	if (gsbi_resource) { -		size = resource_size(gsbi_resource); - -		if (!request_mem_region(gsbi_resource->start, size, -						 "msm_serial")) { -			ret = -EBUSY; -			goto fail_release_port_membase; -		} - -		msm_port->gsbi_base = ioremap(gsbi_resource->start, size); -		if (!msm_port->gsbi_base) { -			ret = -EBUSY; -			goto fail_release_gsbi; -		} -	} -  	return 0; -fail_release_gsbi: -	release_mem_region(gsbi_resource->start, size); -fail_release_port_membase: -	iounmap(port->membase);  fail_release_port:  	release_mem_region(port->mapbase, size);  	return ret; @@ -670,7 +642,6 @@ fail_release_port:  static void msm_config_port(struct uart_port *port, int flags)  { -	struct msm_port *msm_port = UART_TO_MSM(port);  	int ret;  	if (flags & UART_CONFIG_TYPE) {  		port->type = PORT_MSM; @@ -678,9 +649,6 @@ static void msm_config_port(struct uart_port *port, int flags)  		if (ret)  			return;  	} -	if (msm_port->gsbi_base) -		writel_relaxed(GSBI_PROTOCOL_UART, -				msm_port->gsbi_base + GSBI_CONTROL);  }  static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) @@ -711,6 +679,117 @@ static void msm_power(struct uart_port *port, unsigned int state,  	}  } +#ifdef CONFIG_CONSOLE_POLL +static int msm_poll_init(struct uart_port *port) +{ +	struct msm_port *msm_port = UART_TO_MSM(port); + +	/* Enable single character mode on RX FIFO */ +	if (msm_port->is_uartdm >= UARTDM_1P4) +		msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN); + +	return 0; +} + +static int msm_poll_get_char_single(struct uart_port *port) +{ +	struct msm_port *msm_port = UART_TO_MSM(port); +	unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF; + +	if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) +		return NO_POLL_CHAR; +	else +		return msm_read(port, rf_reg) & 0xff; +} + +static int msm_poll_get_char_dm_1p3(struct uart_port *port) +{ +	int c; +	static u32 slop; +	static int count; +	unsigned char *sp = (unsigned char *)&slop; + +	/* Check if a previous read had more than one char */ +	if (count) { +		c = sp[sizeof(slop) - count]; +		count--; +	/* Or if FIFO is empty */ +	} else if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) { +		/* +		 * If RX packing buffer has less than a word, force stale to +		 * push contents into RX FIFO +		 */ +		count = msm_read(port, UARTDM_RXFS); +		count = (count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK; +		if (count) { +			msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); +			slop = msm_read(port, UARTDM_RF); +			c = sp[0]; +			count--; +		} else { +			c = NO_POLL_CHAR; +		} +	/* FIFO has a word */ +	} else { +		slop = msm_read(port, UARTDM_RF); +		c = sp[0]; +		count = sizeof(slop) - 1; +	} + +	return c; +} + +static int msm_poll_get_char(struct uart_port *port) +{ +	u32 imr; +	int c; +	struct msm_port *msm_port = UART_TO_MSM(port); + +	/* Disable all interrupts */ +	imr = msm_read(port, UART_IMR); +	msm_write(port, 0, UART_IMR); + +	if (msm_port->is_uartdm == UARTDM_1P3) +		c = msm_poll_get_char_dm_1p3(port); +	else +		c = msm_poll_get_char_single(port); + +	/* Enable interrupts */ +	msm_write(port, imr, UART_IMR); + +	return c; +} + +static void msm_poll_put_char(struct uart_port *port, unsigned char c) +{ +	u32 imr; +	struct msm_port *msm_port = UART_TO_MSM(port); + +	/* Disable all interrupts */ +	imr = msm_read(port, UART_IMR); +	msm_write(port, 0, UART_IMR); + +	if (msm_port->is_uartdm) +		reset_dm_count(port, 1); + +	/* Wait until FIFO is empty */ +	while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) +		cpu_relax(); + +	/* Write a character */ +	msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + +	/* Wait until FIFO is empty */ +	while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) +		cpu_relax(); + +	/* Enable interrupts */ +	msm_write(port, imr, UART_IMR); + +	return; +} +#endif +  static struct uart_ops msm_uart_pops = {  	.tx_empty = msm_tx_empty,  	.set_mctrl = msm_set_mctrl, @@ -729,6 +808,11 @@ static struct uart_ops msm_uart_pops = {  	.config_port = msm_config_port,  	.verify_port = msm_verify_port,  	.pm = msm_power, +#ifdef CONFIG_CONSOLE_POLL +	.poll_init = msm_poll_init, +	.poll_get_char	= msm_poll_get_char, +	.poll_put_char	= msm_poll_put_char, +#endif  };  static struct msm_port msm_uart_ports[] = { @@ -900,15 +984,19 @@ static struct uart_driver msm_uart_driver = {  static atomic_t msm_uart_next_id = ATOMIC_INIT(0);  static const struct of_device_id msm_uartdm_table[] = { -	{ .compatible = "qcom,msm-uartdm" }, +	{ .compatible = "qcom,msm-uartdm-v1.1", .data = (void *)UARTDM_1P1 }, +	{ .compatible = "qcom,msm-uartdm-v1.2", .data = (void *)UARTDM_1P2 }, +	{ .compatible = "qcom,msm-uartdm-v1.3", .data = (void *)UARTDM_1P3 }, +	{ .compatible = "qcom,msm-uartdm-v1.4", .data = (void *)UARTDM_1P4 },  	{ }  }; -static int __init msm_serial_probe(struct platform_device *pdev) +static int msm_serial_probe(struct platform_device *pdev)  {  	struct msm_port *msm_port;  	struct resource *resource;  	struct uart_port *port; +	const struct of_device_id *id;  	int irq;  	if (pdev->id == -1) @@ -923,8 +1011,9 @@ static int __init msm_serial_probe(struct platform_device *pdev)  	port->dev = &pdev->dev;  	msm_port = UART_TO_MSM(port); -	if (of_match_device(msm_uartdm_table, &pdev->dev)) -		msm_port->is_uartdm = 1; +	id = of_match_device(msm_uartdm_table, &pdev->dev); +	if (id) +		msm_port->is_uartdm = (unsigned long)id->data;  	else  		msm_port->is_uartdm = 0; @@ -976,6 +1065,7 @@ static struct of_device_id msm_match_table[] = {  static struct platform_driver msm_platform_driver = {  	.remove = msm_serial_remove, +	.probe = msm_serial_probe,  	.driver = {  		.name = "msm_serial",  		.owner = THIS_MODULE, @@ -991,7 +1081,7 @@ static int __init msm_serial_init(void)  	if (unlikely(ret))  		return ret; -	ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe); +	ret = platform_driver_register(&msm_platform_driver);  	if (unlikely(ret))  		uart_unregister_driver(&msm_uart_driver); diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h index 469fda50ac6..d98d45efdf8 100644 --- a/drivers/tty/serial/msm_serial.h +++ b/drivers/tty/serial/msm_serial.h @@ -59,6 +59,7 @@  #define UART_CR_CMD_RESET_RFR		(14 << 4)  #define UART_CR_CMD_PROTECTION_EN	(16 << 4)  #define UART_CR_CMD_STALE_EVENT_ENABLE	(80 << 4) +#define UART_CR_CMD_FORCE_STALE		(4 << 8)  #define UART_CR_CMD_RESET_TX_READY	(3 << 8)  #define UART_CR_TX_DISABLE		(1 << 3)  #define UART_CR_TX_ENABLE		(1 << 2) @@ -108,10 +109,13 @@  #define UART_ISR		0x0014  #define UART_ISR_TX_READY	(1 << 7) -#define GSBI_CONTROL		0x0 -#define GSBI_PROTOCOL_CODE	0x30 -#define GSBI_PROTOCOL_UART	0x40 -#define GSBI_PROTOCOL_IDLE	0x0 +#define UARTDM_RXFS		0x50 +#define UARTDM_RXFS_BUF_SHIFT	0x7 +#define UARTDM_RXFS_BUF_MASK	0x7 + +#define UARTDM_DMEN		0x3C +#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) +#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)  #define UARTDM_DMRX		0x34  #define UARTDM_NCF_TX		0x40 diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 7fd6aaaacd8..be127d0da32 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -29,7 +29,7 @@  #include <asm/irq.h>  #include <asm/parisc-device.h> -#ifdef CONFIG_MAGIC_SYSRQ +#if defined(CONFIG_SERIAL_MUX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)  #include <linux/sysrq.h>  #define SUPPORT_SYSRQ  #endif @@ -613,7 +613,7 @@ static void __exit mux_exit(void)  {  	/* Delete the Mux timer. */  	if(port_cnt > 0) { -		del_timer(&mux_timer); +		del_timer_sync(&mux_timer);  #ifdef CONFIG_SERIAL_MUX_CONSOLE  		unregister_console(&mux_console);  #endif diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 10e9d70b5c4..86de4477d98 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -39,6 +39,7 @@  #include <asm/cacheflush.h>  #define MXS_AUART_PORTS 5 +#define MXS_AUART_FIFO_SIZE		16  #define AUART_CTRL0			0x00000000  #define AUART_CTRL0_SET			0x00000004 @@ -199,7 +200,7 @@ static void dma_tx_callback(void *param)  	/* clear the bit used to serialize the DMA tx. */  	clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags); -	smp_mb__after_clear_bit(); +	smp_mb__after_atomic();  	/* wake up the possible processes. */  	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -274,7 +275,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)  			mxs_auart_dma_tx(s, i);  		} else {  			clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags); -			smp_mb__after_clear_bit(); +			smp_mb__after_atomic();  		}  		return;  	} @@ -548,6 +549,9 @@ static int mxs_auart_dma_init(struct mxs_auart_port *s)  	s->flags |= MXS_AUART_DMA_ENABLED;  	dev_dbg(s->dev, "enabled the DMA support."); +	/* The DMA buffer is now the FIFO the TTY subsystem can use */ +	s->port.fifosize = UART_XMIT_SIZE; +  	return 0;  err_out: @@ -600,7 +604,7 @@ static void mxs_auart_settermios(struct uart_port *u,  	if (termios->c_iflag & INPCK)  		u->read_status_mask |= AUART_STAT_PERR; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		u->read_status_mask |= AUART_STAT_BERR;  	/* @@ -730,9 +734,12 @@ static void mxs_auart_reset(struct uart_port *u)  static int mxs_auart_startup(struct uart_port *u)  { +	int ret;  	struct mxs_auart_port *s = to_auart_port(u); -	clk_prepare_enable(s->clk); +	ret = clk_prepare_enable(s->clk); +	if (ret) +		return ret;  	writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); @@ -741,6 +748,9 @@ static int mxs_auart_startup(struct uart_port *u)  	writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,  			u->membase + AUART_INTR); +	/* Reset FIFO size (it could have changed if DMA was enabled) */ +	u->fifosize = MXS_AUART_FIFO_SIZE; +  	/*  	 * Enable fifo so all four bytes of a DMA word are written to  	 * output (otherwise, only the LSB is written, ie. 1 in 4 bytes) @@ -950,7 +960,9 @@ auart_console_setup(struct console *co, char *options)  	if (!s)  		return -ENODEV; -	clk_prepare_enable(s->clk); +	ret = clk_prepare_enable(s->clk); +	if (ret) +		return ret;  	if (options)  		uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1056,7 +1068,7 @@ static int mxs_auart_probe(struct platform_device *pdev)  	s->port.membase = ioremap(r->start, resource_size(r));  	s->port.ops = &mxs_auart_ops;  	s->port.iotype = UPIO_MEM; -	s->port.fifosize = 16; +	s->port.fifosize = MXS_AUART_FIFO_SIZE;  	s->port.uartclk = clk_get_rate(s->clk);  	s->port.type = PORT_IMX;  	s->port.dev = s->dev = &pdev->dev; diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c index 0a4dd70d29e..7a6745601d4 100644 --- a/drivers/tty/serial/netx-serial.c +++ b/drivers/tty/serial/netx-serial.c @@ -419,7 +419,7 @@ netx_set_termios(struct uart_port *port, struct ktermios *termios,  	}  	port->read_status_mask = 0; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= SR_BE;  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= SR_PE | SR_FE; diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 2caf9c6f614..68d4455f3cf 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -9,7 +9,6 @@   *  2 of the License, or (at your option) any later version.   *   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/slab.h>  #include <linux/delay.h> @@ -174,6 +173,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)  	{  		struct uart_8250_port port8250;  		memset(&port8250, 0, sizeof(port8250)); +		port.type = port_type;  		port8250.port = port;  		if (port.fifosize) @@ -183,6 +183,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev)  					  "auto-flow-control"))  			port8250.capabilities |= UART_CAP_AFE; +		if (of_property_read_bool(ofdev->dev.of_node, +					  "has-hw-flow-control")) +			port8250.port.flags |= UPF_HARD_FLOW; +  		ret = serial8250_register_8250_port(&port8250);  		break;  	} diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 816d1a23f9d..d017cec8a34 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -39,6 +39,7 @@  #include <linux/irq.h>  #include <linux/pm_runtime.h>  #include <linux/of.h> +#include <linux/of_irq.h>  #include <linux/gpio.h>  #include <linux/of_gpio.h>  #include <linux/platform_data/serial-omap.h> @@ -134,6 +135,7 @@ struct uart_omap_port {  	struct uart_port	port;  	struct uart_omap_dma	uart_dma;  	struct device		*dev; +	int			wakeirq;  	unsigned char		ier;  	unsigned char		lcr; @@ -161,10 +163,6 @@ struct uart_omap_port {  	u8			wakeups_enabled;  	u32			features; -	int			DTR_gpio; -	int			DTR_inverted; -	int			DTR_active; -  	struct serial_rs485	rs485;  	int			rts_gpio; @@ -175,15 +173,13 @@ struct uart_omap_port {  	bool			is_suspending;  }; -#define to_uart_omap_port(p)	((container_of((p), struct uart_omap_port, port))) +#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port)))  static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];  /* Forward declaration of functions */  static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1); -static struct workqueue_struct *serial_omap_uart_wq; -  static inline unsigned int serial_in(struct uart_omap_port *up, int offset)  {  	offset <<= up->port.regshift; @@ -214,10 +210,28 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up)  	return pdata->get_context_loss_count(up->dev);  } +static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, +				       bool enable) +{ +	if (!up->wakeirq) +		return; + +	if (enable) +		enable_irq(up->wakeirq); +	else +		disable_irq_nosync(up->wakeirq); +} +  static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)  {  	struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); +	if (enable == up->wakeups_enabled) +		return; + +	serial_omap_enable_wakeirq(up, enable); +	up->wakeups_enabled = enable; +  	if (!pdata || !pdata->enable_wakeup)  		return; @@ -242,12 +256,12 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud)  	unsigned int n16 = port->uartclk / (16 * baud);  	int baudAbsDiff13 = baud - (port->uartclk / (13 * n13));  	int baudAbsDiff16 = baud - (port->uartclk / (16 * n16)); -	if(baudAbsDiff13 < 0) +	if (baudAbsDiff13 < 0)  		baudAbsDiff13 = -baudAbsDiff13; -	if(baudAbsDiff16 < 0) +	if (baudAbsDiff16 < 0)  		baudAbsDiff16 = -baudAbsDiff16; -	return (baudAbsDiff13 > baudAbsDiff16); +	return (baudAbsDiff13 >= baudAbsDiff16);  }  /* @@ -258,13 +272,13 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud)  static unsigned int  serial_omap_get_divisor(struct uart_port *port, unsigned int baud)  { -	unsigned int divisor; +	unsigned int mode;  	if (!serial_omap_baud_is_mode16(port, baud)) -		divisor = 13; +		mode = 13;  	else -		divisor = 16; -	return port->uartclk/(baud * divisor); +		mode = 16; +	return port->uartclk/(mode * baud);  }  static void serial_omap_enable_ms(struct uart_port *port) @@ -283,28 +297,40 @@ static void serial_omap_enable_ms(struct uart_port *port)  static void serial_omap_stop_tx(struct uart_port *port)  {  	struct uart_omap_port *up = to_uart_omap_port(port); -	struct circ_buf *xmit = &up->port.state->xmit;  	int res;  	pm_runtime_get_sync(up->dev); -	/* handle rs485 */ +	/* Handle RS-485 */  	if (up->rs485.flags & SER_RS485_ENABLED) { -		/* do nothing if current tx not yet completed */ -		res = serial_in(up, UART_LSR) & UART_LSR_TEMT; -		if (!res) -			return; - -		/* if there's no more data to send, turn off rts */ -		if (uart_circ_empty(xmit)) { -			/* if rts not already disabled */ +		if (up->scr & OMAP_UART_SCR_TX_EMPTY) { +			/* THR interrupt is fired when both TX FIFO and TX +			 * shift register are empty. This means there's nothing +			 * left to transmit now, so make sure the THR interrupt +			 * is fired when TX FIFO is below the trigger level, +			 * disable THR interrupts and toggle the RS-485 GPIO +			 * data direction pin if needed. +			 */ +			up->scr &= ~OMAP_UART_SCR_TX_EMPTY; +			serial_out(up, UART_OMAP_SCR, up->scr);  			res = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;  			if (gpio_get_value(up->rts_gpio) != res) { -				if (up->rs485.delay_rts_after_send > 0) { +				if (up->rs485.delay_rts_after_send > 0)  					mdelay(up->rs485.delay_rts_after_send); -				}  				gpio_set_value(up->rts_gpio, res);  			} +		} else { +			/* We're asked to stop, but there's still stuff in the +			 * UART FIFO, so make sure the THR interrupt is fired +			 * when both TX FIFO and TX shift register are empty. +			 * The next THR interrupt (if no transmission is started +			 * in the meantime) will indicate the end of a +			 * transmission. Therefore we _don't_ disable THR +			 * interrupts in this situation. +			 */ +			up->scr |= OMAP_UART_SCR_TX_EMPTY; +			serial_out(up, UART_OMAP_SCR, up->scr); +			return;  		}  	} @@ -315,7 +341,14 @@ static void serial_omap_stop_tx(struct uart_port *port)  	if ((up->rs485.flags & SER_RS485_ENABLED) &&  	    !(up->rs485.flags & SER_RS485_RX_DURING_TX)) { -		up->ier = UART_IER_RLSI | UART_IER_RDI; +		/* +		 * Empty the RX FIFO, we are not interested in anything +		 * received during the half-duplex transmission. +		 */ +		serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_RCVR); +		/* Re-enable RX interrupts */ +		up->ier |= UART_IER_RLSI | UART_IER_RDI; +		up->port.read_status_mask |= UART_LSR_DR;  		serial_out(up, UART_IER, up->ier);  	} @@ -328,7 +361,7 @@ static void serial_omap_stop_rx(struct uart_port *port)  	struct uart_omap_port *up = to_uart_omap_port(port);  	pm_runtime_get_sync(up->dev); -	up->ier &= ~UART_IER_RLSI; +	up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);  	up->port.read_status_mask &= ~UART_LSR_DR;  	serial_out(up, UART_IER, up->ier);  	pm_runtime_mark_last_busy(up->dev); @@ -359,11 +392,8 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)  			break;  	} while (--count > 0); -	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { -		spin_unlock(&up->port.lock); +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)  		uart_write_wakeup(&up->port); -		spin_lock(&up->port.lock); -	}  	if (uart_circ_empty(xmit))  		serial_omap_stop_tx(&up->port); @@ -384,15 +414,18 @@ static void serial_omap_start_tx(struct uart_port *port)  	pm_runtime_get_sync(up->dev); -	/* handle rs485 */ +	/* Handle RS-485 */  	if (up->rs485.flags & SER_RS485_ENABLED) { +		/* Fire THR interrupts when FIFO is below trigger level */ +		up->scr &= ~OMAP_UART_SCR_TX_EMPTY; +		serial_out(up, UART_OMAP_SCR, up->scr); +  		/* if rts not already enabled */  		res = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0;  		if (gpio_get_value(up->rts_gpio) != res) {  			gpio_set_value(up->rts_gpio, res); -			if (up->rs485.delay_rts_before_send > 0) { +			if (up->rs485.delay_rts_before_send > 0)  				mdelay(up->rs485.delay_rts_before_send); -			}  		}  	} @@ -655,16 +688,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)  	serial_out(up, UART_MCR, up->mcr);  	pm_runtime_mark_last_busy(up->dev);  	pm_runtime_put_autosuspend(up->dev); - -	if (gpio_is_valid(up->DTR_gpio) && -	    !!(mctrl & TIOCM_DTR) != up->DTR_active) { -		up->DTR_active = !up->DTR_active; -		if (gpio_cansleep(up->DTR_gpio)) -			schedule_work(&up->qos_work); -		else -			gpio_set_value(up->DTR_gpio, -				       up->DTR_active != up->DTR_inverted); -	}  }  static void serial_omap_break_ctl(struct uart_port *port, int break_state) @@ -699,6 +722,17 @@ static int serial_omap_startup(struct uart_port *port)  	if (retval)  		return retval; +	/* Optional wake-up IRQ */ +	if (up->wakeirq) { +		retval = request_irq(up->wakeirq, serial_omap_irq, +				     up->port.irqflags, up->name, up); +		if (retval) { +			free_irq(up->port.irq, up); +			return retval; +		} +		disable_irq(up->wakeirq); +	} +  	dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);  	pm_runtime_get_sync(up->dev); @@ -787,6 +821,8 @@ static void serial_omap_shutdown(struct uart_port *port)  	pm_runtime_mark_last_busy(up->dev);  	pm_runtime_put_autosuspend(up->dev);  	free_irq(up->port.irq, up); +	if (up->wakeirq) +		free_irq(up->wakeirq, up);  }  static void serial_omap_uart_qos_work(struct work_struct *work) @@ -795,9 +831,6 @@ static void serial_omap_uart_qos_work(struct work_struct *work)  						qos_work);  	pm_qos_update_request(&up->pm_qos_request, up->latency); -	if (gpio_is_valid(up->DTR_gpio)) -		gpio_set_value_cansleep(up->DTR_gpio, -					up->DTR_active != up->DTR_inverted);  }  static void @@ -938,7 +971,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,  	 */  	/* Set receive FIFO threshold to 16 characters and -	 * transmit FIFO threshold to 16 spaces +	 * transmit FIFO threshold to 32 spaces  	 */  	up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;  	up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK; @@ -1060,15 +1093,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,  	dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line);  } -static int serial_omap_set_wake(struct uart_port *port, unsigned int state) -{ -	struct uart_omap_port *up = to_uart_omap_port(port); - -	serial_omap_enable_wakeup(up, state); - -	return 0; -} -  static void  serial_omap_pm(struct uart_port *port, unsigned int state,  	       unsigned int oldstate) @@ -1353,6 +1377,15 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)  	up->ier = mode;  	serial_out(up, UART_IER, up->ier); +	/* If RS-485 is disabled, make sure the THR interrupt is fired when +	 * TX FIFO is below the trigger level. +	 */ +	if (!(up->rs485.flags & SER_RS485_ENABLED) && +	    (up->scr & OMAP_UART_SCR_TX_EMPTY)) { +		up->scr &= ~OMAP_UART_SCR_TX_EMPTY; +		serial_out(up, UART_OMAP_SCR, up->scr); +	} +  	spin_unlock_irqrestore(&up->port.lock, flags);  	pm_runtime_mark_last_busy(up->dev);  	pm_runtime_put_autosuspend(up->dev); @@ -1365,7 +1398,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)  	switch (cmd) {  	case TIOCSRS485: -		if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg, +		if (copy_from_user(&rs485conf, (void __user *) arg,  					sizeof(rs485conf)))  			return -EFAULT; @@ -1373,7 +1406,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)  		break;  	case TIOCGRS485: -		if (copy_to_user((struct serial_rs485 *) arg, +		if (copy_to_user((void __user *) arg,  					&(to_uart_omap_port(port)->rs485),  					sizeof(rs485conf)))  			return -EFAULT; @@ -1401,7 +1434,6 @@ static struct uart_ops serial_omap_pops = {  	.shutdown	= serial_omap_shutdown,  	.set_termios	= serial_omap_set_termios,  	.pm		= serial_omap_pm, -	.set_wake	= serial_omap_set_wake,  	.type		= serial_omap_type,  	.release_port	= serial_omap_release_port,  	.request_port	= serial_omap_request_port, @@ -1446,6 +1478,11 @@ static int serial_omap_suspend(struct device *dev)  	uart_suspend_port(&serial_omap_reg, &up->port);  	flush_work(&up->qos_work); +	if (device_may_wakeup(dev)) +		serial_omap_enable_wakeup(up, true); +	else +		serial_omap_enable_wakeup(up, false); +  	return 0;  } @@ -1453,6 +1490,9 @@ static int serial_omap_resume(struct device *dev)  {  	struct uart_omap_port *up = dev_get_drvdata(dev); +	if (device_may_wakeup(dev)) +		serial_omap_enable_wakeup(up, false); +  	uart_resume_port(&serial_omap_reg, &up->port);  	return 0; @@ -1552,15 +1592,18 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,  	/* check for tx enable gpio */  	up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags);  	if (gpio_is_valid(up->rts_gpio)) { -		ret = gpio_request(up->rts_gpio, "omap-serial"); +		ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial");  		if (ret < 0)  			return ret;  		ret = gpio_direction_output(up->rts_gpio,  					    flags & SER_RS485_RTS_AFTER_SEND);  		if (ret < 0)  			return ret; -	} else +	} else if (up->rts_gpio == -EPROBE_DEFER) { +		return -EPROBE_DEFER; +	} else {  		up->rts_gpio = -EINVAL; +	}  	if (of_property_read_u32_array(np, "rs485-rts-delay",  				    rs485_delay, 2) == 0) { @@ -1579,62 +1622,46 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,  static int serial_omap_probe(struct platform_device *pdev)  { -	struct uart_omap_port	*up; -	struct resource		*mem, *irq;  	struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev); +	struct uart_omap_port *up; +	struct resource *mem; +	void __iomem *base; +	int uartirq = 0; +	int wakeirq = 0;  	int ret; +	/* The optional wakeirq may be specified in the board dts file */  	if (pdev->dev.of_node) { +		uartirq = irq_of_parse_and_map(pdev->dev.of_node, 0); +		if (!uartirq) +			return -EPROBE_DEFER; +		wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);  		omap_up_info = of_get_uart_port_info(&pdev->dev);  		pdev->dev.platform_data = omap_up_info; -	} - -	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!mem) { -		dev_err(&pdev->dev, "no mem resource?\n"); -		return -ENODEV; -	} - -	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -	if (!irq) { -		dev_err(&pdev->dev, "no irq resource?\n"); -		return -ENODEV; -	} - -	if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), -				pdev->dev.driver->name)) { -		dev_err(&pdev->dev, "memory region already claimed\n"); -		return -EBUSY; -	} - -	if (gpio_is_valid(omap_up_info->DTR_gpio) && -	    omap_up_info->DTR_present) { -		ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial"); -		if (ret < 0) -			return ret; -		ret = gpio_direction_output(omap_up_info->DTR_gpio, -					    omap_up_info->DTR_inverted); -		if (ret < 0) -			return ret; +	} else { +		uartirq = platform_get_irq(pdev, 0); +		if (uartirq < 0) +			return -EPROBE_DEFER;  	}  	up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);  	if (!up)  		return -ENOMEM; -	if (gpio_is_valid(omap_up_info->DTR_gpio) && -	    omap_up_info->DTR_present) { -		up->DTR_gpio = omap_up_info->DTR_gpio; -		up->DTR_inverted = omap_up_info->DTR_inverted; -	} else -		up->DTR_gpio = -EINVAL; -	up->DTR_active = 0; +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	base = devm_ioremap_resource(&pdev->dev, mem); +	if (IS_ERR(base)) +		return PTR_ERR(base);  	up->dev = &pdev->dev;  	up->port.dev = &pdev->dev;  	up->port.type = PORT_OMAP;  	up->port.iotype = UPIO_MEM; -	up->port.irq = irq->start; +	up->port.irq = uartirq; +	up->wakeirq = wakeirq; +	if (!up->wakeirq) +		dev_info(up->port.dev, "no wakeirq for uart%d\n", +			 up->port.line);  	up->port.regshift = 2;  	up->port.fifosize = 64; @@ -1658,32 +1685,26 @@ static int serial_omap_probe(struct platform_device *pdev)  	sprintf(up->name, "OMAP UART%d", up->port.line);  	up->port.mapbase = mem->start; -	up->port.membase = devm_ioremap(&pdev->dev, mem->start, -						resource_size(mem)); -	if (!up->port.membase) { -		dev_err(&pdev->dev, "can't ioremap UART\n"); -		ret = -ENOMEM; -		goto err_ioremap; -	} - +	up->port.membase = base;  	up->port.flags = omap_up_info->flags;  	up->port.uartclk = omap_up_info->uartclk;  	if (!up->port.uartclk) {  		up->port.uartclk = DEFAULT_CLK_SPEED; -		dev_warn(&pdev->dev, "No clock speed specified: using default:" -						"%d\n", DEFAULT_CLK_SPEED); +		dev_warn(&pdev->dev, +			 "No clock speed specified: using default: %d\n", +			 DEFAULT_CLK_SPEED);  	}  	up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;  	up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;  	pm_qos_add_request(&up->pm_qos_request,  		PM_QOS_CPU_DMA_LATENCY, up->latency); -	serial_omap_uart_wq = create_singlethread_workqueue(up->name);  	INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);  	platform_set_drvdata(pdev, up);  	if (omap_up_info->autosuspend_timeout == 0)  		omap_up_info->autosuspend_timeout = -1; +  	device_init_wakeup(up->dev, true);  	pm_runtime_use_autosuspend(&pdev->dev);  	pm_runtime_set_autosuspend_delay(&pdev->dev, @@ -1710,7 +1731,6 @@ static int serial_omap_probe(struct platform_device *pdev)  err_add_port:  	pm_runtime_put(&pdev->dev);  	pm_runtime_disable(&pdev->dev); -err_ioremap:  err_rs485:  err_port_line:  	dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", @@ -1726,6 +1746,7 @@ static int serial_omap_remove(struct platform_device *dev)  	pm_runtime_disable(up->dev);  	uart_remove_one_port(&serial_omap_reg, &up->port);  	pm_qos_remove_request(&up->pm_qos_request); +	device_init_wakeup(&dev->dev, false);  	return 0;  } @@ -1814,17 +1835,7 @@ static int serial_omap_runtime_suspend(struct device *dev)  	up->context_loss_cnt = serial_omap_get_context_loss_count(up); -	if (device_may_wakeup(dev)) { -		if (!up->wakeups_enabled) { -			serial_omap_enable_wakeup(up, true); -			up->wakeups_enabled = true; -		} -	} else { -		if (up->wakeups_enabled) { -			serial_omap_enable_wakeup(up, false); -			up->wakeups_enabled = false; -		} -	} +	serial_omap_enable_wakeup(up, true);  	up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;  	schedule_work(&up->qos_work); @@ -1838,6 +1849,8 @@ static int serial_omap_runtime_resume(struct device *dev)  	int loss_cnt = serial_omap_get_context_loss_count(up); +	serial_omap_enable_wakeup(up, false); +  	if (loss_cnt < 0) {  		dev_dbg(dev, "serial_omap_get_context_loss_count failed : %d\n",  			loss_cnt); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 52379e56a31..0cb6a8e52bd 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -257,6 +257,8 @@ struct eg20t_port {  	dma_addr_t			rx_buf_dma;  	struct dentry	*debugfs; +#define IRQ_NAME_SIZE 17 +	char				irq_name[IRQ_NAME_SIZE];  	/* protect the eg20t_port private structure and io access to membase */  	spinlock_t lock; @@ -667,30 +669,21 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)  static int dma_push_rx(struct eg20t_port *priv, int size)  { -	struct tty_struct *tty;  	int room;  	struct uart_port *port = &priv->port;  	struct tty_port *tport = &port->state->port; -	port = &priv->port; -	tty = tty_port_tty_get(tport); -	if (!tty) { -		dev_dbg(priv->port.dev, "%s:tty is busy now", __func__); -		return 0; -	} -  	room = tty_buffer_request_room(tport, size);  	if (room < size)  		dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",  			 size - room);  	if (!room) -		return room; +		return 0;  	tty_insert_flip_string(tport, sg_virt(&priv->sg_rx), size);  	port->icount.rx += room; -	tty_kref_put(tty);  	return room;  } @@ -1098,6 +1091,8 @@ static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)  	if (tty == NULL) {  		for (i = 0; error_msg[i] != NULL; i++)  			dev_err(&priv->pdev->dev, error_msg[i]); +	} else { +		tty_kref_put(tty);  	}  } @@ -1350,7 +1345,7 @@ static int pch_uart_startup(struct uart_port *port)  		return ret;  	ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED, -			KBUILD_MODNAME, priv); +			priv->irq_name, priv);  	if (ret < 0)  		return ret; @@ -1515,10 +1510,14 @@ static int pch_uart_verify_port(struct uart_port *port,  			__func__);  		return -EOPNOTSUPP;  #endif -		dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); -		if (!priv->use_dma) +		if (!priv->use_dma) {  			pch_request_dma(port); -		priv->use_dma = 1; +			if (priv->chan_rx) +				priv->use_dma = 1; +		} +		dev_info(priv->port.dev, "PCH UART: %s\n", +				priv->use_dma ? +				"Use DMA Mode" : "No DMA");  	}  	return 0; @@ -1591,13 +1590,8 @@ static void pch_uart_put_poll_char(struct uart_port *port,  	wait_for_xmitr(priv, UART_LSR_THRE);  	/*  	 * Send the character out. -	 * If a LF, also do CR...  	 */  	iowrite8(c, priv->membase + PCH_UART_THR); -	if (c == 10) { -		wait_for_xmitr(priv, UART_LSR_THRE); -		iowrite8(13, priv->membase + PCH_UART_THR); -	}  	/*  	 * Finally, wait for transmitter to become empty @@ -1621,7 +1615,6 @@ static struct uart_ops pch_uart_ops = {  	.shutdown = pch_uart_shutdown,  	.set_termios = pch_uart_set_termios,  /*	.pm		= pch_uart_pm,		Not supported yet */ -/*	.set_wake	= pch_uart_set_wake,	Not supported yet */  	.type = pch_uart_type,  	.release_port = pch_uart_release_port,  	.request_port = pch_uart_request_port, @@ -1766,7 +1759,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,  	int fifosize;  	int port_type;  	struct pch_uart_driver_data *board; +#ifdef CONFIG_DEBUG_FS  	char name[32];	/* for debugfs file name */ +#endif  	board = &drv_dat[id->driver_data];  	port_type = board->port_type; @@ -1820,6 +1815,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,  	priv->port.line = board->line_no;  	priv->trigger = PCH_UART_HAL_TRIGGER_M; +	snprintf(priv->irq_name, IRQ_NAME_SIZE, +		 KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d", +		 priv->port.line); +  	spin_lock_init(&priv->port.lock);  	pci_set_drvdata(pdev, priv); @@ -1861,7 +1860,6 @@ static void pch_uart_exit_port(struct eg20t_port *priv)  		debugfs_remove(priv->debugfs);  #endif  	uart_remove_one_port(&pch_uart_driver, &priv->port); -	pci_set_drvdata(priv->pdev, NULL);  	free_page((unsigned long)priv->rxbuf.buf);  } @@ -1915,7 +1913,7 @@ static int pch_uart_pci_resume(struct pci_dev *pdev)  #define pch_uart_pci_resume NULL  #endif -static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { +static const struct pci_device_id pch_uart_pci_id[] = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),  	 .driver_data = pch_et20t_uart0},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812), @@ -2003,6 +2001,8 @@ module_exit(pch_uart_module_exit);  MODULE_LICENSE("GPL v2");  MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver"); +MODULE_DEVICE_TABLE(pci, pch_uart_pci_id); +  module_param(default_baud, uint, S_IRUGO);  MODULE_PARM_DESC(default_baud,                   "Default BAUD for initial driver state and console (default 9600)"); diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index f87f1a0c8c6..f7ad5b90305 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -57,6 +57,8 @@  #include <linux/bitops.h>  #include <linux/sysrq.h>  #include <linux/mutex.h> +#include <linux/of_address.h> +#include <linux/of_irq.h>  #include <asm/sections.h>  #include <asm/io.h>  #include <asm/irq.h> @@ -651,6 +653,8 @@ static void pmz_start_tx(struct uart_port *port)  	} else {  		struct circ_buf *xmit = &port->state->xmit; +		if (uart_circ_empty(xmit)) +			goto out;  		write_zsdata(uap, xmit->buf[xmit->tail]);  		zssync(uap);  		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -659,6 +663,7 @@ static void pmz_start_tx(struct uart_port *port)  		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)  			uart_write_wakeup(&uap->port);  	} + out:  	pmz_debug("pmz: start_tx() done.\n");  } @@ -1072,7 +1077,7 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,  		uap->curregs[5] |= Tx8;  		uap->parity_mask = 0xff;  		break; -	}; +	}  	uap->curregs[4] &= ~(SB_MASK);  	if (cflag & CSTOPB)  		uap->curregs[4] |= SB2; @@ -1090,7 +1095,7 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag,  	uap->port.read_status_mask = Rx_OVR;  	if (iflag & INPCK)  		uap->port.read_status_mask |= CRC_ERR | PAR_ERR; -	if (iflag & (BRKINT | PARMRK)) +	if (iflag & (IGNBRK | BRKINT | PARMRK))  		uap->port.read_status_mask |= BRK_ABRT;  	uap->port.ignore_status_mask = 0; @@ -2050,6 +2055,9 @@ static int __init pmz_console_init(void)  	/* Probe ports */  	pmz_probe(); +	if (pmz_ports_count == 0) +		return -ENODEV; +  	/* TODO: Autoprobe console based on OF */  	/* pmz_console.index = i; */  	register_console(&pmz_console); diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c index de6c05c6368..2ba24a45c97 100644 --- a/drivers/tty/serial/pnx8xxx_uart.c +++ b/drivers/tty/serial/pnx8xxx_uart.c @@ -477,7 +477,7 @@ pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,  		sport->port.read_status_mask |=  			FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |  			FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		sport->port.read_status_mask |=  			ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index f9f20f38376..c638c53cd2b 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -492,7 +492,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,  	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;  	if (termios->c_iflag & INPCK)  		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		up->port.read_status_mask |= UART_LSR_BI;  	/* @@ -711,13 +711,8 @@ static void serial_pxa_put_poll_char(struct uart_port *port,  	wait_for_xmitr(up);  	/*  	 *	Send the character out. -	 *	If a LF, also do CR...  	 */  	serial_out(up, UART_TX, c); -	if (c == 10) { -		wait_for_xmitr(up); -		serial_out(up, UART_TX, 13); -	}  	/*  	 *	Finally, wait for transmitter to become empty diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 328d6deb6b0..056f91b3a4c 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -810,7 +810,7 @@ static void rp2_remove(struct pci_dev *pdev)  	rp2_remove_ports(card);  } -static DEFINE_PCI_DEVICE_TABLE(rp2_pci_tbl) = { +static const struct pci_device_id rp2_pci_tbl[] = {  	/* RocketPort INFINITY cards */ diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index ba25722a713..753d4525b36 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -647,7 +647,10 @@ void sa1100_register_uart_fns(struct sa1100_port_fns *fns)  		sa1100_pops.set_mctrl = fns->set_mctrl;  	sa1100_pops.pm       = fns->pm; -	sa1100_pops.set_wake = fns->set_wake; +	/* +	 * FIXME: fns->set_wake is unused - this should be called from +	 * the suspend() callback if device_may_wakeup(dev)) is set. +	 */  }  void __init sa1100_register_uart(int idx, int port) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index f3dfa19a1cb..c1d3ebdf3b9 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -53,6 +53,29 @@  #include "samsung.h" +#if	defined(CONFIG_SERIAL_SAMSUNG_DEBUG) &&	\ +	defined(CONFIG_DEBUG_LL) &&		\ +	!defined(MODULE) + +extern void printascii(const char *); + +__printf(1, 2) +static void dbg(const char *fmt, ...) +{ +	va_list va; +	char buff[256]; + +	va_start(va, fmt); +	vscnprintf(buff, sizeof(buff), fmt, va); +	va_end(va); + +	printascii(buff); +} + +#else +#define dbg(fmt, ...) do { if (0) no_printk(fmt, ##__VA_ARGS__); } while (0) +#endif +  /* UART name and device definitions */  #define S3C24XX_SERIAL_NAME	"ttySAC" @@ -407,7 +430,14 @@ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)  static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)  { -	/* todo - possibly remove AFC and do manual CTS */ +	unsigned int umcon = rd_regl(port, S3C2410_UMCON); + +	if (mctrl & TIOCM_RTS) +		umcon |= S3C2410_UMCOM_RTS_LOW; +	else +		umcon &= ~S3C2410_UMCOM_RTS_LOW; + +	wr_regl(port, S3C2410_UMCON, umcon);  }  static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) @@ -461,8 +491,8 @@ static int s3c24xx_serial_startup(struct uart_port *port)  	struct s3c24xx_uart_port *ourport = to_ourport(port);  	int ret; -	dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n", -	    port->mapbase, port->membase); +	dbg("s3c24xx_serial_startup: port=%p (%08llx,%p)\n", +	    port, (unsigned long long)port->mapbase, port->membase);  	rx_enabled(port) = 1; @@ -507,8 +537,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)  	struct s3c24xx_uart_port *ourport = to_ourport(port);  	int ret; -	dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n", -	    port->mapbase, port->membase); +	dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n", +	    port, (unsigned long long)port->mapbase, port->membase);  	wr_regl(port, S3C64XX_UINTM, 0xf); @@ -774,8 +804,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,  	if (termios->c_cflag & CSTOPB)  		ulcon |= S3C2410_LCON_STOPB; -	umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0; -  	if (termios->c_cflag & PARENB) {  		if (termios->c_cflag & PARODD)  			ulcon |= S3C2410_LCON_PODD; @@ -792,6 +820,15 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,  	wr_regl(port, S3C2410_ULCON, ulcon);  	wr_regl(port, S3C2410_UBRDIV, quot); + +	umcon = rd_regl(port, S3C2410_UMCON); +	if (termios->c_cflag & CRTSCTS) { +		umcon |= S3C2410_UMCOM_AFC; +		/* Disable RTS when RX FIFO contains 63 bytes */ +		umcon &= ~S3C2412_UMCON_AFC_8; +	} else { +		umcon &= ~S3C2410_UMCOM_AFC; +	}  	wr_regl(port, S3C2410_UMCON, umcon);  	if (ourport->info->has_divslot) @@ -1146,7 +1183,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,  		return -EINVAL;  	} -	dbg("resource %p (%lx..%lx)\n", res, res->start, res->end); +	dbg("resource %pR)\n", res);  	port->membase = devm_ioremap(port->dev, res->start, resource_size(res));  	if (!port->membase) { @@ -1189,13 +1226,12 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,  		wr_regl(port, S3C64XX_UINTSP, 0xf);  	} -	dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n", +	dbg("port: map=%08x, mem=%p, irq=%d (%d,%d), clock=%u\n",  	    port->mapbase, port->membase, port->irq,  	    ourport->rx_irq, ourport->tx_irq, port->uartclk);  	/* reset the fifos (and setup the uart) */  	s3c24xx_serial_resetport(port, cfg); -	clk_disable_unprepare(ourport->clk);  	return 0;  } @@ -1254,7 +1290,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)  	ourport->baudclk = ERR_PTR(-EINVAL);  	ourport->info = ourport->drv_data->info;  	ourport->cfg = (dev_get_platdata(&pdev->dev)) ? -			(struct s3c2410_uartcfg *)dev_get_platdata(&pdev->dev) : +			dev_get_platdata(&pdev->dev) :  			ourport->drv_data->def_cfg;  	ourport->port.fifosize = (ourport->info->fifosize) ? @@ -1269,10 +1305,25 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)  	if (ret < 0)  		goto probe_err; +	if (!s3c24xx_uart_drv.state) { +		ret = uart_register_driver(&s3c24xx_uart_drv); +		if (ret < 0) { +			pr_err("Failed to register Samsung UART driver\n"); +			return ret; +		} +	} +  	dbg("%s: adding port\n", __func__);  	uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);  	platform_set_drvdata(pdev, &ourport->port); +	/* +	 * Deactivate the clock enabled in s3c24xx_serial_init_port here, +	 * so that a potential re-enablement through the pm-callback overlaps +	 * and keeps the clock enabled in this case. +	 */ +	clk_disable_unprepare(ourport->clk); +  #ifdef CONFIG_SAMSUNG_CLOCK  	ret = device_create_file(&pdev->dev, &dev_attr_clock_source);  	if (ret < 0) @@ -1301,6 +1352,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev)  		uart_remove_one_port(&s3c24xx_uart_drv, port);  	} +	uart_unregister_driver(&s3c24xx_uart_drv); +  	return 0;  } @@ -1416,8 +1469,8 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port)  static void s3c24xx_serial_put_poll_char(struct uart_port *port,  		unsigned char c)  { -	unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); -	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); +	unsigned int ufcon = rd_regl(port, S3C2410_UFCON); +	unsigned int ucon = rd_regl(port, S3C2410_UCON);  	/* not possible to xmit on unconfigured port */  	if (!s3c24xx_port_configured(ucon)) @@ -1425,7 +1478,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,  	while (!s3c24xx_serial_console_txrdy(port, ufcon))  		cpu_relax(); -	wr_regb(cons_uart, S3C2410_UTXH, c); +	wr_regb(port, S3C2410_UTXH, c);  }  #endif /* CONFIG_CONSOLE_POLL */ @@ -1433,22 +1486,23 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,  static void  s3c24xx_serial_console_putchar(struct uart_port *port, int ch)  { -	unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); -	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); - -	/* not possible to xmit on unconfigured port */ -	if (!s3c24xx_port_configured(ucon)) -		return; +	unsigned int ufcon = rd_regl(port, S3C2410_UFCON);  	while (!s3c24xx_serial_console_txrdy(port, ufcon)) -		barrier(); -	wr_regb(cons_uart, S3C2410_UTXH, ch); +		cpu_relax(); +	wr_regb(port, S3C2410_UTXH, ch);  }  static void  s3c24xx_serial_console_write(struct console *co, const char *s,  			     unsigned int count)  { +	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); + +	/* not possible to xmit on unconfigured port */ +	if (!s3c24xx_port_configured(ucon)) +		return; +  	uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);  } @@ -1800,35 +1854,7 @@ static struct platform_driver samsung_serial_driver = {  	},  }; -/* module initialisation code */ - -static int __init s3c24xx_serial_modinit(void) -{ -	int ret; - -	ret = uart_register_driver(&s3c24xx_uart_drv); -	if (ret < 0) { -		pr_err("Failed to register Samsung UART driver\n"); -		return ret; -	} - -	ret = platform_driver_register(&samsung_serial_driver); -	if (ret < 0) { -		pr_err("Failed to register platform driver\n"); -		uart_unregister_driver(&s3c24xx_uart_drv); -	} - -	return ret; -} - -static void __exit s3c24xx_serial_modexit(void) -{ -	platform_driver_unregister(&samsung_serial_driver); -	uart_unregister_driver(&s3c24xx_uart_drv); -} - -module_init(s3c24xx_serial_modinit); -module_exit(s3c24xx_serial_modexit); +module_platform_driver(samsung_serial_driver);  MODULE_ALIAS("platform:samsung-uart");  MODULE_DESCRIPTION("Samsung SoC Serial port driver"); diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index aaa617a6c49..eb071dd19b2 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -1,3 +1,6 @@ +#ifndef __SAMSUNG_H +#define __SAMSUNG_H +  /*   * Driver for Samsung SoC onboard UARTs.   * @@ -63,7 +66,7 @@ struct s3c24xx_uart_port {  /* conversion functions */ -#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev) +#define s3c24xx_dev_to_port(__dev) dev_get_drvdata(__dev)  /* register access controls */ @@ -77,24 +80,4 @@ struct s3c24xx_uart_port {  #define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))  #define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) -#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \ -    defined(CONFIG_DEBUG_LL) && \ -    !defined(MODULE) - -extern void printascii(const char *); - -static void dbg(const char *fmt, ...) -{ -	va_list va; -	char buff[256]; - -	va_start(va, fmt); -	vsprintf(buff, fmt, va); -	va_end(va); - -	printascii(buff); -} - -#else -#define dbg(x...) do { } while (0)  #endif diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index a7cdec2962d..771f361c47e 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -596,7 +596,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,  	if (termios->c_iflag & INPCK)  		uport->read_status_mask |= M_DUART_FRM_ERR |  					   M_DUART_PARITY_ERR; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		uport->read_status_mask |= M_DUART_RCVD_BRK;  	uport->ignore_status_mask = 0; diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c new file mode 100644 index 00000000000..1b6a77c4b2c --- /dev/null +++ b/drivers/tty/serial/sc16is7xx.c @@ -0,0 +1,1277 @@ +/* + * SC16IS7xx tty serial driver - Copyright (C) 2014 GridPoint + * Author: Jon Ringle <jringle@gridpoint.com> + * + *  Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/uaccess.h> + +#define SC16IS7XX_NAME			"sc16is7xx" + +/* SC16IS7XX register definitions */ +#define SC16IS7XX_RHR_REG		(0x00) /* RX FIFO */ +#define SC16IS7XX_THR_REG		(0x00) /* TX FIFO */ +#define SC16IS7XX_IER_REG		(0x01) /* Interrupt enable */ +#define SC16IS7XX_IIR_REG		(0x02) /* Interrupt Identification */ +#define SC16IS7XX_FCR_REG		(0x02) /* FIFO control */ +#define SC16IS7XX_LCR_REG		(0x03) /* Line Control */ +#define SC16IS7XX_MCR_REG		(0x04) /* Modem Control */ +#define SC16IS7XX_LSR_REG		(0x05) /* Line Status */ +#define SC16IS7XX_MSR_REG		(0x06) /* Modem Status */ +#define SC16IS7XX_SPR_REG		(0x07) /* Scratch Pad */ +#define SC16IS7XX_TXLVL_REG		(0x08) /* TX FIFO level */ +#define SC16IS7XX_RXLVL_REG		(0x09) /* RX FIFO level */ +#define SC16IS7XX_IODIR_REG		(0x0a) /* I/O Direction +						* - only on 75x/76x +						*/ +#define SC16IS7XX_IOSTATE_REG		(0x0b) /* I/O State +						* - only on 75x/76x +						*/ +#define SC16IS7XX_IOINTENA_REG		(0x0c) /* I/O Interrupt Enable +						* - only on 75x/76x +						*/ +#define SC16IS7XX_IOCONTROL_REG		(0x0e) /* I/O Control +						* - only on 75x/76x +						*/ +#define SC16IS7XX_EFCR_REG		(0x0f) /* Extra Features Control */ + +/* TCR/TLR Register set: Only if ((MCR[2] == 1) && (EFR[4] == 1)) */ +#define SC16IS7XX_TCR_REG		(0x06) /* Transmit control */ +#define SC16IS7XX_TLR_REG		(0x07) /* Trigger level */ + +/* Special Register set: Only if ((LCR[7] == 1) && (LCR != 0xBF)) */ +#define SC16IS7XX_DLL_REG		(0x00) /* Divisor Latch Low */ +#define SC16IS7XX_DLH_REG		(0x01) /* Divisor Latch High */ + +/* Enhanced Register set: Only if (LCR == 0xBF) */ +#define SC16IS7XX_EFR_REG		(0x02) /* Enhanced Features */ +#define SC16IS7XX_XON1_REG		(0x04) /* Xon1 word */ +#define SC16IS7XX_XON2_REG		(0x05) /* Xon2 word */ +#define SC16IS7XX_XOFF1_REG		(0x06) /* Xoff1 word */ +#define SC16IS7XX_XOFF2_REG		(0x07) /* Xoff2 word */ + +/* IER register bits */ +#define SC16IS7XX_IER_RDI_BIT		(1 << 0) /* Enable RX data interrupt */ +#define SC16IS7XX_IER_THRI_BIT		(1 << 1) /* Enable TX holding register +						  * interrupt */ +#define SC16IS7XX_IER_RLSI_BIT		(1 << 2) /* Enable RX line status +						  * interrupt */ +#define SC16IS7XX_IER_MSI_BIT		(1 << 3) /* Enable Modem status +						  * interrupt */ + +/* IER register bits - write only if (EFR[4] == 1) */ +#define SC16IS7XX_IER_SLEEP_BIT		(1 << 4) /* Enable Sleep mode */ +#define SC16IS7XX_IER_XOFFI_BIT		(1 << 5) /* Enable Xoff interrupt */ +#define SC16IS7XX_IER_RTSI_BIT		(1 << 6) /* Enable nRTS interrupt */ +#define SC16IS7XX_IER_CTSI_BIT		(1 << 7) /* Enable nCTS interrupt */ + +/* FCR register bits */ +#define SC16IS7XX_FCR_FIFO_BIT		(1 << 0) /* Enable FIFO */ +#define SC16IS7XX_FCR_RXRESET_BIT	(1 << 1) /* Reset RX FIFO */ +#define SC16IS7XX_FCR_TXRESET_BIT	(1 << 2) /* Reset TX FIFO */ +#define SC16IS7XX_FCR_RXLVLL_BIT	(1 << 6) /* RX Trigger level LSB */ +#define SC16IS7XX_FCR_RXLVLH_BIT	(1 << 7) /* RX Trigger level MSB */ + +/* FCR register bits - write only if (EFR[4] == 1) */ +#define SC16IS7XX_FCR_TXLVLL_BIT	(1 << 4) /* TX Trigger level LSB */ +#define SC16IS7XX_FCR_TXLVLH_BIT	(1 << 5) /* TX Trigger level MSB */ + +/* IIR register bits */ +#define SC16IS7XX_IIR_NO_INT_BIT	(1 << 0) /* No interrupts pending */ +#define SC16IS7XX_IIR_ID_MASK		0x3e     /* Mask for the interrupt ID */ +#define SC16IS7XX_IIR_THRI_SRC		0x02     /* TX holding register empty */ +#define SC16IS7XX_IIR_RDI_SRC		0x04     /* RX data interrupt */ +#define SC16IS7XX_IIR_RLSE_SRC		0x06     /* RX line status error */ +#define SC16IS7XX_IIR_RTOI_SRC		0x0c     /* RX time-out interrupt */ +#define SC16IS7XX_IIR_MSI_SRC		0x00     /* Modem status interrupt +						  * - only on 75x/76x +						  */ +#define SC16IS7XX_IIR_INPIN_SRC		0x30     /* Input pin change of state +						  * - only on 75x/76x +						  */ +#define SC16IS7XX_IIR_XOFFI_SRC		0x10     /* Received Xoff */ +#define SC16IS7XX_IIR_CTSRTS_SRC	0x20     /* nCTS,nRTS change of state +						  * from active (LOW) +						  * to inactive (HIGH) +						  */ +/* LCR register bits */ +#define SC16IS7XX_LCR_LENGTH0_BIT	(1 << 0) /* Word length bit 0 */ +#define SC16IS7XX_LCR_LENGTH1_BIT	(1 << 1) /* Word length bit 1 +						  * +						  * Word length bits table: +						  * 00 -> 5 bit words +						  * 01 -> 6 bit words +						  * 10 -> 7 bit words +						  * 11 -> 8 bit words +						  */ +#define SC16IS7XX_LCR_STOPLEN_BIT	(1 << 2) /* STOP length bit +						  * +						  * STOP length bit table: +						  * 0 -> 1 stop bit +						  * 1 -> 1-1.5 stop bits if +						  *      word length is 5, +						  *      2 stop bits otherwise +						  */ +#define SC16IS7XX_LCR_PARITY_BIT	(1 << 3) /* Parity bit enable */ +#define SC16IS7XX_LCR_EVENPARITY_BIT	(1 << 4) /* Even parity bit enable */ +#define SC16IS7XX_LCR_FORCEPARITY_BIT	(1 << 5) /* 9-bit multidrop parity */ +#define SC16IS7XX_LCR_TXBREAK_BIT	(1 << 6) /* TX break enable */ +#define SC16IS7XX_LCR_DLAB_BIT		(1 << 7) /* Divisor Latch enable */ +#define SC16IS7XX_LCR_WORD_LEN_5	(0x00) +#define SC16IS7XX_LCR_WORD_LEN_6	(0x01) +#define SC16IS7XX_LCR_WORD_LEN_7	(0x02) +#define SC16IS7XX_LCR_WORD_LEN_8	(0x03) +#define SC16IS7XX_LCR_CONF_MODE_A	SC16IS7XX_LCR_DLAB_BIT /* Special +								* reg set */ +#define SC16IS7XX_LCR_CONF_MODE_B	0xBF                   /* Enhanced +								* reg set */ + +/* MCR register bits */ +#define SC16IS7XX_MCR_DTR_BIT		(1 << 0) /* DTR complement +						  * - only on 75x/76x +						  */ +#define SC16IS7XX_MCR_RTS_BIT		(1 << 1) /* RTS complement */ +#define SC16IS7XX_MCR_TCRTLR_BIT	(1 << 2) /* TCR/TLR register enable */ +#define SC16IS7XX_MCR_LOOP_BIT		(1 << 4) /* Enable loopback test mode */ +#define SC16IS7XX_MCR_XONANY_BIT	(1 << 5) /* Enable Xon Any +						  * - write enabled +						  * if (EFR[4] == 1) +						  */ +#define SC16IS7XX_MCR_IRDA_BIT		(1 << 6) /* Enable IrDA mode +						  * - write enabled +						  * if (EFR[4] == 1) +						  */ +#define SC16IS7XX_MCR_CLKSEL_BIT	(1 << 7) /* Divide clock by 4 +						  * - write enabled +						  * if (EFR[4] == 1) +						  */ + +/* LSR register bits */ +#define SC16IS7XX_LSR_DR_BIT		(1 << 0) /* Receiver data ready */ +#define SC16IS7XX_LSR_OE_BIT		(1 << 1) /* Overrun Error */ +#define SC16IS7XX_LSR_PE_BIT		(1 << 2) /* Parity Error */ +#define SC16IS7XX_LSR_FE_BIT		(1 << 3) /* Frame Error */ +#define SC16IS7XX_LSR_BI_BIT		(1 << 4) /* Break Interrupt */ +#define SC16IS7XX_LSR_BRK_ERROR_MASK	0x1E     /* BI, FE, PE, OE bits */ +#define SC16IS7XX_LSR_THRE_BIT		(1 << 5) /* TX holding register empty */ +#define SC16IS7XX_LSR_TEMT_BIT		(1 << 6) /* Transmitter empty */ +#define SC16IS7XX_LSR_FIFOE_BIT		(1 << 7) /* Fifo Error */ + +/* MSR register bits */ +#define SC16IS7XX_MSR_DCTS_BIT		(1 << 0) /* Delta CTS Clear To Send */ +#define SC16IS7XX_MSR_DDSR_BIT		(1 << 1) /* Delta DSR Data Set Ready +						  * or (IO4) +						  * - only on 75x/76x +						  */ +#define SC16IS7XX_MSR_DRI_BIT		(1 << 2) /* Delta RI Ring Indicator +						  * or (IO7) +						  * - only on 75x/76x +						  */ +#define SC16IS7XX_MSR_DCD_BIT		(1 << 3) /* Delta CD Carrier Detect +						  * or (IO6) +						  * - only on 75x/76x +						  */ +#define SC16IS7XX_MSR_CTS_BIT		(1 << 0) /* CTS */ +#define SC16IS7XX_MSR_DSR_BIT		(1 << 1) /* DSR (IO4) +						  * - only on 75x/76x +						  */ +#define SC16IS7XX_MSR_RI_BIT		(1 << 2) /* RI (IO7) +						  * - only on 75x/76x +						  */ +#define SC16IS7XX_MSR_CD_BIT		(1 << 3) /* CD (IO6) +						  * - only on 75x/76x +						  */ +#define SC16IS7XX_MSR_DELTA_MASK	0x0F     /* Any of the delta bits! */ + +/* + * TCR register bits + * TCR trigger levels are available from 0 to 60 characters with a granularity + * of four. + * The programmer must program the TCR such that TCR[3:0] > TCR[7:4]. There is + * no built-in hardware check to make sure this condition is met. Also, the TCR + * must be programmed with this condition before auto RTS or software flow + * control is enabled to avoid spurious operation of the device. + */ +#define SC16IS7XX_TCR_RX_HALT(words)	((((words) / 4) & 0x0f) << 0) +#define SC16IS7XX_TCR_RX_RESUME(words)	((((words) / 4) & 0x0f) << 4) + +/* + * TLR register bits + * If TLR[3:0] or TLR[7:4] are logical 0, the selectable trigger levels via the + * FIFO Control Register (FCR) are used for the transmit and receive FIFO + * trigger levels. Trigger levels from 4 characters to 60 characters are + * available with a granularity of four. + * + * When the trigger level setting in TLR is zero, the SC16IS740/750/760 uses the + * trigger level setting defined in FCR. If TLR has non-zero trigger level value + * the trigger level defined in FCR is discarded. This applies to both transmit + * FIFO and receive FIFO trigger level setting. + * + * When TLR is used for RX trigger level control, FCR[7:6] should be left at the + * default state, that is, '00'. + */ +#define SC16IS7XX_TLR_TX_TRIGGER(words)	((((words) / 4) & 0x0f) << 0) +#define SC16IS7XX_TLR_RX_TRIGGER(words)	((((words) / 4) & 0x0f) << 4) + +/* IOControl register bits (Only 750/760) */ +#define SC16IS7XX_IOCONTROL_LATCH_BIT	(1 << 0) /* Enable input latching */ +#define SC16IS7XX_IOCONTROL_GPIO_BIT	(1 << 1) /* Enable GPIO[7:4] */ +#define SC16IS7XX_IOCONTROL_SRESET_BIT	(1 << 3) /* Software Reset */ + +/* EFCR register bits */ +#define SC16IS7XX_EFCR_9BIT_MODE_BIT	(1 << 0) /* Enable 9-bit or Multidrop +						  * mode (RS485) */ +#define SC16IS7XX_EFCR_RXDISABLE_BIT	(1 << 1) /* Disable receiver */ +#define SC16IS7XX_EFCR_TXDISABLE_BIT	(1 << 2) /* Disable transmitter */ +#define SC16IS7XX_EFCR_AUTO_RS485_BIT	(1 << 4) /* Auto RS485 RTS direction */ +#define SC16IS7XX_EFCR_RTS_INVERT_BIT	(1 << 5) /* RTS output inversion */ +#define SC16IS7XX_EFCR_IRDA_MODE_BIT	(1 << 7) /* IrDA mode +						  * 0 = rate upto 115.2 kbit/s +						  *   - Only 750/760 +						  * 1 = rate upto 1.152 Mbit/s +						  *   - Only 760 +						  */ + +/* EFR register bits */ +#define SC16IS7XX_EFR_AUTORTS_BIT	(1 << 6) /* Auto RTS flow ctrl enable */ +#define SC16IS7XX_EFR_AUTOCTS_BIT	(1 << 7) /* Auto CTS flow ctrl enable */ +#define SC16IS7XX_EFR_XOFF2_DETECT_BIT	(1 << 5) /* Enable Xoff2 detection */ +#define SC16IS7XX_EFR_ENABLE_BIT	(1 << 4) /* Enable enhanced functions +						  * and writing to IER[7:4], +						  * FCR[5:4], MCR[7:5] +						  */ +#define SC16IS7XX_EFR_SWFLOW3_BIT	(1 << 3) /* SWFLOW bit 3 */ +#define SC16IS7XX_EFR_SWFLOW2_BIT	(1 << 2) /* SWFLOW bit 2 +						  * +						  * SWFLOW bits 3 & 2 table: +						  * 00 -> no transmitter flow +						  *       control +						  * 01 -> transmitter generates +						  *       XON2 and XOFF2 +						  * 10 -> transmitter generates +						  *       XON1 and XOFF1 +						  * 11 -> transmitter generates +						  *       XON1, XON2, XOFF1 and +						  *       XOFF2 +						  */ +#define SC16IS7XX_EFR_SWFLOW1_BIT	(1 << 1) /* SWFLOW bit 2 */ +#define SC16IS7XX_EFR_SWFLOW0_BIT	(1 << 0) /* SWFLOW bit 3 +						  * +						  * SWFLOW bits 3 & 2 table: +						  * 00 -> no received flow +						  *       control +						  * 01 -> receiver compares +						  *       XON2 and XOFF2 +						  * 10 -> receiver compares +						  *       XON1 and XOFF1 +						  * 11 -> receiver compares +						  *       XON1, XON2, XOFF1 and +						  *       XOFF2 +						  */ + +/* Misc definitions */ +#define SC16IS7XX_FIFO_SIZE		(64) +#define SC16IS7XX_REG_SHIFT		2 + +struct sc16is7xx_devtype { +	char	name[10]; +	int	nr_gpio; +	int	nr_uart; +}; + +struct sc16is7xx_one { +	struct uart_port		port; +	struct work_struct		tx_work; +	struct work_struct		md_work; + +	struct serial_rs485		rs485; +}; + +struct sc16is7xx_port { +	struct uart_driver		uart; +	struct sc16is7xx_devtype	*devtype; +	struct regmap			*regmap; +	struct mutex			mutex; +	struct clk			*clk; +#ifdef CONFIG_GPIOLIB +	struct gpio_chip		gpio; +#endif +	unsigned char			buf[SC16IS7XX_FIFO_SIZE]; +	struct sc16is7xx_one		p[0]; +}; + +#define to_sc16is7xx_one(p,e)	((container_of((p), struct sc16is7xx_one, e))) + +static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +	unsigned int val = 0; + +	regmap_read(s->regmap, +		    (reg << SC16IS7XX_REG_SHIFT) | port->line, &val); + +	return val; +} + +static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + +	regmap_write(s->regmap, +		     (reg << SC16IS7XX_REG_SHIFT) | port->line, val); +} + +static void sc16is7xx_port_update(struct uart_port *port, u8 reg, +				  u8 mask, u8 val) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + +	regmap_update_bits(s->regmap, +			   (reg << SC16IS7XX_REG_SHIFT) | port->line, +			   mask, val); +} + + +static void sc16is7xx_power(struct uart_port *port, int on) +{ +	sc16is7xx_port_update(port, SC16IS7XX_IER_REG, +			      SC16IS7XX_IER_SLEEP_BIT, +			      on ? 0 : SC16IS7XX_IER_SLEEP_BIT); +} + +static const struct sc16is7xx_devtype sc16is74x_devtype = { +	.name		= "SC16IS74X", +	.nr_gpio	= 0, +	.nr_uart	= 1, +}; + +static const struct sc16is7xx_devtype sc16is750_devtype = { +	.name		= "SC16IS750", +	.nr_gpio	= 8, +	.nr_uart	= 1, +}; + +static const struct sc16is7xx_devtype sc16is752_devtype = { +	.name		= "SC16IS752", +	.nr_gpio	= 8, +	.nr_uart	= 2, +}; + +static const struct sc16is7xx_devtype sc16is760_devtype = { +	.name		= "SC16IS760", +	.nr_gpio	= 8, +	.nr_uart	= 1, +}; + +static const struct sc16is7xx_devtype sc16is762_devtype = { +	.name		= "SC16IS762", +	.nr_gpio	= 8, +	.nr_uart	= 2, +}; + +static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg >> SC16IS7XX_REG_SHIFT) { +	case SC16IS7XX_RHR_REG: +	case SC16IS7XX_IIR_REG: +	case SC16IS7XX_LSR_REG: +	case SC16IS7XX_MSR_REG: +	case SC16IS7XX_TXLVL_REG: +	case SC16IS7XX_RXLVL_REG: +	case SC16IS7XX_IOSTATE_REG: +		return true; +	default: +		break; +	} + +	return false; +} + +static bool sc16is7xx_regmap_precious(struct device *dev, unsigned int reg) +{ +	switch (reg >> SC16IS7XX_REG_SHIFT) { +	case SC16IS7XX_RHR_REG: +		return true; +	default: +		break; +	} + +	return false; +} + +static int sc16is7xx_set_baud(struct uart_port *port, int baud) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +	u8 lcr; +	u8 prescaler = 0; +	unsigned long clk = port->uartclk, div = clk / 16 / baud; + +	if (div > 0xffff) { +		prescaler = SC16IS7XX_MCR_CLKSEL_BIT; +		div /= 4; +	} + +	lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); + +	/* Open the LCR divisors for configuration */ +	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, +			     SC16IS7XX_LCR_CONF_MODE_B); + +	/* Enable enhanced features */ +	regcache_cache_bypass(s->regmap, true); +	sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, +			     SC16IS7XX_EFR_ENABLE_BIT); +	regcache_cache_bypass(s->regmap, false); + +	/* Put LCR back to the normal mode */ +	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + +	sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, +			      SC16IS7XX_MCR_CLKSEL_BIT, +			      prescaler); + +	/* Open the LCR divisors for configuration */ +	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, +			     SC16IS7XX_LCR_CONF_MODE_A); + +	/* Write the new divisor */ +	regcache_cache_bypass(s->regmap, true); +	sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256); +	sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256); +	regcache_cache_bypass(s->regmap, false); + +	/* Put LCR back to the normal mode */ +	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + +	return DIV_ROUND_CLOSEST(clk / 16, div); +} + +static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, +				unsigned int iir) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +	unsigned int lsr = 0, ch, flag, bytes_read, i; +	bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false; + +	if (unlikely(rxlen >= sizeof(s->buf))) { +		dev_warn_ratelimited(port->dev, +				     "Port %i: Possible RX FIFO overrun: %d\n", +				     port->line, rxlen); +		port->icount.buf_overrun++; +		/* Ensure sanity of RX level */ +		rxlen = sizeof(s->buf); +	} + +	while (rxlen) { +		/* Only read lsr if there are possible errors in FIFO */ +		if (read_lsr) { +			lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); +			if (!(lsr & SC16IS7XX_LSR_FIFOE_BIT)) +				read_lsr = false; /* No errors left in FIFO */ +		} else +			lsr = 0; + +		if (read_lsr) { +			s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG); +			bytes_read = 1; +		} else { +			regcache_cache_bypass(s->regmap, true); +			regmap_raw_read(s->regmap, SC16IS7XX_RHR_REG, +					s->buf, rxlen); +			regcache_cache_bypass(s->regmap, false); +			bytes_read = rxlen; +		} + +		lsr &= SC16IS7XX_LSR_BRK_ERROR_MASK; + +		port->icount.rx++; +		flag = TTY_NORMAL; + +		if (unlikely(lsr)) { +			if (lsr & SC16IS7XX_LSR_BI_BIT) { +				port->icount.brk++; +				if (uart_handle_break(port)) +					continue; +			} else if (lsr & SC16IS7XX_LSR_PE_BIT) +				port->icount.parity++; +			else if (lsr & SC16IS7XX_LSR_FE_BIT) +				port->icount.frame++; +			else if (lsr & SC16IS7XX_LSR_OE_BIT) +				port->icount.overrun++; + +			lsr &= port->read_status_mask; +			if (lsr & SC16IS7XX_LSR_BI_BIT) +				flag = TTY_BREAK; +			else if (lsr & SC16IS7XX_LSR_PE_BIT) +				flag = TTY_PARITY; +			else if (lsr & SC16IS7XX_LSR_FE_BIT) +				flag = TTY_FRAME; +			else if (lsr & SC16IS7XX_LSR_OE_BIT) +				flag = TTY_OVERRUN; +		} + +		for (i = 0; i < bytes_read; ++i) { +			ch = s->buf[i]; +			if (uart_handle_sysrq_char(port, ch)) +				continue; + +			if (lsr & port->ignore_status_mask) +				continue; + +			uart_insert_char(port, lsr, SC16IS7XX_LSR_OE_BIT, ch, +					 flag); +		} +		rxlen -= bytes_read; +	} + +	tty_flip_buffer_push(&port->state->port); +} + +static void sc16is7xx_handle_tx(struct uart_port *port) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +	struct circ_buf *xmit = &port->state->xmit; +	unsigned int txlen, to_send, i; + +	if (unlikely(port->x_char)) { +		sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char); +		port->icount.tx++; +		port->x_char = 0; +		return; +	} + +	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) +		return; + +	/* Get length of data pending in circular buffer */ +	to_send = uart_circ_chars_pending(xmit); +	if (likely(to_send)) { +		/* Limit to size of TX FIFO */ +		txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); +		to_send = (to_send > txlen) ? txlen : to_send; + +		/* Add data to send */ +		port->icount.tx += to_send; + +		/* Convert to linear buffer */ +		for (i = 0; i < to_send; ++i) { +			s->buf[i] = xmit->buf[xmit->tail]; +			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); +		} +		regcache_cache_bypass(s->regmap, true); +		regmap_raw_write(s->regmap, SC16IS7XX_THR_REG, s->buf, to_send); +		regcache_cache_bypass(s->regmap, false); +	} + +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) +		uart_write_wakeup(port); +} + +static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) +{ +	struct uart_port *port = &s->p[portno].port; + +	do { +		unsigned int iir, msr, rxlen; + +		iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); +		if (iir & SC16IS7XX_IIR_NO_INT_BIT) +			break; + +		iir &= SC16IS7XX_IIR_ID_MASK; + +		switch (iir) { +		case SC16IS7XX_IIR_RDI_SRC: +		case SC16IS7XX_IIR_RLSE_SRC: +		case SC16IS7XX_IIR_RTOI_SRC: +		case SC16IS7XX_IIR_XOFFI_SRC: +			rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG); +			if (rxlen) +				sc16is7xx_handle_rx(port, rxlen, iir); +			break; + +		case SC16IS7XX_IIR_CTSRTS_SRC: +			msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG); +			uart_handle_cts_change(port, +					       !!(msr & SC16IS7XX_MSR_CTS_BIT)); +			break; +		case SC16IS7XX_IIR_THRI_SRC: +			mutex_lock(&s->mutex); +			sc16is7xx_handle_tx(port); +			mutex_unlock(&s->mutex); +			break; +		default: +			dev_err_ratelimited(port->dev, +					    "Port %i: Unexpected interrupt: %x", +					    port->line, iir); +			break; +		} +	} while (1); +} + +static irqreturn_t sc16is7xx_ist(int irq, void *dev_id) +{ +	struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; +	int i; + +	for (i = 0; i < s->uart.nr; ++i) +		sc16is7xx_port_irq(s, i); + +	return IRQ_HANDLED; +} + +static void sc16is7xx_wq_proc(struct work_struct *ws) +{ +	struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work); +	struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev); + +	mutex_lock(&s->mutex); +	sc16is7xx_handle_tx(&one->port); +	mutex_unlock(&s->mutex); +} + +static void sc16is7xx_stop_tx(struct uart_port* port) +{ +	struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); +	struct circ_buf *xmit = &one->port.state->xmit; + +	/* handle rs485 */ +	if (one->rs485.flags & SER_RS485_ENABLED) { +		/* do nothing if current tx not yet completed */ +		int lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); +		if (!(lsr & SC16IS7XX_LSR_TEMT_BIT)) +			return; + +		if (uart_circ_empty(xmit) && +		    (one->rs485.delay_rts_after_send > 0)) +			mdelay(one->rs485.delay_rts_after_send); +	} + +	sc16is7xx_port_update(port, SC16IS7XX_IER_REG, +			      SC16IS7XX_IER_THRI_BIT, +			      0); +} + +static void sc16is7xx_stop_rx(struct uart_port* port) +{ +	struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + +	one->port.read_status_mask &= ~SC16IS7XX_LSR_DR_BIT; +	sc16is7xx_port_update(port, SC16IS7XX_IER_REG, +			      SC16IS7XX_LSR_DR_BIT, +			      0); +} + +static void sc16is7xx_start_tx(struct uart_port *port) +{ +	struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + +	/* handle rs485 */ +	if ((one->rs485.flags & SER_RS485_ENABLED) && +	    (one->rs485.delay_rts_before_send > 0)) { +		mdelay(one->rs485.delay_rts_before_send); +	} + +	if (!work_pending(&one->tx_work)) +		schedule_work(&one->tx_work); +} + +static unsigned int sc16is7xx_tx_empty(struct uart_port *port) +{ +	unsigned int lvl, lsr; + +	lvl = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); +	lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); + +	return ((lsr & SC16IS7XX_LSR_THRE_BIT) && !lvl) ? TIOCSER_TEMT : 0; +} + +static unsigned int sc16is7xx_get_mctrl(struct uart_port *port) +{ +	/* DCD and DSR are not wired and CTS/RTS is handled automatically +	 * so just indicate DSR and CAR asserted +	 */ +	return TIOCM_DSR | TIOCM_CAR; +} + +static void sc16is7xx_md_proc(struct work_struct *ws) +{ +	struct sc16is7xx_one *one = to_sc16is7xx_one(ws, md_work); + +	sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, +			      SC16IS7XX_MCR_LOOP_BIT, +			      (one->port.mctrl & TIOCM_LOOP) ? +				      SC16IS7XX_MCR_LOOP_BIT : 0); +} + +static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +	struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + +	schedule_work(&one->md_work); +} + +static void sc16is7xx_break_ctl(struct uart_port *port, int break_state) +{ +	sc16is7xx_port_update(port, SC16IS7XX_LCR_REG, +			      SC16IS7XX_LCR_TXBREAK_BIT, +			      break_state ? SC16IS7XX_LCR_TXBREAK_BIT : 0); +} + +static void sc16is7xx_set_termios(struct uart_port *port, +				  struct ktermios *termios, +				  struct ktermios *old) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +	unsigned int lcr, flow = 0; +	int baud; + +	/* Mask termios capabilities we don't support */ +	termios->c_cflag &= ~CMSPAR; + +	/* Word size */ +	switch (termios->c_cflag & CSIZE) { +	case CS5: +		lcr = SC16IS7XX_LCR_WORD_LEN_5; +		break; +	case CS6: +		lcr = SC16IS7XX_LCR_WORD_LEN_6; +		break; +	case CS7: +		lcr = SC16IS7XX_LCR_WORD_LEN_7; +		break; +	case CS8: +		lcr = SC16IS7XX_LCR_WORD_LEN_8; +		break; +	default: +		lcr = SC16IS7XX_LCR_WORD_LEN_8; +		termios->c_cflag &= ~CSIZE; +		termios->c_cflag |= CS8; +		break; +	} + +	/* Parity */ +	if (termios->c_cflag & PARENB) { +		lcr |= SC16IS7XX_LCR_PARITY_BIT; +		if (!(termios->c_cflag & PARODD)) +			lcr |= SC16IS7XX_LCR_EVENPARITY_BIT; +	} + +	/* Stop bits */ +	if (termios->c_cflag & CSTOPB) +		lcr |= SC16IS7XX_LCR_STOPLEN_BIT; /* 2 stops */ + +	/* Set read status mask */ +	port->read_status_mask = SC16IS7XX_LSR_OE_BIT; +	if (termios->c_iflag & INPCK) +		port->read_status_mask |= SC16IS7XX_LSR_PE_BIT | +					  SC16IS7XX_LSR_FE_BIT; +	if (termios->c_iflag & (BRKINT | PARMRK)) +		port->read_status_mask |= SC16IS7XX_LSR_BI_BIT; + +	/* Set status ignore mask */ +	port->ignore_status_mask = 0; +	if (termios->c_iflag & IGNBRK) +		port->ignore_status_mask |= SC16IS7XX_LSR_BI_BIT; +	if (!(termios->c_cflag & CREAD)) +		port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; + +	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, +			     SC16IS7XX_LCR_CONF_MODE_B); + +	/* Configure flow control */ +	regcache_cache_bypass(s->regmap, true); +	sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]); +	sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]); +	if (termios->c_cflag & CRTSCTS) +		flow |= SC16IS7XX_EFR_AUTOCTS_BIT | +			SC16IS7XX_EFR_AUTORTS_BIT; +	if (termios->c_iflag & IXON) +		flow |= SC16IS7XX_EFR_SWFLOW3_BIT; +	if (termios->c_iflag & IXOFF) +		flow |= SC16IS7XX_EFR_SWFLOW1_BIT; + +	sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, flow); +	regcache_cache_bypass(s->regmap, false); + +	/* Update LCR register */ +	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + +	/* Get baud rate generator configuration */ +	baud = uart_get_baud_rate(port, termios, old, +				  port->uartclk / 16 / 4 / 0xffff, +				  port->uartclk / 16); + +	/* Setup baudrate generator */ +	baud = sc16is7xx_set_baud(port, baud); + +	/* Update timeout according to new baud rate */ +	uart_update_timeout(port, termios->c_cflag, baud); +} + +#if defined(TIOCSRS485) && defined(TIOCGRS485) +static void sc16is7xx_config_rs485(struct uart_port *port, +				   struct serial_rs485 *rs485) +{ +	struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + +	one->rs485 = *rs485; + +	if (one->rs485.flags & SER_RS485_ENABLED) { +		sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, +				      SC16IS7XX_EFCR_AUTO_RS485_BIT, +				      SC16IS7XX_EFCR_AUTO_RS485_BIT); +	} else { +		sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, +				      SC16IS7XX_EFCR_AUTO_RS485_BIT, +				      0); +	} +} +#endif + +static int sc16is7xx_ioctl(struct uart_port *port, unsigned int cmd, +			   unsigned long arg) +{ +#if defined(TIOCSRS485) && defined(TIOCGRS485) +	struct serial_rs485 rs485; + +	switch (cmd) { +	case TIOCSRS485: +		if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485))) +			return -EFAULT; + +		sc16is7xx_config_rs485(port, &rs485); +		return 0; +	case TIOCGRS485: +		if (copy_to_user((void __user *)arg, +				 &(to_sc16is7xx_one(port, port)->rs485), +				 sizeof(rs485))) +			return -EFAULT; +		return 0; +	default: +		break; +	} +#endif + +	return -ENOIOCTLCMD; +} + +static int sc16is7xx_startup(struct uart_port *port) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(port->dev); +	unsigned int val; + +	sc16is7xx_power(port, 1); + +	/* Reset FIFOs*/ +	val = SC16IS7XX_FCR_RXRESET_BIT | SC16IS7XX_FCR_TXRESET_BIT; +	sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, val); +	udelay(5); +	sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, +			     SC16IS7XX_FCR_FIFO_BIT); + +	/* Enable EFR */ +	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, +			     SC16IS7XX_LCR_CONF_MODE_B); + +	regcache_cache_bypass(s->regmap, true); + +	/* Enable write access to enhanced features and internal clock div */ +	sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, +			     SC16IS7XX_EFR_ENABLE_BIT); + +	/* Enable TCR/TLR */ +	sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, +			      SC16IS7XX_MCR_TCRTLR_BIT, +			      SC16IS7XX_MCR_TCRTLR_BIT); + +	/* Configure flow control levels */ +	/* Flow control halt level 48, resume level 24 */ +	sc16is7xx_port_write(port, SC16IS7XX_TCR_REG, +			     SC16IS7XX_TCR_RX_RESUME(24) | +			     SC16IS7XX_TCR_RX_HALT(48)); + +	regcache_cache_bypass(s->regmap, false); + +	/* Now, initialize the UART */ +	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); + +	/* Enable the Rx and Tx FIFO */ +	sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, +			      SC16IS7XX_EFCR_RXDISABLE_BIT | +			      SC16IS7XX_EFCR_TXDISABLE_BIT, +			      0); + +	/* Enable RX, TX, CTS change interrupts */ +	val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT | +	      SC16IS7XX_IER_CTSI_BIT; +	sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); + +	return 0; +} + +static void sc16is7xx_shutdown(struct uart_port *port) +{ +	/* Disable all interrupts */ +	sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); +	/* Disable TX/RX */ +	sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG, +			     SC16IS7XX_EFCR_RXDISABLE_BIT | +			     SC16IS7XX_EFCR_TXDISABLE_BIT); + +	sc16is7xx_power(port, 0); +} + +static const char *sc16is7xx_type(struct uart_port *port) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + +	return (port->type == PORT_SC16IS7XX) ? s->devtype->name : NULL; +} + +static int sc16is7xx_request_port(struct uart_port *port) +{ +	/* Do nothing */ +	return 0; +} + +static void sc16is7xx_config_port(struct uart_port *port, int flags) +{ +	if (flags & UART_CONFIG_TYPE) +		port->type = PORT_SC16IS7XX; +} + +static int sc16is7xx_verify_port(struct uart_port *port, +				 struct serial_struct *s) +{ +	if ((s->type != PORT_UNKNOWN) && (s->type != PORT_SC16IS7XX)) +		return -EINVAL; +	if (s->irq != port->irq) +		return -EINVAL; + +	return 0; +} + +static void sc16is7xx_pm(struct uart_port *port, unsigned int state, +			 unsigned int oldstate) +{ +	sc16is7xx_power(port, (state == UART_PM_STATE_ON) ? 1 : 0); +} + +static void sc16is7xx_null_void(struct uart_port *port) +{ +	/* Do nothing */ +} + +static const struct uart_ops sc16is7xx_ops = { +	.tx_empty	= sc16is7xx_tx_empty, +	.set_mctrl	= sc16is7xx_set_mctrl, +	.get_mctrl	= sc16is7xx_get_mctrl, +	.stop_tx	= sc16is7xx_stop_tx, +	.start_tx	= sc16is7xx_start_tx, +	.stop_rx	= sc16is7xx_stop_rx, +	.enable_ms	= sc16is7xx_null_void, +	.break_ctl	= sc16is7xx_break_ctl, +	.startup	= sc16is7xx_startup, +	.shutdown	= sc16is7xx_shutdown, +	.set_termios	= sc16is7xx_set_termios, +	.type		= sc16is7xx_type, +	.request_port	= sc16is7xx_request_port, +	.release_port	= sc16is7xx_null_void, +	.config_port	= sc16is7xx_config_port, +	.verify_port	= sc16is7xx_verify_port, +	.ioctl		= sc16is7xx_ioctl, +	.pm		= sc16is7xx_pm, +}; + +#ifdef CONFIG_GPIOLIB +static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset) +{ +	unsigned int val; +	struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, +						gpio); +	struct uart_port *port = &s->p[0].port; + +	val = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG); + +	return !!(val & BIT(offset)); +} + +static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ +	struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, +						gpio); +	struct uart_port *port = &s->p[0].port; + +	sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), +			      val ? BIT(offset) : 0); +} + +static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip, +					  unsigned offset) +{ +	struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, +						gpio); +	struct uart_port *port = &s->p[0].port; + +	sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), 0); + +	return 0; +} + +static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, +					   unsigned offset, int val) +{ +	struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, +						gpio); +	struct uart_port *port = &s->p[0].port; + +	sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), +			      val ? BIT(offset) : 0); +	sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), +			      BIT(offset)); + +	return 0; +} +#endif + +static int sc16is7xx_probe(struct device *dev, +			   struct sc16is7xx_devtype *devtype, +			   struct regmap *regmap, int irq, unsigned long flags) +{ +	unsigned long freq, *pfreq = dev_get_platdata(dev); +	struct clk *clk; +	int i, ret; +	struct sc16is7xx_port *s; + +	if (IS_ERR(regmap)) +		return PTR_ERR(regmap); + +	/* Alloc port structure */ +	s = devm_kzalloc(dev, sizeof(*s) + +			 sizeof(struct sc16is7xx_one) * devtype->nr_uart, +			 GFP_KERNEL); +	if (!s) { +		dev_err(dev, "Error allocating port structure\n"); +		return -ENOMEM; +	} + +	clk = devm_clk_get(dev, NULL); +	if (IS_ERR(clk)) { +		if (pfreq) +			freq = *pfreq; +		else +			return PTR_ERR(clk); +	} else { +		freq = clk_get_rate(clk); +	} + +	s->regmap = regmap; +	s->devtype = devtype; +	dev_set_drvdata(dev, s); + +	/* Register UART driver */ +	s->uart.owner		= THIS_MODULE; +	s->uart.dev_name	= "ttySC"; +	s->uart.nr		= devtype->nr_uart; +	ret = uart_register_driver(&s->uart); +	if (ret) { +		dev_err(dev, "Registering UART driver failed\n"); +		goto out_clk; +	} + +#ifdef CONFIG_GPIOLIB +	if (devtype->nr_gpio) { +		/* Setup GPIO cotroller */ +		s->gpio.owner		 = THIS_MODULE; +		s->gpio.dev		 = dev; +		s->gpio.label		 = dev_name(dev); +		s->gpio.direction_input	 = sc16is7xx_gpio_direction_input; +		s->gpio.get		 = sc16is7xx_gpio_get; +		s->gpio.direction_output = sc16is7xx_gpio_direction_output; +		s->gpio.set		 = sc16is7xx_gpio_set; +		s->gpio.base		 = -1; +		s->gpio.ngpio		 = devtype->nr_gpio; +		s->gpio.can_sleep	 = 1; +		ret = gpiochip_add(&s->gpio); +		if (ret) +			goto out_uart; +	} +#endif + +	mutex_init(&s->mutex); + +	for (i = 0; i < devtype->nr_uart; ++i) { +		/* Initialize port data */ +		s->p[i].port.line	= i; +		s->p[i].port.dev	= dev; +		s->p[i].port.irq	= irq; +		s->p[i].port.type	= PORT_SC16IS7XX; +		s->p[i].port.fifosize	= SC16IS7XX_FIFO_SIZE; +		s->p[i].port.flags	= UPF_FIXED_TYPE | UPF_LOW_LATENCY; +		s->p[i].port.iotype	= UPIO_PORT; +		s->p[i].port.uartclk	= freq; +		s->p[i].port.ops	= &sc16is7xx_ops; +		/* Disable all interrupts */ +		sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); +		/* Disable TX/RX */ +		sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG, +				     SC16IS7XX_EFCR_RXDISABLE_BIT | +				     SC16IS7XX_EFCR_TXDISABLE_BIT); +		/* Initialize queue for start TX */ +		INIT_WORK(&s->p[i].tx_work, sc16is7xx_wq_proc); +		/* Initialize queue for changing mode */ +		INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc); +		/* Register port */ +		uart_add_one_port(&s->uart, &s->p[i].port); +		/* Go to suspend mode */ +		sc16is7xx_power(&s->p[i].port, 0); +	} + +	/* Setup interrupt */ +	ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist, +					IRQF_ONESHOT | flags, dev_name(dev), s); +	if (!ret) +		return 0; + +	mutex_destroy(&s->mutex); + +#ifdef CONFIG_GPIOLIB +	if (devtype->nr_gpio) +		WARN_ON(gpiochip_remove(&s->gpio)); + +out_uart: +#endif +	uart_unregister_driver(&s->uart); + +out_clk: +	if (!IS_ERR(s->clk)) +		clk_disable_unprepare(s->clk); + +	return ret; +} + +static int sc16is7xx_remove(struct device *dev) +{ +	struct sc16is7xx_port *s = dev_get_drvdata(dev); +	int i, ret = 0; + +#ifdef CONFIG_GPIOLIB +	if (s->devtype->nr_gpio) { +		ret = gpiochip_remove(&s->gpio); +		if (ret) +			return ret; +	} +#endif + +	for (i = 0; i < s->uart.nr; i++) { +		cancel_work_sync(&s->p[i].tx_work); +		cancel_work_sync(&s->p[i].md_work); +		uart_remove_one_port(&s->uart, &s->p[i].port); +		sc16is7xx_power(&s->p[i].port, 0); +	} + +	mutex_destroy(&s->mutex); +	uart_unregister_driver(&s->uart); +	if (!IS_ERR(s->clk)) +		clk_disable_unprepare(s->clk); + +	return ret; +} + +static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { +	{ .compatible = "nxp,sc16is740",	.data = &sc16is74x_devtype, }, +	{ .compatible = "nxp,sc16is741",	.data = &sc16is74x_devtype, }, +	{ .compatible = "nxp,sc16is750",	.data = &sc16is750_devtype, }, +	{ .compatible = "nxp,sc16is752",	.data = &sc16is752_devtype, }, +	{ .compatible = "nxp,sc16is760",	.data = &sc16is760_devtype, }, +	{ .compatible = "nxp,sc16is762",	.data = &sc16is762_devtype, }, +	{ } +}; +MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids); + +static struct regmap_config regcfg = { +	.reg_bits = 7, +	.pad_bits = 1, +	.val_bits = 8, +	.cache_type = REGCACHE_RBTREE, +	.volatile_reg = sc16is7xx_regmap_volatile, +	.precious_reg = sc16is7xx_regmap_precious, +}; + +static int sc16is7xx_i2c_probe(struct i2c_client *i2c, +			       const struct i2c_device_id *id) +{ +	struct sc16is7xx_devtype *devtype; +	unsigned long flags = 0; +	struct regmap *regmap; + +	if (i2c->dev.of_node) { +		const struct of_device_id *of_id = +				of_match_device(sc16is7xx_dt_ids, &i2c->dev); + +		devtype = (struct sc16is7xx_devtype *)of_id->data; +	} else { +		devtype = (struct sc16is7xx_devtype *)id->driver_data; +		flags = IRQF_TRIGGER_FALLING; +	} + +	regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | +			      (devtype->nr_uart - 1); +	regmap = devm_regmap_init_i2c(i2c, ®cfg); + +	return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq, flags); +} + +static int sc16is7xx_i2c_remove(struct i2c_client *client) +{ +	return sc16is7xx_remove(&client->dev); +} + +static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { +	{ "sc16is74x",	(kernel_ulong_t)&sc16is74x_devtype, }, +	{ "sc16is750",	(kernel_ulong_t)&sc16is750_devtype, }, +	{ "sc16is752",	(kernel_ulong_t)&sc16is752_devtype, }, +	{ "sc16is760",	(kernel_ulong_t)&sc16is760_devtype, }, +	{ "sc16is762",	(kernel_ulong_t)&sc16is762_devtype, }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); + +static struct i2c_driver sc16is7xx_i2c_uart_driver = { +	.driver = { +		.name		= SC16IS7XX_NAME, +		.owner		= THIS_MODULE, +		.of_match_table	= of_match_ptr(sc16is7xx_dt_ids), +	}, +	.probe		= sc16is7xx_i2c_probe, +	.remove		= sc16is7xx_i2c_remove, +	.id_table	= sc16is7xx_i2c_id_table, +}; +module_i2c_driver(sc16is7xx_i2c_uart_driver); +MODULE_ALIAS("i2c:sc16is7xx"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>"); +MODULE_DESCRIPTION("SC16IS7XX serial driver"); diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c deleted file mode 100644 index 887b4f77074..00000000000 --- a/drivers/tty/serial/sc26xx.c +++ /dev/null @@ -1,749 +0,0 @@ -/* - * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices. - * - * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de) - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/major.h> -#include <linux/circ_buf.h> -#include <linux/serial.h> -#include <linux/sysrq.h> -#include <linux/console.h> -#include <linux/spinlock.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/irq.h> -#include <linux/io.h> - -#warning "Please try migrate to use new driver SCCNXP and report the status" \ -	 "in the linux-serial mailing list." - -#if defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include <linux/serial_core.h> - -#define SC26XX_MAJOR         204 -#define SC26XX_MINOR_START   205 -#define SC26XX_NR            2 - -struct uart_sc26xx_port { -	struct uart_port      port[2]; -	u8     dsr_mask[2]; -	u8     cts_mask[2]; -	u8     dcd_mask[2]; -	u8     ri_mask[2]; -	u8     dtr_mask[2]; -	u8     rts_mask[2]; -	u8     imr; -}; - -/* register common to both ports */ -#define RD_ISR      0x14 -#define RD_IPR      0x34 - -#define WR_ACR      0x10 -#define WR_IMR      0x14 -#define WR_OPCR     0x34 -#define WR_OPR_SET  0x38 -#define WR_OPR_CLR  0x3C - -/* access common register */ -#define READ_SC(p, r)        readb((p)->membase + RD_##r) -#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r) - -/* register per port */ -#define RD_PORT_MRx 0x00 -#define RD_PORT_SR  0x04 -#define RD_PORT_RHR 0x0c - -#define WR_PORT_MRx 0x00 -#define WR_PORT_CSR 0x04 -#define WR_PORT_CR  0x08 -#define WR_PORT_THR 0x0c - -/* SR bits */ -#define SR_BREAK    (1 << 7) -#define SR_FRAME    (1 << 6) -#define SR_PARITY   (1 << 5) -#define SR_OVERRUN  (1 << 4) -#define SR_TXRDY    (1 << 2) -#define SR_RXRDY    (1 << 0) - -#define CR_RES_MR   (1 << 4) -#define CR_RES_RX   (2 << 4) -#define CR_RES_TX   (3 << 4) -#define CR_STRT_BRK (6 << 4) -#define CR_STOP_BRK (7 << 4) -#define CR_DIS_TX   (1 << 3) -#define CR_ENA_TX   (1 << 2) -#define CR_DIS_RX   (1 << 1) -#define CR_ENA_RX   (1 << 0) - -/* ISR bits */ -#define ISR_RXRDYB  (1 << 5) -#define ISR_TXRDYB  (1 << 4) -#define ISR_RXRDYA  (1 << 1) -#define ISR_TXRDYA  (1 << 0) - -/* IMR bits */ -#define IMR_RXRDY   (1 << 1) -#define IMR_TXRDY   (1 << 0) - -/* access port register */ -static inline u8 read_sc_port(struct uart_port *p, u8 reg) -{ -	return readb(p->membase + p->line * 0x20 + reg); -} - -static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val) -{ -	writeb(val, p->membase + p->line * 0x20 + reg); -} - -#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r) -#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v) - -static void sc26xx_enable_irq(struct uart_port *port, int mask) -{ -	struct uart_sc26xx_port *up; -	int line = port->line; - -	port -= line; -	up = container_of(port, struct uart_sc26xx_port, port[0]); - -	up->imr |= mask << (line * 4); -	WRITE_SC(port, IMR, up->imr); -} - -static void sc26xx_disable_irq(struct uart_port *port, int mask) -{ -	struct uart_sc26xx_port *up; -	int line = port->line; - -	port -= line; -	up = container_of(port, struct uart_sc26xx_port, port[0]); - -	up->imr &= ~(mask << (line * 4)); -	WRITE_SC(port, IMR, up->imr); -} - -static bool receive_chars(struct uart_port *port) -{ -	struct tty_port *tport = NULL; -	int limit = 10000; -	unsigned char ch; -	char flag; -	u8 status; - -	/* FIXME what is this trying to achieve? */ -	if (port->state != NULL)		/* Unopened serial console */ -		tport = &port->state->port; - -	while (limit-- > 0) { -		status = READ_SC_PORT(port, SR); -		if (!(status & SR_RXRDY)) -			break; -		ch = READ_SC_PORT(port, RHR); - -		flag = TTY_NORMAL; -		port->icount.rx++; - -		if (unlikely(status & (SR_BREAK | SR_FRAME | -				       SR_PARITY | SR_OVERRUN))) { -			if (status & SR_BREAK) { -				status &= ~(SR_PARITY | SR_FRAME); -				port->icount.brk++; -				if (uart_handle_break(port)) -					continue; -			} else if (status & SR_PARITY) -				port->icount.parity++; -			else if (status & SR_FRAME) -				port->icount.frame++; -			if (status & SR_OVERRUN) -				port->icount.overrun++; - -			status &= port->read_status_mask; -			if (status & SR_BREAK) -				flag = TTY_BREAK; -			else if (status & SR_PARITY) -				flag = TTY_PARITY; -			else if (status & SR_FRAME) -				flag = TTY_FRAME; -		} - -		if (uart_handle_sysrq_char(port, ch)) -			continue; - -		if (status & port->ignore_status_mask) -			continue; - -		tty_insert_flip_char(tport, ch, flag); -	} -	return !!tport; -} - -static void transmit_chars(struct uart_port *port) -{ -	struct circ_buf *xmit; - -	if (!port->state) -		return; - -	xmit = &port->state->xmit; -	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -		sc26xx_disable_irq(port, IMR_TXRDY); -		return; -	} -	while (!uart_circ_empty(xmit)) { -		if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) -			break; - -		WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); -		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -		port->icount.tx++; -	} -	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -		uart_write_wakeup(port); -} - -static irqreturn_t sc26xx_interrupt(int irq, void *dev_id) -{ -	struct uart_sc26xx_port *up = dev_id; -	unsigned long flags; -	bool push; -	u8 isr; - -	spin_lock_irqsave(&up->port[0].lock, flags); - -	push = false; -	isr = READ_SC(&up->port[0], ISR); -	if (isr & ISR_TXRDYA) -	    transmit_chars(&up->port[0]); -	if (isr & ISR_RXRDYA) -	    push = receive_chars(&up->port[0]); - -	spin_unlock(&up->port[0].lock); - -	if (push) -		tty_flip_buffer_push(&up->port[0].state->port); - -	spin_lock(&up->port[1].lock); - -	push = false; -	if (isr & ISR_TXRDYB) -	    transmit_chars(&up->port[1]); -	if (isr & ISR_RXRDYB) -	    push = receive_chars(&up->port[1]); - -	spin_unlock_irqrestore(&up->port[1].lock, flags); - -	if (push) -		tty_flip_buffer_push(&up->port[1].state->port); - -	return IRQ_HANDLED; -} - -/* port->lock is not held.  */ -static unsigned int sc26xx_tx_empty(struct uart_port *port) -{ -	return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0; -} - -/* port->lock held by caller.  */ -static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -	struct uart_sc26xx_port *up; -	int line = port->line; - -	port -= line; -	up = container_of(port, struct uart_sc26xx_port, port[0]); - -	if (up->dtr_mask[line]) { -		if (mctrl & TIOCM_DTR) -			WRITE_SC(port, OPR_SET, up->dtr_mask[line]); -		else -			WRITE_SC(port, OPR_CLR, up->dtr_mask[line]); -	} -	if (up->rts_mask[line]) { -		if (mctrl & TIOCM_RTS) -			WRITE_SC(port, OPR_SET, up->rts_mask[line]); -		else -			WRITE_SC(port, OPR_CLR, up->rts_mask[line]); -	} -} - -/* port->lock is held by caller and interrupts are disabled.  */ -static unsigned int sc26xx_get_mctrl(struct uart_port *port) -{ -	struct uart_sc26xx_port *up; -	int line = port->line; -	unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; -	u8 ipr; - -	port -= line; -	up = container_of(port, struct uart_sc26xx_port, port[0]); -	ipr = READ_SC(port, IPR) ^ 0xff; - -	if (up->dsr_mask[line]) { -		mctrl &= ~TIOCM_DSR; -		mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0; -	} -	if (up->cts_mask[line]) { -		mctrl &= ~TIOCM_CTS; -		mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0; -	} -	if (up->dcd_mask[line]) { -		mctrl &= ~TIOCM_CAR; -		mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0; -	} -	if (up->ri_mask[line]) { -		mctrl &= ~TIOCM_RNG; -		mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0; -	} -	return mctrl; -} - -/* port->lock held by caller.  */ -static void sc26xx_stop_tx(struct uart_port *port) -{ -	return; -} - -/* port->lock held by caller.  */ -static void sc26xx_start_tx(struct uart_port *port) -{ -	struct circ_buf *xmit = &port->state->xmit; - -	while (!uart_circ_empty(xmit)) { -		if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) { -			sc26xx_enable_irq(port, IMR_TXRDY); -			break; -		} -		WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); -		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -		port->icount.tx++; -	} -} - -/* port->lock held by caller.  */ -static void sc26xx_stop_rx(struct uart_port *port) -{ -} - -/* port->lock held by caller.  */ -static void sc26xx_enable_ms(struct uart_port *port) -{ -} - -/* port->lock is not held.  */ -static void sc26xx_break_ctl(struct uart_port *port, int break_state) -{ -	if (break_state == -1) -		WRITE_SC_PORT(port, CR, CR_STRT_BRK); -	else -		WRITE_SC_PORT(port, CR, CR_STOP_BRK); -} - -/* port->lock is not held.  */ -static int sc26xx_startup(struct uart_port *port) -{ -	sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); -	WRITE_SC(port, OPCR, 0); - -	/* reset tx and rx */ -	WRITE_SC_PORT(port, CR, CR_RES_RX); -	WRITE_SC_PORT(port, CR, CR_RES_TX); - -	/* start rx/tx */ -	WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); - -	/* enable irqs */ -	sc26xx_enable_irq(port, IMR_RXRDY); -	return 0; -} - -/* port->lock is not held.  */ -static void sc26xx_shutdown(struct uart_port *port) -{ -	/* disable interrupst */ -	sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); - -	/* stop tx/rx */ -	WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); -} - -/* port->lock is not held.  */ -static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios, -			      struct ktermios *old) -{ -	unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); -	unsigned int quot = uart_get_divisor(port, baud); -	unsigned int iflag, cflag; -	unsigned long flags; -	u8 mr1, mr2, csr; - -	spin_lock_irqsave(&port->lock, flags); - -	while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) -		udelay(2); - -	WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); - -	iflag = termios->c_iflag; -	cflag = termios->c_cflag; - -	port->read_status_mask = SR_OVERRUN; -	if (iflag & INPCK) -		port->read_status_mask |= SR_PARITY | SR_FRAME; -	if (iflag & (BRKINT | PARMRK)) -		port->read_status_mask |= SR_BREAK; - -	port->ignore_status_mask = 0; -	if (iflag & IGNBRK) -		port->ignore_status_mask |= SR_BREAK; -	if ((cflag & CREAD) == 0) -		port->ignore_status_mask |= SR_BREAK | SR_FRAME | -					    SR_PARITY | SR_OVERRUN; - -	switch (cflag & CSIZE) { -	case CS5: -		mr1 = 0x00; -		break; -	case CS6: -		mr1 = 0x01; -		break; -	case CS7: -		mr1 = 0x02; -		break; -	default: -	case CS8: -		mr1 = 0x03; -		break; -	} -	mr2 = 0x07; -	if (cflag & CSTOPB) -		mr2 = 0x0f; -	if (cflag & PARENB) { -		if (cflag & PARODD) -			mr1 |= (1 << 2); -	} else -		mr1 |= (2 << 3); - -	switch (baud) { -	case 50: -		csr = 0x00; -		break; -	case 110: -		csr = 0x11; -		break; -	case 134: -		csr = 0x22; -		break; -	case 200: -		csr = 0x33; -		break; -	case 300: -		csr = 0x44; -		break; -	case 600: -		csr = 0x55; -		break; -	case 1200: -		csr = 0x66; -		break; -	case 2400: -		csr = 0x88; -		break; -	case 4800: -		csr = 0x99; -		break; -	default: -	case 9600: -		csr = 0xbb; -		break; -	case 19200: -		csr = 0xcc; -		break; -	} - -	WRITE_SC_PORT(port, CR, CR_RES_MR); -	WRITE_SC_PORT(port, MRx, mr1); -	WRITE_SC_PORT(port, MRx, mr2); - -	WRITE_SC(port, ACR, 0x80); -	WRITE_SC_PORT(port, CSR, csr); - -	/* reset tx and rx */ -	WRITE_SC_PORT(port, CR, CR_RES_RX); -	WRITE_SC_PORT(port, CR, CR_RES_TX); - -	WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); -	while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) -		udelay(2); - -	/* XXX */ -	uart_update_timeout(port, cflag, -			    (port->uartclk / (16 * quot))); - -	spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *sc26xx_type(struct uart_port *port) -{ -	return "SC26XX"; -} - -static void sc26xx_release_port(struct uart_port *port) -{ -} - -static int sc26xx_request_port(struct uart_port *port) -{ -	return 0; -} - -static void sc26xx_config_port(struct uart_port *port, int flags) -{ -} - -static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser) -{ -	return -EINVAL; -} - -static struct uart_ops sc26xx_ops = { -	.tx_empty	= sc26xx_tx_empty, -	.set_mctrl	= sc26xx_set_mctrl, -	.get_mctrl	= sc26xx_get_mctrl, -	.stop_tx	= sc26xx_stop_tx, -	.start_tx	= sc26xx_start_tx, -	.stop_rx	= sc26xx_stop_rx, -	.enable_ms	= sc26xx_enable_ms, -	.break_ctl	= sc26xx_break_ctl, -	.startup	= sc26xx_startup, -	.shutdown	= sc26xx_shutdown, -	.set_termios	= sc26xx_set_termios, -	.type		= sc26xx_type, -	.release_port	= sc26xx_release_port, -	.request_port	= sc26xx_request_port, -	.config_port	= sc26xx_config_port, -	.verify_port	= sc26xx_verify_port, -}; - -static struct uart_port *sc26xx_port; - -#ifdef CONFIG_SERIAL_SC26XX_CONSOLE -static void sc26xx_console_putchar(struct uart_port *port, char c) -{ -	unsigned long flags; -	int limit = 1000000; - -	spin_lock_irqsave(&port->lock, flags); - -	while (limit-- > 0) { -		if (READ_SC_PORT(port, SR) & SR_TXRDY) { -			WRITE_SC_PORT(port, THR, c); -			break; -		} -		udelay(2); -	} - -	spin_unlock_irqrestore(&port->lock, flags); -} - -static void sc26xx_console_write(struct console *con, const char *s, unsigned n) -{ -	struct uart_port *port = sc26xx_port; -	int i; - -	for (i = 0; i < n; i++) { -		if (*s == '\n') -			sc26xx_console_putchar(port, '\r'); -		sc26xx_console_putchar(port, *s++); -	} -} - -static int __init sc26xx_console_setup(struct console *con, char *options) -{ -	struct uart_port *port = sc26xx_port; -	int baud = 9600; -	int bits = 8; -	int parity = 'n'; -	int flow = 'n'; - -	if (port->type != PORT_SC26XX) -		return -1; - -	printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index); -	if (options) -		uart_parse_options(options, &baud, &parity, &bits, &flow); - -	return uart_set_options(port, con, baud, parity, bits, flow); -} - -static struct uart_driver sc26xx_reg; -static struct console sc26xx_console = { -	.name	=	"ttySC", -	.write	=	sc26xx_console_write, -	.device	=	uart_console_device, -	.setup  =       sc26xx_console_setup, -	.flags	=	CON_PRINTBUFFER, -	.index	=	-1, -	.data	=	&sc26xx_reg, -}; -#define SC26XX_CONSOLE   &sc26xx_console -#else -#define SC26XX_CONSOLE   NULL -#endif - -static struct uart_driver sc26xx_reg = { -	.owner			= THIS_MODULE, -	.driver_name		= "SC26xx", -	.dev_name		= "ttySC", -	.major			= SC26XX_MAJOR, -	.minor			= SC26XX_MINOR_START, -	.nr			= SC26XX_NR, -	.cons                   = SC26XX_CONSOLE, -}; - -static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos) -{ -	unsigned int bit = (flags >> bitpos) & 15; - -	return bit ? (1 << (bit - 1)) : 0; -} - -static void sc26xx_init_masks(struct uart_sc26xx_port *up, -					int line, unsigned int data) -{ -	up->dtr_mask[line] = sc26xx_flags2mask(data,  0); -	up->rts_mask[line] = sc26xx_flags2mask(data,  4); -	up->dsr_mask[line] = sc26xx_flags2mask(data,  8); -	up->cts_mask[line] = sc26xx_flags2mask(data, 12); -	up->dcd_mask[line] = sc26xx_flags2mask(data, 16); -	up->ri_mask[line]  = sc26xx_flags2mask(data, 20); -} - -static int sc26xx_probe(struct platform_device *dev) -{ -	struct resource *res; -	struct uart_sc26xx_port *up; -	unsigned int *sc26xx_data = dev_get_platdata(&dev->dev); -	int err; - -	res = platform_get_resource(dev, IORESOURCE_MEM, 0); -	if (!res) -		return -ENODEV; - -	up = kzalloc(sizeof *up, GFP_KERNEL); -	if (unlikely(!up)) -		return -ENOMEM; - -	up->port[0].line = 0; -	up->port[0].ops = &sc26xx_ops; -	up->port[0].type = PORT_SC26XX; -	up->port[0].uartclk = (29491200 / 16); /* arbitrary */ - -	up->port[0].mapbase = res->start; -	up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40); -	up->port[0].iotype = UPIO_MEM; -	up->port[0].irq = platform_get_irq(dev, 0); - -	up->port[0].dev = &dev->dev; - -	sc26xx_init_masks(up, 0, sc26xx_data[0]); - -	sc26xx_port = &up->port[0]; - -	up->port[1].line = 1; -	up->port[1].ops = &sc26xx_ops; -	up->port[1].type = PORT_SC26XX; -	up->port[1].uartclk = (29491200 / 16); /* arbitrary */ - -	up->port[1].mapbase = up->port[0].mapbase; -	up->port[1].membase = up->port[0].membase; -	up->port[1].iotype = UPIO_MEM; -	up->port[1].irq = up->port[0].irq; - -	up->port[1].dev = &dev->dev; - -	sc26xx_init_masks(up, 1, sc26xx_data[1]); - -	err = uart_register_driver(&sc26xx_reg); -	if (err) -		goto out_free_port; - -	sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor; - -	err = uart_add_one_port(&sc26xx_reg, &up->port[0]); -	if (err) -		goto out_unregister_driver; - -	err = uart_add_one_port(&sc26xx_reg, &up->port[1]); -	if (err) -		goto out_remove_port0; - -	err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up); -	if (err) -		goto out_remove_ports; - -	platform_set_drvdata(dev, up); -	return 0; - -out_remove_ports: -	uart_remove_one_port(&sc26xx_reg, &up->port[1]); -out_remove_port0: -	uart_remove_one_port(&sc26xx_reg, &up->port[0]); - -out_unregister_driver: -	uart_unregister_driver(&sc26xx_reg); - -out_free_port: -	kfree(up); -	sc26xx_port = NULL; -	return err; -} - - -static int __exit sc26xx_driver_remove(struct platform_device *dev) -{ -	struct uart_sc26xx_port *up = platform_get_drvdata(dev); - -	free_irq(up->port[0].irq, up); - -	uart_remove_one_port(&sc26xx_reg, &up->port[0]); -	uart_remove_one_port(&sc26xx_reg, &up->port[1]); - -	uart_unregister_driver(&sc26xx_reg); - -	kfree(up); -	sc26xx_port = NULL; - -	return 0; -} - -static struct platform_driver sc26xx_driver = { -	.probe	= sc26xx_probe, -	.remove	= sc26xx_driver_remove, -	.driver	= { -		.name	= "SC26xx", -		.owner	= THIS_MODULE, -	}, -}; - -module_platform_driver(sc26xx_driver); - -MODULE_AUTHOR("Thomas Bogendörfer"); -MODULE_DESCRIPTION("SC681/SC2692 serial driver"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:SC26xx"); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 49e9bbfe6ca..e84b6a3bdd1 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -474,9 +474,7 @@ static void sccnxp_timer(unsigned long data)  	sccnxp_handle_events(s);  	spin_unlock_irqrestore(&s->lock, flags); -	if (!timer_pending(&s->timer)) -		mod_timer(&s->timer, jiffies + -			  usecs_to_jiffies(s->pdata.poll_time_us)); +	mod_timer(&s->timer, jiffies + usecs_to_jiffies(s->pdata.poll_time_us));  }  static irqreturn_t sccnxp_ist(int irq, void *dev_id) @@ -667,13 +665,15 @@ static void sccnxp_set_termios(struct uart_port *port,  	port->read_status_mask = SR_OVR;  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= SR_PE | SR_FE; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= SR_BRK;  	/* Set status ignore mask */  	port->ignore_status_mask = 0;  	if (termios->c_iflag & IGNBRK)  		port->ignore_status_mask |= SR_BRK; +	if (termios->c_iflag & IGNPAR) +		port->ignore_status_mask |= SR_PE;  	if (!(termios->c_cflag & CREAD))  		port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK; @@ -986,6 +986,7 @@ static int sccnxp_probe(struct platform_device *pdev)  		return 0;  	} +	uart_unregister_driver(&s->uart);  err_out:  	if (!IS_ERR(s->regulator))  		return regulator_disable(s->regulator); diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index d0d972f7e43..d5c2a287b7e 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -34,6 +34,7 @@  #include <linux/of_device.h>  #include <linux/pagemap.h>  #include <linux/platform_device.h> +#include <linux/reset.h>  #include <linux/serial.h>  #include <linux/serial_8250.h>  #include <linux/serial_core.h> @@ -44,8 +45,6 @@  #include <linux/tty.h>  #include <linux/tty_flip.h> -#include <linux/clk/tegra.h> -  #define TEGRA_UART_TYPE				"TEGRA_UART"  #define TX_EMPTY_STATUS				(UART_LSR_TEMT | UART_LSR_THRE)  #define BYTES_TO_ALIGN(x)			((unsigned long)(x) & 0x3) @@ -103,6 +102,7 @@ struct tegra_uart_port {  	const struct tegra_uart_chip_data	*cdata;  	struct clk				*uart_clk; +	struct reset_control			*rst;  	unsigned int				current_baud;  	/* Register shadow */ @@ -120,7 +120,6 @@ struct tegra_uart_port {  	bool					rx_timeout;  	int					rx_in_progress;  	int					symb_bit; -	int					dma_req_sel;  	struct dma_chan				*rx_dma_chan;  	struct dma_chan				*tx_dma_chan; @@ -732,7 +731,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)  static void tegra_uart_stop_rx(struct uart_port *u)  {  	struct tegra_uart_port *tup = to_tegra_uport(u); -	struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); +	struct tty_struct *tty;  	struct tty_port *port = &u->state->port;  	struct dma_tx_state state;  	unsigned long ier; @@ -744,6 +743,8 @@ static void tegra_uart_stop_rx(struct uart_port *u)  	if (!tup->rx_in_progress)  		return; +	tty = tty_port_tty_get(&tup->uport.state->port); +  	tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */  	ier = tup->ier_shadow; @@ -830,9 +831,9 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)  	clk_prepare_enable(tup->uart_clk);  	/* Reset the UART controller to clear all previous status.*/ -	tegra_periph_reset_assert(tup->uart_clk); +	reset_control_assert(tup->rst);  	udelay(10); -	tegra_periph_reset_deassert(tup->uart_clk); +	reset_control_deassert(tup->rst);  	tup->rx_in_progress = 0;  	tup->tx_in_progress = 0; @@ -908,15 +909,14 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,  	dma_addr_t dma_phys;  	int ret;  	struct dma_slave_config dma_sconfig; -	dma_cap_mask_t mask; -	dma_cap_zero(mask); -	dma_cap_set(DMA_SLAVE, mask); -	dma_chan = dma_request_channel(mask, NULL, NULL); -	if (!dma_chan) { +	dma_chan = dma_request_slave_channel_reason(tup->uport.dev, +						dma_to_memory ? "rx" : "tx"); +	if (IS_ERR(dma_chan)) { +		ret = PTR_ERR(dma_chan);  		dev_err(tup->uport.dev, -			"Dma channel is not available, will try later\n"); -		return -EPROBE_DEFER; +			"DMA channel alloc failed: %d\n", ret); +		return ret;  	}  	if (dma_to_memory) { @@ -936,7 +936,6 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,  		dma_buf = tup->uport.state->xmit.buf;  	} -	dma_sconfig.slave_id = tup->dma_req_sel;  	if (dma_to_memory) {  		dma_sconfig.src_addr = tup->uport.mapbase;  		dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; @@ -1016,7 +1015,7 @@ static int tegra_uart_startup(struct uart_port *u)  		goto fail_hw_init;  	} -	ret = request_irq(u->irq, tegra_uart_isr, IRQF_DISABLED, +	ret = request_irq(u->irq, tegra_uart_isr, 0,  				dev_name(u->dev), tup);  	if (ret < 0) {  		dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq); @@ -1220,17 +1219,8 @@ static int tegra_uart_parse_dt(struct platform_device *pdev,  	struct tegra_uart_port *tup)  {  	struct device_node *np = pdev->dev.of_node; -	u32 of_dma[2];  	int port; -	if (of_property_read_u32_array(np, "nvidia,dma-request-selector", -				of_dma, 2) >= 0) { -		tup->dma_req_sel = of_dma[1]; -	} else { -		dev_err(&pdev->dev, "missing dma requestor in device tree\n"); -		return -EINVAL; -	} -  	port = of_alias_get_id(np, "serial");  	if (port < 0) {  		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", port); @@ -1318,6 +1308,12 @@ static int tegra_uart_probe(struct platform_device *pdev)  		return PTR_ERR(tup->uart_clk);  	} +	tup->rst = devm_reset_control_get(&pdev->dev, "serial"); +	if (IS_ERR(tup->rst)) { +		dev_err(&pdev->dev, "Couldn't get the reset\n"); +		return PTR_ERR(tup->rst); +	} +  	u->iotype = UPIO_MEM32;  	u->irq = platform_get_irq(pdev, 0);  	u->regshift = 2; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0f02351c923..fbf6c5ad222 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -89,8 +89,7 @@ static void __uart_start(struct tty_struct *tty)  	struct uart_state *state = tty->driver_data;  	struct uart_port *port = state->uart_port; -	if (!uart_circ_empty(&state->xmit) && state->xmit.buf && -	    !tty->stopped && !tty->hw_stopped) +	if (!tty->stopped && !tty->hw_stopped)  		port->ops->start_tx(port);  } @@ -138,6 +137,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,  		return 1;  	/* +	 * Make sure the device is in D0 state. +	 */ +	uart_change_pm(state, UART_PM_STATE_ON); + +	/*  	 * Initialise and allocate the transmit and temporary  	 * buffer.  	 */ @@ -170,8 +174,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,  			if (tty->termios.c_cflag & CBAUD)  				uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);  		} - -		if (tty_port_cts_enabled(port)) { +		/* +		 * if hw support flow control without software intervention, +		 * then skip the below check +		 */ +		if (tty_port_cts_enabled(port) && +		    !(uport->flags & UPF_HARD_FLOW)) {  			spin_lock_irq(&uport->lock);  			if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))  				tty->hw_stopped = 1; @@ -826,25 +834,29 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,  		 * If we fail to request resources for the  		 * new port, try to restore the old settings.  		 */ -		if (retval && old_type != PORT_UNKNOWN) { +		if (retval) {  			uport->iobase = old_iobase;  			uport->type = old_type;  			uport->hub6 = old_hub6;  			uport->iotype = old_iotype;  			uport->regshift = old_shift;  			uport->mapbase = old_mapbase; -			retval = uport->ops->request_port(uport); -			/* -			 * If we failed to restore the old settings, -			 * we fail like this. -			 */ -			if (retval) -				uport->type = PORT_UNKNOWN; -			/* -			 * We failed anyway. -			 */ -			retval = -EBUSY; +			if (old_type != PORT_UNKNOWN) { +				retval = uport->ops->request_port(uport); +				/* +				 * If we failed to restore the old settings, +				 * we fail like this. +				 */ +				if (retval) +					uport->type = PORT_UNKNOWN; + +				/* +				 * We failed anyway. +				 */ +				retval = -EBUSY; +			} +  			/* Added to return the correct error -Ram Gupta */  			goto exit;  		} @@ -1319,9 +1331,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp)  	uport = state->uart_port;  	port = &state->port; -	pr_debug("uart_close(%d) called\n", uport->line); +	pr_debug("uart_close(%d) called\n", uport ? uport->line : -1); -	if (tty_port_close_start(port, tty, filp) == 0) +	if (!port->count || tty_port_close_start(port, tty, filp) == 0)  		return;  	/* @@ -1452,6 +1464,8 @@ static void uart_hangup(struct tty_struct *tty)  		clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);  		spin_unlock_irqrestore(&port->lock, flags);  		tty_port_tty_set(port, NULL); +		if (!uart_console(state->uart_port)) +			uart_change_pm(state, UART_PM_STATE_OFF);  		wake_up_interruptible(&port->open_wait);  		wake_up_interruptible(&port->delta_msr_wait);  	} @@ -1570,12 +1584,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)  	}  	/* -	 * Make sure the device is in D0 state. -	 */ -	if (port->count == 1) -		uart_change_pm(state, UART_PM_STATE_ON); - -	/*  	 * Start up the serial port.  	 */  	retval = uart_startup(tty, state, 0); @@ -1762,7 +1770,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)  }  /** - *	uart_parse_options - Parse serial port baud/parity/bits/flow contro. + *	uart_parse_options - Parse serial port baud/parity/bits/flow control.   *	@options: pointer to option string   *	@baud: pointer to an 'int' variable for the baud rate.   *	@parity: pointer to an 'int' variable for the parity. @@ -1830,9 +1838,13 @@ uart_set_options(struct uart_port *port, struct console *co,  	/*  	 * Ensure that the serial console lock is initialised  	 * early. +	 * If this port is a console, then the spinlock is already +	 * initialised.  	 */ -	spin_lock_init(&port->lock); -	lockdep_set_class(&port->lock, &port_lock_key); +	if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) { +		spin_lock_init(&port->lock); +		lockdep_set_class(&port->lock, &port_lock_key); +	}  	memset(&termios, 0, sizeof(struct ktermios)); @@ -2231,6 +2243,9 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)  		return;  	port = state->uart_port; + +	if (ch == '\n') +		port->ops->poll_put_char(port, '\r');  	port->ops->poll_put_char(port, ch);  }  #endif @@ -2605,7 +2620,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)  	/*  	 * Register the port whether it's detected or not.  This allows -	 * setserial to be used to alter this ports parameters. +	 * setserial to be used to alter this port's parameters.  	 */  	tty_dev = tty_port_register_device_attr(port, drv->tty_driver,  			uport->line, uport->dev, port, tty_dev_attr_groups); @@ -2641,6 +2656,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)  {  	struct uart_state *state = drv->state + uport->line;  	struct tty_port *port = &state->port; +	struct tty_struct *tty;  	int ret = 0;  	BUG_ON(in_interrupt()); @@ -2669,8 +2685,17 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)  	 */  	tty_unregister_device(drv->tty_driver, uport->line); -	if (port->tty) +	tty = tty_port_tty_get(port); +	if (tty) {  		tty_vhangup(port->tty); +		tty_kref_put(tty); +	} + +	/* +	 * If the port is used as a console, unregister it +	 */ +	if (uart_console(uport)) +		unregister_console(uport->cons);  	/*  	 * Free the port IO and memory resources, if any. @@ -2754,7 +2779,9 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)  	uport->icount.cts++; -	if (tty_port_cts_enabled(port)) { +	/* skip below code if the hw flow control is supported */ +	if (tty_port_cts_enabled(port) && +	    !(uport->flags & UPF_HARD_FLOW)) {  		if (tty->hw_stopped) {  			if (status) {  				tty->hw_stopped = 0; diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c index e1caa99e3d3..5c79bdab985 100644 --- a/drivers/tty/serial/serial_ks8695.c +++ b/drivers/tty/serial/serial_ks8695.c @@ -437,7 +437,7 @@ static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *term  	port->read_status_mask = URLS_URROE;  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= (URLS_URFE | URLS_URPE); -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= URLS_URBI;  	/* diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c new file mode 100644 index 00000000000..bf9560ffe3f --- /dev/null +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -0,0 +1,143 @@ +/* + * Helpers for controlling modem lines via GPIO + * + * Copyright (C) 2014 Paratronic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + */ + +#include <linux/err.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <uapi/asm-generic/termios.h> + +#include "serial_mctrl_gpio.h" + +struct mctrl_gpios { +	struct gpio_desc *gpio[UART_GPIO_MAX]; +}; + +static const struct { +	const char *name; +	unsigned int mctrl; +	bool dir_out; +} mctrl_gpios_desc[UART_GPIO_MAX] = { +	{ "cts", TIOCM_CTS, false, }, +	{ "dsr", TIOCM_DSR, false, }, +	{ "dcd", TIOCM_CD, false, }, +	{ "rng", TIOCM_RNG, false, }, +	{ "rts", TIOCM_RTS, true, }, +	{ "dtr", TIOCM_DTR, true, }, +	{ "out1", TIOCM_OUT1, true, }, +	{ "out2", TIOCM_OUT2, true, }, +}; + +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) +{ +	enum mctrl_gpio_idx i; + +	if (IS_ERR_OR_NULL(gpios)) +		return; + +	for (i = 0; i < UART_GPIO_MAX; i++) +		if (!IS_ERR_OR_NULL(gpios->gpio[i]) && +		    mctrl_gpios_desc[i].dir_out) +			gpiod_set_value(gpios->gpio[i], +					!!(mctrl & mctrl_gpios_desc[i].mctrl)); +} +EXPORT_SYMBOL_GPL(mctrl_gpio_set); + +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, +				      enum mctrl_gpio_idx gidx) +{ +	if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx])) +		return gpios->gpio[gidx]; +	else +		return NULL; +} +EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod); + +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) +{ +	enum mctrl_gpio_idx i; + +	/* +	 * return it unchanged if the structure is not allocated +	 */ +	if (IS_ERR_OR_NULL(gpios)) +		return *mctrl; + +	for (i = 0; i < UART_GPIO_MAX; i++) { +		if (!IS_ERR_OR_NULL(gpios->gpio[i]) && +		    !mctrl_gpios_desc[i].dir_out) { +			if (gpiod_get_value(gpios->gpio[i])) +				*mctrl |= mctrl_gpios_desc[i].mctrl; +			else +				*mctrl &= ~mctrl_gpios_desc[i].mctrl; +		} +	} + +	return *mctrl; +} +EXPORT_SYMBOL_GPL(mctrl_gpio_get); + +struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) +{ +	struct mctrl_gpios *gpios; +	enum mctrl_gpio_idx i; +	int err; + +	gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL); +	if (!gpios) +		return ERR_PTR(-ENOMEM); + +	for (i = 0; i < UART_GPIO_MAX; i++) { +		gpios->gpio[i] = devm_gpiod_get_index(dev, +						      mctrl_gpios_desc[i].name, +						      idx); + +		/* +		 * The GPIOs are maybe not all filled, +		 * this is not an error. +		 */ +		if (IS_ERR_OR_NULL(gpios->gpio[i])) +			continue; + +		if (mctrl_gpios_desc[i].dir_out) +			err = gpiod_direction_output(gpios->gpio[i], 0); +		else +			err = gpiod_direction_input(gpios->gpio[i]); +		if (err) { +			dev_dbg(dev, "Unable to set direction for %s GPIO", +				mctrl_gpios_desc[i].name); +			devm_gpiod_put(dev, gpios->gpio[i]); +			gpios->gpio[i] = NULL; +		} +	} + +	return gpios; +} +EXPORT_SYMBOL_GPL(mctrl_gpio_init); + +void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) +{ +	enum mctrl_gpio_idx i; + +	if (IS_ERR_OR_NULL(gpios)) +		return; + +	for (i = 0; i < UART_GPIO_MAX; i++) +		if (!IS_ERR_OR_NULL(gpios->gpio[i])) +			devm_gpiod_put(dev, gpios->gpio[i]); +	devm_kfree(dev, gpios); +} +EXPORT_SYMBOL_GPL(mctrl_gpio_free); diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h new file mode 100644 index 00000000000..400ba0494a1 --- /dev/null +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -0,0 +1,110 @@ +/* + * Helpers for controlling modem lines via GPIO + * + * Copyright (C) 2014 Paratronic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + */ + +#ifndef __SERIAL_MCTRL_GPIO__ +#define __SERIAL_MCTRL_GPIO__ + +#include <linux/err.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> + +enum mctrl_gpio_idx { +	UART_GPIO_CTS, +	UART_GPIO_DSR, +	UART_GPIO_DCD, +	UART_GPIO_RNG, +	UART_GPIO_RI = UART_GPIO_RNG, +	UART_GPIO_RTS, +	UART_GPIO_DTR, +	UART_GPIO_OUT1, +	UART_GPIO_OUT2, +	UART_GPIO_MAX, +}; + +/* + * Opaque descriptor for modem lines controlled by GPIOs + */ +struct mctrl_gpios; + +#ifdef CONFIG_GPIOLIB + +/* + * Set state of the modem control output lines via GPIOs. + */ +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl); + +/* + * Get state of the modem control output lines from GPIOs. + * The mctrl flags are updated and returned. + */ +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl); + +/* + * Returns the associated struct gpio_desc to the modem line gidx + */ +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, +				      enum mctrl_gpio_idx gidx); + +/* + * Request and set direction of modem control lines GPIOs. + * devm_* functions are used, so there's no need to call mctrl_gpio_free(). + * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on + * allocation error. + */ +struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx); + +/* + * Free the mctrl_gpios structure. + * Normally, this function will not be called, as the GPIOs will + * be disposed of by the resource management code. + */ +void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios); + +#else /* GPIOLIB */ + +static inline +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) +{ +} + +static inline +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) +{ +	return *mctrl; +} + +static inline +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, +				      enum mctrl_gpio_idx gidx) +{ +	return ERR_PTR(-ENOSYS); +} + +static inline +struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) +{ +	return ERR_PTR(-ENOSYS); +} + +static inline +void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) +{ +} + +#endif /* GPIOLIB */ + +#endif diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 440a962412d..ea8546092c7 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -535,13 +535,8 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)  	wait_for_xmitr(up);  	/*  	 *	Send the character out. -	 *	If a LF, also do CR...  	 */  	sio_out(up, TXX9_SITFIFO, c); -	if (c == 10) { -		wait_for_xmitr(up); -		sio_out(up, TXX9_SITFIFO, 13); -	}  	/*  	 *	Finally, wait for transmitter to become empty @@ -702,7 +697,7 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,  		TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS;  	if (termios->c_iflag & INPCK)  		up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		up->port.read_status_mask |= TXX9_SIDISR_UBRK;  	/* @@ -1220,8 +1215,6 @@ static void pciserial_txx9_remove_one(struct pci_dev *dev)  {  	struct uart_txx9_port *up = pci_get_drvdata(dev); -	pci_set_drvdata(dev, NULL); -  	if (up) {  		serial_txx9_unregister_port(up->port.line);  		pci_disable_device(dev); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 537750261aa..88236da0ddf 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -23,35 +23,35 @@  #undef DEBUG -#include <linux/module.h> +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/ctype.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/err.h>  #include <linux/errno.h> -#include <linux/sh_dma.h> -#include <linux/timer.h> +#include <linux/init.h>  #include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/sysrq.h>  #include <linux/ioport.h> +#include <linux/major.h> +#include <linux/module.h>  #include <linux/mm.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/console.h> -#include <linux/platform_device.h> -#include <linux/serial_sci.h>  #include <linux/notifier.h> +#include <linux/of.h> +#include <linux/platform_device.h>  #include <linux/pm_runtime.h> -#include <linux/cpufreq.h> -#include <linux/clk.h> -#include <linux/ctype.h> -#include <linux/err.h> -#include <linux/dmaengine.h> -#include <linux/dma-mapping.h>  #include <linux/scatterlist.h> +#include <linux/serial.h> +#include <linux/serial_sci.h> +#include <linux/sh_dma.h>  #include <linux/slab.h> -#include <linux/gpio.h> +#include <linux/string.h> +#include <linux/sysrq.h> +#include <linux/timer.h> +#include <linux/tty.h> +#include <linux/tty_flip.h>  #ifdef CONFIG_SUPERH  #include <asm/sh_bios.h> @@ -59,11 +59,32 @@  #include "sh-sci.h" +/* Offsets into the sci_port->irqs array */ +enum { +	SCIx_ERI_IRQ, +	SCIx_RXI_IRQ, +	SCIx_TXI_IRQ, +	SCIx_BRI_IRQ, +	SCIx_NR_IRQS, + +	SCIx_MUX_IRQ = SCIx_NR_IRQS,	/* special case */ +}; + +#define SCIx_IRQ_IS_MUXED(port)			\ +	((port)->irqs[SCIx_ERI_IRQ] ==	\ +	 (port)->irqs[SCIx_RXI_IRQ]) ||	\ +	((port)->irqs[SCIx_ERI_IRQ] &&	\ +	 ((port)->irqs[SCIx_RXI_IRQ] < 0)) +  struct sci_port {  	struct uart_port	port;  	/* Platform configuration */  	struct plat_sci_port	*cfg; +	int			overrun_bit; +	unsigned int		error_mask; +	unsigned int		sampling_rate; +  	/* Break timer */  	struct timer_list	break_timer; @@ -74,8 +95,8 @@ struct sci_port {  	/* Function clock */  	struct clk		*fclk; +	int			irqs[SCIx_NR_IRQS];  	char			*irqstr[SCIx_NR_IRQS]; -	char			*gpiostr[SCIx_NR_FNS];  	struct dma_chan			*chan_tx;  	struct dma_chan			*chan_rx; @@ -407,7 +428,7 @@ static int sci_probe_regmap(struct plat_sci_port *cfg)  		cfg->regtype = SCIx_HSCIF_REGTYPE;  		break;  	default: -		printk(KERN_ERR "Can't probe register map for given port\n"); +		pr_err("Can't probe register map for given port\n");  		return -EINVAL;  	} @@ -421,9 +442,9 @@ static void sci_port_enable(struct sci_port *sci_port)  	pm_runtime_get_sync(sci_port->port.dev); -	clk_enable(sci_port->iclk); +	clk_prepare_enable(sci_port->iclk);  	sci_port->port.uartclk = clk_get_rate(sci_port->iclk); -	clk_enable(sci_port->fclk); +	clk_prepare_enable(sci_port->fclk);  }  static void sci_port_disable(struct sci_port *sci_port) @@ -431,8 +452,16 @@ static void sci_port_disable(struct sci_port *sci_port)  	if (!sci_port->port.dev)  		return; -	clk_disable(sci_port->fclk); -	clk_disable(sci_port->iclk); +	/* Cancel the break timer to ensure that the timer handler will not try +	 * to access the hardware with clocks and power disabled. Reset the +	 * break flag to make the break debouncing state machine ready for the +	 * next break. +	 */ +	del_timer_sync(&sci_port->break_timer); +	sci_port->break_flag = 0; + +	clk_disable_unprepare(sci_port->fclk); +	clk_disable_unprepare(sci_port->iclk);  	pm_runtime_put_sync(sci_port->port.dev);  } @@ -557,7 +586,7 @@ static inline int sci_rxd_in(struct uart_port *port)  		return 1;  	/* Cast for ARM damage */ -	return !!__raw_readb((void __iomem *)s->cfg->port_reg); +	return !!__raw_readb((void __iomem *)(uintptr_t)s->cfg->port_reg);  }  /* ********************************************************************** * @@ -733,8 +762,6 @@ static void sci_break_timer(unsigned long data)  {  	struct sci_port *port = (struct sci_port *)data; -	sci_port_enable(port); -  	if (sci_rxd_in(&port->port) == 0) {  		port->break_flag = 1;  		sci_schedule_break_timer(port); @@ -744,8 +771,6 @@ static void sci_break_timer(unsigned long data)  		sci_schedule_break_timer(port);  	} else  		port->break_flag = 0; - -	sci_port_disable(port);  }  static int sci_handle_errors(struct uart_port *port) @@ -755,19 +780,15 @@ static int sci_handle_errors(struct uart_port *port)  	struct tty_port *tport = &port->state->port;  	struct sci_port *s = to_sci_port(port); -	/* -	 * Handle overruns, if supported. -	 */ -	if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) { -		if (status & (1 << s->cfg->overrun_bit)) { -			port->icount.overrun++; +	/* Handle overruns */ +	if (status & (1 << s->overrun_bit)) { +		port->icount.overrun++; -			/* overrun error */ -			if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) -				copied++; +		/* overrun error */ +		if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) +			copied++; -			dev_notice(port->dev, "overrun error"); -		} +		dev_notice(port->dev, "overrun error\n");  	}  	if (status & SCxSR_FER(port)) { @@ -809,7 +830,7 @@ static int sci_handle_errors(struct uart_port *port)  		if (tty_insert_flip_char(tport, 0, TTY_PARITY))  			copied++; -		dev_notice(port->dev, "parity error"); +		dev_notice(port->dev, "parity error\n");  	}  	if (copied) @@ -829,7 +850,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)  	if (!reg->size)  		return 0; -	if ((serial_port_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) { +	if ((serial_port_in(port, SCLSR) & (1 << s->overrun_bit))) {  		serial_port_out(port, SCLSR, 0);  		port->icount.overrun++; @@ -890,7 +911,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)  		/* Disable future Rx interrupts */  		if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {  			disable_irq_nosync(irq); -			scr |= 0x4000; +			scr |= SCSCR_RDRQE;  		} else {  			scr &= ~SCSCR_RIE;  		} @@ -1020,8 +1041,7 @@ static int sci_notifier(struct notifier_block *self,  	sci_port = container_of(self, struct sci_port, freq_transition); -	if ((phase == CPUFREQ_POSTCHANGE) || -	    (phase == CPUFREQ_RESUMECHANGE)) { +	if (phase == CPUFREQ_POSTCHANGE) {  		struct uart_port *port = &sci_port->port;  		spin_lock_irqsave(&port->lock, flags); @@ -1075,19 +1095,19 @@ static int sci_request_irq(struct sci_port *port)  	for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) {  		struct sci_irq_desc *desc; -		unsigned int irq; +		int irq;  		if (SCIx_IRQ_IS_MUXED(port)) {  			i = SCIx_MUX_IRQ;  			irq = up->irq;  		} else { -			irq = port->cfg->irqs[i]; +			irq = port->irqs[i];  			/*  			 * Certain port types won't support all of the  			 * available interrupt sources.  			 */ -			if (unlikely(!irq)) +			if (unlikely(irq < 0))  				continue;  		} @@ -1112,7 +1132,7 @@ static int sci_request_irq(struct sci_port *port)  out_noirq:  	while (--i >= 0) -		free_irq(port->cfg->irqs[i], port); +		free_irq(port->irqs[i], port);  out_nomem:  	while (--j >= 0) @@ -1130,16 +1150,16 @@ static void sci_free_irq(struct sci_port *port)  	 * IRQ first.  	 */  	for (i = 0; i < SCIx_NR_IRQS; i++) { -		unsigned int irq = port->cfg->irqs[i]; +		int irq = port->irqs[i];  		/*  		 * Certain port types won't support all of the available  		 * interrupt sources.  		 */ -		if (unlikely(!irq)) +		if (unlikely(irq < 0))  			continue; -		free_irq(port->cfg->irqs[i], port); +		free_irq(port->irqs[i], port);  		kfree(port->irqstr[i]);  		if (SCIx_IRQ_IS_MUXED(port)) { @@ -1149,67 +1169,6 @@ static void sci_free_irq(struct sci_port *port)  	}  } -static const char *sci_gpio_names[SCIx_NR_FNS] = { -	"sck", "rxd", "txd", "cts", "rts", -}; - -static const char *sci_gpio_str(unsigned int index) -{ -	return sci_gpio_names[index]; -} - -static void sci_init_gpios(struct sci_port *port) -{ -	struct uart_port *up = &port->port; -	int i; - -	if (!port->cfg) -		return; - -	for (i = 0; i < SCIx_NR_FNS; i++) { -		const char *desc; -		int ret; - -		if (!port->cfg->gpios[i]) -			continue; - -		desc = sci_gpio_str(i); - -		port->gpiostr[i] = kasprintf(GFP_KERNEL, "%s:%s", -					     dev_name(up->dev), desc); - -		/* -		 * If we've failed the allocation, we can still continue -		 * on with a NULL string. -		 */ -		if (!port->gpiostr[i]) -			dev_notice(up->dev, "%s string allocation failure\n", -				   desc); - -		ret = gpio_request(port->cfg->gpios[i], port->gpiostr[i]); -		if (unlikely(ret != 0)) { -			dev_notice(up->dev, "failed %s gpio request\n", desc); - -			/* -			 * If we can't get the GPIO for whatever reason, -			 * no point in keeping the verbose string around. -			 */ -			kfree(port->gpiostr[i]); -		} -	} -} - -static void sci_free_gpios(struct sci_port *port) -{ -	int i; - -	for (i = 0; i < SCIx_NR_FNS; i++) -		if (port->cfg->gpios[i]) { -			gpio_free(port->cfg->gpios[i]); -			kfree(port->gpiostr[i]); -		} -} -  static unsigned int sci_tx_empty(struct uart_port *port)  {  	unsigned short status = serial_port_in(port, SCxSR); @@ -1240,7 +1199,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)  		 */  		reg = sci_getreg(port, SCFCR);  		if (reg->size) -			serial_port_out(port, SCFCR, serial_port_in(port, SCFCR) | 1); +			serial_port_out(port, SCFCR, +					serial_port_in(port, SCFCR) | +					SCFCR_LOOP);  	}  } @@ -1309,7 +1270,7 @@ static int sci_dma_rx_push(struct sci_port *s, size_t count)  	}  	if (room < count) -		dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", +		dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n",  			 count - room);  	if (!room)  		return room; @@ -1330,7 +1291,8 @@ static void sci_dma_rx_complete(void *arg)  	unsigned long flags;  	int count; -	dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx); +	dev_dbg(port->dev, "%s(%d) active #%d\n", +		__func__, port->line, s->active_rx);  	spin_lock_irqsave(&port->lock, flags); @@ -1406,8 +1368,8 @@ static void sci_submit_rx(struct sci_port *s)  			sci_rx_dma_release(s, true);  			return;  		} -		dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, -			s->cookie_rx[i], i); +		dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", +			__func__, s->cookie_rx[i], i);  	}  	s->active_rx = s->cookie_rx[0]; @@ -1433,7 +1395,7 @@ static void work_fn_rx(struct work_struct *work)  	desc = s->desc_rx[new];  	if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != -	    DMA_SUCCESS) { +	    DMA_COMPLETE) {  		/* Handle incomplete DMA receive */  		struct dma_chan *chan = s->chan_rx;  		struct shdma_desc *sh_desc = container_of(desc, @@ -1442,7 +1404,7 @@ static void work_fn_rx(struct work_struct *work)  		int count;  		chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); -		dev_dbg(port->dev, "Read %u bytes with cookie %d\n", +		dev_dbg(port->dev, "Read %zu bytes with cookie %d\n",  			sh_desc->partial, sh_desc->cookie);  		spin_lock_irqsave(&port->lock, flags); @@ -1466,8 +1428,8 @@ static void work_fn_rx(struct work_struct *work)  	s->active_rx = s->cookie_rx[!new]; -	dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__, -		s->cookie_rx[new], new, s->active_rx); +	dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", +		__func__, s->cookie_rx[new], new, s->active_rx);  }  static void work_fn_tx(struct work_struct *work) @@ -1520,8 +1482,8 @@ static void work_fn_tx(struct work_struct *work)  		return;  	} -	dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__, -		xmit->buf, xmit->tail, xmit->head, s->cookie_tx); +	dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", +		__func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);  	dma_async_issue_pending(chan);  } @@ -1536,9 +1498,9 @@ static void sci_start_tx(struct uart_port *port)  	if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {  		u16 new, scr = serial_port_in(port, SCSCR);  		if (s->chan_tx) -			new = scr | 0x8000; +			new = scr | SCSCR_TDRQE;  		else -			new = scr & ~0x8000; +			new = scr & ~SCSCR_TDRQE;  		if (new != scr)  			serial_port_out(port, SCSCR, new);  	} @@ -1565,7 +1527,7 @@ static void sci_stop_tx(struct uart_port *port)  	ctrl = serial_port_in(port, SCSCR);  	if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) -		ctrl &= ~0x8000; +		ctrl &= ~SCSCR_TDRQE;  	ctrl &= ~SCSCR_TIE; @@ -1579,7 +1541,7 @@ static void sci_start_rx(struct uart_port *port)  	ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port);  	if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) -		ctrl &= ~0x4000; +		ctrl &= ~SCSCR_RDRQE;  	serial_port_out(port, SCSCR, ctrl);  } @@ -1591,7 +1553,7 @@ static void sci_stop_rx(struct uart_port *port)  	ctrl = serial_port_in(port, SCSCR);  	if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) -		ctrl &= ~0x4000; +		ctrl &= ~SCSCR_RDRQE;  	ctrl &= ~port_rx_irq_mask(port); @@ -1640,8 +1602,8 @@ static bool filter(struct dma_chan *chan, void *slave)  {  	struct sh_dmae_slave *param = slave; -	dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, -		param->shdma_slave.slave_id); +	dev_dbg(chan->device->dev, "%s: slave ID %d\n", +		__func__, param->shdma_slave.slave_id);  	chan->private = ¶m->shdma_slave;  	return true; @@ -1654,8 +1616,8 @@ static void rx_timer_fn(unsigned long arg)  	u16 scr = serial_port_in(port, SCSCR);  	if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { -		scr &= ~0x4000; -		enable_irq(s->cfg->irqs[1]); +		scr &= ~SCSCR_RDRQE; +		enable_irq(s->irqs[SCIx_RXI_IRQ]);  	}  	serial_port_out(port, SCSCR, scr | SCSCR_RIE);  	dev_dbg(port->dev, "DMA Rx timed out\n"); @@ -1670,8 +1632,7 @@ static void sci_request_dma(struct uart_port *port)  	dma_cap_mask_t mask;  	int nent; -	dev_dbg(port->dev, "%s: port %d\n", __func__, -		port->line); +	dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);  	if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)  		return; @@ -1691,16 +1652,18 @@ static void sci_request_dma(struct uart_port *port)  		s->chan_tx = chan;  		sg_init_table(&s->sg_tx, 1);  		/* UART circular tx buffer is an aligned page. */ -		BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); +		BUG_ON((uintptr_t)port->state->xmit.buf & ~PAGE_MASK);  		sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), -			    UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK); +			    UART_XMIT_SIZE, +			    (uintptr_t)port->state->xmit.buf & ~PAGE_MASK);  		nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);  		if (!nent)  			sci_tx_dma_release(s, false);  		else -			dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, -				sg_dma_len(&s->sg_tx), -				port->state->xmit.buf, sg_dma_address(&s->sg_tx)); +			dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", +				__func__, +				sg_dma_len(&s->sg_tx), port->state->xmit.buf, +				&sg_dma_address(&s->sg_tx));  		s->sg_len_tx = nent; @@ -1740,7 +1703,7 @@ static void sci_request_dma(struct uart_port *port)  			sg_init_table(sg, 1);  			sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, -				    (int)buf[i] & ~PAGE_MASK); +				    (uintptr_t)buf[i] & ~PAGE_MASK);  			sg_dma_address(sg) = dma[i];  		} @@ -1808,21 +1771,11 @@ static void sci_shutdown(struct uart_port *port)  	sci_free_irq(s);  } -static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, +static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,  				   unsigned long freq)  { -	switch (algo_id) { -	case SCBRR_ALGO_1: -		return ((freq + 16 * bps) / (16 * bps) - 1); -	case SCBRR_ALGO_2: -		return ((freq + 16 * bps) / (32 * bps) - 1); -	case SCBRR_ALGO_3: -		return (((freq * 2) + 16 * bps) / (16 * bps) - 1); -	case SCBRR_ALGO_4: -		return (((freq * 2) + 16 * bps) / (32 * bps) - 1); -	case SCBRR_ALGO_5: -		return (((freq * 1000 / 32) / bps) - 1); -	} +	if (s->sampling_rate) +		return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1;  	/* Warn, but use a safe default */  	WARN_ON(1); @@ -1903,12 +1856,11 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,  	baud = uart_get_baud_rate(port, termios, old, 0, max_baud);  	if (likely(baud && port->uartclk)) { -		if (s->cfg->scbrr_algo_id == SCBRR_ALGO_6) { +		if (s->cfg->type == PORT_HSCIF) {  			sci_baud_calc_hscif(baud, port->uartclk, &t, &srr,  					    &cks);  		} else { -			t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, -					   port->uartclk); +			t = sci_scbrr_calc(s, baud, port->uartclk);  			for (cks = 0; t >= 256 && cks <= 3; cks++)  				t >>= 2;  		} @@ -1921,13 +1873,13 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,  	smr_val = serial_port_in(port, SCSMR) & 3;  	if ((termios->c_cflag & CSIZE) == CS7) -		smr_val |= 0x40; +		smr_val |= SCSMR_CHR;  	if (termios->c_cflag & PARENB) -		smr_val |= 0x20; +		smr_val |= SCSMR_PE;  	if (termios->c_cflag & PARODD) -		smr_val |= 0x30; +		smr_val |= SCSMR_PE | SCSMR_ODD;  	if (termios->c_cflag & CSTOPB) -		smr_val |= 0x08; +		smr_val |= SCSMR_STOP;  	uart_update_timeout(port, termios->c_cflag, baud); @@ -1935,7 +1887,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,  		__func__, smr_val, cks, t, s->cfg->scscr);  	if (t >= 0) { -		serial_port_out(port, SCSMR, (smr_val & ~3) | cks); +		serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks);  		serial_port_out(port, SCBRR, t);  		reg = sci_getreg(port, HSSRR);  		if (reg->size) @@ -1983,8 +1935,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,  	if (s->chan_rx) {  		s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /  			port->fifosize / 2; -		dev_dbg(port->dev, -			"DMA Rx t-out %ums, tty t-out %u jiffies\n", +		dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n",  			s->rx_timeout * 1000 / HZ, port->timeout);  		if (s->rx_timeout < msecs_to_jiffies(20))  			s->rx_timeout = msecs_to_jiffies(20); @@ -2003,7 +1954,7 @@ static void sci_pm(struct uart_port *port, unsigned int state,  	struct sci_port *sci_port = to_sci_port(port);  	switch (state) { -	case 3: +	case UART_PM_STATE_OFF:  		sci_port_disable(sci_port);  		break;  	default: @@ -2068,7 +2019,7 @@ static int sci_remap_port(struct uart_port *port)  		 * need to do any remapping, just cast the cookie  		 * directly.  		 */ -		port->membase = (void __iomem *)port->mapbase; +		port->membase = (void __iomem *)(uintptr_t)port->mapbase;  	}  	return 0; @@ -2115,10 +2066,6 @@ static void sci_config_port(struct uart_port *port, int flags)  static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)  { -	struct sci_port *s = to_sci_port(port); - -	if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) -		return -EINVAL;  	if (ser->baud_base < 2400)  		/* No paper tape reader for Mitch.. */  		return -EINVAL; @@ -2151,11 +2098,13 @@ static struct uart_ops sci_uart_ops = {  };  static int sci_init_single(struct platform_device *dev, -				     struct sci_port *sci_port, -				     unsigned int index, -				     struct plat_sci_port *p) +			   struct sci_port *sci_port, unsigned int index, +			   struct plat_sci_port *p, bool early)  {  	struct uart_port *port = &sci_port->port; +	const struct resource *res; +	unsigned int sampling_rate; +	unsigned int i;  	int ret;  	sci_port->cfg	= p; @@ -2164,31 +2113,76 @@ static int sci_init_single(struct platform_device *dev,  	port->iotype	= UPIO_MEM;  	port->line	= index; +	res = platform_get_resource(dev, IORESOURCE_MEM, 0); +	if (res == NULL) +		return -ENOMEM; + +	port->mapbase = res->start; + +	for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) +		sci_port->irqs[i] = platform_get_irq(dev, i); + +	/* The SCI generates several interrupts. They can be muxed together or +	 * connected to different interrupt lines. In the muxed case only one +	 * interrupt resource is specified. In the non-muxed case three or four +	 * interrupt resources are specified, as the BRI interrupt is optional. +	 */ +	if (sci_port->irqs[0] < 0) +		return -ENXIO; + +	if (sci_port->irqs[1] < 0) { +		sci_port->irqs[1] = sci_port->irqs[0]; +		sci_port->irqs[2] = sci_port->irqs[0]; +		sci_port->irqs[3] = sci_port->irqs[0]; +	} + +	if (p->regtype == SCIx_PROBE_REGTYPE) { +		ret = sci_probe_regmap(p); +		if (unlikely(ret)) +			return ret; +	} +  	switch (p->type) {  	case PORT_SCIFB:  		port->fifosize = 256; +		sci_port->overrun_bit = 9; +		sampling_rate = 16;  		break;  	case PORT_HSCIF:  		port->fifosize = 128; +		sampling_rate = 0; +		sci_port->overrun_bit = 0;  		break;  	case PORT_SCIFA:  		port->fifosize = 64; +		sci_port->overrun_bit = 9; +		sampling_rate = 16;  		break;  	case PORT_SCIF:  		port->fifosize = 16; +		if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { +			sci_port->overrun_bit = 9; +			sampling_rate = 16; +		} else { +			sci_port->overrun_bit = 0; +			sampling_rate = 32; +		}  		break;  	default:  		port->fifosize = 1; +		sci_port->overrun_bit = 5; +		sampling_rate = 32;  		break;  	} -	if (p->regtype == SCIx_PROBE_REGTYPE) { -		ret = sci_probe_regmap(p); -		if (unlikely(ret)) -			return ret; -	} +	/* SCIFA on sh7723 and sh7724 need a custom sampling rate that doesn't +	 * match the SoC datasheet, this should be investigated. Let platform +	 * data override the sampling rate for now. +	 */ +	sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate +				: sampling_rate; -	if (dev) { +	if (!early) {  		sci_port->iclk = clk_get(&dev->dev, "sci_ick");  		if (IS_ERR(sci_port->iclk)) {  			sci_port->iclk = clk_get(&dev->dev, "peripheral_clk"); @@ -2208,8 +2202,6 @@ static int sci_init_single(struct platform_device *dev,  		port->dev = &dev->dev; -		sci_init_gpios(sci_port); -  		pm_runtime_enable(&dev->dev);  	} @@ -2220,32 +2212,22 @@ static int sci_init_single(struct platform_device *dev,  	/*  	 * Establish some sensible defaults for the error detection.  	 */ -	if (!p->error_mask) -		p->error_mask = (p->type == PORT_SCI) ? +	sci_port->error_mask = (p->type == PORT_SCI) ?  			SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK;  	/*  	 * Establish sensible defaults for the overrun detection, unless  	 * the part has explicitly disabled support for it.  	 */ -	if (p->overrun_bit != SCIx_NOT_SUPPORTED) { -		if (p->type == PORT_SCI) -			p->overrun_bit = 5; -		else if (p->scbrr_algo_id == SCBRR_ALGO_4) -			p->overrun_bit = 9; -		else -			p->overrun_bit = 0; -		/* -		 * Make the error mask inclusive of overrun detection, if -		 * supported. -		 */ -		p->error_mask |= (1 << p->overrun_bit); -	} +	/* +	 * Make the error mask inclusive of overrun detection, if +	 * supported. +	 */ +	sci_port->error_mask |= 1 << sci_port->overrun_bit; -	port->mapbase		= p->mapbase;  	port->type		= p->type; -	port->flags		= p->flags; +	port->flags		= UPF_FIXED_PORT | p->flags;  	port->regshift		= p->regshift;  	/* @@ -2255,7 +2237,7 @@ static int sci_init_single(struct platform_device *dev,  	 *  	 * For the muxed case there's nothing more to do.  	 */ -	port->irq		= p->irqs[SCIx_RXI_IRQ]; +	port->irq		= sci_port->irqs[SCIx_RXI_IRQ];  	port->irqflags		= 0;  	port->serial_in		= sci_serial_in; @@ -2270,8 +2252,6 @@ static int sci_init_single(struct platform_device *dev,  static void sci_cleanup_single(struct sci_port *port)  { -	sci_free_gpios(port); -  	clk_put(port->iclk);  	clk_put(port->fclk); @@ -2387,7 +2367,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev)  	early_serial_console.index = pdev->id; -	sci_init_single(NULL, &sci_ports[pdev->id], pdev->id, cfg); +	sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true);  	serial_console_setup(&early_serial_console, early_serial_buf); @@ -2410,8 +2390,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)  #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ -static char banner[] __initdata = -	KERN_INFO "SuperH (H)SCI(F) driver initialized\n"; +static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";  static struct uart_driver sci_uart_driver = {  	.owner		= THIS_MODULE, @@ -2437,6 +2416,83 @@ static int sci_remove(struct platform_device *dev)  	return 0;  } +struct sci_port_info { +	unsigned int type; +	unsigned int regtype; +}; + +static const struct of_device_id of_sci_match[] = { +	{ +		.compatible = "renesas,scif", +		.data = &(const struct sci_port_info) { +			.type = PORT_SCIF, +			.regtype = SCIx_SH4_SCIF_REGTYPE, +		}, +	}, { +		.compatible = "renesas,scifa", +		.data = &(const struct sci_port_info) { +			.type = PORT_SCIFA, +			.regtype = SCIx_SCIFA_REGTYPE, +		}, +	}, { +		.compatible = "renesas,scifb", +		.data = &(const struct sci_port_info) { +			.type = PORT_SCIFB, +			.regtype = SCIx_SCIFB_REGTYPE, +		}, +	}, { +		.compatible = "renesas,hscif", +		.data = &(const struct sci_port_info) { +			.type = PORT_HSCIF, +			.regtype = SCIx_HSCIF_REGTYPE, +		}, +	}, { +		/* Terminator */ +	}, +}; +MODULE_DEVICE_TABLE(of, of_sci_match); + +static struct plat_sci_port * +sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) +{ +	struct device_node *np = pdev->dev.of_node; +	const struct of_device_id *match; +	const struct sci_port_info *info; +	struct plat_sci_port *p; +	int id; + +	if (!IS_ENABLED(CONFIG_OF) || !np) +		return NULL; + +	match = of_match_node(of_sci_match, pdev->dev.of_node); +	if (!match) +		return NULL; + +	info = match->data; + +	p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL); +	if (!p) { +		dev_err(&pdev->dev, "failed to allocate DT config data\n"); +		return NULL; +	} + +	/* Get the line number for the aliases node. */ +	id = of_alias_get_id(np, "serial"); +	if (id < 0) { +		dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); +		return NULL; +	} + +	*dev_id = id; + +	p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; +	p->type = info->type; +	p->regtype = info->regtype; +	p->scscr = SCSCR_RE | SCSCR_TE; + +	return p; +} +  static int sci_probe_single(struct platform_device *dev,  				      unsigned int index,  				      struct plat_sci_port *p, @@ -2446,15 +2502,13 @@ static int sci_probe_single(struct platform_device *dev,  	/* Sanity check */  	if (unlikely(index >= SCI_NPORTS)) { -		dev_notice(&dev->dev, "Attempting to register port " -			   "%d when only %d are available.\n", +		dev_notice(&dev->dev, "Attempting to register port %d when only %d are available\n",  			   index+1, SCI_NPORTS); -		dev_notice(&dev->dev, "Consider bumping " -			   "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); +		dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");  		return -EINVAL;  	} -	ret = sci_init_single(dev, sciport, index, p); +	ret = sci_init_single(dev, sciport, index, p, false);  	if (ret)  		return ret; @@ -2469,8 +2523,9 @@ static int sci_probe_single(struct platform_device *dev,  static int sci_probe(struct platform_device *dev)  { -	struct plat_sci_port *p = dev_get_platdata(&dev->dev); -	struct sci_port *sp = &sci_ports[dev->id]; +	struct plat_sci_port *p; +	struct sci_port *sp; +	unsigned int dev_id;  	int ret;  	/* @@ -2481,9 +2536,24 @@ static int sci_probe(struct platform_device *dev)  	if (is_early_platform_device(dev))  		return sci_probe_earlyprintk(dev); +	if (dev->dev.of_node) { +		p = sci_parse_dt(dev, &dev_id); +		if (p == NULL) +			return -EINVAL; +	} else { +		p = dev->dev.platform_data; +		if (p == NULL) { +			dev_err(&dev->dev, "no platform data supplied\n"); +			return -EINVAL; +		} + +		dev_id = dev->id; +	} + +	sp = &sci_ports[dev_id];  	platform_set_drvdata(dev, sp); -	ret = sci_probe_single(dev, dev->id, p, sp); +	ret = sci_probe_single(dev, dev_id, p, sp);  	if (ret)  		return ret; @@ -2492,6 +2562,7 @@ static int sci_probe(struct platform_device *dev)  	ret = cpufreq_register_notifier(&sp->freq_transition,  					CPUFREQ_TRANSITION_NOTIFIER);  	if (unlikely(ret < 0)) { +		uart_remove_one_port(&sci_uart_driver, &sp->port);  		sci_cleanup_single(sp);  		return ret;  	} @@ -2535,6 +2606,7 @@ static struct platform_driver sci_driver = {  		.name	= "sh-sci",  		.owner	= THIS_MODULE,  		.pm	= &sci_dev_pm_ops, +		.of_match_table = of_match_ptr(of_sci_match),  	},  }; @@ -2542,7 +2614,7 @@ static int __init sci_init(void)  {  	int ret; -	printk(banner); +	pr_info("%s\n", banner);  	ret = uart_register_driver(&sci_uart_driver);  	if (likely(ret == 0)) { diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 5aca7364634..d5db81a0a43 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -9,7 +9,7 @@  #define SCxSR_PER(port)		(((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)  #define SCxSR_BRK(port)		(((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK) -#define SCxSR_ERRORS(port)	(to_sci_port(port)->cfg->error_mask) +#define SCxSR_ERRORS(port)	(to_sci_port(port)->error_mask)  #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \      defined(CONFIG_CPU_SUBTYPE_SH7720) || \ diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 61c1ad03db5..9b4d71cff00 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -24,7 +24,6 @@  #include <linux/dmaengine.h>  #include <linux/dma-direction.h>  #include <linux/dma-mapping.h> -#include <linux/sirfsoc_dma.h>  #include <asm/irq.h>  #include <asm/mach/irq.h> @@ -173,7 +172,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)  	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;  	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; -	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) { +	if (sirfport->tx_dma_chan) {  		if (sirfport->tx_dma_state == TX_DMA_RUNNING) {  			dmaengine_pause(sirfport->tx_dma_chan);  			sirfport->tx_dma_state = TX_DMA_PAUSE; @@ -288,7 +287,7 @@ static void sirfsoc_uart_start_tx(struct uart_port *port)  	struct sirfsoc_uart_port *sirfport = to_sirfport(port);  	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;  	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; -	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) +	if (sirfport->tx_dma_chan)  		sirfsoc_uart_tx_with_dma(sirfport);  	else {  		sirfsoc_uart_pio_tx_chars(sirfport, 1); @@ -310,7 +309,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)  	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;  	wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); -	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) { +	if (sirfport->rx_dma_chan) {  		if (!sirfport->is_marco)  			wr_regl(port, ureg->sirfsoc_int_en_reg,  				rd_regl(port, ureg->sirfsoc_int_en_reg) & @@ -359,9 +358,11 @@ static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)  {  	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;  	struct uart_port *port = &sirfport->port; +	spin_lock(&port->lock);  	if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)  		uart_handle_cts_change(port,  				!gpio_get_value(sirfport->cts_gpio)); +	spin_unlock(&port->lock);  	return IRQ_HANDLED;  } @@ -429,10 +430,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)  	sirfport->rx_io_count += rx_count;  	port->icount.rx += rx_count; -	spin_unlock(&port->lock); -	tty_flip_buffer_push(&port->state->port); -	spin_lock(&port->lock); -  	return rx_count;  } @@ -466,6 +463,7 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)  	struct circ_buf *xmit = &port->state->xmit;  	unsigned long flags; +	spin_lock_irqsave(&port->lock, flags);  	xmit->tail = (xmit->tail + sirfport->transfer_size) &  				(UART_XMIT_SIZE - 1);  	port->icount.tx += sirfport->transfer_size; @@ -474,10 +472,9 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)  	if (sirfport->tx_dma_addr)  		dma_unmap_single(port->dev, sirfport->tx_dma_addr,  				sirfport->transfer_size, DMA_TO_DEVICE); -	spin_lock_irqsave(&sirfport->tx_lock, flags);  	sirfport->tx_dma_state = TX_DMA_IDLE;  	sirfsoc_uart_tx_with_dma(sirfport); -	spin_unlock_irqrestore(&sirfport->tx_lock, flags); +	spin_unlock_irqrestore(&port->lock, flags);  }  static void sirfsoc_uart_insert_rx_buf_to_tty( @@ -490,7 +487,6 @@ static void sirfsoc_uart_insert_rx_buf_to_tty(  	inserted = tty_insert_flip_string(tport,  		sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);  	port->icount.rx += inserted; -	tty_flip_buffer_push(tport);  }  static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index) @@ -524,12 +520,14 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)  	struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;  	unsigned int count;  	unsigned long flags; +	struct dma_tx_state tx_state; -	spin_lock_irqsave(&sirfport->rx_lock, flags); -	while (sirfport->rx_completed != sirfport->rx_issued) { +	spin_lock_irqsave(&port->lock, flags); +	while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, +		sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {  		sirfsoc_uart_insert_rx_buf_to_tty(sirfport,  					SIRFSOC_RX_DMA_BUF_SIZE); -		sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++); +		sirfport->rx_completed++;  		sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;  	}  	count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head, @@ -541,9 +539,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)  			rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |  			SIRFUART_IO_MODE);  	sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); -	spin_unlock_irqrestore(&sirfport->rx_lock, flags);  	if (sirfport->rx_io_count == 4) { -		spin_lock_irqsave(&sirfport->rx_lock, flags);  		sirfport->rx_io_count = 0;  		wr_regl(port, ureg->sirfsoc_int_st_reg,  				uint_st->sirfsoc_rx_done); @@ -554,11 +550,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)  		else  			wr_regl(port, SIRFUART_INT_EN_CLR,  					uint_en->sirfsoc_rx_done_en); -		spin_unlock_irqrestore(&sirfport->rx_lock, flags); -  		sirfsoc_uart_start_next_rx_dma(port);  	} else { -		spin_lock_irqsave(&sirfport->rx_lock, flags);  		wr_regl(port, ureg->sirfsoc_int_st_reg,  				uint_st->sirfsoc_rx_done);  		if (!sirfport->is_marco) @@ -568,8 +561,9 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)  		else  			wr_regl(port, ureg->sirfsoc_int_en_reg,  					uint_en->sirfsoc_rx_done_en); -		spin_unlock_irqrestore(&sirfport->rx_lock, flags);  	} +	spin_unlock_irqrestore(&port->lock, flags); +	tty_flip_buffer_push(&port->state->port);  }  static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport) @@ -578,8 +572,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)  	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;  	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;  	struct dma_tx_state tx_state; -	spin_lock(&sirfport->rx_lock); -  	dmaengine_tx_status(sirfport->rx_dma_chan,  		sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);  	dmaengine_terminate_all(sirfport->rx_dma_chan); @@ -592,7 +584,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)  	else  		wr_regl(port, SIRFUART_INT_EN_CLR,  				uint_en->sirfsoc_rx_timeout_en); -	spin_unlock(&sirfport->rx_lock);  	tasklet_schedule(&sirfport->rx_tmo_process_tasklet);  } @@ -656,7 +647,6 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)  		intr_status &= port->read_status_mask;  		uart_insert_char(port, intr_status,  					uint_en->sirfsoc_rx_oflow_en, 0, flag); -		tty_flip_buffer_push(&state->port);  	}  recv_char:  	if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) && @@ -671,7 +661,7 @@ recv_char:  		uart_handle_cts_change(port, cts_status);  		wake_up_interruptible(&state->port.delta_msr_wait);  	} -	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) { +	if (sirfport->rx_dma_chan) {  		if (intr_status & uint_st->sirfsoc_rx_timeout)  			sirfsoc_uart_handle_rx_tmo(sirfport);  		if (intr_status & uint_st->sirfsoc_rx_done) @@ -681,8 +671,11 @@ recv_char:  			sirfsoc_uart_pio_rx_chars(port,  					SIRFSOC_UART_IO_RX_MAX_CNT);  	} +	spin_unlock(&port->lock); +	tty_flip_buffer_push(&state->port); +	spin_lock(&port->lock);  	if (intr_status & uint_st->sirfsoc_txfifo_empty) { -		if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) +		if (sirfport->tx_dma_chan)  			sirfsoc_uart_tx_with_dma(sirfport);  		else {  			if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { @@ -699,6 +692,7 @@ recv_char:  		}  	}  	spin_unlock(&port->lock); +  	return IRQ_HANDLED;  } @@ -706,25 +700,37 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)  {  	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;  	struct uart_port *port = &sirfport->port; +	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; +	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;  	unsigned long flags; -	spin_lock_irqsave(&sirfport->rx_lock, flags); -	while (sirfport->rx_completed != sirfport->rx_issued) { +	struct dma_tx_state tx_state; +	spin_lock_irqsave(&port->lock, flags); +	while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, +			sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {  		sirfsoc_uart_insert_rx_buf_to_tty(sirfport,  					SIRFSOC_RX_DMA_BUF_SIZE); -		sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++); +		if (rd_regl(port, ureg->sirfsoc_int_en_reg) & +				uint_en->sirfsoc_rx_timeout_en) +			sirfsoc_rx_submit_one_dma_desc(port, +					sirfport->rx_completed++); +		else +			sirfport->rx_completed++;  		sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;  	} -	spin_unlock_irqrestore(&sirfport->rx_lock, flags); +	spin_unlock_irqrestore(&port->lock, flags); +	tty_flip_buffer_push(&port->state->port);  }  static void sirfsoc_uart_rx_dma_complete_callback(void *param)  {  	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; -	spin_lock(&sirfport->rx_lock); +	unsigned long flags; + +	spin_lock_irqsave(&sirfport->port.lock, flags);  	sirfport->rx_issued++;  	sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT; -	spin_unlock(&sirfport->rx_lock);  	tasklet_schedule(&sirfport->rx_dma_complete_tasklet); +	spin_unlock_irqrestore(&sirfport->port.lock, flags);  }  /* submit rx dma task into dmaengine */ @@ -733,18 +739,14 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)  	struct sirfsoc_uart_port *sirfport = to_sirfport(port);  	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;  	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; -	unsigned long flags;  	int i; -	spin_lock_irqsave(&sirfport->rx_lock, flags);  	sirfport->rx_io_count = 0;  	wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,  		rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &  		~SIRFUART_IO_MODE); -	spin_unlock_irqrestore(&sirfport->rx_lock, flags);  	for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)  		sirfsoc_rx_submit_one_dma_desc(port, i);  	sirfport->rx_completed = sirfport->rx_issued = 0; -	spin_lock_irqsave(&sirfport->rx_lock, flags);  	if (!sirfport->is_marco)  		wr_regl(port, ureg->sirfsoc_int_en_reg,  				rd_regl(port, ureg->sirfsoc_int_en_reg) | @@ -752,7 +754,6 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)  	else  		wr_regl(port, ureg->sirfsoc_int_en_reg,  			SIRFUART_RX_DMA_INT_EN(port, uint_en)); -	spin_unlock_irqrestore(&sirfport->rx_lock, flags);  }  static void sirfsoc_uart_start_rx(struct uart_port *port) @@ -765,7 +766,7 @@ static void sirfsoc_uart_start_rx(struct uart_port *port)  	wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);  	wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);  	wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); -	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) +	if (sirfport->rx_dma_chan)  		sirfsoc_uart_start_next_rx_dma(port);  	else {  		if (!sirfport->is_marco) @@ -895,7 +896,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,  		if (termios->c_iflag & INPCK)  			port->read_status_mask |= uint_en->sirfsoc_frm_err_en;  	} -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  			port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;  	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {  		if (termios->c_iflag & IGNPAR) @@ -1001,11 +1002,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,  			(sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<  			SIRFSOC_USP_ASYNC_DIV2_OFFSET);  	} -	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) +	if (sirfport->tx_dma_chan)  		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE);  	else  		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE); -	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) +	if (sirfport->rx_dma_chan)  		wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);  	else  		wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE); @@ -1026,91 +1027,14 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,  	spin_unlock_irqrestore(&port->lock, flags);  } -static unsigned int sirfsoc_uart_init_tx_dma(struct uart_port *port) +static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state, +			      unsigned int oldstate)  {  	struct sirfsoc_uart_port *sirfport = to_sirfport(port); -	dma_cap_mask_t dma_mask; -	struct dma_slave_config tx_slv_cfg = { -		.dst_maxburst = 2, -	}; - -	dma_cap_zero(dma_mask); -	dma_cap_set(DMA_SLAVE, dma_mask); -	sirfport->tx_dma_chan = dma_request_channel(dma_mask, -		(dma_filter_fn)sirfsoc_dma_filter_id, -		(void *)sirfport->tx_dma_no); -	if (!sirfport->tx_dma_chan) { -		dev_err(port->dev, "Uart Request Dma Channel Fail %d\n", -					sirfport->tx_dma_no); -		return  -EPROBE_DEFER; -	} -	dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg); - -	return 0; -} - -static unsigned int sirfsoc_uart_init_rx_dma(struct uart_port *port) -{ -	struct sirfsoc_uart_port *sirfport = to_sirfport(port); -	dma_cap_mask_t dma_mask; -	int ret; -	int i, j; -	struct dma_slave_config slv_cfg = { -		.src_maxburst = 2, -	}; - -	dma_cap_zero(dma_mask); -	dma_cap_set(DMA_SLAVE, dma_mask); -	sirfport->rx_dma_chan = dma_request_channel(dma_mask, -					(dma_filter_fn)sirfsoc_dma_filter_id, -					(void *)sirfport->rx_dma_no); -	if (!sirfport->rx_dma_chan) { -		dev_err(port->dev, "Uart Request Dma Channel Fail %d\n", -				sirfport->rx_dma_no); -		ret = -EPROBE_DEFER; -		goto request_err; -	} -	for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) { -		sirfport->rx_dma_items[i].xmit.buf = -			dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, -			&sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL); -		if (!sirfport->rx_dma_items[i].xmit.buf) { -			dev_err(port->dev, "Uart alloc bufa failed\n"); -			ret = -ENOMEM; -			goto alloc_coherent_err; -		} -		sirfport->rx_dma_items[i].xmit.head = -			sirfport->rx_dma_items[i].xmit.tail = 0; -	} -	dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg); - -	return 0; -alloc_coherent_err: -	for (j = 0; j < i; j++) -		dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, -				sirfport->rx_dma_items[j].xmit.buf, -				sirfport->rx_dma_items[j].dma_addr); -	dma_release_channel(sirfport->rx_dma_chan); -request_err: -	return ret; -} - -static void sirfsoc_uart_uninit_tx_dma(struct sirfsoc_uart_port *sirfport) -{ -	dmaengine_terminate_all(sirfport->tx_dma_chan); -	dma_release_channel(sirfport->tx_dma_chan); -} - -static void sirfsoc_uart_uninit_rx_dma(struct sirfsoc_uart_port *sirfport) -{ -	int i; -	struct uart_port *port = &sirfport->port; -	dmaengine_terminate_all(sirfport->rx_dma_chan); -	dma_release_channel(sirfport->rx_dma_chan); -	for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) -		dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, -				sirfport->rx_dma_items[i].xmit.buf, -				sirfport->rx_dma_items[i].dma_addr); +	if (!state) +		clk_prepare_enable(sirfport->clk); +	else +		clk_disable_unprepare(sirfport->clk);  }  static int sirfsoc_uart_startup(struct uart_port *port) @@ -1151,18 +1075,12 @@ static int sirfsoc_uart_startup(struct uart_port *port)  	wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);  	wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));  	wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port)); - -	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) { -		ret = sirfsoc_uart_init_rx_dma(port); -		if (ret) -			goto init_rx_err; +	if (sirfport->rx_dma_chan)  		wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk, -				SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) | -				SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) | -				SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b)); -	} -	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) { -		sirfsoc_uart_init_tx_dma(port); +			SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) | +			SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) | +			SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b)); +	if (sirfport->tx_dma_chan) {  		sirfport->tx_dma_state = TX_DMA_IDLE;  		wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk,  				SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) | @@ -1209,12 +1127,8 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)  		gpio_set_value(sirfport->rts_gpio, 1);  		free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport);  	} -	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) -		sirfsoc_uart_uninit_rx_dma(sirfport); -	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) { -		sirfsoc_uart_uninit_tx_dma(sirfport); +	if (sirfport->tx_dma_chan)  		sirfport->tx_dma_state = TX_DMA_IDLE; -	}  }  static const char *sirfsoc_uart_type(struct uart_port *port) @@ -1257,6 +1171,7 @@ static struct uart_ops sirfsoc_uart_ops = {  	.startup	= sirfsoc_uart_startup,  	.shutdown	= sirfsoc_uart_shutdown,  	.set_termios	= sirfsoc_uart_set_termios, +	.pm		= sirfsoc_uart_pm,  	.type		= sirfsoc_uart_type,  	.release_port	= sirfsoc_uart_release_port,  	.request_port	= sirfsoc_uart_request_port, @@ -1289,8 +1204,8 @@ sirfsoc_uart_console_setup(struct console *co, char *options)  	port->cons = co;  	/* default console tx/rx transfer using io mode */ -	sirfport->rx_dma_no = UNVALID_DMA_CHAN; -	sirfport->tx_dma_no = UNVALID_DMA_CHAN; +	sirfport->rx_dma_chan = NULL; +	sirfport->tx_dma_chan = NULL;  	return uart_set_options(port, co, baud, parity, bits, flow);  } @@ -1302,7 +1217,7 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)  	while (rd_regl(port,  		ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))  		cpu_relax(); -	wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch); +	wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch);  }  static void sirfsoc_uart_console_write(struct console *co, const char *s, @@ -1358,6 +1273,13 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)  	struct uart_port *port;  	struct resource *res;  	int ret; +	int i, j; +	struct dma_slave_config slv_cfg = { +		.src_maxburst = 2, +	}; +	struct dma_slave_config tx_slv_cfg = { +		.dst_maxburst = 2, +	};  	const struct of_device_id *match;  	match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node); @@ -1378,27 +1300,10 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)  	sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,  		"sirf,uart-has-rtscts"); -	if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) { +	if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart"))  		sirfport->uart_reg->uart_type = SIRF_REAL_UART; -		if (of_property_read_u32(pdev->dev.of_node, -				"sirf,uart-dma-rx-channel", -				&sirfport->rx_dma_no)) -			sirfport->rx_dma_no = UNVALID_DMA_CHAN; -		if (of_property_read_u32(pdev->dev.of_node, -				"sirf,uart-dma-tx-channel", -				&sirfport->tx_dma_no)) -			sirfport->tx_dma_no = UNVALID_DMA_CHAN; -	}  	if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) {  		sirfport->uart_reg->uart_type =	SIRF_USP_UART; -		if (of_property_read_u32(pdev->dev.of_node, -				"sirf,usp-dma-rx-channel", -				&sirfport->rx_dma_no)) -			sirfport->rx_dma_no = UNVALID_DMA_CHAN; -		if (of_property_read_u32(pdev->dev.of_node, -				"sirf,usp-dma-tx-channel", -				&sirfport->tx_dma_no)) -			sirfport->tx_dma_no = UNVALID_DMA_CHAN;  		if (!sirfport->hw_flow_ctrl)  			goto usp_no_flow_control;  		if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL)) @@ -1453,8 +1358,6 @@ usp_no_flow_control:  		ret = -EFAULT;  		goto err;  	} -	spin_lock_init(&sirfport->rx_lock); -	spin_lock_init(&sirfport->tx_lock);  	tasklet_init(&sirfport->rx_dma_complete_tasklet,  			sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);  	tasklet_init(&sirfport->rx_tmo_process_tasklet, @@ -1479,7 +1382,6 @@ usp_no_flow_control:  		ret = PTR_ERR(sirfport->clk);  		goto err;  	} -	clk_prepare_enable(sirfport->clk);  	port->uartclk = clk_get_rate(sirfport->clk);  	port->ops = &sirfsoc_uart_ops; @@ -1492,10 +1394,33 @@ usp_no_flow_control:  		goto port_err;  	} -	return 0; +	sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx"); +	for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) { +		sirfport->rx_dma_items[i].xmit.buf = +			dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, +			&sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL); +		if (!sirfport->rx_dma_items[i].xmit.buf) { +			dev_err(port->dev, "Uart alloc bufa failed\n"); +			ret = -ENOMEM; +			goto alloc_coherent_err; +		} +		sirfport->rx_dma_items[i].xmit.head = +			sirfport->rx_dma_items[i].xmit.tail = 0; +	} +	if (sirfport->rx_dma_chan) +		dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg); +	sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx"); +	if (sirfport->tx_dma_chan) +		dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg); +	return 0; +alloc_coherent_err: +	for (j = 0; j < i; j++) +		dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, +				sirfport->rx_dma_items[j].xmit.buf, +				sirfport->rx_dma_items[j].dma_addr); +	dma_release_channel(sirfport->rx_dma_chan);  port_err: -	clk_disable_unprepare(sirfport->clk);  	clk_put(sirfport->clk);  err:  	return ret; @@ -1505,38 +1430,55 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)  {  	struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);  	struct uart_port *port = &sirfport->port; -	clk_disable_unprepare(sirfport->clk);  	clk_put(sirfport->clk);  	uart_remove_one_port(&sirfsoc_uart_drv, port); +	if (sirfport->rx_dma_chan) { +		int i; +		dmaengine_terminate_all(sirfport->rx_dma_chan); +		dma_release_channel(sirfport->rx_dma_chan); +		for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) +			dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, +					sirfport->rx_dma_items[i].xmit.buf, +					sirfport->rx_dma_items[i].dma_addr); +	} +	if (sirfport->tx_dma_chan) { +		dmaengine_terminate_all(sirfport->tx_dma_chan); +		dma_release_channel(sirfport->tx_dma_chan); +	}  	return 0;  } +#ifdef CONFIG_PM_SLEEP  static int -sirfsoc_uart_suspend(struct platform_device *pdev, pm_message_t state) +sirfsoc_uart_suspend(struct device *pdev)  { -	struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev); +	struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev);  	struct uart_port *port = &sirfport->port;  	uart_suspend_port(&sirfsoc_uart_drv, port);  	return 0;  } -static int sirfsoc_uart_resume(struct platform_device *pdev) +static int sirfsoc_uart_resume(struct device *pdev)  { -	struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev); +	struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev);  	struct uart_port *port = &sirfport->port;  	uart_resume_port(&sirfsoc_uart_drv, port);  	return 0;  } +#endif + +static const struct dev_pm_ops sirfsoc_uart_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_uart_suspend, sirfsoc_uart_resume) +};  static struct platform_driver sirfsoc_uart_driver = {  	.probe		= sirfsoc_uart_probe,  	.remove		= sirfsoc_uart_remove, -	.suspend	= sirfsoc_uart_suspend, -	.resume		= sirfsoc_uart_resume,  	.driver		= {  		.name	= SIRFUART_PORT_NAME,  		.owner	= THIS_MODULE,  		.of_match_table = sirfsoc_uart_ids, +		.pm	= &sirfsoc_uart_pm_ops,  	},  }; diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index fb8d0a00260..69a62ebd3af 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -368,15 +368,6 @@ struct sirfsoc_uart_register sirfsoc_uart = {  #define SIRFSOC_UART_NR				6  #define SIRFSOC_PORT_TYPE			0xa5 -/* Baud Rate Calculation */ -#define SIRF_MIN_SAMPLE_DIV			0xf -#define SIRF_MAX_SAMPLE_DIV			0x3f -#define SIRF_IOCLK_DIV_MAX			0xffff -#define SIRF_SAMPLE_DIV_SHIFT			16 -#define SIRF_IOCLK_DIV_MASK			0xffff -#define SIRF_SAMPLE_DIV_MASK			0x3f0000 -#define SIRF_BAUD_RATE_SUPPORT_NR		18 -  /* Uart Common Use Macro*/  #define SIRFSOC_RX_DMA_BUF_SIZE	256  #define BYTES_TO_ALIGN(dma_addr)	((unsigned long)(dma_addr) & 0x3) @@ -401,9 +392,6 @@ struct sirfsoc_uart_register sirfsoc_uart = {  /* Indicate how many buffers used */  #define SIRFSOC_RX_LOOP_BUF_CNT		2 -/* Indicate if DMA channel valid */ -#define IS_DMA_CHAN_VALID(x)	((x) != -1) -#define UNVALID_DMA_CHAN	-1  /* For Fast Baud Rate Calculation */  struct sirfsoc_baudrate_to_regv {  	unsigned int baud_rate; @@ -432,14 +420,10 @@ struct sirfsoc_uart_port {  	/* for SiRFmarco, there are SET/CLR for UART_INT_EN */  	bool				is_marco;  	struct sirfsoc_uart_register	*uart_reg; -	int				rx_dma_no; -	int				tx_dma_no;  	struct dma_chan			*rx_dma_chan;  	struct dma_chan			*tx_dma_chan;  	dma_addr_t			tx_dma_addr;  	struct dma_async_tx_descriptor	*tx_dma_desc; -	spinlock_t			rx_lock; -	spinlock_t			tx_lock;  	struct tasklet_struct		rx_dma_complete_tasklet;  	struct tasklet_struct		rx_tmo_process_tasklet;  	unsigned int			rx_io_count; @@ -453,14 +437,9 @@ struct sirfsoc_uart_port {  	int				rx_issued;  }; -/* Hardware Flow Control */ -#define SIRFUART_AFC_CTRL_RX_THD	0x70 -  /* Register Access Control */  #define portaddr(port, reg)		((port)->membase + (reg)) -#define rd_regb(port, reg)		(__raw_readb(portaddr(port, reg)))  #define rd_regl(port, reg)		(__raw_readl(portaddr(port, reg))) -#define wr_regb(port, reg, val)		__raw_writeb(val, portaddr(port, reg))  #define wr_regl(port, reg, val)		__raw_writel(val, portaddr(port, reg))  /* UART Port Mask */ diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 21e6e84c0df..f48b1cc07ee 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -194,9 +194,9 @@ static inline u32 asc_txfifo_is_empty(struct uart_port *port)  	return asc_in(port, ASC_STA) & ASC_STA_TE;  } -static inline int asc_txfifo_is_full(struct uart_port *port) +static inline u32 asc_txfifo_is_half_empty(struct uart_port *port)  { -	return asc_in(port, ASC_STA) & ASC_STA_TF; +	return asc_in(port, ASC_STA) & ASC_STA_THE;  }  static inline const char *asc_port_name(struct uart_port *port) @@ -295,7 +295,7 @@ static void asc_receive_chars(struct uart_port *port)  			status & ASC_STA_OE) {  			if (c & ASC_RXBUF_FE) { -				if (c == ASC_RXBUF_FE) { +				if (c == (ASC_RXBUF_FE | ASC_RXBUF_DUMMY_RX)) {  					port->icount.brk++;  					if (uart_handle_break(port))  						continue; @@ -325,7 +325,7 @@ static void asc_receive_chars(struct uart_port *port)  				flag = TTY_FRAME;  		} -		if (uart_handle_sysrq_char(port, c)) +		if (uart_handle_sysrq_char(port, c & 0xff))  			continue;  		uart_insert_char(port, c, ASC_RXBUF_DUMMY_OE, c & 0xff, flag); @@ -547,7 +547,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,  	ascport->port.read_status_mask = ASC_RXBUF_DUMMY_OE;  	if (termios->c_iflag & INPCK)  		ascport->port.read_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		ascport->port.read_status_mask |= ASC_RXBUF_DUMMY_BE;  	/* @@ -628,7 +628,7 @@ static int asc_get_poll_char(struct uart_port *port)  static void asc_put_poll_char(struct uart_port *port, unsigned char c)  { -	while (asc_txfifo_is_full(port)) +	while (!asc_txfifo_is_half_empty(port))  		cpu_relax();  	asc_out(port, ASC_TXBUF, c);  } @@ -783,7 +783,7 @@ static void asc_console_putchar(struct uart_port *port, int ch)  	unsigned int timeout = 1000000;  	/* Wait for upto 1 second in case flow control is stopping us. */ -	while (--timeout && asc_txfifo_is_full(port)) +	while (--timeout && !asc_txfifo_is_half_empty(port))  		udelay(1);  	asc_out(port, ASC_TXBUF, ch); diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index cf86e729532..dc697cee248 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -433,13 +433,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign  	unsigned long flags;  	int locked = 1; -	local_irq_save(flags); -	if (port->sysrq) { -		locked = 0; -	} else if (oops_in_progress) { -		locked = spin_trylock(&port->lock); -	} else -		spin_lock(&port->lock); +	if (port->sysrq || oops_in_progress) +		locked = spin_trylock_irqsave(&port->lock, flags); +	else +		spin_lock_irqsave(&port->lock, flags);  	while (n > 0) {  		unsigned long ra = __pa(con_write_page); @@ -470,8 +467,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign  	}  	if (locked) -		spin_unlock(&port->lock); -	local_irq_restore(flags); +		spin_unlock_irqrestore(&port->lock, flags);  }  static inline void sunhv_console_putchar(struct uart_port *port, char c) @@ -492,7 +488,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig  	unsigned long flags;  	int i, locked = 1; -	local_irq_save(flags); +	if (port->sysrq || oops_in_progress) +		locked = spin_trylock_irqsave(&port->lock, flags); +	else +		spin_lock_irqsave(&port->lock, flags);  	if (port->sysrq) {  		locked = 0;  	} else if (oops_in_progress) { @@ -507,8 +506,7 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig  	}  	if (locked) -		spin_unlock(&port->lock); -	local_irq_restore(flags); +		spin_unlock_irqrestore(&port->lock, flags);  }  static struct console sunhv_console = { diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 5d6136b2a04..2f57df9a71d 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -427,6 +427,9 @@ static void sunsab_start_tx(struct uart_port *port)  	struct circ_buf *xmit = &up->port.state->xmit;  	int i; +	if (uart_circ_empty(xmit)) +		return; +  	up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);  	writeb(up->interrupt_mask1, &up->regs->w.imr1); @@ -719,7 +722,7 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla  	if (iflag & INPCK)  		up->port.read_status_mask |= (SAB82532_ISR0_PERR |  					      SAB82532_ISR0_FERR); -	if (iflag & (BRKINT | PARMRK)) +	if (iflag & (IGNBRK | BRKINT | PARMRK))  		up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8);  	/* @@ -844,20 +847,16 @@ static void sunsab_console_write(struct console *con, const char *s, unsigned n)  	unsigned long flags;  	int locked = 1; -	local_irq_save(flags); -	if (up->port.sysrq) { -		locked = 0; -	} else if (oops_in_progress) { -		locked = spin_trylock(&up->port.lock); -	} else -		spin_lock(&up->port.lock); +	if (up->port.sysrq || oops_in_progress) +		locked = spin_trylock_irqsave(&up->port.lock, flags); +	else +		spin_lock_irqsave(&up->port.lock, flags);  	uart_console_write(&up->port, s, n, sunsab_console_putchar);  	sunsab_tec_wait(up);  	if (locked) -		spin_unlock(&up->port.lock); -	local_irq_restore(flags); +		spin_unlock_irqrestore(&up->port.lock, flags);  }  static int sunsab_console_setup(struct console *con, char *options) @@ -894,7 +893,7 @@ static int sunsab_console_setup(struct console *con, char *options)  	case B115200: baud = 115200; break;  	case B230400: baud = 230400; break;  	case B460800: baud = 460800; break; -	}; +	}  	/*  	 * Temporary fix. diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 699cc1b5f6a..5326ae195e5 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -522,7 +522,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)  				serio_interrupt(&up->serio, ch, 0);  #endif  				break; -			}; +			}  		}  	} while (serial_in(up, UART_LSR) & UART_LSR_DR);  } @@ -834,7 +834,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,  	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;  	if (iflag & INPCK)  		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; -	if (iflag & (BRKINT | PARMRK)) +	if (iflag & (IGNBRK | BRKINT | PARMRK))  		up->port.read_status_mask |= UART_LSR_BI;  	/* @@ -1295,13 +1295,10 @@ static void sunsu_console_write(struct console *co, const char *s,  	unsigned int ier;  	int locked = 1; -	local_irq_save(flags); -	if (up->port.sysrq) { -		locked = 0; -	} else if (oops_in_progress) { -		locked = spin_trylock(&up->port.lock); -	} else -		spin_lock(&up->port.lock); +	if (up->port.sysrq || oops_in_progress) +		locked = spin_trylock_irqsave(&up->port.lock, flags); +	else +		spin_lock_irqsave(&up->port.lock, flags);  	/*  	 *	First save the UER then disable the interrupts @@ -1319,8 +1316,7 @@ static void sunsu_console_write(struct console *co, const char *s,  	serial_out(up, UART_IER, ier);  	if (locked) -		spin_unlock(&up->port.lock); -	local_irq_restore(flags); +		spin_unlock_irqrestore(&up->port.lock, flags);  }  /* diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 135a1520353..02df3940b95 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -319,7 +319,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,  				serio_interrupt(&up->serio, ch, 0);  #endif  			break; -		}; +		}  	}  } @@ -703,6 +703,8 @@ static void sunzilog_start_tx(struct uart_port *port)  	} else {  		struct circ_buf *xmit = &port->state->xmit; +		if (uart_circ_empty(xmit)) +			return;  		writeb(xmit->buf[xmit->tail], &channel->data);  		ZSDELAY();  		ZS_WSYNC(channel); @@ -897,7 +899,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,  		up->curregs[R5] |= Tx8;  		up->parity_mask = 0xff;  		break; -	}; +	}  	up->curregs[R4] &= ~0x0c;  	if (cflag & CSTOPB)  		up->curregs[R4] |= SB2; @@ -915,7 +917,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,  	up->port.read_status_mask = Rx_OVR;  	if (iflag & INPCK)  		up->port.read_status_mask |= CRC_ERR | PAR_ERR; -	if (iflag & (BRKINT | PARMRK)) +	if (iflag & (IGNBRK | BRKINT | PARMRK))  		up->port.read_status_mask |= BRK_ABRT;  	up->port.ignore_status_mask = 0; @@ -1195,20 +1197,16 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)  	unsigned long flags;  	int locked = 1; -	local_irq_save(flags); -	if (up->port.sysrq) { -		locked = 0; -	} else if (oops_in_progress) { -		locked = spin_trylock(&up->port.lock); -	} else -		spin_lock(&up->port.lock); +	if (up->port.sysrq || oops_in_progress) +		locked = spin_trylock_irqsave(&up->port.lock, flags); +	else +		spin_lock_irqsave(&up->port.lock, flags);  	uart_console_write(&up->port, s, count, sunzilog_putchar);  	udelay(2);  	if (locked) -		spin_unlock(&up->port.lock); -	local_irq_restore(flags); +		spin_unlock_irqrestore(&up->port.lock, flags);  }  static int __init sunzilog_console_setup(struct console *con, char *options) @@ -1239,7 +1237,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)  	default: case B9600: baud = 9600; break;  	case B19200: baud = 19200; break;  	case B38400: baud = 38400; break; -	}; +	}  	brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c index f92d7e6bd87..613ccf09dc2 100644 --- a/drivers/tty/serial/tilegx.c +++ b/drivers/tty/serial/tilegx.c @@ -359,8 +359,8 @@ static int tilegx_startup(struct uart_port *port)  		}  		/* Create our IRQs. */ -		port->irq = create_irq(); -		if (port->irq < 0) +		port->irq = irq_alloc_hwirq(-1); +		if (!port->irq)  			goto err_uart_dest;  		tile_irq_activate(port->irq, TILE_IRQ_PERCPU); @@ -395,7 +395,7 @@ static int tilegx_startup(struct uart_port *port)  err_free_irq:  	free_irq(port->irq, port);  err_dest_irq: -	destroy_irq(port->irq); +	irq_free_hwirq(port->irq);  err_uart_dest:  	gxio_uart_destroy(context);  	ret = -ENXIO; @@ -435,7 +435,7 @@ static void tilegx_shutdown(struct uart_port *port)  	if (port->irq > 0) {  		free_irq(port->irq, port); -		destroy_irq(port->irq); +		irq_free_hwirq(port->irq);  		port->irq = 0;  	} diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 5f90ef24d47..dce27f34937 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -418,14 +418,23 @@ static struct uart_ops ulite_ops = {  #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE  static void ulite_console_wait_tx(struct uart_port *port)  { -	int i;  	u8 val; - -	/* Spin waiting for TX fifo to have space available */ -	for (i = 0; i < 100000; i++) { +	unsigned long timeout; + +	/* +	 * Spin waiting for TX fifo to have space available. +	 * When using the Microblaze Debug Module this can take up to 1s +	 */ +	timeout = jiffies + msecs_to_jiffies(1000); +	while (1) {  		val = uart_in32(ULITE_STATUS, port);  		if ((val & ULITE_STATUS_TXFULL) == 0)  			break; +		if (time_after(jiffies, timeout)) { +			dev_warn(port->dev, +				 "timeout waiting for TX buffer empty\n"); +			break; +		}  		cpu_relax();  	}  } diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 88317482b81..1c52074c38d 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -25,6 +25,8 @@  #include <linux/tty.h>  #include <linux/tty_flip.h>  #include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h>  #include <linux/dma-mapping.h> @@ -269,7 +271,7 @@ static unsigned int qe_uart_tx_empty(struct uart_port *port)  			return 1;  		bdp++; -	}; +	}  }  /* @@ -934,7 +936,7 @@ static void qe_uart_set_termios(struct uart_port *port,  	port->read_status_mask = BD_SC_EMPTY | BD_SC_OV;  	if (termios->c_iflag & INPCK)  		port->read_status_mask |= BD_SC_FR | BD_SC_PR; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= BD_SC_BR;  	/* diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index a63c14bc9a2..db0c8a4ab03 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -559,7 +559,7 @@ static void siu_set_termios(struct uart_port *port, struct ktermios *new,  	port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;  	if (c_iflag & INPCK)  		port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; -	if (c_iflag & (BRKINT | PARMRK)) +	if (c_iflag & (IGNBRK | BRKINT | PARMRK))  		port->read_status_mask |= UART_LSR_BI;  	port->ignore_status_mask = 0; diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 93b697a0de6..15ad6fcda88 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -561,12 +561,13 @@ static int vt8500_serial_probe(struct platform_device *pdev)  	if (!mmres || !irqres)  		return -ENODEV; -	if (np) +	if (np) {  		port = of_alias_get_id(np, "serial");  		if (port >= VT8500_MAX_PORTS)  			port = -1; -	else +	} else {  		port = -1; +	}  	if (port < 0) {  		/* calculate the port id */ diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 7e4150aa69c..8809775e2ba 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1,7 +1,7 @@  /* - * Xilinx PS UART driver + * Cadence UART driver (found in Xilinx Zynq)   * - * 2011 (c) Xilinx Inc. + * 2011 - 2014 (C) Xilinx Inc.   *   * This program is free software; you can redistribute it   * and/or modify it under the terms of the GNU General Public @@ -9,103 +9,105 @@   * either version 2 of the License, or (at your option) any   * later version.   * + * This driver has originally been pushed by Xilinx using a Zynq-branding. This + * still shows in the naming of this file, the kconfig symbols and some symbols + * in the code.   */ +#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif +  #include <linux/platform_device.h>  #include <linux/serial.h> +#include <linux/console.h>  #include <linux/serial_core.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_flip.h> -#include <linux/console.h>  #include <linux/clk.h>  #include <linux/irq.h>  #include <linux/io.h>  #include <linux/of.h>  #include <linux/module.h> -#define XUARTPS_TTY_NAME	"ttyPS" -#define XUARTPS_NAME		"xuartps" -#define XUARTPS_MAJOR		0	/* use dynamic node allocation */ -#define XUARTPS_MINOR		0	/* works best with devtmpfs */ -#define XUARTPS_NR_PORTS	2 -#define XUARTPS_FIFO_SIZE	16	/* FIFO size */ -#define XUARTPS_REGISTER_SPACE	0xFFF +#define CDNS_UART_TTY_NAME	"ttyPS" +#define CDNS_UART_NAME		"xuartps" +#define CDNS_UART_MAJOR		0	/* use dynamic node allocation */ +#define CDNS_UART_MINOR		0	/* works best with devtmpfs */ +#define CDNS_UART_NR_PORTS	2 +#define CDNS_UART_FIFO_SIZE	64	/* FIFO size */ +#define CDNS_UART_REGISTER_SPACE	0xFFF + +#define cdns_uart_readl(offset)		ioread32(port->membase + offset) +#define cdns_uart_writel(val, offset)	iowrite32(val, port->membase + offset) + +/* Rx Trigger level */ +static int rx_trigger_level = 56; +module_param(rx_trigger_level, uint, S_IRUGO); +MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes"); + +/* Rx Timeout */ +static int rx_timeout = 10; +module_param(rx_timeout, uint, S_IRUGO); +MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); + +/* Register offsets for the UART. */ +#define CDNS_UART_CR_OFFSET		0x00  /* Control Register */ +#define CDNS_UART_MR_OFFSET		0x04  /* Mode Register */ +#define CDNS_UART_IER_OFFSET		0x08  /* Interrupt Enable */ +#define CDNS_UART_IDR_OFFSET		0x0C  /* Interrupt Disable */ +#define CDNS_UART_IMR_OFFSET		0x10  /* Interrupt Mask */ +#define CDNS_UART_ISR_OFFSET		0x14  /* Interrupt Status */ +#define CDNS_UART_BAUDGEN_OFFSET	0x18  /* Baud Rate Generator */ +#define CDNS_UART_RXTOUT_OFFSET		0x1C  /* RX Timeout */ +#define CDNS_UART_RXWM_OFFSET		0x20  /* RX FIFO Trigger Level */ +#define CDNS_UART_MODEMCR_OFFSET	0x24  /* Modem Control */ +#define CDNS_UART_MODEMSR_OFFSET	0x28  /* Modem Status */ +#define CDNS_UART_SR_OFFSET		0x2C  /* Channel Status */ +#define CDNS_UART_FIFO_OFFSET		0x30  /* FIFO */ +#define CDNS_UART_BAUDDIV_OFFSET	0x34  /* Baud Rate Divider */ +#define CDNS_UART_FLOWDEL_OFFSET	0x38  /* Flow Delay */ +#define CDNS_UART_IRRX_PWIDTH_OFFSET	0x3C  /* IR Min Received Pulse Width */ +#define CDNS_UART_IRTX_PWIDTH_OFFSET	0x40  /* IR Transmitted pulse Width */ +#define CDNS_UART_TXWM_OFFSET		0x44  /* TX FIFO Trigger Level */ + +/* Control Register Bit Definitions */ +#define CDNS_UART_CR_STOPBRK	0x00000100  /* Stop TX break */ +#define CDNS_UART_CR_STARTBRK	0x00000080  /* Set TX break */ +#define CDNS_UART_CR_TX_DIS	0x00000020  /* TX disabled. */ +#define CDNS_UART_CR_TX_EN	0x00000010  /* TX enabled */ +#define CDNS_UART_CR_RX_DIS	0x00000008  /* RX disabled. */ +#define CDNS_UART_CR_RX_EN	0x00000004  /* RX enabled */ +#define CDNS_UART_CR_TXRST	0x00000002  /* TX logic reset */ +#define CDNS_UART_CR_RXRST	0x00000001  /* RX logic reset */ +#define CDNS_UART_CR_RST_TO	0x00000040  /* Restart Timeout Counter */ -#define xuartps_readl(offset)		ioread32(port->membase + offset) -#define xuartps_writel(val, offset)	iowrite32(val, port->membase + offset) - -/********************************Register Map********************************/ -/** UART - * - * Register offsets for the UART. - * - */ -#define XUARTPS_CR_OFFSET	0x00  /* Control Register [8:0] */ -#define XUARTPS_MR_OFFSET	0x04  /* Mode Register [10:0] */ -#define XUARTPS_IER_OFFSET	0x08  /* Interrupt Enable [10:0] */ -#define XUARTPS_IDR_OFFSET	0x0C  /* Interrupt Disable [10:0] */ -#define XUARTPS_IMR_OFFSET	0x10  /* Interrupt Mask [10:0] */ -#define XUARTPS_ISR_OFFSET	0x14  /* Interrupt Status [10:0]*/ -#define XUARTPS_BAUDGEN_OFFSET	0x18  /* Baud Rate Generator [15:0] */ -#define XUARTPS_RXTOUT_OFFSET	0x1C  /* RX Timeout [7:0] */ -#define XUARTPS_RXWM_OFFSET	0x20  /* RX FIFO Trigger Level [5:0] */ -#define XUARTPS_MODEMCR_OFFSET	0x24  /* Modem Control [5:0] */ -#define XUARTPS_MODEMSR_OFFSET	0x28  /* Modem Status [8:0] */ -#define XUARTPS_SR_OFFSET	0x2C  /* Channel Status [11:0] */ -#define XUARTPS_FIFO_OFFSET	0x30  /* FIFO [15:0] or [7:0] */ -#define XUARTPS_BAUDDIV_OFFSET	0x34  /* Baud Rate Divider [7:0] */ -#define XUARTPS_FLOWDEL_OFFSET	0x38  /* Flow Delay [15:0] */ -#define XUARTPS_IRRX_PWIDTH_OFFSET 0x3C /* IR Minimum Received Pulse -						Width [15:0] */ -#define XUARTPS_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse -						Width [7:0] */ -#define XUARTPS_TXWM_OFFSET	0x44  /* TX FIFO Trigger Level [5:0] */ - -/** Control Register - * - * The Control register (CR) controls the major functions of the device. - * - * Control Register Bit Definitions - */ -#define XUARTPS_CR_STOPBRK	0x00000100  /* Stop TX break */ -#define XUARTPS_CR_STARTBRK	0x00000080  /* Set TX break */ -#define XUARTPS_CR_TX_DIS	0x00000020  /* TX disabled. */ -#define XUARTPS_CR_TX_EN	0x00000010  /* TX enabled */ -#define XUARTPS_CR_RX_DIS	0x00000008  /* RX disabled. */ -#define XUARTPS_CR_RX_EN	0x00000004  /* RX enabled */ -#define XUARTPS_CR_TXRST	0x00000002  /* TX logic reset */ -#define XUARTPS_CR_RXRST	0x00000001  /* RX logic reset */ -#define XUARTPS_CR_RST_TO	0x00000040  /* Restart Timeout Counter */ - -/** Mode Register - * +/* + * Mode Register:   * The mode register (MR) defines the mode of transfer as well as the data   * format. If this register is modified during transmission or reception,   * data validity cannot be guaranteed. - * - * Mode Register Bit Definitions - *   */ -#define XUARTPS_MR_CLKSEL		0x00000001  /* Pre-scalar selection */ -#define XUARTPS_MR_CHMODE_L_LOOP	0x00000200  /* Local loop back mode */ -#define XUARTPS_MR_CHMODE_NORM		0x00000000  /* Normal mode */ +#define CDNS_UART_MR_CLKSEL		0x00000001  /* Pre-scalar selection */ +#define CDNS_UART_MR_CHMODE_L_LOOP	0x00000200  /* Local loop back mode */ +#define CDNS_UART_MR_CHMODE_NORM	0x00000000  /* Normal mode */ -#define XUARTPS_MR_STOPMODE_2_BIT	0x00000080  /* 2 stop bits */ -#define XUARTPS_MR_STOPMODE_1_BIT	0x00000000  /* 1 stop bit */ +#define CDNS_UART_MR_STOPMODE_2_BIT	0x00000080  /* 2 stop bits */ +#define CDNS_UART_MR_STOPMODE_1_BIT	0x00000000  /* 1 stop bit */ -#define XUARTPS_MR_PARITY_NONE		0x00000020  /* No parity mode */ -#define XUARTPS_MR_PARITY_MARK		0x00000018  /* Mark parity mode */ -#define XUARTPS_MR_PARITY_SPACE		0x00000010  /* Space parity mode */ -#define XUARTPS_MR_PARITY_ODD		0x00000008  /* Odd parity mode */ -#define XUARTPS_MR_PARITY_EVEN		0x00000000  /* Even parity mode */ +#define CDNS_UART_MR_PARITY_NONE	0x00000020  /* No parity mode */ +#define CDNS_UART_MR_PARITY_MARK	0x00000018  /* Mark parity mode */ +#define CDNS_UART_MR_PARITY_SPACE	0x00000010  /* Space parity mode */ +#define CDNS_UART_MR_PARITY_ODD		0x00000008  /* Odd parity mode */ +#define CDNS_UART_MR_PARITY_EVEN	0x00000000  /* Even parity mode */ -#define XUARTPS_MR_CHARLEN_6_BIT	0x00000006  /* 6 bits data */ -#define XUARTPS_MR_CHARLEN_7_BIT	0x00000004  /* 7 bits data */ -#define XUARTPS_MR_CHARLEN_8_BIT	0x00000000  /* 8 bits data */ +#define CDNS_UART_MR_CHARLEN_6_BIT	0x00000006  /* 6 bits data */ +#define CDNS_UART_MR_CHARLEN_7_BIT	0x00000004  /* 7 bits data */ +#define CDNS_UART_MR_CHARLEN_8_BIT	0x00000000  /* 8 bits data */ -/** Interrupt Registers - * +/* + * Interrupt Registers:   * Interrupt control logic uses the interrupt enable register (IER) and the   * interrupt disable register (IDR) to set the value of the bits in the   * interrupt mask register (IMR). The IMR determines whether to pass an @@ -113,50 +115,65 @@   * Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an   * interrupt. IMR and ISR are read only, and IER and IDR are write only.   * Reading either IER or IDR returns 0x00. - *   * All four registers have the same bit definitions.   */ -#define XUARTPS_IXR_TOUT	0x00000100 /* RX Timeout error interrupt */ -#define XUARTPS_IXR_PARITY	0x00000080 /* Parity error interrupt */ -#define XUARTPS_IXR_FRAMING	0x00000040 /* Framing error interrupt */ -#define XUARTPS_IXR_OVERRUN	0x00000020 /* Overrun error interrupt */ -#define XUARTPS_IXR_TXFULL	0x00000010 /* TX FIFO Full interrupt */ -#define XUARTPS_IXR_TXEMPTY	0x00000008 /* TX FIFO empty interrupt */ -#define XUARTPS_ISR_RXEMPTY	0x00000002 /* RX FIFO empty interrupt */ -#define XUARTPS_IXR_RXTRIG	0x00000001 /* RX FIFO trigger interrupt */ -#define XUARTPS_IXR_RXFULL	0x00000004 /* RX FIFO full interrupt. */ -#define XUARTPS_IXR_RXEMPTY	0x00000002 /* RX FIFO empty interrupt. */ -#define XUARTPS_IXR_MASK	0x00001FFF /* Valid bit mask */ - -/** Channel Status Register - * +#define CDNS_UART_IXR_TOUT	0x00000100 /* RX Timeout error interrupt */ +#define CDNS_UART_IXR_PARITY	0x00000080 /* Parity error interrupt */ +#define CDNS_UART_IXR_FRAMING	0x00000040 /* Framing error interrupt */ +#define CDNS_UART_IXR_OVERRUN	0x00000020 /* Overrun error interrupt */ +#define CDNS_UART_IXR_TXFULL	0x00000010 /* TX FIFO Full interrupt */ +#define CDNS_UART_IXR_TXEMPTY	0x00000008 /* TX FIFO empty interrupt */ +#define CDNS_UART_ISR_RXEMPTY	0x00000002 /* RX FIFO empty interrupt */ +#define CDNS_UART_IXR_RXTRIG	0x00000001 /* RX FIFO trigger interrupt */ +#define CDNS_UART_IXR_RXFULL	0x00000004 /* RX FIFO full interrupt. */ +#define CDNS_UART_IXR_RXEMPTY	0x00000002 /* RX FIFO empty interrupt. */ +#define CDNS_UART_IXR_MASK	0x00001FFF /* Valid bit mask */ + +/* Goes in read_status_mask for break detection as the HW doesn't do it*/ +#define CDNS_UART_IXR_BRK	0x80000000 + +/* + * Channel Status Register:   * The channel status register (CSR) is provided to enable the control logic   * to monitor the status of bits in the channel interrupt status register,   * even if these are masked out by the interrupt mask register.   */ -#define XUARTPS_SR_RXEMPTY	0x00000002 /* RX FIFO empty */ -#define XUARTPS_SR_TXEMPTY	0x00000008 /* TX FIFO empty */ -#define XUARTPS_SR_TXFULL	0x00000010 /* TX FIFO full */ -#define XUARTPS_SR_RXTRIG	0x00000001 /* Rx Trigger */ +#define CDNS_UART_SR_RXEMPTY	0x00000002 /* RX FIFO empty */ +#define CDNS_UART_SR_TXEMPTY	0x00000008 /* TX FIFO empty */ +#define CDNS_UART_SR_TXFULL	0x00000010 /* TX FIFO full */ +#define CDNS_UART_SR_RXTRIG	0x00000001 /* Rx Trigger */ + +/* baud dividers min/max values */ +#define CDNS_UART_BDIV_MIN	4 +#define CDNS_UART_BDIV_MAX	255 +#define CDNS_UART_CD_MAX	65535  /** - * struct xuartps - device data - * @refclk	Reference clock - * @aperclk	APB clock + * struct cdns_uart - device data + * @port:		Pointer to the UART port + * @uartclk:		Reference clock + * @pclk:		APB clock + * @baud:		Current baud rate + * @clk_rate_change_nb:	Notifier block for clock changes   */ -struct xuartps { -	struct clk		*refclk; -	struct clk		*aperclk; +struct cdns_uart { +	struct uart_port	*port; +	struct clk		*uartclk; +	struct clk		*pclk; +	unsigned int		baud; +	struct notifier_block	clk_rate_change_nb;  }; +#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ +		clk_rate_change_nb);  /** - * xuartps_isr - Interrupt handler + * cdns_uart_isr - Interrupt handler   * @irq: Irq number   * @dev_id: Id of the port   * - * Returns IRQHANDLED - **/ -static irqreturn_t xuartps_isr(int irq, void *dev_id) + * Return: IRQHANDLED + */ +static irqreturn_t cdns_uart_isr(int irq, void *dev_id)  {  	struct uart_port *port = (struct uart_port *)dev_id;  	unsigned long flags; @@ -169,33 +186,76 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)  	/* Read the interrupt status register to determine which  	 * interrupt(s) is/are active.  	 */ -	isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET); +	isrstatus = cdns_uart_readl(CDNS_UART_ISR_OFFSET); + +	/* +	 * There is no hardware break detection, so we interpret framing +	 * error with all-zeros data as a break sequence. Most of the time, +	 * there's another non-zero byte at the end of the sequence. +	 */ +	if (isrstatus & CDNS_UART_IXR_FRAMING) { +		while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & +					CDNS_UART_SR_RXEMPTY)) { +			if (!cdns_uart_readl(CDNS_UART_FIFO_OFFSET)) { +				port->read_status_mask |= CDNS_UART_IXR_BRK; +				isrstatus &= ~CDNS_UART_IXR_FRAMING; +			} +		} +		cdns_uart_writel(CDNS_UART_IXR_FRAMING, CDNS_UART_ISR_OFFSET); +	}  	/* drop byte with parity error if IGNPAR specified */ -	if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY) -		isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT); +	if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY) +		isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT);  	isrstatus &= port->read_status_mask;  	isrstatus &= ~port->ignore_status_mask; -	if ((isrstatus & XUARTPS_IXR_TOUT) || -		(isrstatus & XUARTPS_IXR_RXTRIG)) { +	if ((isrstatus & CDNS_UART_IXR_TOUT) || +		(isrstatus & CDNS_UART_IXR_RXTRIG)) {  		/* Receive Timeout Interrupt */ -		while ((xuartps_readl(XUARTPS_SR_OFFSET) & -			XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { -			data = xuartps_readl(XUARTPS_FIFO_OFFSET); +		while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & +			CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { +			data = cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + +			/* Non-NULL byte after BREAK is garbage (99%) */ +			if (data && (port->read_status_mask & +						CDNS_UART_IXR_BRK)) { +				port->read_status_mask &= ~CDNS_UART_IXR_BRK; +				port->icount.brk++; +				if (uart_handle_break(port)) +					continue; +			} + +#ifdef SUPPORT_SYSRQ +			/* +			 * uart_handle_sysrq_char() doesn't work if +			 * spinlocked, for some reason +			 */ +			 if (port->sysrq) { +				spin_unlock(&port->lock); +				if (uart_handle_sysrq_char(port, +							(unsigned char)data)) { +					spin_lock(&port->lock); +					continue; +				} +				spin_lock(&port->lock); +			} +#endif +  			port->icount.rx++; -			if (isrstatus & XUARTPS_IXR_PARITY) { +			if (isrstatus & CDNS_UART_IXR_PARITY) {  				port->icount.parity++;  				status = TTY_PARITY; -			} else if (isrstatus & XUARTPS_IXR_FRAMING) { +			} else if (isrstatus & CDNS_UART_IXR_FRAMING) {  				port->icount.frame++;  				status = TTY_FRAME; -			} else if (isrstatus & XUARTPS_IXR_OVERRUN) +			} else if (isrstatus & CDNS_UART_IXR_OVERRUN) {  				port->icount.overrun++; +			} -			uart_insert_char(port, isrstatus, XUARTPS_IXR_OVERRUN, +			uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,  					data, status);  		}  		spin_unlock(&port->lock); @@ -204,10 +264,10 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)  	}  	/* Dispatch an appropriate handler */ -	if ((isrstatus & XUARTPS_IXR_TXEMPTY) == XUARTPS_IXR_TXEMPTY) { +	if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) {  		if (uart_circ_empty(&port->state->xmit)) { -			xuartps_writel(XUARTPS_IXR_TXEMPTY, -						XUARTPS_IDR_OFFSET); +			cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, +						CDNS_UART_IDR_OFFSET);  		} else {  			numbytes = port->fifosize;  			/* Break if no more data available in the UART buffer */ @@ -215,12 +275,12 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)  				if (uart_circ_empty(&port->state->xmit))  					break;  				/* Get the data from the UART circular buffer -				 * and write it to the xuartps's TX_FIFO +				 * and write it to the cdns_uart's TX_FIFO  				 * register.  				 */ -				xuartps_writel( +				cdns_uart_writel(  					port->state->xmit.buf[port->state->xmit. -					tail], XUARTPS_FIFO_OFFSET); +					tail], CDNS_UART_FIFO_OFFSET);  				port->icount.tx++; @@ -228,7 +288,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)  				 * the buffer if it reaches limit.  				 */  				port->state->xmit.tail = -					(port->state->xmit.tail + 1) & \ +					(port->state->xmit.tail + 1) &  						(UART_XMIT_SIZE - 1);  			} @@ -238,7 +298,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)  		}  	} -	xuartps_writel(isrstatus, XUARTPS_ISR_OFFSET); +	cdns_uart_writel(isrstatus, CDNS_UART_ISR_OFFSET);  	/* be sure to release the lock and tty before leaving */  	spin_unlock_irqrestore(&port->lock, flags); @@ -247,97 +307,226 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)  }  /** - * xuartps_set_baud_rate - Calculate and set the baud rate - * @port: Handle to the uart port structure - * @baud: Baud rate to set + * cdns_uart_calc_baud_divs - Calculate baud rate divisors + * @clk: UART module input clock + * @baud: Desired baud rate + * @rbdiv: BDIV value (return value) + * @rcd: CD value (return value) + * @div8: Value for clk_sel bit in mod (return value) + * Return: baud rate, requested baud when possible, or actual baud when there + *	was too much error, zero if no valid divisors are found.   * - * Returns baud rate, requested baud when possible, or actual baud when there - *	was too much error - **/ -static unsigned int xuartps_set_baud_rate(struct uart_port *port, -						unsigned int baud) + * Formula to obtain baud rate is + *	baud_tx/rx rate = clk/CD * (BDIV + 1) + *	input_clk = (Uart User Defined Clock or Apb Clock) + *		depends on UCLKEN in MR Reg + *	clk = input_clk or input_clk/8; + *		depends on CLKS in MR reg + *	CD and BDIV depends on values in + *			baud rate generate register + *			baud rate clock divisor register + */ +static unsigned int cdns_uart_calc_baud_divs(unsigned int clk, +		unsigned int baud, u32 *rbdiv, u32 *rcd, int *div8)  { -	unsigned int sel_clk; -	unsigned int calc_baud = 0; -	unsigned int brgr_val, brdiv_val; +	u32 cd, bdiv; +	unsigned int calc_baud; +	unsigned int bestbaud = 0;  	unsigned int bauderror; +	unsigned int besterror = ~0; -	/* Formula to obtain baud rate is -	 *	baud_tx/rx rate = sel_clk/CD * (BDIV + 1) -	 *	input_clk = (Uart User Defined Clock or Apb Clock) -	 *		depends on UCLKEN in MR Reg -	 *	sel_clk = input_clk or input_clk/8; -	 *		depends on CLKS in MR reg -	 *	CD and BDIV depends on values in -	 *			baud rate generate register -	 *			baud rate clock divisor register -	 */ -	sel_clk = port->uartclk; -	if (xuartps_readl(XUARTPS_MR_OFFSET) & XUARTPS_MR_CLKSEL) -		sel_clk = sel_clk / 8; - -	/* Find the best values for baud generation */ -	for (brdiv_val = 4; brdiv_val < 255; brdiv_val++) { +	if (baud < clk / ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX)) { +		*div8 = 1; +		clk /= 8; +	} else { +		*div8 = 0; +	} -		brgr_val = sel_clk / (baud * (brdiv_val + 1)); -		if (brgr_val < 2 || brgr_val > 65535) +	for (bdiv = CDNS_UART_BDIV_MIN; bdiv <= CDNS_UART_BDIV_MAX; bdiv++) { +		cd = DIV_ROUND_CLOSEST(clk, baud * (bdiv + 1)); +		if (cd < 1 || cd > CDNS_UART_CD_MAX)  			continue; -		calc_baud = sel_clk / (brgr_val * (brdiv_val + 1)); +		calc_baud = clk / (cd * (bdiv + 1));  		if (baud > calc_baud)  			bauderror = baud - calc_baud;  		else  			bauderror = calc_baud - baud; -		/* use the values when percent error is acceptable */ -		if (((bauderror * 100) / baud) < 3) { -			calc_baud = baud; -			break; +		if (besterror > bauderror) { +			*rbdiv = bdiv; +			*rcd = cd; +			bestbaud = calc_baud; +			besterror = bauderror;  		}  	} +	/* use the values when percent error is acceptable */ +	if (((besterror * 100) / baud) < 3) +		bestbaud = baud; -	/* Set the values for the new baud rate */ -	xuartps_writel(brgr_val, XUARTPS_BAUDGEN_OFFSET); -	xuartps_writel(brdiv_val, XUARTPS_BAUDDIV_OFFSET); +	return bestbaud; +} + +/** + * cdns_uart_set_baud_rate - Calculate and set the baud rate + * @port: Handle to the uart port structure + * @baud: Baud rate to set + * Return: baud rate, requested baud when possible, or actual baud when there + *	   was too much error, zero if no valid divisors are found. + */ +static unsigned int cdns_uart_set_baud_rate(struct uart_port *port, +		unsigned int baud) +{ +	unsigned int calc_baud; +	u32 cd = 0, bdiv = 0; +	u32 mreg; +	int div8; +	struct cdns_uart *cdns_uart = port->private_data; + +	calc_baud = cdns_uart_calc_baud_divs(port->uartclk, baud, &bdiv, &cd, +			&div8); + +	/* Write new divisors to hardware */ +	mreg = cdns_uart_readl(CDNS_UART_MR_OFFSET); +	if (div8) +		mreg |= CDNS_UART_MR_CLKSEL; +	else +		mreg &= ~CDNS_UART_MR_CLKSEL; +	cdns_uart_writel(mreg, CDNS_UART_MR_OFFSET); +	cdns_uart_writel(cd, CDNS_UART_BAUDGEN_OFFSET); +	cdns_uart_writel(bdiv, CDNS_UART_BAUDDIV_OFFSET); +	cdns_uart->baud = baud;  	return calc_baud;  } -/*----------------------Uart Operations---------------------------*/ +#ifdef CONFIG_COMMON_CLK +/** + * cdns_uart_clk_notitifer_cb - Clock notifier callback + * @nb:		Notifier block + * @event:	Notify event + * @data:	Notifier data + * Return:	NOTIFY_OK or NOTIFY_DONE on success, NOTIFY_BAD on error. + */ +static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, +		unsigned long event, void *data) +{ +	u32 ctrl_reg; +	struct uart_port *port; +	int locked = 0; +	struct clk_notifier_data *ndata = data; +	unsigned long flags = 0; +	struct cdns_uart *cdns_uart = to_cdns_uart(nb); + +	port = cdns_uart->port; +	if (port->suspended) +		return NOTIFY_OK; + +	switch (event) { +	case PRE_RATE_CHANGE: +	{ +		u32 bdiv, cd; +		int div8; + +		/* +		 * Find out if current baud-rate can be achieved with new clock +		 * frequency. +		 */ +		if (!cdns_uart_calc_baud_divs(ndata->new_rate, cdns_uart->baud, +					&bdiv, &cd, &div8)) { +			dev_warn(port->dev, "clock rate change rejected\n"); +			return NOTIFY_BAD; +		} + +		spin_lock_irqsave(&cdns_uart->port->lock, flags); + +		/* Disable the TX and RX to set baud rate */ +		ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); +		ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; +		cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + +		spin_unlock_irqrestore(&cdns_uart->port->lock, flags); + +		return NOTIFY_OK; +	} +	case POST_RATE_CHANGE: +		/* +		 * Set clk dividers to generate correct baud with new clock +		 * frequency. +		 */ + +		spin_lock_irqsave(&cdns_uart->port->lock, flags); + +		locked = 1; +		port->uartclk = ndata->new_rate; + +		cdns_uart->baud = cdns_uart_set_baud_rate(cdns_uart->port, +				cdns_uart->baud); +		/* fall through */ +	case ABORT_RATE_CHANGE: +		if (!locked) +			spin_lock_irqsave(&cdns_uart->port->lock, flags); + +		/* Set TX/RX Reset */ +		ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); +		ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; +		cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + +		while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & +				(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) +			cpu_relax(); + +		/* +		 * Clear the RX disable and TX disable bits and then set the TX +		 * enable bit and RX enable bit to enable the transmitter and +		 * receiver. +		 */ +		cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); +		ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); +		ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); +		ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; +		cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + +		spin_unlock_irqrestore(&cdns_uart->port->lock, flags); + +		return NOTIFY_OK; +	default: +		return NOTIFY_DONE; +	} +} +#endif  /** - * xuartps_start_tx -  Start transmitting bytes + * cdns_uart_start_tx -  Start transmitting bytes   * @port: Handle to the uart port structure - * - **/ -static void xuartps_start_tx(struct uart_port *port) + */ +static void cdns_uart_start_tx(struct uart_port *port)  {  	unsigned int status, numbytes = port->fifosize;  	if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port))  		return; -	status = xuartps_readl(XUARTPS_CR_OFFSET); +	status = cdns_uart_readl(CDNS_UART_CR_OFFSET);  	/* Set the TX enable bit and clear the TX disable bit to enable the  	 * transmitter.  	 */ -	xuartps_writel((status & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN, -		XUARTPS_CR_OFFSET); - -	while (numbytes-- && ((xuartps_readl(XUARTPS_SR_OFFSET) -		& XUARTPS_SR_TXFULL)) != XUARTPS_SR_TXFULL) { +	cdns_uart_writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, +		CDNS_UART_CR_OFFSET); +	while (numbytes-- && ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & +				CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) {  		/* Break if no more data available in the UART buffer */  		if (uart_circ_empty(&port->state->xmit))  			break;  		/* Get the data from the UART circular buffer and -		 * write it to the xuartps's TX_FIFO register. +		 * write it to the cdns_uart's TX_FIFO register.  		 */ -		xuartps_writel( +		cdns_uart_writel(  			port->state->xmit.buf[port->state->xmit.tail], -			XUARTPS_FIFO_OFFSET); +			CDNS_UART_FIFO_OFFSET);  		port->icount.tx++;  		/* Adjust the tail of the UART buffer and wrap @@ -346,173 +535,173 @@ static void xuartps_start_tx(struct uart_port *port)  		port->state->xmit.tail = (port->state->xmit.tail + 1) &  					(UART_XMIT_SIZE - 1);  	} - +	cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_ISR_OFFSET);  	/* Enable the TX Empty interrupt */ -	xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_IER_OFFSET); +	cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_IER_OFFSET);  	if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS)  		uart_write_wakeup(port);  }  /** - * xuartps_stop_tx - Stop TX + * cdns_uart_stop_tx - Stop TX   * @port: Handle to the uart port structure - * - **/ -static void xuartps_stop_tx(struct uart_port *port) + */ +static void cdns_uart_stop_tx(struct uart_port *port)  {  	unsigned int regval; -	regval = xuartps_readl(XUARTPS_CR_OFFSET); -	regval |= XUARTPS_CR_TX_DIS; +	regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); +	regval |= CDNS_UART_CR_TX_DIS;  	/* Disable the transmitter */ -	xuartps_writel(regval, XUARTPS_CR_OFFSET); +	cdns_uart_writel(regval, CDNS_UART_CR_OFFSET);  }  /** - * xuartps_stop_rx - Stop RX + * cdns_uart_stop_rx - Stop RX   * @port: Handle to the uart port structure - * - **/ -static void xuartps_stop_rx(struct uart_port *port) + */ +static void cdns_uart_stop_rx(struct uart_port *port)  {  	unsigned int regval; -	regval = xuartps_readl(XUARTPS_CR_OFFSET); -	regval |= XUARTPS_CR_RX_DIS; +	regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); +	regval |= CDNS_UART_CR_RX_DIS;  	/* Disable the receiver */ -	xuartps_writel(regval, XUARTPS_CR_OFFSET); +	cdns_uart_writel(regval, CDNS_UART_CR_OFFSET);  }  /** - * xuartps_tx_empty -  Check whether TX is empty + * cdns_uart_tx_empty -  Check whether TX is empty   * @port: Handle to the uart port structure   * - * Returns TIOCSER_TEMT on success, 0 otherwise - **/ -static unsigned int xuartps_tx_empty(struct uart_port *port) + * Return: TIOCSER_TEMT on success, 0 otherwise + */ +static unsigned int cdns_uart_tx_empty(struct uart_port *port)  {  	unsigned int status; -	status = xuartps_readl(XUARTPS_ISR_OFFSET) & XUARTPS_IXR_TXEMPTY; +	status = cdns_uart_readl(CDNS_UART_ISR_OFFSET) & CDNS_UART_IXR_TXEMPTY;  	return status ? TIOCSER_TEMT : 0;  }  /** - * xuartps_break_ctl - Based on the input ctl we have to start or stop + * cdns_uart_break_ctl - Based on the input ctl we have to start or stop   *			transmitting char breaks   * @port: Handle to the uart port structure   * @ctl: Value based on which start or stop decision is taken - * - **/ -static void xuartps_break_ctl(struct uart_port *port, int ctl) + */ +static void cdns_uart_break_ctl(struct uart_port *port, int ctl)  {  	unsigned int status;  	unsigned long flags;  	spin_lock_irqsave(&port->lock, flags); -	status = xuartps_readl(XUARTPS_CR_OFFSET); +	status = cdns_uart_readl(CDNS_UART_CR_OFFSET);  	if (ctl == -1) -		xuartps_writel(XUARTPS_CR_STARTBRK | status, -					XUARTPS_CR_OFFSET); +		cdns_uart_writel(CDNS_UART_CR_STARTBRK | status, +					CDNS_UART_CR_OFFSET);  	else { -		if ((status & XUARTPS_CR_STOPBRK) == 0) -			xuartps_writel(XUARTPS_CR_STOPBRK | status, -					 XUARTPS_CR_OFFSET); +		if ((status & CDNS_UART_CR_STOPBRK) == 0) +			cdns_uart_writel(CDNS_UART_CR_STOPBRK | status, +					 CDNS_UART_CR_OFFSET);  	}  	spin_unlock_irqrestore(&port->lock, flags);  }  /** - * xuartps_set_termios - termios operations, handling data length, parity, + * cdns_uart_set_termios - termios operations, handling data length, parity,   *				stop bits, flow control, baud rate   * @port: Handle to the uart port structure   * @termios: Handle to the input termios structure   * @old: Values of the previously saved termios structure - * - **/ -static void xuartps_set_termios(struct uart_port *port, + */ +static void cdns_uart_set_termios(struct uart_port *port,  				struct ktermios *termios, struct ktermios *old)  {  	unsigned int cval = 0; -	unsigned int baud; +	unsigned int baud, minbaud, maxbaud;  	unsigned long flags;  	unsigned int ctrl_reg, mode_reg;  	spin_lock_irqsave(&port->lock, flags);  	/* Empty the receive FIFO 1st before making changes */ -	while ((xuartps_readl(XUARTPS_SR_OFFSET) & -		 XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { -		xuartps_readl(XUARTPS_FIFO_OFFSET); +	while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & +		 CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { +		cdns_uart_readl(CDNS_UART_FIFO_OFFSET);  	}  	/* Disable the TX and RX to set baud rate */ -	xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | -			(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), -			XUARTPS_CR_OFFSET); +	ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); +	ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; +	cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); -	/* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk */ -	baud = uart_get_baud_rate(port, termios, old, 0, 10000000); -	baud = xuartps_set_baud_rate(port, baud); +	/* +	 * Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk +	 * min and max baud should be calculated here based on port->uartclk. +	 * this way we get a valid baud and can safely call set_baud() +	 */ +	minbaud = port->uartclk / +			((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX * 8); +	maxbaud = port->uartclk / (CDNS_UART_BDIV_MIN + 1); +	baud = uart_get_baud_rate(port, termios, old, minbaud, maxbaud); +	baud = cdns_uart_set_baud_rate(port, baud);  	if (tty_termios_baud_rate(termios))  		tty_termios_encode_baud_rate(termios, baud, baud); -	/* -	 * Update the per-port timeout. -	 */ +	/* Update the per-port timeout. */  	uart_update_timeout(port, termios->c_cflag, baud);  	/* Set TX/RX Reset */ -	xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | -			(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), -			XUARTPS_CR_OFFSET); - -	ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); +	ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); +	ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; +	cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); -	/* Clear the RX disable and TX disable bits and then set the TX enable +	/* +	 * Clear the RX disable and TX disable bits and then set the TX enable  	 * bit and RX enable bit to enable the transmitter and receiver.  	 */ -	xuartps_writel( -		(ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) -			| (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), -			XUARTPS_CR_OFFSET); +	ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); +	ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); +	ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; +	cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); -	xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); +	cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); -	port->read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG | -			XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT; +	port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | +			CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;  	port->ignore_status_mask = 0;  	if (termios->c_iflag & INPCK) -		port->read_status_mask |= XUARTPS_IXR_PARITY | -		XUARTPS_IXR_FRAMING; +		port->read_status_mask |= CDNS_UART_IXR_PARITY | +		CDNS_UART_IXR_FRAMING;  	if (termios->c_iflag & IGNPAR) -		port->ignore_status_mask |= XUARTPS_IXR_PARITY | -			XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN; +		port->ignore_status_mask |= CDNS_UART_IXR_PARITY | +			CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN;  	/* ignore all characters if CREAD is not set */  	if ((termios->c_cflag & CREAD) == 0) -		port->ignore_status_mask |= XUARTPS_IXR_RXTRIG | -			XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY | -			XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN; +		port->ignore_status_mask |= CDNS_UART_IXR_RXTRIG | +			CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY | +			CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN; -	mode_reg = xuartps_readl(XUARTPS_MR_OFFSET); +	mode_reg = cdns_uart_readl(CDNS_UART_MR_OFFSET);  	/* Handling Data Size */  	switch (termios->c_cflag & CSIZE) {  	case CS6: -		cval |= XUARTPS_MR_CHARLEN_6_BIT; +		cval |= CDNS_UART_MR_CHARLEN_6_BIT;  		break;  	case CS7: -		cval |= XUARTPS_MR_CHARLEN_7_BIT; +		cval |= CDNS_UART_MR_CHARLEN_7_BIT;  		break;  	default:  	case CS8: -		cval |= XUARTPS_MR_CHARLEN_8_BIT; +		cval |= CDNS_UART_MR_CHARLEN_8_BIT;  		termios->c_cflag &= ~CSIZE;  		termios->c_cflag |= CS8;  		break; @@ -520,124 +709,135 @@ static void xuartps_set_termios(struct uart_port *port,  	/* Handling Parity and Stop Bits length */  	if (termios->c_cflag & CSTOPB) -		cval |= XUARTPS_MR_STOPMODE_2_BIT; /* 2 STOP bits */ +		cval |= CDNS_UART_MR_STOPMODE_2_BIT; /* 2 STOP bits */  	else -		cval |= XUARTPS_MR_STOPMODE_1_BIT; /* 1 STOP bit */ +		cval |= CDNS_UART_MR_STOPMODE_1_BIT; /* 1 STOP bit */  	if (termios->c_cflag & PARENB) {  		/* Mark or Space parity */  		if (termios->c_cflag & CMSPAR) {  			if (termios->c_cflag & PARODD) -				cval |= XUARTPS_MR_PARITY_MARK; +				cval |= CDNS_UART_MR_PARITY_MARK;  			else -				cval |= XUARTPS_MR_PARITY_SPACE; -		} else if (termios->c_cflag & PARODD) -				cval |= XUARTPS_MR_PARITY_ODD; +				cval |= CDNS_UART_MR_PARITY_SPACE; +		} else { +			if (termios->c_cflag & PARODD) +				cval |= CDNS_UART_MR_PARITY_ODD;  			else -				cval |= XUARTPS_MR_PARITY_EVEN; -	} else -		cval |= XUARTPS_MR_PARITY_NONE; -	xuartps_writel(cval , XUARTPS_MR_OFFSET); +				cval |= CDNS_UART_MR_PARITY_EVEN; +		} +	} else { +		cval |= CDNS_UART_MR_PARITY_NONE; +	} +	cval |= mode_reg & 1; +	cdns_uart_writel(cval, CDNS_UART_MR_OFFSET);  	spin_unlock_irqrestore(&port->lock, flags);  }  /** - * xuartps_startup - Called when an application opens a xuartps port + * cdns_uart_startup - Called when an application opens a cdns_uart port   * @port: Handle to the uart port structure   * - * Returns 0 on success, negative error otherwise - **/ -static int xuartps_startup(struct uart_port *port) + * Return: 0 on success, negative errno otherwise + */ +static int cdns_uart_startup(struct uart_port *port)  {  	unsigned int retval = 0, status = 0; -	retval = request_irq(port->irq, xuartps_isr, 0, XUARTPS_NAME, +	retval = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME,  								(void *)port);  	if (retval)  		return retval;  	/* Disable the TX and RX */ -	xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS, -						XUARTPS_CR_OFFSET); +	cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, +						CDNS_UART_CR_OFFSET);  	/* Set the Control Register with TX/RX Enable, TX/RX Reset,  	 * no break chars.  	 */ -	xuartps_writel(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST, -				XUARTPS_CR_OFFSET); +	cdns_uart_writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, +				CDNS_UART_CR_OFFSET); -	status = xuartps_readl(XUARTPS_CR_OFFSET); +	status = cdns_uart_readl(CDNS_UART_CR_OFFSET);  	/* Clear the RX disable and TX disable bits and then set the TX enable  	 * bit and RX enable bit to enable the transmitter and receiver.  	 */ -	xuartps_writel((status & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) -			| (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN | -			XUARTPS_CR_STOPBRK), XUARTPS_CR_OFFSET); +	cdns_uart_writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS)) +			| (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN | +			CDNS_UART_CR_STOPBRK), CDNS_UART_CR_OFFSET);  	/* Set the Mode Register with normal mode,8 data bits,1 stop bit,  	 * no parity.  	 */ -	xuartps_writel(XUARTPS_MR_CHMODE_NORM | XUARTPS_MR_STOPMODE_1_BIT -		| XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT, -		 XUARTPS_MR_OFFSET); +	cdns_uart_writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT +		| CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT, +		 CDNS_UART_MR_OFFSET); -	/* Set the RX FIFO Trigger level to 14 assuming FIFO size as 16 */ -	xuartps_writel(14, XUARTPS_RXWM_OFFSET); +	/* +	 * Set the RX FIFO Trigger level to use most of the FIFO, but it +	 * can be tuned with a module parameter +	 */ +	cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); -	/* Receive Timeout register is enabled with value of 10 */ -	xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); +	/* +	 * Receive Timeout register is enabled but it +	 * can be tuned with a module parameter +	 */ +	cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET);  	/* Clear out any pending interrupts before enabling them */ -	xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET); +	cdns_uart_writel(cdns_uart_readl(CDNS_UART_ISR_OFFSET), +			CDNS_UART_ISR_OFFSET);  	/* Set the Interrupt Registers with desired interrupts */ -	xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY | -		XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN | -		XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); +	cdns_uart_writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY | +		CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN | +		CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT, +		CDNS_UART_IER_OFFSET);  	return retval;  }  /** - * xuartps_shutdown - Called when an application closes a xuartps port + * cdns_uart_shutdown - Called when an application closes a cdns_uart port   * @port: Handle to the uart port structure - * - **/ -static void xuartps_shutdown(struct uart_port *port) + */ +static void cdns_uart_shutdown(struct uart_port *port)  {  	int status;  	/* Disable interrupts */ -	status = xuartps_readl(XUARTPS_IMR_OFFSET); -	xuartps_writel(status, XUARTPS_IDR_OFFSET); +	status = cdns_uart_readl(CDNS_UART_IMR_OFFSET); +	cdns_uart_writel(status, CDNS_UART_IDR_OFFSET);  	/* Disable the TX and RX */ -	xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS, -				 XUARTPS_CR_OFFSET); +	cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, +				 CDNS_UART_CR_OFFSET);  	free_irq(port->irq, port);  }  /** - * xuartps_type - Set UART type to xuartps port + * cdns_uart_type - Set UART type to cdns_uart port   * @port: Handle to the uart port structure   * - * Returns string on success, NULL otherwise - **/ -static const char *xuartps_type(struct uart_port *port) + * Return: string on success, NULL otherwise + */ +static const char *cdns_uart_type(struct uart_port *port)  { -	return port->type == PORT_XUARTPS ? XUARTPS_NAME : NULL; +	return port->type == PORT_XUARTPS ? CDNS_UART_NAME : NULL;  }  /** - * xuartps_verify_port - Verify the port params + * cdns_uart_verify_port - Verify the port params   * @port: Handle to the uart port structure   * @ser: Handle to the structure whose members are compared   * - * Returns 0 if success otherwise -EINVAL - **/ -static int xuartps_verify_port(struct uart_port *port, + * Return: 0 on success, negative errno otherwise. + */ +static int cdns_uart_verify_port(struct uart_port *port,  					struct serial_struct *ser)  {  	if (ser->type != PORT_UNKNOWN && ser->type != PORT_XUARTPS) @@ -654,135 +854,170 @@ static int xuartps_verify_port(struct uart_port *port,  }  /** - * xuartps_request_port - Claim the memory region attached to xuartps port, - *				called when the driver adds a xuartps port via + * cdns_uart_request_port - Claim the memory region attached to cdns_uart port, + *				called when the driver adds a cdns_uart port via   *				uart_add_one_port()   * @port: Handle to the uart port structure   * - * Returns 0, -ENOMEM if request fails - **/ -static int xuartps_request_port(struct uart_port *port) + * Return: 0 on success, negative errno otherwise. + */ +static int cdns_uart_request_port(struct uart_port *port)  { -	if (!request_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE, -					 XUARTPS_NAME)) { +	if (!request_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE, +					 CDNS_UART_NAME)) {  		return -ENOMEM;  	} -	port->membase = ioremap(port->mapbase, XUARTPS_REGISTER_SPACE); +	port->membase = ioremap(port->mapbase, CDNS_UART_REGISTER_SPACE);  	if (!port->membase) {  		dev_err(port->dev, "Unable to map registers\n"); -		release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE); +		release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE);  		return -ENOMEM;  	}  	return 0;  }  /** - * xuartps_release_port - Release the memory region attached to a xuartps - *				port, called when the driver removes a xuartps - *				port via uart_remove_one_port(). + * cdns_uart_release_port - Release UART port   * @port: Handle to the uart port structure   * - **/ -static void xuartps_release_port(struct uart_port *port) + * Release the memory region attached to a cdns_uart port. Called when the + * driver removes a cdns_uart port via uart_remove_one_port(). + */ +static void cdns_uart_release_port(struct uart_port *port)  { -	release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE); +	release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE);  	iounmap(port->membase);  	port->membase = NULL;  }  /** - * xuartps_config_port - Configure xuartps, called when the driver adds a - *				xuartps port + * cdns_uart_config_port - Configure UART port   * @port: Handle to the uart port structure   * @flags: If any - * - **/ -static void xuartps_config_port(struct uart_port *port, int flags) + */ +static void cdns_uart_config_port(struct uart_port *port, int flags)  { -	if (flags & UART_CONFIG_TYPE && xuartps_request_port(port) == 0) +	if (flags & UART_CONFIG_TYPE && cdns_uart_request_port(port) == 0)  		port->type = PORT_XUARTPS;  }  /** - * xuartps_get_mctrl - Get the modem control state - * + * cdns_uart_get_mctrl - Get the modem control state   * @port: Handle to the uart port structure   * - * Returns the modem control state - * - **/ -static unsigned int xuartps_get_mctrl(struct uart_port *port) + * Return: the modem control state + */ +static unsigned int cdns_uart_get_mctrl(struct uart_port *port)  {  	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;  } -static void xuartps_set_mctrl(struct uart_port *port, unsigned int mctrl) +static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)  {  	/* N/A */  } -static void xuartps_enable_ms(struct uart_port *port) +static void cdns_uart_enable_ms(struct uart_port *port)  {  	/* N/A */  } -/** The UART operations structure - */ -static struct uart_ops xuartps_ops = { -	.set_mctrl	= xuartps_set_mctrl, -	.get_mctrl	= xuartps_get_mctrl, -	.enable_ms	= xuartps_enable_ms, - -	.start_tx	= xuartps_start_tx,	/* Start transmitting */ -	.stop_tx	= xuartps_stop_tx,	/* Stop transmission */ -	.stop_rx	= xuartps_stop_rx,	/* Stop reception */ -	.tx_empty	= xuartps_tx_empty,	/* Transmitter busy? */ -	.break_ctl	= xuartps_break_ctl,	/* Start/stop -						 * transmitting break -						 */ -	.set_termios	= xuartps_set_termios,	/* Set termios */ -	.startup	= xuartps_startup,	/* App opens xuartps */ -	.shutdown	= xuartps_shutdown,	/* App closes xuartps */ -	.type		= xuartps_type,		/* Set UART type */ -	.verify_port	= xuartps_verify_port,	/* Verification of port -						 * params -						 */ -	.request_port	= xuartps_request_port,	/* Claim resources -						 * associated with a -						 * xuartps port -						 */ -	.release_port	= xuartps_release_port,	/* Release resources -						 * associated with a -						 * xuartps port -						 */ -	.config_port	= xuartps_config_port,	/* Configure when driver -						 * adds a xuartps port -						 */ +#ifdef CONFIG_CONSOLE_POLL +static int cdns_uart_poll_get_char(struct uart_port *port) +{ +	u32 imr; +	int c; + +	/* Disable all interrupts */ +	imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); +	cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + +	/* Check if FIFO is empty */ +	if (cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY) +		c = NO_POLL_CHAR; +	else /* Read a character */ +		c = (unsigned char) cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + +	/* Enable interrupts */ +	cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + +	return c; +} + +static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) +{ +	u32 imr; + +	/* Disable all interrupts */ +	imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); +	cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + +	/* Wait until FIFO is empty */ +	while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) +		cpu_relax(); + +	/* Write a character */ +	cdns_uart_writel(c, CDNS_UART_FIFO_OFFSET); + +	/* Wait until FIFO is empty */ +	while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) +		cpu_relax(); + +	/* Enable interrupts */ +	cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + +	return; +} +#endif + +static struct uart_ops cdns_uart_ops = { +	.set_mctrl	= cdns_uart_set_mctrl, +	.get_mctrl	= cdns_uart_get_mctrl, +	.enable_ms	= cdns_uart_enable_ms, +	.start_tx	= cdns_uart_start_tx, +	.stop_tx	= cdns_uart_stop_tx, +	.stop_rx	= cdns_uart_stop_rx, +	.tx_empty	= cdns_uart_tx_empty, +	.break_ctl	= cdns_uart_break_ctl, +	.set_termios	= cdns_uart_set_termios, +	.startup	= cdns_uart_startup, +	.shutdown	= cdns_uart_shutdown, +	.type		= cdns_uart_type, +	.verify_port	= cdns_uart_verify_port, +	.request_port	= cdns_uart_request_port, +	.release_port	= cdns_uart_release_port, +	.config_port	= cdns_uart_config_port, +#ifdef CONFIG_CONSOLE_POLL +	.poll_get_char	= cdns_uart_poll_get_char, +	.poll_put_char	= cdns_uart_poll_put_char, +#endif  }; -static struct uart_port xuartps_port[2]; +static struct uart_port cdns_uart_port[2];  /** - * xuartps_get_port - Configure the port from the platform device resource - *			info + * cdns_uart_get_port - Configure the port from platform device resource info + * @id: Port id   * - * Returns a pointer to a uart_port or NULL for failure - **/ -static struct uart_port *xuartps_get_port(void) + * Return: a pointer to a uart_port or NULL for failure + */ +static struct uart_port *cdns_uart_get_port(int id)  {  	struct uart_port *port; -	int id; -	/* Find the next unused port */ -	for (id = 0; id < XUARTPS_NR_PORTS; id++) -		if (xuartps_port[id].mapbase == 0) -			break; +	/* Try the given port id if failed use default method */ +	if (cdns_uart_port[id].mapbase != 0) { +		/* Find the next unused port */ +		for (id = 0; id < CDNS_UART_NR_PORTS; id++) +			if (cdns_uart_port[id].mapbase == 0) +				break; +	} -	if (id >= XUARTPS_NR_PORTS) +	if (id >= CDNS_UART_NR_PORTS)  		return NULL; -	port = &xuartps_port[id]; +	port = &cdns_uart_port[id];  	/* At this point, we've got an empty uart_port struct, initialize it */  	spin_lock_init(&port->lock); @@ -792,52 +1027,48 @@ static struct uart_port *xuartps_get_port(void)  	port->type	= PORT_UNKNOWN;  	port->iotype	= UPIO_MEM32;  	port->flags	= UPF_BOOT_AUTOCONF; -	port->ops	= &xuartps_ops; -	port->fifosize	= XUARTPS_FIFO_SIZE; +	port->ops	= &cdns_uart_ops; +	port->fifosize	= CDNS_UART_FIFO_SIZE;  	port->line	= id;  	port->dev	= NULL;  	return port;  } -/*-----------------------Console driver operations--------------------------*/ -  #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE  /** - * xuartps_console_wait_tx - Wait for the TX to be full + * cdns_uart_console_wait_tx - Wait for the TX to be full   * @port: Handle to the uart port structure - * - **/ -static void xuartps_console_wait_tx(struct uart_port *port) + */ +static void cdns_uart_console_wait_tx(struct uart_port *port)  { -	while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY) -				!= XUARTPS_SR_TXEMPTY) +	while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY) +				!= CDNS_UART_SR_TXEMPTY)  		barrier();  }  /** - * xuartps_console_putchar - write the character to the FIFO buffer + * cdns_uart_console_putchar - write the character to the FIFO buffer   * @port: Handle to the uart port structure   * @ch: Character to be written - * - **/ -static void xuartps_console_putchar(struct uart_port *port, int ch) + */ +static void cdns_uart_console_putchar(struct uart_port *port, int ch)  { -	xuartps_console_wait_tx(port); -	xuartps_writel(ch, XUARTPS_FIFO_OFFSET); +	cdns_uart_console_wait_tx(port); +	cdns_uart_writel(ch, CDNS_UART_FIFO_OFFSET);  }  /** - * xuartps_console_write - perform write operation - * @port: Handle to the uart port structure + * cdns_uart_console_write - perform write operation + * @co: Console handle   * @s: Pointer to character array   * @count: No of characters - **/ -static void xuartps_console_write(struct console *co, const char *s, + */ +static void cdns_uart_console_write(struct console *co, const char *s,  				unsigned int count)  { -	struct uart_port *port = &xuartps_port[co->index]; +	struct uart_port *port = &cdns_uart_port[co->index];  	unsigned long flags; -	unsigned int imr; +	unsigned int imr, ctrl;  	int locked = 1;  	if (oops_in_progress) @@ -846,39 +1077,45 @@ static void xuartps_console_write(struct console *co, const char *s,  		spin_lock_irqsave(&port->lock, flags);  	/* save and disable interrupt */ -	imr = xuartps_readl(XUARTPS_IMR_OFFSET); -	xuartps_writel(imr, XUARTPS_IDR_OFFSET); - -	uart_console_write(port, s, count, xuartps_console_putchar); -	xuartps_console_wait_tx(port); +	imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); +	cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); -	/* restore interrupt state, it seems like there may be a h/w bug -	 * in that the interrupt enable register should not need to be -	 * written based on the data sheet +	/* +	 * Make sure that the tx part is enabled. Set the TX enable bit and +	 * clear the TX disable bit to enable the transmitter.  	 */ -	xuartps_writel(~imr, XUARTPS_IDR_OFFSET); -	xuartps_writel(imr, XUARTPS_IER_OFFSET); +	ctrl = cdns_uart_readl(CDNS_UART_CR_OFFSET); +	cdns_uart_writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, +		CDNS_UART_CR_OFFSET); + +	uart_console_write(port, s, count, cdns_uart_console_putchar); +	cdns_uart_console_wait_tx(port); + +	cdns_uart_writel(ctrl, CDNS_UART_CR_OFFSET); + +	/* restore interrupt state */ +	cdns_uart_writel(imr, CDNS_UART_IER_OFFSET);  	if (locked)  		spin_unlock_irqrestore(&port->lock, flags);  }  /** - * xuartps_console_setup - Initialize the uart to default config + * cdns_uart_console_setup - Initialize the uart to default config   * @co: Console handle   * @options: Initial settings of uart   * - * Returns 0, -ENODEV if no device - **/ -static int __init xuartps_console_setup(struct console *co, char *options) + * Return: 0 on success, negative errno otherwise. + */ +static int __init cdns_uart_console_setup(struct console *co, char *options)  { -	struct uart_port *port = &xuartps_port[co->index]; +	struct uart_port *port = &cdns_uart_port[co->index];  	int baud = 9600;  	int bits = 8;  	int parity = 'n';  	int flow = 'n'; -	if (co->index < 0 || co->index >= XUARTPS_NR_PORTS) +	if (co->index < 0 || co->index >= CDNS_UART_NR_PORTS)  		return -EINVAL;  	if (!port->mapbase) { @@ -892,89 +1129,208 @@ static int __init xuartps_console_setup(struct console *co, char *options)  	return uart_set_options(port, co, baud, parity, bits, flow);  } -static struct uart_driver xuartps_uart_driver; +static struct uart_driver cdns_uart_uart_driver; -static struct console xuartps_console = { -	.name	= XUARTPS_TTY_NAME, -	.write	= xuartps_console_write, +static struct console cdns_uart_console = { +	.name	= CDNS_UART_TTY_NAME, +	.write	= cdns_uart_console_write,  	.device	= uart_console_device, -	.setup	= xuartps_console_setup, +	.setup	= cdns_uart_console_setup,  	.flags	= CON_PRINTBUFFER,  	.index	= -1, /* Specified on the cmdline (e.g. console=ttyPS ) */ -	.data	= &xuartps_uart_driver, +	.data	= &cdns_uart_uart_driver,  };  /** - * xuartps_console_init - Initialization call + * cdns_uart_console_init - Initialization call   * - * Returns 0 on success, negative error otherwise - **/ -static int __init xuartps_console_init(void) + * Return: 0 on success, negative errno otherwise + */ +static int __init cdns_uart_console_init(void)  { -	register_console(&xuartps_console); +	register_console(&cdns_uart_console);  	return 0;  } -console_initcall(xuartps_console_init); +console_initcall(cdns_uart_console_init);  #endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */ -/** Structure Definitions - */ -static struct uart_driver xuartps_uart_driver = { -	.owner		= THIS_MODULE,		/* Owner */ -	.driver_name	= XUARTPS_NAME,		/* Driver name */ -	.dev_name	= XUARTPS_TTY_NAME,	/* Node name */ -	.major		= XUARTPS_MAJOR,	/* Major number */ -	.minor		= XUARTPS_MINOR,	/* Minor number */ -	.nr		= XUARTPS_NR_PORTS,	/* Number of UART ports */ +static struct uart_driver cdns_uart_uart_driver = { +	.owner		= THIS_MODULE, +	.driver_name	= CDNS_UART_NAME, +	.dev_name	= CDNS_UART_TTY_NAME, +	.major		= CDNS_UART_MAJOR, +	.minor		= CDNS_UART_MINOR, +	.nr		= CDNS_UART_NR_PORTS,  #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE -	.cons		= &xuartps_console,	/* Console */ +	.cons		= &cdns_uart_console,  #endif  }; -/* --------------------------------------------------------------------- - * Platform bus binding +#ifdef CONFIG_PM_SLEEP +/** + * cdns_uart_suspend - suspend event + * @device: Pointer to the device structure + * + * Return: 0 + */ +static int cdns_uart_suspend(struct device *device) +{ +	struct uart_port *port = dev_get_drvdata(device); +	struct tty_struct *tty; +	struct device *tty_dev; +	int may_wake = 0; + +	/* Get the tty which could be NULL so don't assume it's valid */ +	tty = tty_port_tty_get(&port->state->port); +	if (tty) { +		tty_dev = tty->dev; +		may_wake = device_may_wakeup(tty_dev); +		tty_kref_put(tty); +	} + +	/* +	 * Call the API provided in serial_core.c file which handles +	 * the suspend. +	 */ +	uart_suspend_port(&cdns_uart_uart_driver, port); +	if (console_suspend_enabled && !may_wake) { +		struct cdns_uart *cdns_uart = port->private_data; + +		clk_disable(cdns_uart->uartclk); +		clk_disable(cdns_uart->pclk); +	} else { +		unsigned long flags = 0; + +		spin_lock_irqsave(&port->lock, flags); +		/* Empty the receive FIFO 1st before making changes */ +		while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & +					CDNS_UART_SR_RXEMPTY)) +			cdns_uart_readl(CDNS_UART_FIFO_OFFSET); +		/* set RX trigger level to 1 */ +		cdns_uart_writel(1, CDNS_UART_RXWM_OFFSET); +		/* disable RX timeout interrups */ +		cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IDR_OFFSET); +		spin_unlock_irqrestore(&port->lock, flags); +	} + +	return 0; +} + +/** + * cdns_uart_resume - Resume after a previous suspend + * @device: Pointer to the device structure + * + * Return: 0   */ +static int cdns_uart_resume(struct device *device) +{ +	struct uart_port *port = dev_get_drvdata(device); +	unsigned long flags = 0; +	u32 ctrl_reg; +	struct tty_struct *tty; +	struct device *tty_dev; +	int may_wake = 0; + +	/* Get the tty which could be NULL so don't assume it's valid */ +	tty = tty_port_tty_get(&port->state->port); +	if (tty) { +		tty_dev = tty->dev; +		may_wake = device_may_wakeup(tty_dev); +		tty_kref_put(tty); +	} + +	if (console_suspend_enabled && !may_wake) { +		struct cdns_uart *cdns_uart = port->private_data; + +		clk_enable(cdns_uart->pclk); +		clk_enable(cdns_uart->uartclk); + +		spin_lock_irqsave(&port->lock, flags); + +		/* Set TX/RX Reset */ +		ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); +		ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; +		cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); +		while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & +				(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) +			cpu_relax(); + +		/* restore rx timeout value */ +		cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); +		/* Enable Tx/Rx */ +		ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); +		ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); +		ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; +		cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + +		spin_unlock_irqrestore(&port->lock, flags); +	} else { +		spin_lock_irqsave(&port->lock, flags); +		/* restore original rx trigger level */ +		cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); +		/* enable RX timeout interrupt */ +		cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IER_OFFSET); +		spin_unlock_irqrestore(&port->lock, flags); +	} + +	return uart_resume_port(&cdns_uart_uart_driver, port); +} +#endif /* ! CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend, +		cdns_uart_resume); +  /** - * xuartps_probe - Platform driver probe + * cdns_uart_probe - Platform driver probe   * @pdev: Pointer to the platform device structure   * - * Returns 0 on success, negative error otherwise - **/ -static int xuartps_probe(struct platform_device *pdev) + * Return: 0 on success, negative errno otherwise + */ +static int cdns_uart_probe(struct platform_device *pdev)  { -	int rc; +	int rc, id;  	struct uart_port *port;  	struct resource *res, *res2; -	struct xuartps *xuartps_data; +	struct cdns_uart *cdns_uart_data; -	xuartps_data = kzalloc(sizeof(*xuartps_data), GFP_KERNEL); -	if (!xuartps_data) +	cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data), +			GFP_KERNEL); +	if (!cdns_uart_data)  		return -ENOMEM; -	xuartps_data->aperclk = clk_get(&pdev->dev, "aper_clk"); -	if (IS_ERR(xuartps_data->aperclk)) { -		dev_err(&pdev->dev, "aper_clk clock not found.\n"); -		rc = PTR_ERR(xuartps_data->aperclk); -		goto err_out_free; +	cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk"); +	if (IS_ERR(cdns_uart_data->pclk)) { +		cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk"); +		if (!IS_ERR(cdns_uart_data->pclk)) +			dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n"); +	} +	if (IS_ERR(cdns_uart_data->pclk)) { +		dev_err(&pdev->dev, "pclk clock not found.\n"); +		return PTR_ERR(cdns_uart_data->pclk); +	} + +	cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk"); +	if (IS_ERR(cdns_uart_data->uartclk)) { +		cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "ref_clk"); +		if (!IS_ERR(cdns_uart_data->uartclk)) +			dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n");  	} -	xuartps_data->refclk = clk_get(&pdev->dev, "ref_clk"); -	if (IS_ERR(xuartps_data->refclk)) { -		dev_err(&pdev->dev, "ref_clk clock not found.\n"); -		rc = PTR_ERR(xuartps_data->refclk); -		goto err_out_clk_put_aper; +	if (IS_ERR(cdns_uart_data->uartclk)) { +		dev_err(&pdev->dev, "uart_clk clock not found.\n"); +		return PTR_ERR(cdns_uart_data->uartclk);  	} -	rc = clk_prepare_enable(xuartps_data->aperclk); +	rc = clk_prepare_enable(cdns_uart_data->pclk);  	if (rc) { -		dev_err(&pdev->dev, "Unable to enable APER clock.\n"); -		goto err_out_clk_put; +		dev_err(&pdev->dev, "Unable to enable pclk clock.\n"); +		return rc;  	} -	rc = clk_prepare_enable(xuartps_data->refclk); +	rc = clk_prepare_enable(cdns_uart_data->uartclk);  	if (rc) {  		dev_err(&pdev->dev, "Unable to enable device clock.\n"); -		goto err_out_clk_dis_aper; +		goto err_out_clk_dis_pclk;  	}  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -989,13 +1345,25 @@ static int xuartps_probe(struct platform_device *pdev)  		goto err_out_clk_disable;  	} +#ifdef CONFIG_COMMON_CLK +	cdns_uart_data->clk_rate_change_nb.notifier_call = +			cdns_uart_clk_notifier_cb; +	if (clk_notifier_register(cdns_uart_data->uartclk, +				&cdns_uart_data->clk_rate_change_nb)) +		dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); +#endif +	/* Look for a serialN alias */ +	id = of_alias_get_id(pdev->dev.of_node, "serial"); +	if (id < 0) +		id = 0; +  	/* Initialize the port structure */ -	port = xuartps_get_port(); +	port = cdns_uart_get_port(id);  	if (!port) {  		dev_err(&pdev->dev, "Cannot get uart_port structure\n");  		rc = -ENODEV; -		goto err_out_clk_disable; +		goto err_out_notif_unreg;  	} else {  		/* Register the port.  		 * This function also registers this device with the tty layer @@ -1004,116 +1372,104 @@ static int xuartps_probe(struct platform_device *pdev)  		port->mapbase = res->start;  		port->irq = res2->start;  		port->dev = &pdev->dev; -		port->uartclk = clk_get_rate(xuartps_data->refclk); -		port->private_data = xuartps_data; +		port->uartclk = clk_get_rate(cdns_uart_data->uartclk); +		port->private_data = cdns_uart_data; +		cdns_uart_data->port = port;  		platform_set_drvdata(pdev, port); -		rc = uart_add_one_port(&xuartps_uart_driver, port); +		rc = uart_add_one_port(&cdns_uart_uart_driver, port);  		if (rc) {  			dev_err(&pdev->dev,  				"uart_add_one_port() failed; err=%i\n", rc); -			goto err_out_clk_disable; +			goto err_out_notif_unreg;  		}  		return 0;  	} +err_out_notif_unreg: +#ifdef CONFIG_COMMON_CLK +	clk_notifier_unregister(cdns_uart_data->uartclk, +			&cdns_uart_data->clk_rate_change_nb); +#endif  err_out_clk_disable: -	clk_disable_unprepare(xuartps_data->refclk); -err_out_clk_dis_aper: -	clk_disable_unprepare(xuartps_data->aperclk); -err_out_clk_put: -	clk_put(xuartps_data->refclk); -err_out_clk_put_aper: -	clk_put(xuartps_data->aperclk); -err_out_free: -	kfree(xuartps_data); +	clk_disable_unprepare(cdns_uart_data->uartclk); +err_out_clk_dis_pclk: +	clk_disable_unprepare(cdns_uart_data->pclk);  	return rc;  }  /** - * xuartps_remove - called when the platform driver is unregistered + * cdns_uart_remove - called when the platform driver is unregistered   * @pdev: Pointer to the platform device structure   * - * Returns 0 on success, negative error otherwise - **/ -static int xuartps_remove(struct platform_device *pdev) + * Return: 0 on success, negative errno otherwise + */ +static int cdns_uart_remove(struct platform_device *pdev)  {  	struct uart_port *port = platform_get_drvdata(pdev); -	struct xuartps *xuartps_data = port->private_data; +	struct cdns_uart *cdns_uart_data = port->private_data;  	int rc; -	/* Remove the xuartps port from the serial core */ -	rc = uart_remove_one_port(&xuartps_uart_driver, port); +	/* Remove the cdns_uart port from the serial core */ +#ifdef CONFIG_COMMON_CLK +	clk_notifier_unregister(cdns_uart_data->uartclk, +			&cdns_uart_data->clk_rate_change_nb); +#endif +	rc = uart_remove_one_port(&cdns_uart_uart_driver, port);  	port->mapbase = 0; -	clk_disable_unprepare(xuartps_data->refclk); -	clk_disable_unprepare(xuartps_data->aperclk); -	clk_put(xuartps_data->refclk); -	clk_put(xuartps_data->aperclk); -	kfree(xuartps_data); +	clk_disable_unprepare(cdns_uart_data->uartclk); +	clk_disable_unprepare(cdns_uart_data->pclk);  	return rc;  }  /* Match table for of_platform binding */ -static struct of_device_id xuartps_of_match[] = { +static struct of_device_id cdns_uart_of_match[] = {  	{ .compatible = "xlnx,xuartps", }, +	{ .compatible = "cdns,uart-r1p8", },  	{}  }; -MODULE_DEVICE_TABLE(of, xuartps_of_match); +MODULE_DEVICE_TABLE(of, cdns_uart_of_match); -static struct platform_driver xuartps_platform_driver = { -	.probe   = xuartps_probe,		/* Probe method */ -	.remove  = xuartps_remove,		/* Detach method */ +static struct platform_driver cdns_uart_platform_driver = { +	.probe   = cdns_uart_probe, +	.remove  = cdns_uart_remove,  	.driver  = {  		.owner = THIS_MODULE, -		.name = XUARTPS_NAME,		/* Driver name */ -		.of_match_table = xuartps_of_match, +		.name = CDNS_UART_NAME, +		.of_match_table = cdns_uart_of_match, +		.pm = &cdns_uart_dev_pm_ops,  		},  }; -/* --------------------------------------------------------------------- - * Module Init and Exit - */ -/** - * xuartps_init - Initial driver registration call - * - * Returns whether the registration was successful or not - **/ -static int __init xuartps_init(void) +static int __init cdns_uart_init(void)  {  	int retval = 0; -	/* Register the xuartps driver with the serial core */ -	retval = uart_register_driver(&xuartps_uart_driver); +	/* Register the cdns_uart driver with the serial core */ +	retval = uart_register_driver(&cdns_uart_uart_driver);  	if (retval)  		return retval;  	/* Register the platform driver */ -	retval = platform_driver_register(&xuartps_platform_driver); +	retval = platform_driver_register(&cdns_uart_platform_driver);  	if (retval) -		uart_unregister_driver(&xuartps_uart_driver); +		uart_unregister_driver(&cdns_uart_uart_driver);  	return retval;  } -/** - * xuartps_exit - Driver unregistration call - **/ -static void __exit xuartps_exit(void) +static void __exit cdns_uart_exit(void)  { -	/* The order of unregistration is important. Unregister the -	 * UART driver before the platform driver crashes the system. -	 */ -  	/* Unregister the platform driver */ -	platform_driver_unregister(&xuartps_platform_driver); +	platform_driver_unregister(&cdns_uart_platform_driver); -	/* Unregister the xuartps driver */ -	uart_unregister_driver(&xuartps_uart_driver); +	/* Unregister the cdns_uart driver */ +	uart_unregister_driver(&cdns_uart_uart_driver);  } -module_init(xuartps_init); -module_exit(xuartps_exit); +module_init(cdns_uart_init); +module_exit(cdns_uart_exit); -MODULE_DESCRIPTION("Driver for PS UART"); +MODULE_DESCRIPTION("Driver for Cadence UART");  MODULE_AUTHOR("Xilinx Inc.");  MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 6a169877109..2b65bb7ffb8 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -923,7 +923,7 @@ static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,  	uport->read_status_mask = Rx_OVR;  	if (termios->c_iflag & INPCK)  		uport->read_status_mask |= FRM_ERR | PAR_ERR; -	if (termios->c_iflag & (BRKINT | PARMRK)) +	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))  		uport->read_status_mask |= Rx_BRK;  	uport->ignore_status_mask = 0; diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index e1ce141bad5..d48e040cd8c 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3404,8 +3404,8 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)  	/* If port is closing, signal caller to try again */  	if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ -		if (info->port.flags & ASYNC_CLOSING) -			interruptible_sleep_on(&info->port.close_wait); +		wait_event_interruptible_tty(tty, info->port.close_wait, +				     !(info->port.flags & ASYNC_CLOSING));  		retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?  			-EAGAIN : -ERESTARTSYS);  		goto cleanup; @@ -7866,6 +7866,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)  					      HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |  					      HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN); +		memset(&new_line, 0, sizeof(new_line));  		switch (flags){  		case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;  		case (HDLC_FLAG_RXC_BRG    | HDLC_FLAG_TXC_BRG):    new_line.clock_type = CLOCK_INT; break; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 1abf946463f..c359a91f734 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -674,8 +674,8 @@ static int open(struct tty_struct *tty, struct file *filp)  	/* If port is closing, signal caller to try again */  	if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ -		if (info->port.flags & ASYNC_CLOSING) -			interruptible_sleep_on(&info->port.close_wait); +		wait_event_interruptible_tty(tty, info->port.close_wait, +					     !(info->port.flags & ASYNC_CLOSING));  		retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?  			-EAGAIN : -ERESTARTSYS);  		goto cleanup; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index dc6e96996ea..53ba8537de8 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -754,8 +754,8 @@ static int open(struct tty_struct *tty, struct file *filp)  	/* If port is closing, signal caller to try again */  	if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ -		if (info->port.flags & ASYNC_CLOSING) -			interruptible_sleep_on(&info->port.close_wait); +		wait_event_interruptible_tty(tty, info->port.close_wait, +					     !(info->port.flags & ASYNC_CLOSING));  		retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?  			-EAGAIN : -ERESTARTSYS);  		goto cleanup; @@ -1766,6 +1766,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)  					      HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |  					      HDLC_FLAG_TXC_BRG    | HDLC_FLAG_TXC_RXCPIN); +		memset(&new_line, 0, sizeof(new_line));  		switch (flags){  		case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;  		case (HDLC_FLAG_RXC_BRG    | HDLC_FLAG_TXC_BRG):    new_line.clock_type = CLOCK_INT; break; diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 40a9fe9d3b1..454b65898e2 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -46,12 +46,13 @@  #include <linux/jiffies.h>  #include <linux/syscalls.h>  #include <linux/of.h> +#include <linux/rcupdate.h>  #include <asm/ptrace.h>  #include <asm/irq_regs.h>  /* Whether we react on sysrq keys or just ignore them */ -static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; +static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;  static bool __read_mostly sysrq_always_enabled;  unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED }; @@ -88,7 +89,7 @@ static void sysrq_handle_loglevel(int key)  	int i;  	i = key - '0'; -	console_loglevel = 7; +	console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;  	printk("Loglevel set to %d\n", i);  	console_loglevel = i;  } @@ -343,7 +344,7 @@ static void send_sig_all(int sig)  static void sysrq_handle_term(int key)  {  	send_sig_all(SIGTERM); -	console_loglevel = 8; +	console_loglevel = CONSOLE_LOGLEVEL_DEBUG;  }  static struct sysrq_key_op sysrq_term_op = {  	.handler	= sysrq_handle_term, @@ -387,7 +388,7 @@ static struct sysrq_key_op sysrq_thaw_op = {  static void sysrq_handle_kill(int key)  {  	send_sig_all(SIGKILL); -	console_loglevel = 8; +	console_loglevel = CONSOLE_LOGLEVEL_DEBUG;  }  static struct sysrq_key_op sysrq_kill_op = {  	.handler	= sysrq_handle_kill, @@ -510,9 +511,9 @@ void __handle_sysrq(int key, bool check_mask)  	struct sysrq_key_op *op_p;  	int orig_log_level;  	int i; -	unsigned long flags; -	spin_lock_irqsave(&sysrq_key_table_lock, flags); +	rcu_sysrq_start(); +	rcu_read_lock();  	/*  	 * Raise the apparent loglevel to maximum so that the sysrq header  	 * is shown to provide the user with positive feedback.  We do not @@ -520,7 +521,7 @@ void __handle_sysrq(int key, bool check_mask)  	 * routing in the consumers of /proc/kmsg.  	 */  	orig_log_level = console_loglevel; -	console_loglevel = 7; +	console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;  	printk(KERN_INFO "SysRq : ");          op_p = __sysrq_get_key_op(key); @@ -554,7 +555,8 @@ void __handle_sysrq(int key, bool check_mask)  		printk("\n");  		console_loglevel = orig_log_level;  	} -	spin_unlock_irqrestore(&sysrq_key_table_lock, flags); +	rcu_read_unlock(); +	rcu_sysrq_end();  }  void handle_sysrq(int key) @@ -1043,16 +1045,23 @@ static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,                                  struct sysrq_key_op *remove_op_p)  {  	int retval; -	unsigned long flags; -	spin_lock_irqsave(&sysrq_key_table_lock, flags); +	spin_lock(&sysrq_key_table_lock);  	if (__sysrq_get_key_op(key) == remove_op_p) {  		__sysrq_put_key_op(key, insert_op_p);  		retval = 0;  	} else {  		retval = -1;  	} -	spin_unlock_irqrestore(&sysrq_key_table_lock, flags); +	spin_unlock(&sysrq_key_table_lock); + +	/* +	 * A concurrent __handle_sysrq either got the old op or the new op. +	 * Wait for it to go away before returning, so the code for an old +	 * op is not freed (eg. on module unload) while it is in use. +	 */ +	synchronize_rcu(); +  	return retval;  } diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index a4fdce74f88..90ca082935f 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c @@ -65,16 +65,17 @@ static void tty_audit_log(const char *description, int major, int minor,  {  	struct audit_buffer *ab;  	struct task_struct *tsk = current; +	pid_t pid = task_pid_nr(tsk);  	uid_t uid = from_kuid(&init_user_ns, task_uid(tsk));  	uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(tsk)); -	u32 sessionid = audit_get_sessionid(tsk); +	unsigned int sessionid = audit_get_sessionid(tsk);  	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);  	if (ab) {  		char name[sizeof(tsk->comm)];  		audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d" -				 " minor=%d comm=", description, tsk->pid, uid, +				 " minor=%d comm=", description, pid, uid,  				 loginuid, sessionid, major, minor);  		get_task_comm(name, tsk);  		audit_log_untrustedstring(ab, name); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index c043136fbe5..143deb62467 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -11,7 +11,6 @@  #include <linux/string.h>  #include <linux/slab.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <linux/wait.h>  #include <linux/bitops.h>  #include <linux/delay.h> @@ -26,7 +25,7 @@   * Byte threshold to limit memory consumption for flip buffers.   * The actual memory limit is > 2x this amount.   */ -#define TTYB_MEM_LIMIT	65536 +#define TTYB_DEFAULT_MEM_LIMIT	65536  /*   * We default to dicing tty buffer allocations to this many characters @@ -61,6 +60,7 @@ void tty_buffer_lock_exclusive(struct tty_port *port)  	atomic_inc(&buf->priority);  	mutex_lock(&buf->lock);  } +EXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive);  void tty_buffer_unlock_exclusive(struct tty_port *port)  { @@ -74,6 +74,7 @@ void tty_buffer_unlock_exclusive(struct tty_port *port)  	if (restart)  		queue_work(system_unbound_wq, &buf->work);  } +EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive);  /**   *	tty_buffer_space_avail	-	return unused buffer space @@ -89,9 +90,10 @@ void tty_buffer_unlock_exclusive(struct tty_port *port)  int tty_buffer_space_avail(struct tty_port *port)  { -	int space = TTYB_MEM_LIMIT - atomic_read(&port->buf.memory_used); +	int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used);  	return max(space, 0);  } +EXPORT_SYMBOL_GPL(tty_buffer_space_avail);  static void tty_buffer_reset(struct tty_buffer *p, size_t size)  { @@ -100,6 +102,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size)  	p->next = NULL;  	p->commit = 0;  	p->read = 0; +	p->flags = 0;  }  /** @@ -129,7 +132,7 @@ void tty_buffer_free_all(struct tty_port *port)  	buf->head = &buf->sentinel;  	buf->tail = &buf->sentinel; -	atomic_set(&buf->memory_used, 0); +	atomic_set(&buf->mem_used, 0);  }  /** @@ -162,7 +165,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)  	/* Should possibly check if this fails for the largest buffer we  	   have queued and recycle that ? */ -	if (atomic_read(&port->buf.memory_used) > TTYB_MEM_LIMIT) +	if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit)  		return NULL;  	p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);  	if (p == NULL) @@ -170,7 +173,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)  found:  	tty_buffer_reset(p, size); -	atomic_add(size, &port->buf.memory_used); +	atomic_add(size, &port->buf.mem_used);  	return p;  } @@ -188,7 +191,7 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)  	struct tty_bufhead *buf = &port->buf;  	/* Dumb strategy for now - should keep some stats */ -	WARN_ON(atomic_sub_return(b->size, &buf->memory_used) < 0); +	WARN_ON(atomic_sub_return(b->size, &buf->mem_used) < 0);  	if (b->size > MIN_TTYB_SIZE)  		kfree(b); @@ -200,9 +203,7 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)   *	tty_buffer_flush		-	flush full tty buffers   *	@tty: tty to flush   * - *	flush all the buffers containing receive data. If the buffer is - *	being processed by flush_to_ldisc then we defer the processing - *	to that function + *	flush all the buffers containing receive data.   *   *	Locking: takes buffer lock to ensure single-threaded flip buffer   *		 'consumer' @@ -230,31 +231,53 @@ void tty_buffer_flush(struct tty_struct *tty)   *	tty_buffer_request_room		-	grow tty buffer if needed   *	@tty: tty structure   *	@size: size desired + *	@flags: buffer flags if new buffer allocated (default = 0)   *   *	Make at least size bytes of linear space available for the tty   *	buffer. If we fail return the size we managed to find. + * + *	Will change over to a new buffer if the current buffer is encoded as + *	TTY_NORMAL (so has no flags buffer) and the new buffer requires + *	a flags buffer.   */ -int tty_buffer_request_room(struct tty_port *port, size_t size) +static int __tty_buffer_request_room(struct tty_port *port, size_t size, +				     int flags)  {  	struct tty_bufhead *buf = &port->buf;  	struct tty_buffer *b, *n; -	int left; +	int left, change;  	b = buf->tail; -	left = b->size - b->used; +	if (b->flags & TTYB_NORMAL) +		left = 2 * b->size - b->used; +	else +		left = b->size - b->used; -	if (left < size) { +	change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL); +	if (change || left < size) {  		/* This is the slow path - looking for new buffers to use */  		if ((n = tty_buffer_alloc(port, size)) != NULL) { +			n->flags = flags;  			buf->tail = n;  			b->commit = b->used; -			smp_mb(); +			/* paired w/ barrier in flush_to_ldisc(); ensures the +			 * latest commit value can be read before the head is +			 * advanced to the next buffer +			 */ +			smp_wmb();  			b->next = n; -		} else +		} else if (change) +			size = 0; +		else  			size = left;  	}  	return size;  } + +int tty_buffer_request_room(struct tty_port *port, size_t size) +{ +	return __tty_buffer_request_room(port, size, 0); +}  EXPORT_SYMBOL_GPL(tty_buffer_request_room);  /** @@ -274,12 +297,14 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,  	int copied = 0;  	do {  		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); -		int space = tty_buffer_request_room(port, goal); +		int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; +		int space = __tty_buffer_request_room(port, goal, flags);  		struct tty_buffer *tb = port->buf.tail;  		if (unlikely(space == 0))  			break;  		memcpy(char_buf_ptr(tb, tb->used), chars, space); -		memset(flag_buf_ptr(tb, tb->used), flag, space); +		if (~tb->flags & TTYB_NORMAL) +			memset(flag_buf_ptr(tb, tb->used), flag, space);  		tb->used += space;  		copied += space;  		chars += space; @@ -332,14 +357,11 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);   *	Takes any pending buffers and transfers their ownership to the   *	ldisc side of the queue. It then schedules those characters for   *	processing by the line discipline. - *	Note that this function can only be used when the low_latency flag - *	is unset. Otherwise the workqueue won't be flushed.   */  void tty_schedule_flip(struct tty_port *port)  {  	struct tty_bufhead *buf = &port->buf; -	WARN_ON(port->low_latency);  	buf->tail->commit = buf->tail->used;  	schedule_work(&buf->work); @@ -362,52 +384,28 @@ EXPORT_SYMBOL(tty_schedule_flip);  int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,  		size_t size)  { -	int space = tty_buffer_request_room(port, size); +	int space = __tty_buffer_request_room(port, size, TTYB_NORMAL);  	if (likely(space)) {  		struct tty_buffer *tb = port->buf.tail;  		*chars = char_buf_ptr(tb, tb->used); -		memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space); +		if (~tb->flags & TTYB_NORMAL) +			memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);  		tb->used += space;  	}  	return space;  }  EXPORT_SYMBOL_GPL(tty_prepare_flip_string); -/** - *	tty_prepare_flip_string_flags	-	make room for characters - *	@port: tty port - *	@chars: return pointer for character write area - *	@flags: return pointer for status flag write area - *	@size: desired size - * - *	Prepare a block of space in the buffer for data. Returns the length - *	available and buffer pointer to the space which is now allocated and - *	accounted for as ready for characters. This is used for drivers - *	that need their own block copy routines into the buffer. There is no - *	guarantee the buffer is a DMA target! - */ - -int tty_prepare_flip_string_flags(struct tty_port *port, -			unsigned char **chars, char **flags, size_t size) -{ -	int space = tty_buffer_request_room(port, size); -	if (likely(space)) { -		struct tty_buffer *tb = port->buf.tail; -		*chars = char_buf_ptr(tb, tb->used); -		*flags = flag_buf_ptr(tb, tb->used); -		tb->used += space; -	} -	return space; -} -EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); -  static int  receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)  {  	struct tty_ldisc *disc = tty->ldisc;  	unsigned char *p = char_buf_ptr(head, head->read); -	char	      *f = flag_buf_ptr(head, head->read); +	char	      *f = NULL; + +	if (~head->flags & TTYB_NORMAL) +		f = flag_buf_ptr(head, head->read);  	if (disc->ops->receive_buf2)  		count = disc->ops->receive_buf2(tty, p, f, count); @@ -452,17 +450,24 @@ static void flush_to_ldisc(struct work_struct *work)  	while (1) {  		struct tty_buffer *head = buf->head; +		struct tty_buffer *next;  		int count;  		/* Ldisc or user is trying to gain exclusive access */  		if (atomic_read(&buf->priority))  			break; +		next = head->next; +		/* paired w/ barrier in __tty_buffer_request_room(); +		 * ensures commit value read is not stale if the head +		 * is advancing to the next buffer +		 */ +		smp_rmb();  		count = head->commit - head->read;  		if (!count) { -			if (head->next == NULL) +			if (next == NULL)  				break; -			buf->head = head->next; +			buf->head = next;  			tty_buffer_free(port, head);  			continue;  		} @@ -487,17 +492,15 @@ static void flush_to_ldisc(struct work_struct *work)   */  void tty_flush_to_ldisc(struct tty_struct *tty)  { -	if (!tty->port->low_latency) -		flush_work(&tty->port->buf.work); +	flush_work(&tty->port->buf.work);  }  /**   *	tty_flip_buffer_push	-	terminal   *	@port: tty port to push   * - *	Queue a push of the terminal flip buffers to the line discipline. This - *	function must not be called from IRQ context if port->low_latency is - *	set. + *	Queue a push of the terminal flip buffers to the line discipline. + *	Can be called from IRQ/atomic context.   *   *	In the event of the queue being busy for flipping the work will be   *	held off and retried later. @@ -505,14 +508,7 @@ void tty_flush_to_ldisc(struct tty_struct *tty)  void tty_flip_buffer_push(struct tty_port *port)  { -	struct tty_bufhead *buf = &port->buf; - -	buf->tail->commit = buf->tail->used; - -	if (port->low_latency) -		flush_to_ldisc(&buf->work); -	else -		schedule_work(&buf->work); +	tty_schedule_flip(port);  }  EXPORT_SYMBOL(tty_flip_buffer_push); @@ -533,7 +529,25 @@ void tty_buffer_init(struct tty_port *port)  	buf->head = &buf->sentinel;  	buf->tail = &buf->sentinel;  	init_llist_head(&buf->free); -	atomic_set(&buf->memory_used, 0); +	atomic_set(&buf->mem_used, 0);  	atomic_set(&buf->priority, 0);  	INIT_WORK(&buf->work, flush_to_ldisc); +	buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT; +} + +/** + *	tty_buffer_set_limit	-	change the tty buffer memory limit + *	@port: tty port to change + * + *	Change the tty buffer memory limit. + *	Must be called before the other tty buffer functions are used. + */ + +int tty_buffer_set_limit(struct tty_port *port, int limit) +{ +	if (limit < MIN_TTYB_SIZE) +		return -EINVAL; +	port->buf.mem_limit = limit; +	return 0;  } +EXPORT_SYMBOL_GPL(tty_buffer_set_limit); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index a9355ce1c6d..34110719fe0 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -854,7 +854,8 @@ void disassociate_ctty(int on_exit)  			struct pid *tty_pgrp = tty_get_pgrp(tty);  			if (tty_pgrp) {  				kill_pgrp(tty_pgrp, SIGHUP, on_exit); -				kill_pgrp(tty_pgrp, SIGCONT, on_exit); +				if (!on_exit) +					kill_pgrp(tty_pgrp, SIGCONT, on_exit);  				put_pid(tty_pgrp);  			}  		} @@ -877,9 +878,8 @@ void disassociate_ctty(int on_exit)  	spin_lock_irq(¤t->sighand->siglock);  	put_pid(current->signal->tty_old_pgrp);  	current->signal->tty_old_pgrp = NULL; -	spin_unlock_irq(¤t->sighand->siglock); -	tty = get_current_tty(); +	tty = tty_kref_get(current->signal->tty);  	if (tty) {  		unsigned long flags;  		spin_lock_irqsave(&tty->ctrl_lock, flags); @@ -896,6 +896,7 @@ void disassociate_ctty(int on_exit)  #endif  	} +	spin_unlock_irq(¤t->sighand->siglock);  	/* Now clear signal->tty under the lock */  	read_lock(&tasklist_lock);  	session_clear_tty(task_session(current)); @@ -1270,12 +1271,13 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)   *   *	Locking: None   */ -static void tty_line_name(struct tty_driver *driver, int index, char *p) +static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)  {  	if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE) -		strcpy(p, driver->name); +		return sprintf(p, "%s", driver->name);  	else -		sprintf(p, "%s%d", driver->name, index + driver->name_base); +		return sprintf(p, "%s%d", driver->name, +			       index + driver->name_base);  }  /** @@ -2085,6 +2087,7 @@ retry_open:  			filp->f_op = &tty_fops;  		goto retry_open;  	} +	clear_bit(TTY_HUPPED, &tty->flags);  	tty_unlock(tty); @@ -3543,9 +3546,19 @@ static ssize_t show_cons_active(struct device *dev,  		if (i >= ARRAY_SIZE(cs))  			break;  	} -	while (i--) -		count += sprintf(buf + count, "%s%d%c", -				 cs[i]->name, cs[i]->index, i ? ' ':'\n'); +	while (i--) { +		int index = cs[i]->index; +		struct tty_driver *drv = cs[i]->device(cs[i], &index); + +		/* don't resolve tty0 as some programs depend on it */ +		if (drv && (cs[i]->index > 0 || drv->major != TTY_MAJOR)) +			count += tty_line_name(drv, index, buf + count); +		else +			count += sprintf(buf + count, "%s%d", +					 cs[i]->name, cs[i]->index); + +		count += sprintf(buf + count, "%c", i ? ' ':'\n'); +	}  	console_unlock();  	return count; diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 03ba081c577..6fd60fece6b 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -1201,6 +1201,9 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,  		}  		return 0;  	case TCFLSH: +		retval = tty_check_change(tty); +		if (retval) +			return retval;  		return __tty_perform_flush(tty, arg);  	default:  		/* Try the mode commands */ diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 6458e11e8e9..2d822aa259b 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -11,7 +11,6 @@  #include <linux/slab.h>  #include <linux/poll.h>  #include <linux/proc_fs.h> -#include <linux/init.h>  #include <linux/module.h>  #include <linux/device.h>  #include <linux/wait.h> diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c index 22fad8ad5ac..0ffb0cbe282 100644 --- a/drivers/tty/tty_ldsem.c +++ b/drivers/tty/tty_ldsem.c @@ -39,17 +39,10 @@  				lock_acquire(&(l)->dep_map, s, t, r, c, n, i)  # define __rel(l, n, i)				\  				lock_release(&(l)->dep_map, n, i) -# ifdef CONFIG_PROVE_LOCKING -#  define lockdep_acquire(l, s, t, i)		__acq(l, s, t, 0, 2, NULL, i) -#  define lockdep_acquire_nest(l, s, t, n, i)	__acq(l, s, t, 0, 2, n, i) -#  define lockdep_acquire_read(l, s, t, i)	__acq(l, s, t, 1, 2, NULL, i) -#  define lockdep_release(l, n, i)		__rel(l, n, i) -# else -#  define lockdep_acquire(l, s, t, i)		__acq(l, s, t, 0, 1, NULL, i) -#  define lockdep_acquire_nest(l, s, t, n, i)	__acq(l, s, t, 0, 1, n, i) -#  define lockdep_acquire_read(l, s, t, i)	__acq(l, s, t, 1, 1, NULL, i) -#  define lockdep_release(l, n, i)		__rel(l, n, i) -# endif +#define lockdep_acquire(l, s, t, i)		__acq(l, s, t, 0, 1, NULL, i) +#define lockdep_acquire_nest(l, s, t, n, i)	__acq(l, s, t, 0, 1, n, i) +#define lockdep_acquire_read(l, s, t, i)	__acq(l, s, t, 1, 1, NULL, i) +#define lockdep_release(l, n, i)		__rel(l, n, i)  #else  # define lockdep_acquire(l, s, t, i)		do { } while (0)  # define lockdep_acquire_nest(l, s, t, n, i)	do { } while (0) @@ -86,11 +79,21 @@ static inline long ldsem_atomic_update(long delta, struct ld_semaphore *sem)  	return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);  } +/* + * ldsem_cmpxchg() updates @*old with the last-known sem->count value. + * Returns 1 if count was successfully changed; @*old will have @new value. + * Returns 0 if count was not changed; @*old will have most recent sem->count + */  static inline int ldsem_cmpxchg(long *old, long new, struct ld_semaphore *sem)  { -	long tmp = *old; -	*old = atomic_long_cmpxchg(&sem->count, *old, new); -	return *old == tmp; +	long tmp = atomic_long_cmpxchg(&sem->count, *old, new); +	if (tmp == *old) { +		*old = new; +		return 1; +	} else { +		*old = tmp; +		return 0; +	}  }  /* diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index f597e88a705..3f746c8eb0d 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -12,7 +12,6 @@  #include <linux/string.h>  #include <linux/slab.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <linux/wait.h>  #include <linux/bitops.h>  #include <linux/delay.h> @@ -140,6 +139,10 @@ EXPORT_SYMBOL(tty_port_destroy);  static void tty_port_destructor(struct kref *kref)  {  	struct tty_port *port = container_of(kref, struct tty_port, kref); + +	/* check if last port ref was dropped before tty release */ +	if (WARN_ON(port->itty)) +		return;  	if (port->xmit_buf)  		free_page((unsigned long)port->xmit_buf);  	tty_port_destroy(port); @@ -480,8 +483,6 @@ int tty_port_close_start(struct tty_port *port,  	if (port->count) {  		spin_unlock_irqrestore(&port->lock, flags); -		if (port->ops->drop) -			port->ops->drop(port);  		return 0;  	}  	set_bit(ASYNCB_CLOSING, &port->flags); @@ -500,9 +501,7 @@ int tty_port_close_start(struct tty_port *port,  	/* Flush the ldisc buffering */  	tty_ldisc_flush(tty); -	/* Don't call port->drop for the last reference. Callers will want -	   to drop the last active reference in ->shutdown() or the tty -	   shutdown path */ +	/* Report to caller this is the last port reference */  	return 1;  }  EXPORT_SYMBOL(tty_port_close_start); diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 2978ca596a7..610b720d3b9 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -179,7 +179,6 @@ struct uni_pagedir {  	unsigned long	sum;  	unsigned char	*inverse_translations[4];  	u16		*inverse_trans_unicode; -	int		readonly;  };  static struct uni_pagedir *dflt; @@ -262,7 +261,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)  	int m;  	if (glyph < 0 || glyph >= MAX_GLYPH)  		return 0; -	else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc)) +	else if (!(p = *conp->vc_uni_pagedir_loc))  		return glyph;  	else if (use_unicode) {  		if (!p->inverse_trans_unicode) @@ -287,7 +286,7 @@ static void update_user_maps(void)  	for (i = 0; i < MAX_NR_CONSOLES; i++) {  		if (!vc_cons_allocated(i))  			continue; -		p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; +		p = *vc_cons[i].d->vc_uni_pagedir_loc;  		if (p && p != q) {  			set_inverse_transl(vc_cons[i].d, p, USER_MAP);  			set_inverse_trans_unicode(vc_cons[i].d, p); @@ -418,10 +417,10 @@ void con_free_unimap(struct vc_data *vc)  {  	struct uni_pagedir *p; -	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; +	p = *vc->vc_uni_pagedir_loc;  	if (!p)  		return; -	*vc->vc_uni_pagedir_loc = 0; +	*vc->vc_uni_pagedir_loc = NULL;  	if (--p->refcount)  		return;  	con_release_unimap(p); @@ -436,7 +435,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)  	for (i = 0; i < MAX_NR_CONSOLES; i++) {  		if (!vc_cons_allocated(i))  			continue; -		q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; +		q = *vc_cons[i].d->vc_uni_pagedir_loc;  		if (!q || q == p || q->sum != p->sum)  			continue;  		for (j = 0; j < 32; j++) { @@ -459,7 +458,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)  		}  		if (j == 32) {  			q->refcount++; -			*conp->vc_uni_pagedir_loc = (unsigned long)q; +			*conp->vc_uni_pagedir_loc = q;  			con_release_unimap(p);  			kfree(p);  			return 1; @@ -500,10 +499,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)  {  	struct uni_pagedir *p, *q; -	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; -	if (p && p->readonly) -		return -EIO; - +	p = *vc->vc_uni_pagedir_loc;  	if (!p || --p->refcount) {  		q = kzalloc(sizeof(*p), GFP_KERNEL);  		if (!q) { @@ -512,7 +508,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)  			return -ENOMEM;  		}  		q->refcount=1; -		*vc->vc_uni_pagedir_loc = (unsigned long)q; +		*vc->vc_uni_pagedir_loc = q;  	} else {  		if (p == dflt) dflt = NULL;  		p->refcount++; @@ -536,19 +532,13 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)  	int err = 0, err1, i;  	struct uni_pagedir *p, *q; +	if (!ct) +		return 0; +  	console_lock();  	/* Save original vc_unipagdir_loc in case we allocate a new one */ -	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; -	if (p->readonly) { -		console_unlock(); -		return -EIO; -	} -	 -	if (!ct) { -		console_unlock(); -		return 0; -	} +	p = *vc->vc_uni_pagedir_loc;  	if (p->refcount > 1) {  		int j, k; @@ -564,7 +554,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)  		 * Since refcount was > 1, con_clear_unimap() allocated a  		 * a new uni_pagedir for this vc.  Re: p != q  		 */ -		q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; +		q = *vc->vc_uni_pagedir_loc;  		/*  		 * uni_pgdir is a 32*32*64 table with rows allocated @@ -586,7 +576,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)  					err1 = con_insert_unipair(q, l, p2[k]);  					if (err1) {  						p->refcount++; -						*vc->vc_uni_pagedir_loc = (unsigned long)p; +						*vc->vc_uni_pagedir_loc = p;  						con_release_unimap(q);  						kfree(q);  						console_unlock(); @@ -655,12 +645,12 @@ int con_set_default_unimap(struct vc_data *vc)  	struct uni_pagedir *p;  	if (dflt) { -		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; +		p = *vc->vc_uni_pagedir_loc;  		if (p == dflt)  			return 0;  		dflt->refcount++; -		*vc->vc_uni_pagedir_loc = (unsigned long)dflt; +		*vc->vc_uni_pagedir_loc = dflt;  		if (p && !--p->refcount) {  			con_release_unimap(p);  			kfree(p); @@ -674,7 +664,7 @@ int con_set_default_unimap(struct vc_data *vc)  	if (err)  		return err; -	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; +	p = *vc->vc_uni_pagedir_loc;  	q = dfont_unitable;  	for (i = 0; i < 256; i++) @@ -685,7 +675,7 @@ int con_set_default_unimap(struct vc_data *vc)  		}  	if (con_unify_unimap(vc, p)) { -		dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; +		dflt = *vc->vc_uni_pagedir_loc;  		return err;  	} @@ -713,9 +703,9 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)  	if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)  		return 0;  	con_free_unimap(dst_vc); -	q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc; +	q = *src_vc->vc_uni_pagedir_loc;  	q->refcount++; -	*dst_vc->vc_uni_pagedir_loc = (long)q; +	*dst_vc->vc_uni_pagedir_loc = q;  	return 0;  }  EXPORT_SYMBOL(con_copy_unimap); @@ -737,7 +727,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni  	ect = 0;  	if (*vc->vc_uni_pagedir_loc) { -		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; +		p = *vc->vc_uni_pagedir_loc;  		for (i = 0; i < 32; i++)  		if ((p1 = p->uni_pgdir[i]))  			for (j = 0; j < 32; j++) @@ -810,7 +800,7 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)  	if (!*conp->vc_uni_pagedir_loc)  		return -3; -	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;   +	p = *conp->vc_uni_pagedir_loc;  	if ((p1 = p->uni_pgdir[ucs >> 11]) &&  	    (p2 = p1[(ucs >> 6) & 0x1f]) &&  	    (h = p2[ucs & 0x3f]) < MAX_GLYPH) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 9a8e8c5a0c7..b33b00b386d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -735,7 +735,7 @@ static void visual_init(struct vc_data *vc, int num, int init)  	vc->vc_num = num;  	vc->vc_display_fg = &master_display_fg;  	vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; -	vc->vc_uni_pagedir = 0; +	vc->vc_uni_pagedir = NULL;  	vc->vc_hi_font_mask = 0;  	vc->vc_complement_mask = 0;  	vc->vc_can_do_color = 0; @@ -1164,6 +1164,8 @@ static void csi_J(struct vc_data *vc, int vpar)  			scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,  				    vc->vc_screenbuf_size >> 1);  			set_origin(vc); +			if (CON_IS_VISIBLE(vc)) +				update_screen(vc);  			/* fall through */  		case 2: /* erase whole display */  			count = vc->vc_cols * vc->vc_rows; @@ -1229,6 +1231,52 @@ static void default_attr(struct vc_data *vc)  	vc->vc_color = vc->vc_def_color;  } +struct rgb { u8 r; u8 g; u8 b; }; + +struct rgb rgb_from_256(int i) +{ +	struct rgb c; +	if (i < 8) {            /* Standard colours. */ +		c.r = i&1 ? 0xaa : 0x00; +		c.g = i&2 ? 0xaa : 0x00; +		c.b = i&4 ? 0xaa : 0x00; +	} else if (i < 16) { +		c.r = i&1 ? 0xff : 0x55; +		c.g = i&2 ? 0xff : 0x55; +		c.b = i&4 ? 0xff : 0x55; +	} else if (i < 232) {   /* 6x6x6 colour cube. */ +		c.r = (i - 16) / 36 * 85 / 2; +		c.g = (i - 16) / 6 % 6 * 85 / 2; +		c.b = (i - 16) % 6 * 85 / 2; +	} else                  /* Grayscale ramp. */ +		c.r = c.g = c.b = i * 10 - 2312; +	return c; +} + +static void rgb_foreground(struct vc_data *vc, struct rgb c) +{ +	u8 hue, max = c.r; +	if (c.g > max) +		max = c.g; +	if (c.b > max) +		max = c.b; +	hue = (c.r > max/2 ? 4 : 0) +	    | (c.g > max/2 ? 2 : 0) +	    | (c.b > max/2 ? 1 : 0); +	if (hue == 7 && max <= 0x55) +		hue = 0, vc->vc_intensity = 2; +	else +		vc->vc_intensity = (max > 0xaa) + 1; +	vc->vc_color = (vc->vc_color & 0xf0) | hue; +} + +static void rgb_background(struct vc_data *vc, struct rgb c) +{ +	/* For backgrounds, err on the dark side. */ +	vc->vc_color = (vc->vc_color & 0x0f) +		| (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3; +} +  /* console_lock is held */  static void csi_m(struct vc_data *vc)  { @@ -1300,21 +1348,55 @@ static void csi_m(struct vc_data *vc)  			case 27:  				vc->vc_reverse = 0;  				break; -			case 38: /* ANSI X3.64-1979 (SCO-ish?) -				  * Enables underscore, white foreground -				  * with white underscore (Linux - use -				  * default foreground). +			case 38: /* ITU T.416 +				  * Higher colour modes. +				  * They break the usual properties of SGR codes +				  * and thus need to be detected and ignored by +				  * hand.  Strictly speaking, that standard also +				  * wants : rather than ; as separators, contrary +				  * to ECMA-48, but no one produces such codes +				  * and almost no one accepts them.  				  */ -				vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); -				vc->vc_underline = 1; +				i++; +				if (i > vc->vc_npar) +					break; +				if (vc->vc_par[i] == 5 &&  /* 256 colours */ +				    i < vc->vc_npar) {     /* ubiquitous */ +					i++; +					rgb_foreground(vc, +						rgb_from_256(vc->vc_par[i])); +				} else if (vc->vc_par[i] == 2 &&  /* 24 bit */ +				           i <= vc->vc_npar + 3) {/* extremely rare */ +					struct rgb c = {r:vc->vc_par[i+1], +							g:vc->vc_par[i+2], +							b:vc->vc_par[i+3]}; +					rgb_foreground(vc, c); +					i += 3; +				} +				/* Subcommands 3 (CMY) and 4 (CMYK) are so insane +				 * there's no point in supporting them. +				 */  				break; -			case 39: /* ANSI X3.64-1979 (SCO-ish?) -				  * Disable underline option. -				  * Reset colour to default? It did this -				  * before... -				  */ +			case 48: +				i++; +				if (i > vc->vc_npar) +					break; +				if (vc->vc_par[i] == 5 &&  /* 256 colours */ +				    i < vc->vc_npar) { +					i++; +					rgb_background(vc, +						rgb_from_256(vc->vc_par[i])); +				} else if (vc->vc_par[i] == 2 && /* 24 bit */ +				           i <= vc->vc_npar + 3) { +					struct rgb c = {r:vc->vc_par[i+1], +							g:vc->vc_par[i+2], +							b:vc->vc_par[i+3]}; +					rgb_background(vc, c); +					i += 3; +				} +				break; +			case 39:  				vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); -				vc->vc_underline = 0;  				break;  			case 49:  				vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f); @@ -1579,9 +1661,9 @@ static void restore_cur(struct vc_data *vc)  	vc->vc_need_wrap = 0;  } -enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,  	EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, -	ESpalette }; +	ESpalette, ESosc };  /* console_lock is held (except via vc_init()) */  static void reset_terminal(struct vc_data *vc, int do_clear) @@ -1641,11 +1723,15 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)  	 *  Control characters can be used in the _middle_  	 *  of an escape sequence.  	 */ +	if (vc->vc_state == ESosc && c>=8 && c<=13) /* ... except for OSC */ +		return;  	switch (c) {  	case 0:  		return;  	case 7: -		if (vc->vc_bell_duration) +		if (vc->vc_state == ESosc) +			vc->vc_state = ESnormal; +		else if (vc->vc_bell_duration)  			kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);  		return;  	case 8: @@ -1756,7 +1842,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)  		} else if (c=='R') {   /* reset palette */  			reset_palette(vc);  			vc->vc_state = ESnormal; -		} else +		} else if (c>='0' && c<='9') +			vc->vc_state = ESosc; +		else  			vc->vc_state = ESnormal;  		return;  	case ESpalette: @@ -1796,9 +1884,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)  			vc->vc_par[vc->vc_npar] *= 10;  			vc->vc_par[vc->vc_npar] += c - '0';  			return; -		} else -			vc->vc_state = ESgotpars; -	case ESgotpars: +		}  		vc->vc_state = ESnormal;  		switch(c) {  		case 'h': @@ -2012,6 +2098,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)  			vc->vc_translate = set_translate(vc->vc_G1_charset, vc);  		vc->vc_state = ESnormal;  		return; +	case ESosc: +		return;  	default:  		vc->vc_state = ESnormal;  	} @@ -3138,8 +3226,7 @@ int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt  	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {  		con_back = ®istered_con_driver[i]; -		if (con_back->con && -		    !(con_back->flag & CON_DRIVER_FLAG_MODULE)) { +		if (con_back->con && con_back->con != csw) {  			defcsw = con_back->con;  			retval = 0;  			break; @@ -3244,6 +3331,7 @@ static int vt_unbind(struct con_driver *con)  {  	const struct consw *csw = NULL;  	int i, more = 1, first = -1, last = -1, deflt = 0; +	int ret;   	if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||  	    con_is_graphics(con->con, con->first, con->last)) @@ -3269,8 +3357,10 @@ static int vt_unbind(struct con_driver *con)  		if (first != -1) {  			console_lock(); -			do_unbind_con_driver(csw, first, last, deflt); +			ret = do_unbind_con_driver(csw, first, last, deflt);  			console_unlock(); +			if (ret != 0) +				return ret;  		}  		first = -1; @@ -3557,17 +3647,20 @@ err:   */  int do_unregister_con_driver(const struct consw *csw)  { -	int i, retval = -ENODEV; +	int i;  	/* cannot unregister a bound driver */  	if (con_is_bound(csw)) -		goto err; +		return -EBUSY; + +	if (csw == conswitchp) +		return -EINVAL;  	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {  		struct con_driver *con_driver = ®istered_con_driver[i];  		if (con_driver->con == csw && -		    con_driver->flag & CON_DRIVER_FLAG_MODULE) { +		    con_driver->flag & CON_DRIVER_FLAG_INIT) {  			vtconsole_deinit_device(con_driver);  			device_destroy(vtconsole_class,  				       MKDEV(0, con_driver->node)); @@ -3578,12 +3671,11 @@ int do_unregister_con_driver(const struct consw *csw)  			con_driver->flag = 0;  			con_driver->first = 0;  			con_driver->last = 0; -			retval = 0; -			break; +			return 0;  		}  	} -err: -	return retval; + +	return -ENODEV;  }  EXPORT_SYMBOL_GPL(do_unregister_con_driver);  | 
