From 47948d2bd6d27648a107a27357b3bc5ad054ff64 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Apr 2009 11:42:47 +0900 Subject: serial: sh-sci: SH7724 support. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.h | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index d0aa82d7fce..84cc6512f08 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -91,6 +91,9 @@ # define SCSPTR5 0xa4050128 # define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7724) +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ @@ -361,7 +364,8 @@ h8_sci_offset, h8_sci_size) \ CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \ CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \ @@ -390,7 +394,8 @@ SCIF_FNS(SCFDR, 0x1c, 16) SCIF_FNS(SCxTDR, 0x20, 8) SCIF_FNS(SCxRDR, 0x24, 8) SCIF_FNS(SCLSR, 0x24, 16) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8) SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16) @@ -604,6 +609,17 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */ return 1; } +#elif defined(CONFIG_CPU_SUBTYPE_SH7724) +# define SCFSR 0x0010 +# define SCASSR 0x0014 +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->type == PORT_SCIF) + return ctrl_inw((port->mapbase + SCFSR)) & SCIF_BRK ? 1 : 0; + if (port->type == PORT_SCIFA) + return ctrl_inw((port->mapbase + SCASSR)) & SCIF_BRK ? 1 : 0; + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) static inline int sci_rxd_in(struct uart_port *port) { @@ -757,7 +773,8 @@ static inline int sci_rxd_in(struct uart_port *port) defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) static inline int scbrr_calc(struct uart_port *port, int bps, int clk) { if (port->type == PORT_SCIF) -- cgit v1.2.3 From 0fb849b9d743a20056f2418cd955e5c650658663 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 7 May 2009 18:10:27 +0900 Subject: sh: Integrate the SH-5 onchip_remap() more coherently. Presently this is special-cased for early initialization. While there are situations where these static early initializations are still necessary, with minor changes it is possible to use this for the regular ioremap implementation as well. This allows us to kill off the special-casing for the remap completely and to start tidying up all of the SH-5 special-casing in drivers. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index dbf5357a77b..728d6a062bf 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -985,13 +985,7 @@ static void sci_config_port(struct uart_port *port, int flags) port->type = s->type; if (port->flags & UPF_IOREMAP && !port->membase) { -#if defined(CONFIG_SUPERH64) - port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF"); - port->membase = (void __iomem *)port->mapbase; -#else port->membase = ioremap_nocache(port->mapbase, 0x40); -#endif - dev_err(port->dev, "can't remap port#%d\n", port->line); } } -- cgit v1.2.3 From 8c8fdbc9bd9718b21146065de61c0cafdff11ecb Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 1 Apr 2009 12:40:15 +0200 Subject: [ARM] Remove arch-imx from build system arch-imx is superseeded by the MXC architecture support. This patch removes arch-imx from the build system. Signed-off-by: Sascha Hauer --- drivers/serial/imx.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 9f460b175c5..3f5d5a20048 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -66,7 +66,7 @@ #define ONEMS 0xb0 /* One Millisecond register */ #define UTS 0xb4 /* UART Test Register */ #endif -#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1) +#ifdef CONFIG_ARCH_MX1 #define BIPR1 0xb0 /* Incremental Preset Register 1 */ #define BIPR2 0xb4 /* Incremental Preset Register 2 */ #define BIPR3 0xb8 /* Incremental Preset Register 3 */ @@ -96,7 +96,7 @@ #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ #define UCR1_SNDBRK (1<<4) /* Send break */ #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ -#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1) +#ifdef CONFIG_ARCH_MX1 #define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ #endif #if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2 @@ -127,7 +127,7 @@ #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 */ -#ifdef CONFIG_ARCH_IMX +#ifdef CONFIG_ARCH_MX1 #define UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ #define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ #endif @@ -180,13 +180,6 @@ #define UTS_SOFTRST (1<<0) /* Software reset */ /* We've been assigned a range on the "Low-density serial ports" major */ -#ifdef CONFIG_ARCH_IMX -#define SERIAL_IMX_MAJOR 204 -#define MINOR_START 41 -#define DEV_NAME "ttySMX" -#define MAX_INTERNAL_IRQ IMX_IRQS -#endif - #ifdef CONFIG_ARCH_MXC #define SERIAL_IMX_MAJOR 207 #define MINOR_START 16 -- cgit v1.2.3 From e552de2413edad1a7b0c7f82a2f2753e4f905d93 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 21 Jan 2009 15:13:42 +0000 Subject: sh-sci: add platform device private data This patch adds per-platform private data to the sh-sci driver. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 127 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 42 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 728d6a062bf..af5da110d52 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef CONFIG_SUPERH #include @@ -77,6 +78,16 @@ struct sci_port { #ifdef CONFIG_HAVE_CLK /* Port clock */ struct clk *clk; +#endif + struct list_head node; +}; + +struct sh_sci_priv { + spinlock_t lock; + struct list_head ports; + +#ifdef CONFIG_HAVE_CLK + struct notifier_block clk_nb; #endif }; @@ -726,19 +737,22 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p) { - int i; + struct sh_sci_priv *priv = container_of(self, + struct sh_sci_priv, clk_nb); + struct sci_port *sci_port; + unsigned long flags; if ((phase == CPUFREQ_POSTCHANGE) || - (phase == CPUFREQ_RESUMECHANGE)) - for (i = 0; i < SCI_NPORTS; i++) { - struct sci_port *s = &sci_ports[i]; - s->port.uartclk = clk_get_rate(s->clk); - } + (phase == CPUFREQ_RESUMECHANGE)) { + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(sci_port, &priv->ports, node) + sci_port->port.uartclk = clk_get_rate(sci_port->clk); + + spin_unlock_irqrestore(&priv->lock, flags); + } return NOTIFY_OK; } - -static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; #endif static int sci_request_irq(struct sci_port *port) @@ -1201,6 +1215,27 @@ static struct uart_driver sci_uart_driver = { .cons = SCI_CONSOLE, }; + +static int __devexit sci_remove(struct platform_device *dev) +{ + struct sh_sci_priv *priv = platform_get_drvdata(dev); + struct sci_port *p; + unsigned long flags; + +#ifdef CONFIG_HAVE_CLK + cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); +#endif + + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(p, &priv->ports, node) + uart_remove_one_port(&sci_uart_driver, &p->port); + + spin_unlock_irqrestore(&priv->lock, flags); + + kfree(priv); + return 0; +} + /* * Register a set of serial devices attached to a platform device. The * list is terminated with a zero flags entry, which means we expect @@ -1210,7 +1245,22 @@ static struct uart_driver sci_uart_driver = { static int __devinit sci_probe(struct platform_device *dev) { struct plat_sci_port *p = dev->dev.platform_data; + struct sh_sci_priv *priv; int i, ret = -EINVAL; + unsigned long flags; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + INIT_LIST_HEAD(&priv->ports); + spin_lock_init(&priv->lock); + platform_set_drvdata(dev, priv); + +#ifdef CONFIG_HAVE_CLK + priv->clk_nb.notifier_call = sci_notifier; + cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); +#endif for (i = 0; p && p->flags != 0; p++, i++) { struct sci_port *sciport = &sci_ports[i]; @@ -1254,12 +1304,19 @@ static int __devinit sci_probe(struct platform_device *dev) memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); - uart_add_one_port(&sci_uart_driver, &sciport->port); - } + ret = uart_add_one_port(&sci_uart_driver, &sciport->port); -#ifdef CONFIG_HAVE_CLK - cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); -#endif + if (ret && (p->flags & UPF_IOREMAP)) { + iounmap(p->membase); + goto err_unreg; + } + + INIT_LIST_HEAD(&sciport->node); + + spin_lock_irqsave(&priv->lock, flags); + list_add(&sciport->node, &priv->ports); + spin_unlock_irqrestore(&priv->lock, flags); + } #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_gdb_detach(); @@ -1268,50 +1325,36 @@ static int __devinit sci_probe(struct platform_device *dev) return 0; err_unreg: - for (i = i - 1; i >= 0; i--) - uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); - + sci_remove(dev); return ret; } -static int __devexit sci_remove(struct platform_device *dev) -{ - int i; - -#ifdef CONFIG_HAVE_CLK - cpufreq_unregister_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); -#endif - - for (i = 0; i < SCI_NPORTS; i++) - uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); - - return 0; -} - static int sci_suspend(struct platform_device *dev, pm_message_t state) { - int i; + struct sh_sci_priv *priv = platform_get_drvdata(dev); + struct sci_port *p; + unsigned long flags; - for (i = 0; i < SCI_NPORTS; i++) { - struct sci_port *p = &sci_ports[i]; + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(p, &priv->ports, node) + uart_suspend_port(&sci_uart_driver, &p->port); - if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) - uart_suspend_port(&sci_uart_driver, &p->port); - } + spin_unlock_irqrestore(&priv->lock, flags); return 0; } static int sci_resume(struct platform_device *dev) { - int i; + struct sh_sci_priv *priv = platform_get_drvdata(dev); + struct sci_port *p; + unsigned long flags; - for (i = 0; i < SCI_NPORTS; i++) { - struct sci_port *p = &sci_ports[i]; + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(p, &priv->ports, node) + uart_resume_port(&sci_uart_driver, &p->port); - if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) - uart_resume_port(&sci_uart_driver, &p->port); - } + spin_unlock_irqrestore(&priv->lock, flags); return 0; } -- cgit v1.2.3 From 9080b72819650c3a757d173a19bc930d603b79d6 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 21 Jan 2009 15:13:58 +0000 Subject: sh-sci: remove early_sci_setup() Remove unused early_sci_setup() function from sh-sci. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index af5da110d52..5f37f7d3166 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -1082,20 +1082,6 @@ static void __init sci_init_ports(void) } } -int __init early_sci_setup(struct uart_port *port) -{ - if (unlikely(port->line > SCI_NPORTS)) - return -ENODEV; - - sci_init_ports(); - - sci_ports[port->line].port.membase = port->membase; - sci_ports[port->line].port.mapbase = port->mapbase; - sci_ports[port->line].port.type = port->type; - - return 0; -} - #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE /* * Print a string to the serial port trying not to disturb -- cgit v1.2.3 From dc8e6f5bfcd6a307a8196d3e41fd9798be5a1c76 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 21 Jan 2009 15:14:06 +0000 Subject: sh-sci: rework serial console support Rework sh-sci serial console code. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 5f37f7d3166..d2cd1a400c1 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -91,10 +91,6 @@ struct sh_sci_priv { #endif }; -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE -static struct sci_port *serial_console_port; -#endif - /* Function prototypes */ static void sci_stop_tx(struct uart_port *port); @@ -1083,6 +1079,18 @@ static void __init sci_init_ports(void) } #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +static struct tty_driver *serial_console_device(struct console *co, int *index) +{ + struct uart_driver *p = &sci_uart_driver; + *index = co->index; + return p->tty_driver; +} + +static void serial_console_putchar(struct uart_port *port, int ch) +{ + sci_poll_put_char(port, ch); +} + /* * Print a string to the serial port trying not to disturb * any possible real use of the port... @@ -1090,16 +1098,10 @@ static void __init sci_init_ports(void) static void serial_console_write(struct console *co, const char *s, unsigned count) { - struct uart_port *port = &serial_console_port->port; + struct uart_port *port = co->data; unsigned short bits; - int i; - for (i = 0; i < count; i++) { - if (*s == 10) - sci_poll_put_char(port, '\r'); - - sci_poll_put_char(port, *s++); - } + uart_console_write(co->data, s, count, serial_console_putchar); /* wait until fifo is empty and last bit has been transmitted */ bits = SCxSR_TDxE(port) | SCxSR_TEND(port); @@ -1109,6 +1111,7 @@ static void serial_console_write(struct console *co, const char *s, static int __init serial_console_setup(struct console *co, char *options) { + struct sci_port *sci_port; struct uart_port *port; int baud = 115200; int bits = 8; @@ -1124,8 +1127,9 @@ static int __init serial_console_setup(struct console *co, char *options) if (co->index >= SCI_NPORTS) co->index = 0; - serial_console_port = &sci_ports[co->index]; - port = &serial_console_port->port; + sci_port = &sci_ports[co->index]; + port = &sci_port->port; + co->data = port; /* * Also need to check port->type, we don't actually have any @@ -1135,21 +1139,17 @@ static int __init serial_console_setup(struct console *co, char *options) */ if (!port->type) return -ENODEV; - if (!port->membase || !port->mapbase) - return -ENODEV; - - port->type = serial_console_port->type; #ifdef CONFIG_HAVE_CLK - if (!serial_console_port->clk) - serial_console_port->clk = clk_get(NULL, "module_clk"); + if (!sci_port->clk) + sci_port->clk = clk_get(NULL, "module_clk"); #endif if (port->flags & UPF_IOREMAP) sci_config_port(port, 0); - if (serial_console_port->enable) - serial_console_port->enable(port); + if (sci_port->enable) + sci_port->enable(port); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1165,12 +1165,11 @@ static int __init serial_console_setup(struct console *co, char *options) static struct console serial_console = { .name = "ttySC", - .device = uart_console_device, + .device = serial_console_device, .write = serial_console_write, .setup = serial_console_setup, .flags = CON_PRINTBUFFER, .index = -1, - .data = &sci_uart_driver, }; static int __init sci_console_init(void) -- cgit v1.2.3 From a5660adae85918f2ab6b10ab58e2f574c1bd5ce1 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 21 Jan 2009 15:14:38 +0000 Subject: sh-sci: use to_sci_port() if possible Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index d2cd1a400c1..17fa7f17bbe 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -618,7 +618,7 @@ static inline int sci_handle_breaks(struct uart_port *port) int copied = 0; unsigned short status = sci_in(port, SCxSR); struct tty_struct *tty = port->info->port.tty; - struct sci_port *s = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); if (uart_handle_break(port)) return 0; @@ -875,7 +875,7 @@ static void sci_break_ctl(struct uart_port *port, int break_state) static int sci_startup(struct uart_port *port) { - struct sci_port *s = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); if (s->enable) s->enable(port); @@ -893,7 +893,7 @@ static int sci_startup(struct uart_port *port) static void sci_shutdown(struct uart_port *port) { - struct sci_port *s = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); sci_stop_rx(port); sci_stop_tx(port); @@ -990,7 +990,7 @@ static int sci_request_port(struct uart_port *port) static void sci_config_port(struct uart_port *port, int flags) { - struct sci_port *s = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); port->type = s->type; @@ -1002,7 +1002,7 @@ 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 = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) return -EINVAL; -- cgit v1.2.3 From 0ee70712922c15252183db8b50a7e369c96017c0 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 21 Jan 2009 15:13:50 +0000 Subject: sh-sci: allow single port platform devices Allow registration of single port sh-sci platform devices. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 125 ++++++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 53 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 17fa7f17bbe..e9b350c58ba 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -1221,6 +1221,70 @@ static int __devexit sci_remove(struct platform_device *dev) return 0; } +static int __devinit sci_probe_single(struct platform_device *dev, + unsigned int index, + struct plat_sci_port *p, + struct sci_port *sciport) +{ + struct sh_sci_priv *priv = platform_get_drvdata(dev); + unsigned long flags; + int ret; + + /* Sanity check */ + if (unlikely(index >= SCI_NPORTS)) { + 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"); + return 0; + } + + sciport->port.mapbase = p->mapbase; + + if (p->mapbase && !p->membase) { + if (p->flags & UPF_IOREMAP) { + p->membase = ioremap_nocache(p->mapbase, 0x40); + if (IS_ERR(p->membase)) + return PTR_ERR(p->membase); + } else { + /* + * For the simple (and majority of) cases + * where we don't need to do any remapping, + * just cast the cookie directly. + */ + p->membase = (void __iomem *)p->mapbase; + } + } + + sciport->port.membase = p->membase; + + sciport->port.irq = p->irqs[SCIx_TXI_IRQ]; + sciport->port.flags = p->flags; + sciport->port.dev = &dev->dev; + + sciport->type = sciport->port.type = p->type; + + memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); + + ret = uart_add_one_port(&sci_uart_driver, &sciport->port); + + if (ret) { + if (p->flags & UPF_IOREMAP) + iounmap(p->membase); + + return ret; + } + + INIT_LIST_HEAD(&sciport->node); + + spin_lock_irqsave(&priv->lock, flags); + list_add(&sciport->node, &priv->ports); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + /* * Register a set of serial devices attached to a platform device. The * list is terminated with a zero flags entry, which means we expect @@ -1232,7 +1296,6 @@ static int __devinit sci_probe(struct platform_device *dev) struct plat_sci_port *p = dev->dev.platform_data; struct sh_sci_priv *priv; int i, ret = -EINVAL; - unsigned long flags; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -1247,60 +1310,16 @@ static int __devinit sci_probe(struct platform_device *dev) cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); #endif - for (i = 0; p && p->flags != 0; p++, i++) { - struct sci_port *sciport = &sci_ports[i]; - - /* Sanity check */ - if (unlikely(i == SCI_NPORTS)) { - dev_notice(&dev->dev, "Attempting to register port " - "%d when only %d are available.\n", - i+1, SCI_NPORTS); - dev_notice(&dev->dev, "Consider bumping " - "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); - break; - } - - sciport->port.mapbase = p->mapbase; - - if (p->mapbase && !p->membase) { - if (p->flags & UPF_IOREMAP) { - p->membase = ioremap_nocache(p->mapbase, 0x40); - if (IS_ERR(p->membase)) { - ret = PTR_ERR(p->membase); - goto err_unreg; - } - } else { - /* - * For the simple (and majority of) cases - * where we don't need to do any remapping, - * just cast the cookie directly. - */ - p->membase = (void __iomem *)p->mapbase; - } - } - - sciport->port.membase = p->membase; - - sciport->port.irq = p->irqs[SCIx_TXI_IRQ]; - sciport->port.flags = p->flags; - sciport->port.dev = &dev->dev; - - sciport->type = sciport->port.type = p->type; - - memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); - - ret = uart_add_one_port(&sci_uart_driver, &sciport->port); - - if (ret && (p->flags & UPF_IOREMAP)) { - iounmap(p->membase); + if (dev->id != -1) { + ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]); + if (ret) goto err_unreg; + } else { + for (i = 0; p && p->flags != 0; p++, i++) { + ret = sci_probe_single(dev, i, p, &sci_ports[i]); + if (ret) + goto err_unreg; } - - INIT_LIST_HEAD(&sciport->node); - - spin_lock_irqsave(&priv->lock, flags); - list_add(&sciport->node, &priv->ports); - spin_unlock_irqrestore(&priv->lock, flags); } #ifdef CONFIG_SH_STANDARD_BIOS -- cgit v1.2.3 From 7ed7e0711b3ff85b3e15591081b42f2af96d584b Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 21 Jan 2009 15:14:14 +0000 Subject: sh-sci: replace sci_init_ports() Replace sci_init_ports() with sci_init_single(). Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 107 ++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 57 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index e9b350c58ba..039c700ce1e 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -1036,46 +1036,64 @@ static struct uart_ops sci_uart_ops = { #endif }; -static void __init sci_init_ports(void) +static int __devinit sci_init_single(struct sci_port *sci_port, + unsigned int index, + struct plat_sci_port *p) { - static int first = 1; - int i; - - if (!first) - return; - - first = 0; - - for (i = 0; i < SCI_NPORTS; i++) { - sci_ports[i].port.ops = &sci_uart_ops; - sci_ports[i].port.iotype = UPIO_MEM; - sci_ports[i].port.line = i; - sci_ports[i].port.fifosize = 1; + sci_port->port.ops = &sci_uart_ops; + sci_port->port.iotype = UPIO_MEM; + sci_port->port.line = index; + sci_port->port.fifosize = 1; #if defined(__H8300H__) || defined(__H8300S__) #ifdef __H8300S__ - sci_ports[i].enable = h8300_sci_enable; - sci_ports[i].disable = h8300_sci_disable; + sci_port->enable = h8300_sci_enable; + sci_port->disable = h8300_sci_disable; #endif - sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK; + sci_port->port.uartclk = CONFIG_CPU_CLOCK; #elif defined(CONFIG_HAVE_CLK) - /* - * XXX: We should use a proper SCI/SCIF clock - */ - { - struct clk *clk = clk_get(NULL, "module_clk"); - sci_ports[i].port.uartclk = clk_get_rate(clk); - clk_put(clk); - } + /* + * XXX: We should use a proper SCI/SCIF clock + */ + { + struct clk *clk = clk_get(NULL, "module_clk"); + sci_port->port.uartclk = clk_get_rate(clk); + clk_put(clk); + } #else #error "Need a valid uartclk" #endif - sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i]; - sci_ports[i].break_timer.function = sci_break_timer; + sci_port->break_timer.data = (unsigned long)sci_port; + sci_port->break_timer.function = sci_break_timer; + init_timer(&sci_port->break_timer); + + sci_port->port.mapbase = p->mapbase; - init_timer(&sci_ports[i].break_timer); + if (p->mapbase && !p->membase) { + if (p->flags & UPF_IOREMAP) { + p->membase = ioremap_nocache(p->mapbase, 0x40); + if (IS_ERR(p->membase)) + return PTR_ERR(p->membase); + } else { + /* + * For the simple (and majority of) cases + * where we don't need to do any remapping, + * just cast the cookie directly. + */ + p->membase = (void __iomem *)p->mapbase; + } } + + sci_port->port.membase = p->membase; + + sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; + sci_port->port.flags = p->flags; + sci_port->type = sci_port->port.type = p->type; + + memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); + + return 0; } #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE @@ -1174,7 +1192,6 @@ static struct console serial_console = { static int __init sci_console_init(void) { - sci_init_ports(); register_console(&serial_console); return 0; } @@ -1240,32 +1257,10 @@ static int __devinit sci_probe_single(struct platform_device *dev, return 0; } - sciport->port.mapbase = p->mapbase; - - if (p->mapbase && !p->membase) { - if (p->flags & UPF_IOREMAP) { - p->membase = ioremap_nocache(p->mapbase, 0x40); - if (IS_ERR(p->membase)) - return PTR_ERR(p->membase); - } else { - /* - * For the simple (and majority of) cases - * where we don't need to do any remapping, - * just cast the cookie directly. - */ - p->membase = (void __iomem *)p->mapbase; - } - } - - sciport->port.membase = p->membase; - - sciport->port.irq = p->irqs[SCIx_TXI_IRQ]; - sciport->port.flags = p->flags; - sciport->port.dev = &dev->dev; - - sciport->type = sciport->port.type = p->type; - - memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); + sciport->port.dev = &dev->dev; + ret = sci_init_single(sciport, index, p); + if (ret) + return ret; ret = uart_add_one_port(&sci_uart_driver, &sciport->port); @@ -1380,8 +1375,6 @@ static int __init sci_init(void) printk(banner); - sci_init_ports(); - ret = uart_register_driver(&sci_uart_driver); if (likely(ret == 0)) { ret = platform_driver_register(&sci_driver); -- cgit v1.2.3 From 08f8cb315fdf9195b472aeb440ae65b189b151da Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 21 Jan 2009 15:14:22 +0000 Subject: sh-sci: ioremap() in a single place Handle ioremap() in sci_config_port only. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 54 ++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 34 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 039c700ce1e..408624ae7fe 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -994,9 +994,21 @@ static void sci_config_port(struct uart_port *port, int flags) port->type = s->type; - if (port->flags & UPF_IOREMAP && !port->membase) { + if (port->membase) + return; + + if (port->flags & UPF_IOREMAP) { port->membase = ioremap_nocache(port->mapbase, 0x40); - dev_err(port->dev, "can't remap port#%d\n", port->line); + + if (IS_ERR(port->membase)) + dev_err(port->dev, "can't remap port#%d\n", port->line); + } else { + /* + * For the simple (and majority of) cases where we don't + * need to do any remapping, just cast the cookie + * directly. + */ + port->membase = (void __iomem *)port->mapbase; } } @@ -1036,9 +1048,9 @@ static struct uart_ops sci_uart_ops = { #endif }; -static int __devinit sci_init_single(struct sci_port *sci_port, - unsigned int index, - struct plat_sci_port *p) +static void __devinit sci_init_single(struct sci_port *sci_port, + unsigned int index, + struct plat_sci_port *p) { sci_port->port.ops = &sci_uart_ops; sci_port->port.iotype = UPIO_MEM; @@ -1069,22 +1081,6 @@ static int __devinit sci_init_single(struct sci_port *sci_port, init_timer(&sci_port->break_timer); sci_port->port.mapbase = p->mapbase; - - if (p->mapbase && !p->membase) { - if (p->flags & UPF_IOREMAP) { - p->membase = ioremap_nocache(p->mapbase, 0x40); - if (IS_ERR(p->membase)) - return PTR_ERR(p->membase); - } else { - /* - * For the simple (and majority of) cases - * where we don't need to do any remapping, - * just cast the cookie directly. - */ - p->membase = (void __iomem *)p->mapbase; - } - } - sci_port->port.membase = p->membase; sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; @@ -1092,8 +1088,6 @@ static int __devinit sci_init_single(struct sci_port *sci_port, sci_port->type = sci_port->port.type = p->type; memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); - - return 0; } #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE @@ -1163,8 +1157,7 @@ static int __init serial_console_setup(struct console *co, char *options) sci_port->clk = clk_get(NULL, "module_clk"); #endif - if (port->flags & UPF_IOREMAP) - sci_config_port(port, 0); + sci_config_port(port, 0); if (sci_port->enable) sci_port->enable(port); @@ -1258,18 +1251,11 @@ static int __devinit sci_probe_single(struct platform_device *dev, } sciport->port.dev = &dev->dev; - ret = sci_init_single(sciport, index, p); - if (ret) - return ret; + sci_init_single(sciport, index, p); ret = uart_add_one_port(&sci_uart_driver, &sciport->port); - - if (ret) { - if (p->flags & UPF_IOREMAP) - iounmap(p->membase); - + if (ret) return ret; - } INIT_LIST_HEAD(&sciport->node); -- cgit v1.2.3 From 501b825d01efb93766c87d29f299851152cf4eb0 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 21 Jan 2009 15:14:30 +0000 Subject: sh-sci: improve clock framework support Use enable/disable hooks for clock framework integration. Make sure we control the clock for the serial console as well. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 77 +++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 31 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 408624ae7fe..3daf76725ac 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -76,8 +76,10 @@ struct sci_port { int break_flag; #ifdef CONFIG_HAVE_CLK - /* Port clock */ - struct clk *clk; + /* Interface clock */ + struct clk *iclk; + /* Data clock */ + struct clk *dclk; #endif struct list_head node; }; @@ -166,12 +168,12 @@ static void h8300_sci_config(struct uart_port *port, unsigned int ctrl) *mstpcrl &= ~mask; } -static inline void h8300_sci_enable(struct uart_port *port) +static void h8300_sci_enable(struct uart_port *port) { h8300_sci_config(port, sci_enable); } -static inline void h8300_sci_disable(struct uart_port *port) +static void h8300_sci_disable(struct uart_port *port) { h8300_sci_config(port, sci_disable); } @@ -742,13 +744,34 @@ static int sci_notifier(struct notifier_block *self, (phase == CPUFREQ_RESUMECHANGE)) { spin_lock_irqsave(&priv->lock, flags); list_for_each_entry(sci_port, &priv->ports, node) - sci_port->port.uartclk = clk_get_rate(sci_port->clk); + sci_port->port.uartclk = clk_get_rate(sci_port->dclk); spin_unlock_irqrestore(&priv->lock, flags); } return NOTIFY_OK; } + +static void sci_clk_enable(struct uart_port *port) +{ + struct sci_port *sci_port = to_sci_port(port); + + clk_enable(sci_port->dclk); + sci_port->port.uartclk = clk_get_rate(sci_port->dclk); + + if (sci_port->iclk) + clk_enable(sci_port->iclk); +} + +static void sci_clk_disable(struct uart_port *port) +{ + struct sci_port *sci_port = to_sci_port(port); + + if (sci_port->iclk) + clk_disable(sci_port->iclk); + + clk_disable(sci_port->dclk); +} #endif static int sci_request_irq(struct sci_port *port) @@ -880,10 +903,6 @@ static int sci_startup(struct uart_port *port) if (s->enable) s->enable(port); -#ifdef CONFIG_HAVE_CLK - s->clk = clk_get(NULL, "module_clk"); -#endif - sci_request_irq(s); sci_start_tx(port); sci_start_rx(port, 1); @@ -901,11 +920,6 @@ static void sci_shutdown(struct uart_port *port) if (s->disable) s->disable(port); - -#ifdef CONFIG_HAVE_CLK - clk_put(s->clk); - s->clk = NULL; -#endif } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, @@ -1048,7 +1062,8 @@ static struct uart_ops sci_uart_ops = { #endif }; -static void __devinit sci_init_single(struct sci_port *sci_port, +static void __devinit sci_init_single(struct platform_device *dev, + struct sci_port *sci_port, unsigned int index, struct plat_sci_port *p) { @@ -1064,14 +1079,10 @@ static void __devinit sci_init_single(struct sci_port *sci_port, #endif sci_port->port.uartclk = CONFIG_CPU_CLOCK; #elif defined(CONFIG_HAVE_CLK) - /* - * XXX: We should use a proper SCI/SCIF clock - */ - { - struct clk *clk = clk_get(NULL, "module_clk"); - sci_port->port.uartclk = clk_get_rate(clk); - clk_put(clk); - } + sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL; + sci_port->dclk = clk_get(&dev->dev, "module_clk"); + sci_port->enable = sci_clk_enable; + sci_port->disable = sci_clk_disable; #else #error "Need a valid uartclk" #endif @@ -1085,9 +1096,11 @@ static void __devinit sci_init_single(struct sci_port *sci_port, sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; sci_port->port.flags = p->flags; + sci_port->port.dev = &dev->dev; sci_port->type = sci_port->port.type = p->type; memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); + } #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE @@ -1111,14 +1124,21 @@ static void serial_console_write(struct console *co, const char *s, unsigned count) { struct uart_port *port = co->data; + struct sci_port *sci_port = to_sci_port(port); unsigned short bits; - uart_console_write(co->data, s, count, serial_console_putchar); + if (sci_port->enable) + sci_port->enable(port); + + uart_console_write(port, s, count, serial_console_putchar); /* wait until fifo is empty and last bit has been transmitted */ bits = SCxSR_TDxE(port) | SCxSR_TEND(port); while ((sci_in(port, SCxSR) & bits) != bits) cpu_relax(); + + if (sci_port->disable); + sci_port->disable(port); } static int __init serial_console_setup(struct console *co, char *options) @@ -1152,11 +1172,6 @@ static int __init serial_console_setup(struct console *co, char *options) if (!port->type) return -ENODEV; -#ifdef CONFIG_HAVE_CLK - if (!sci_port->clk) - sci_port->clk = clk_get(NULL, "module_clk"); -#endif - sci_config_port(port, 0); if (sci_port->enable) @@ -1171,6 +1186,7 @@ static int __init serial_console_setup(struct console *co, char *options) if (ret == 0) sci_stop_rx(port); #endif + /* TODO: disable clock */ return ret; } @@ -1250,8 +1266,7 @@ static int __devinit sci_probe_single(struct platform_device *dev, return 0; } - sciport->port.dev = &dev->dev; - sci_init_single(sciport, index, p); + sci_init_single(dev, sciport, index, p); ret = uart_add_one_port(&sci_uart_driver, &sciport->port); if (ret) -- cgit v1.2.3 From 54507f6ee99778a727ff1b38a1f4050fe6479835 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 8 May 2009 23:48:33 +0900 Subject: serial: sh-sci: Fix up section mismatch in error path. The sci_probe_single() path attempts to use sci_remove() for the error path, while sci_remove() is still flagged as __devexit. So, we simply discard the section annotation. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 3daf76725ac..686e4a456e3 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -1227,7 +1227,7 @@ static struct uart_driver sci_uart_driver = { }; -static int __devexit sci_remove(struct platform_device *dev) +static int sci_remove(struct platform_device *dev) { struct sh_sci_priv *priv = platform_get_drvdata(dev); struct sci_port *p; -- cgit v1.2.3 From 168f36237b16e2b3159e24c7d3b658e3c912d149 Mon Sep 17 00:00:00 2001 From: Yoshinori Sato Date: Tue, 28 Apr 2009 04:40:15 +0000 Subject: serial: sh-sci: Fix up h8300 support. - Dummy SCIF functions define. - h8300 specific header include. Signed-off-by: Yoshinori Sato Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 4 ++++ drivers/serial/sh-sci.h | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 686e4a456e3..4e3248d5860 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -54,6 +54,10 @@ #include #endif +#ifdef CONFIG_H8300 +#include +#endif + #include "sh-sci.h" struct sci_port { diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 84cc6512f08..e3eae4eaadd 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -317,7 +317,18 @@ } \ } -#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ +#ifdef CONFIG_H8300 +/* h8300 don't have SCIF */ +#define CPU_SCIF_FNS(name) \ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + return 0; \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + } +#else +#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ static inline unsigned int sci_##name##_in(struct uart_port *port) \ { \ SCI_IN(scif_size, scif_offset); \ @@ -326,6 +337,7 @@ { \ SCI_OUT(scif_size, scif_offset, value); \ } +#endif #define CPU_SCI_FNS(name, sci_offset, sci_size) \ static inline unsigned int sci_##name##_in(struct uart_port* port) \ @@ -363,7 +375,8 @@ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ h8_sci_offset, h8_sci_size) \ CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) -#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name) #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ defined(CONFIG_CPU_SUBTYPE_SH7724) #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \ -- cgit v1.2.3 From e9e8b1fb995543c4cc3930f465923a552b2e48b7 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 9 May 2009 14:31:37 +0900 Subject: sh: Fix up the sh64 earlyprintk build. sci_rxd_in() on SH-5 wants to be using SCSPTR, not SCSPTR2. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index e3eae4eaadd..38072c15b84 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -636,7 +636,7 @@ static inline int sci_rxd_in(struct uart_port *port) #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) static inline int sci_rxd_in(struct uart_port *port) { - return sci_in(port, SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ + return sci_in(port, SCSPTR)&0x0001 ? 1 : 0; /* SCIF */ } #elif defined(__H8300H__) || defined(__H8300S__) static inline int sci_rxd_in(struct uart_port *port) -- cgit v1.2.3 From af777ce42d3d51cdef353ce296d6f99dc503feef Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 13 May 2009 16:59:40 +0900 Subject: sh: clkfwk: module_clk -> peripheral_clk rename. For consistenct naming, and to allow us to fix up some confusion in the SH-Mobile clock framework, amongst other places. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 4e3248d5860..fa4d52a6c03 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -1084,7 +1084,7 @@ static void __devinit sci_init_single(struct platform_device *dev, sci_port->port.uartclk = CONFIG_CPU_CLOCK; #elif defined(CONFIG_HAVE_CLK) sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL; - sci_port->dclk = clk_get(&dev->dev, "module_clk"); + sci_port->dclk = clk_get(&dev->dev, "peripheral_clk"); sci_port->enable = sci_clk_enable; sci_port->disable = sci_clk_disable; #else -- cgit v1.2.3 From 0003b795c310da83501fcf0329f6be7a0984647d Mon Sep 17 00:00:00 2001 From: Eric Lammerts Date: Tue, 19 May 2009 20:53:20 -0400 Subject: fix oops when using console=ttymxcN with N > 0 Signed-off-by: Eric Lammerts Signed-off-by: Sascha Hauer --- drivers/serial/imx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 3f5d5a20048..738c8a5f64f 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -1024,6 +1024,8 @@ imx_console_setup(struct console *co, char *options) if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) co->index = 0; sport = imx_ports[co->index]; + if(sport == NULL) + return -ENODEV; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); -- cgit v1.2.3 From 03fbdb15c14e9746c63168e3ff2c64b9c8336d33 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini Date: Wed, 20 May 2009 22:39:08 +0100 Subject: [ARM] 5519/1: amba probe: pass "struct amba_id *" instead of void * The second argument of the probe method points to the amba_id structure, so it's better passed with the correct type. None of the current in-tree drivers uses the pointer, so they have only been checked for a clean compile. Change suggested by Russell King. Signed-off-by: Alessandro Rubini Signed-off-by: Russell King --- drivers/serial/amba-pl010.c | 2 +- drivers/serial/amba-pl011.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index e3a5ad5ef1d..cdc049d4350 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -665,7 +665,7 @@ static struct uart_driver amba_reg = { .cons = AMBA_CONSOLE, }; -static int pl010_probe(struct amba_device *dev, void *id) +static int pl010_probe(struct amba_device *dev, struct amba_id *id) { struct uart_amba_port *uap; void __iomem *base; diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 8b2b9700f3e..88fdac51b6c 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -729,7 +729,7 @@ static struct uart_driver amba_reg = { .cons = AMBA_CONSOLE, }; -static int pl011_probe(struct amba_device *dev, void *id) +static int pl011_probe(struct amba_device *dev, struct amba_id *id) { struct uart_amba_port *uap; void __iomem *base; -- cgit v1.2.3 From 95caa0a9bdaf93607bd0cc8932f53112496f2f22 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 22 May 2009 21:30:39 -0300 Subject: icom: fix rmmod crash Actually the icom driver is crashing when is being removed because the driver is kfreeing the adapter structure before calling pci_release_regions(), which result in the following error: Unable to handle kernel paging request for data at address 0x6b6b6b6b6b6b6d33 Faulting instruction address: 0xc000000000246b80 Oops: Kernel access of bad area, sig: 11 [#1] .... [c000000012d436a0] [c0000000001002d0] .kfree+0x120/0x34c (unreliable) [c000000012d43730] [c000000000246d60] .pci_release_selected_regions+0x3c/0x68 [c000000012d437c0] [d000000002d54700] .icom_kref_release+0xf4/0x118 [icom] [c000000012d43850] [c000000000232e50] .kref_put+0x74/0x94 [c000000012d438d0] [d000000002d56c58] .icom_remove+0x40/0xa4 [icom] [c000000012d43960] [c000000000249e48] .pci_device_remove+0x50/0x90 [c000000012d439e0] [c0000000002d68d8] .__device_release_driver+0x94/0xd4 [c000000012d43a70] [c0000000002d7104] .driver_detach+0xf8/0x12c [c000000012d43b00] [c0000000002d549c] .bus_remove_driver+0xbc/0x11c [c000000012d43b90] [c0000000002d71dc] .driver_unregister+0x60/0x80 [c000000012d43c20] [c00000000024a07c] .pci_unregister_driver+0x44/0xe8 [c000000012d43cb0] [d000000002d56bf4] .icom_exit+0x1c/0x40 [icom] [c000000012d43d30] [c000000000095fa8] .SyS_delete_module+0x214/0x2a8 [c000000012d43e30] [c00000000000852c] syscall_exit+0x0/0x40 Signed-off-by: Breno Leitao Cc: stable@kernel.org Cc: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/icom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 6579e2be1dd..a461b3b2c72 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -1472,8 +1472,8 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter) free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); iounmap(icom_adapter->base_addr); - icom_free_adapter(icom_adapter); pci_release_regions(icom_adapter->pci_dev); + icom_free_adapter(icom_adapter); } static void icom_kref_release(struct kref *kref) -- cgit v1.2.3 From b898f4f869da5b9d41f297fff87aca4cd42d80b3 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Thu, 28 May 2009 14:34:29 -0700 Subject: drivers/serial/mpc52xx_uart.c: fix array overindexing check The check for an overindexing of mpc52xx_uart_{ports,nodes} has an off-by-one. Signed-off-by: Roel Kluin Acked-by: Wolfram Sang Acked-by: Grant Likely Cc: Benjamin Herrenschmidt Cc: Alan Cox Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/mpc52xx_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 7f72f8ceaa6..b3feb6198d5 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -988,7 +988,7 @@ mpc52xx_console_setup(struct console *co, char *options) pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n", co, co->index, options); - if ((co->index < 0) || (co->index > MPC52xx_PSC_MAXNUM)) { + if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) { pr_debug("PSC%x out of range\n", co->index); return -EINVAL; } -- cgit v1.2.3 From 8e8e8267f0a08c2415d5f51bc9a9fde6d5400619 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Thu, 28 May 2009 14:34:34 -0700 Subject: serial: 8250_gsc: fix printk format error drivers/serial/8250_gsc.c:44: warning: format '%lx' expects type 'long unsigned int', but argument 2 has type 'resource_size_t' [akpm@linux-foundation.org: fix it to handle u64's] Signed-off-by: Alexander Beregalov Cc: Alan Cox Cc: Kyle McMartin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/8250_gsc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index 418b4fe9a0a..33149d982e8 100644 --- a/drivers/serial/8250_gsc.c +++ b/drivers/serial/8250_gsc.c @@ -39,9 +39,9 @@ static int __init serial_init_chip(struct parisc_device *dev) */ if (parisc_parent(dev)->id.hw_type != HPHW_IOA) printk(KERN_INFO - "Serial: device 0x%lx not configured.\n" + "Serial: device 0x%llx not configured.\n" "Enable support for Wax, Lasi, Asp or Dino.\n", - dev->hpa.start); + (unsigned long long)dev->hpa.start); return -ENODEV; } -- cgit v1.2.3 From b8e7e40abeac49644fec4a4f52ffe74c7b05eca0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 28 May 2009 14:01:35 +0100 Subject: 8250: Fix oops from setserial If you setserial a port which has never been initialised we change the type but don't update the I/O method pointers. The same problem is true if you change the io type of a port - but nobody ever does that so nobody noticed! Remember the old type and when attaching if the type has changed reload the port accessor pointers. We can't do it blindly as some 8250 drivers load custom accessors and we must not stomp those. Tested-by: Victor Seryodkin Closes-bug: #13367 Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/8250.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index b4b39811b44..a0127e93ade 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -137,6 +137,7 @@ struct uart_8250_port { unsigned char mcr; unsigned char mcr_mask; /* mask of user bits */ unsigned char mcr_force; /* mask of forced bits */ + unsigned char cur_iotype; /* Running I/O type */ /* * Some bits in registers are cleared on a read, so they must @@ -471,6 +472,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value) static void set_io_from_upio(struct uart_port *p) { + struct uart_8250_port *up = (struct uart_8250_port *)p; switch (p->iotype) { case UPIO_HUB6: p->serial_in = hub6_serial_in; @@ -509,6 +511,8 @@ static void set_io_from_upio(struct uart_port *p) p->serial_out = io_serial_out; break; } + /* Remember loaded iotype */ + up->cur_iotype = p->iotype; } static void @@ -1937,6 +1941,9 @@ static int serial8250_startup(struct uart_port *port) up->capabilities = uart_config[up->port.type].flags; up->mcr = 0; + if (up->port.iotype != up->cur_iotype) + set_io_from_upio(port); + if (up->port.type == PORT_16C950) { /* Wake up and initialize UART */ up->acr = 0; @@ -2563,6 +2570,9 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (ret < 0) probeflags &= ~PROBE_RSA; + if (up->port.iotype != up->cur_iotype) + set_io_from_upio(port); + if (flags & UART_CONFIG_TYPE) autoconfig(up, probeflags); if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) @@ -2671,6 +2681,11 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) { int i; + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + up->cur_iotype = 0xFF; + } + serial8250_isa_init_ports(); for (i = 0; i < nr_uarts; i++) { -- cgit v1.2.3 From 4dd9e742df98f8f600b4302d3adbb087a68237f7 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini Date: Tue, 5 May 2009 05:54:13 +0100 Subject: [ARM] 5505/1: serial amba-pl011: move to arch_initcall for earlier console Signed-off-by: Alessandro Rubini " Signed-off-by: Russell King --- drivers/serial/amba-pl011.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 88fdac51b6c..4cfa1eb2689 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -845,7 +845,11 @@ static void __exit pl011_exit(void) uart_unregister_driver(&amba_reg); } -module_init(pl011_init); +/* + * While this can be a module, if builtin it's most likely the console + * So let's leave module_exit but move module_init to an earlier place + */ +arch_initcall(pl011_init); module_exit(pl011_exit); MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); -- cgit v1.2.3 From dd0a3e77c825c9f5c6d2a97deb047f8d52026581 Mon Sep 17 00:00:00 2001 From: SUGIOKA Toshinobu Date: Mon, 1 Jun 2009 03:53:41 +0000 Subject: serial: sh-sci: Fix up PORT_SCI console output ordering. Fix SCI transmission sequence in console output function. This reorders the write sequence to match the SH-3 manual, and corrects a console corruption bug observed on SH-3 SCI. Signed-off-by: Toshinobu Sugioka Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index fa4d52a6c03..a4cf1079b31 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -151,9 +151,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) status = sci_in(port, SCxSR); } while (!(status & SCxSR_TDxE(port))); - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); sci_out(port, SCxTDR, c); + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ -- cgit v1.2.3 From e76afc4e7816a0a5300073098cdac93a994eb5ca Mon Sep 17 00:00:00 2001 From: Eric Lammerts Date: Tue, 19 May 2009 20:53:20 -0400 Subject: fix oops when using console=ttymxcN with N > 0 Signed-off-by: Eric Lammerts Signed-off-by: Sascha Hauer --- drivers/serial/imx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 9f460b175c5..5f0be40dfda 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -1031,6 +1031,8 @@ imx_console_setup(struct console *co, char *options) if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) co->index = 0; sport = imx_ports[co->index]; + if(sport == NULL) + return -ENODEV; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); -- cgit v1.2.3 From 5926a295bb78272b3f648f62febecd19a1b6a6ca Mon Sep 17 00:00:00 2001 From: Alessandro Rubini Date: Thu, 4 Jun 2009 17:43:04 +0100 Subject: [ARM] 5541/1: serial/amba-pl011.c: add support for the modified port found in Nomadik The Nomadik 8815 SoC has a slightly modified version of the PL011 block. The patch uses the different ID value as a key to select a vendor structure that is used to keep track of the differences, as suggested by Russell King. Signed-off-by: Alessandro Rubini Acked-by: Andrea Gallo Acked-by: Linus Walleij Signed-off-by: Russell King --- drivers/serial/amba-pl011.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 4cfa1eb2689..8c5bda27736 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -70,6 +70,23 @@ struct uart_amba_port { struct clk *clk; unsigned int im; /* interrupt mask */ unsigned int old_status; + unsigned int ifls; /* vendor-specific */ +}; + +/* There is by now at least one vendor with differing details, so handle it */ +struct vendor_data { + unsigned int ifls; + unsigned int fifosize; +}; + +static struct vendor_data vendor_arm = { + .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + .fifosize = 16, +}; + +static struct vendor_data vendor_st = { + .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, + .fifosize = 64, }; static void pl011_stop_tx(struct uart_port *port) @@ -360,8 +377,7 @@ static int pl011_startup(struct uart_port *port) if (retval) goto clk_dis; - writew(UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - uap->port.membase + UART011_IFLS); + writew(uap->ifls, uap->port.membase + UART011_IFLS); /* * Provoke TX FIFO interrupt into asserting. @@ -732,6 +748,7 @@ static struct uart_driver amba_reg = { static int pl011_probe(struct amba_device *dev, struct amba_id *id) { struct uart_amba_port *uap; + struct vendor_data *vendor = id->data; void __iomem *base; int i, ret; @@ -762,12 +779,13 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) goto unmap; } + uap->ifls = vendor->ifls; uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; uap->port.membase = base; uap->port.iotype = UPIO_MEM; uap->port.irq = dev->irq[0]; - uap->port.fifosize = 16; + uap->port.fifosize = vendor->fifosize; uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = i; @@ -812,6 +830,12 @@ static struct amba_id pl011_ids[] __initdata = { { .id = 0x00041011, .mask = 0x000fffff, + .data = &vendor_arm, + }, + { + .id = 0x00380802, + .mask = 0x00ffffff, + .data = &vendor_st, }, { 0, 0 }, }; -- cgit v1.2.3 From dc890c2dcd63a90de68ee5f0253eefbb89d725f0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 7 Jun 2009 23:27:31 +0100 Subject: [ARM] 5544/1: Trust PrimeCell resource sizes I found the PrimeCell/AMBA Bus drivers distrusting the resource passed in as part of the struct amba_device abstraction. This patch removes all hard coded resource sizes found in the PrimeCell drivers and move the responsibility of this definition back to the platform/board device definition, which already exist and appear to be correct for all in-tree users of these drivers. We do this using the resource_size() inline function which was also replicated in the only driver using the resource size, so that has been changed too. The KMI_SIZE was left in kmi.h in case someone likes it. Test-compiled against Versatile and Integrator defconfigs, seems to work but I don't posess these boards and cannot test them. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/serial/amba-pl010.c | 2 +- drivers/serial/amba-pl011.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index cdc049d4350..58a4879c7e4 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -686,7 +686,7 @@ static int pl010_probe(struct amba_device *dev, struct amba_id *id) goto out; } - base = ioremap(dev->res.start, PAGE_SIZE); + base = ioremap(dev->res.start, resource_size(&dev->res)); if (!base) { ret = -ENOMEM; goto free; diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 8c5bda27736..bf82e28770a 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -767,7 +767,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) goto out; } - base = ioremap(dev->res.start, PAGE_SIZE); + base = ioremap(dev->res.start, resource_size(&dev->res)); if (!base) { ret = -ENOMEM; goto free; -- cgit v1.2.3 From 70fd8fdecc4430ffcede7704dd812d4054d1faf9 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 11 Jun 2009 12:41:57 +0100 Subject: 8250_pci: add the OXCB950 chip to the 8250 PCI driver. This adds support for the following serial controller chip: Oxford Semiconductor OXCB950 for PCI Cardbus interface http://www.transdimension.com/products/serial/OXCB950.html on this card: ExSys EX-1370 1 port high-speed serial card for ExpressCard/34 slot Signed-off-by: Andre Przywara Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/8250_pci.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 938bc1b6c3f..e371a9c1534 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -2776,6 +2776,9 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_OXSEMI, 0x950a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_2_1130000 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950, + PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0, + pbn_b0_1_921600 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_4_115200 }, -- cgit v1.2.3 From 13858d36903990441a89eb342247b71436808eeb Mon Sep 17 00:00:00 2001 From: "Alexander Y. Fomichev" Date: Thu, 11 Jun 2009 12:56:00 +0100 Subject: jsm: correctly support multiple 4/8-port boards If there are more then one 4/8-port board jsm_uart_port_init allocate a line numbers of the second and further boards from range of previous one. This patch fixed the problem. Signed-off-by: Alexander Y. Fomichev [printks fixed to add jsm: ] Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/jsm/jsm.h | 1 + drivers/serial/jsm/jsm_tty.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h index c0a3e2734e2..4e5f3bde046 100644 --- a/drivers/serial/jsm/jsm.h +++ b/drivers/serial/jsm/jsm.h @@ -61,6 +61,7 @@ enum { if ((DBG_##nlevel & jsm_debug)) \ dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) +#define MAXLINES 256 #define MAXPORTS 8 #define MAX_STOPS_SENT 5 diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 31496dc0a0d..107ce2e187b 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c @@ -33,6 +33,8 @@ #include "jsm.h" +static DECLARE_BITMAP(linemap, MAXLINES); + static void jsm_carrier(struct jsm_channel *ch); static inline int jsm_get_mstat(struct jsm_channel *ch) @@ -433,6 +435,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd) int __devinit jsm_uart_port_init(struct jsm_board *brd) { int i; + unsigned int line; struct jsm_channel *ch; if (!brd) @@ -459,9 +462,15 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd) brd->channels[i]->uart_port.membase = brd->re_map_membase; brd->channels[i]->uart_port.fifosize = 16; brd->channels[i]->uart_port.ops = &jsm_ops; - brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2; + line = find_first_zero_bit(linemap, MAXLINES); + if (line >= MAXLINES) { + printk(KERN_INFO "jsm: linemap is full, added device failed\n"); + continue; + } else + set_bit((int)line, linemap); + brd->channels[i]->uart_port.line = line; if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) - printk(KERN_INFO "Added device failed\n"); + printk(KERN_INFO "jsm: add device failed\n"); else printk(KERN_INFO "Added device \n"); } @@ -494,6 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd) ch = brd->channels[i]; + clear_bit((int)(ch->uart_port.line), linemap); uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); } -- cgit v1.2.3 From aba6593bf77371e71331ba76dacc98b47760cba3 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 11 Jun 2009 13:02:59 +0100 Subject: icom: fixing a if clause spaghetti adapter->version can only be ADAPTER_V2 or ADAPTER_V1. So, that OR operand in the "if" clause is non-sense and can be removed. Signed-off-by: Breno Leitao Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/icom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index a461b3b2c72..fd5fd23804b 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -408,7 +408,7 @@ static void load_code(struct icom_port *icom_port) release_firmware(fw); /* Set Hardware level */ - if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2) + if (icom_port->adapter->version == ADAPTER_V2) writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); /* Start the processor in Adapter */ @@ -861,7 +861,7 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id) /* find icom_port for this interrupt */ icom_adapter = (struct icom_adapter *) dev_id; - if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) { + if (icom_adapter->version == ADAPTER_V2) { int_reg = icom_adapter->base_addr + 0x8024; adapter_interrupts = readl(int_reg); -- cgit v1.2.3 From 257a6e8cc7f9274f0af090494a3f1ee06548b5bd Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 11 Jun 2009 13:20:09 +0100 Subject: icom: fix compile errors when defining ICOM_TRACE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it is, defining ICOM_TRACE produces some compile errors, as "parameter name omitted" and "redefinition of ‘trace’" This patch removes the wrong trace definition. Signed-off-by: Breno Leitao Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/icom.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index fd5fd23804b..9f2891c2c4a 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -137,7 +137,12 @@ static LIST_HEAD(icom_adapter_head); static spinlock_t icom_lock; #ifdef ICOM_TRACE -static inline void trace(struct icom_port *, char *, unsigned long) {}; +static inline void trace(struct icom_port *icom_port, char *trace_pt, + unsigned long trace_data) +{ + dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", + icom_port->port, trace_pt, trace_data); +} #else static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; #endif @@ -1647,15 +1652,6 @@ static void __exit icom_exit(void) module_init(icom_init); module_exit(icom_exit); -#ifdef ICOM_TRACE -static inline void trace(struct icom_port *icom_port, char *trace_pt, - unsigned long trace_data) -{ - dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", - icom_port->port, trace_pt, trace_data); -} -#endif - MODULE_AUTHOR("Michael Anderson "); MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); MODULE_SUPPORTED_DEVICE -- cgit v1.2.3 From 08e0992f60ad44025a8a8b8a821838ca4a562686 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 11 Jun 2009 13:21:24 +0100 Subject: serial: add support for the TI AR7 internal UART This patch adds support for the TI AR7 internal UART. Signed-off-by: Florian Fainelli Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/8250.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index a0127e93ade..fb867a9f55e 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -287,6 +287,13 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO, }, + [PORT_AR7] = { + .name = "AR7", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, }; #if defined (CONFIG_SERIAL_8250_AU1X00) -- cgit v1.2.3 From b5c6794fe4256fd63664aa185c468647c28bfd4a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 11 Jun 2009 13:23:02 +0100 Subject: Blackfin SPORT UART: fix typo in sport_set_termios prototype Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_sport_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index 529c0ff7952..fd5cb9576a0 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c @@ -419,7 +419,7 @@ static void sport_shutdown(struct uart_port *port) } static void sport_set_termios(struct uart_port *port, - struct termios *termios, struct termios *old) + struct ktermios *termios, struct ktermios *old) { pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); uart_update_timeout(port, CS8 ,port->uartclk); -- cgit v1.2.3 From a19e8b205915b2925aca75b2d2bf0c3104c8be14 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 11 Jun 2009 13:23:42 +0100 Subject: Blackfin SPORT UART: fix data misses while using transmit frame sync SPORT transmit frame sync (TFS) isn't used as an electrical signal during normal SPORT UART emulation. However, it is useful in EIA RS-485 emulation as RS-485 Transceiver Driver Enable DE strobe. This patch configures: TFS to be active high in order to drive an DE strobe of an eventually connected RS-485 Transceiver. Late frame sync mode (LATFS) gating the entire TX shift cycle. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_sport_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index fd5cb9576a0..6687ccd422b 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c @@ -149,7 +149,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) int tclkdiv, tfsdiv, rclkdiv; /* Set TCR1 and TCR2 */ - SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK)); + SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK)); SPORT_PUT_TCR2(up, 10); pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); -- cgit v1.2.3 From 4328e3e5ef1ae3427a4f6863aa65916a68ec2dd9 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 11 Jun 2009 13:37:11 +0100 Subject: Blackfin SPORT UART: rewrite inline assembly Hopefuly the new version is easier to read, but in the process it declares proper clobber lists and better constraints so that GCC can do a better job at allocating free registers. Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_sport_uart.c | 54 +++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index 6687ccd422b..34b4ae0fe76 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c @@ -101,15 +101,16 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) { pr_debug("%s value:%x\n", __func__, value); /* Place a Start and Stop bit */ - __asm__ volatile ( - "R2 = b#01111111100;\n\t" - "R3 = b#10000000001;\n\t" - "%0 <<= 2;\n\t" - "%0 = %0 & R2;\n\t" - "%0 = %0 | R3;\n\t" - :"=r"(value) - :"0"(value) - :"R2", "R3"); + __asm__ __volatile__ ( + "R2 = b#01111111100;" + "R3 = b#10000000001;" + "%0 <<= 2;" + "%0 = %0 & R2;" + "%0 = %0 | R3;" + : "=d"(value) + : "d"(value) + : "ASTAT", "R2", "R3" + ); pr_debug("%s value:%x\n", __func__, value); SPORT_PUT_TX(up, value); @@ -118,27 +119,30 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) static inline unsigned int rx_one_byte(struct sport_uart_port *up) { unsigned int value, extract; + u32 tmp_mask1, tmp_mask2, tmp_shift, tmp; value = SPORT_GET_RX32(up); pr_debug("%s value:%x\n", __func__, value); /* Extract 8 bits data */ - __asm__ volatile ( - "R5 = 0;\n\t" - "P0 = 8;\n\t" - "R1 = 0x1801(Z);\n\t" - "R3 = 0x0300(Z);\n\t" - "R4 = 0;\n\t" - "LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t" - "R2 = extract(%1, R1.L)(Z);\n\t" - "R2 <<= R4;\n\t" - "R5 = R5 | R2;\n\t" - "R1 = R1 - R3;\nloop_e:\t" - "R4 += 1;\n\t" - "%0 = R5;\n\t" - :"=r"(extract) - :"r"(value) - :"P0", "R1", "R2","R3","R4", "R5"); + __asm__ __volatile__ ( + "%[extr] = 0;" + "%[mask1] = 0x1801(Z);" + "%[mask2] = 0x0300(Z);" + "%[shift] = 0;" + "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];" + ".Lloop_s:" + "%[tmp] = extract(%[val], %[mask1].L)(Z);" + "%[tmp] <<= %[shift];" + "%[extr] = %[extr] | %[tmp];" + "%[mask1] = %[mask1] - %[mask2];" + ".Lloop_e:" + "%[shift] += 1;" + : [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp), + [mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2) + : "d"(value), [lc]"a"(8) + : "ASTAT", "LB0", "LC0", "LT0" + ); pr_debug(" extract:%x\n", extract); return extract; -- cgit v1.2.3 From 8516c568f25666a012ec4c859e640a76fc9b6ec0 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 11 Jun 2009 13:38:16 +0100 Subject: Blackfin Serial Driver: fix error while transferring large files Ignore receiving data if new position is in the same line of current buffer tail and is small. This should decrease overruns. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_5xx.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index d86123e0339..65a4c07f619 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -477,6 +477,15 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) spin_lock_irqsave(&uart->port.lock, flags); + /* 2D DMA RX buffer ring is used. Because curr_y_count and + * curr_x_count can't be read as an atomic operation, + * curr_y_count should be read before curr_x_count. When + * curr_x_count is read, curr_y_count may already indicate + * next buffer line. But, the position calculated here is + * still indicate the old line. The wrong position data may + * be smaller than current buffer tail, which cause garbages + * are received if it is not prohibit. + */ uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); x_pos = get_dma_curr_xcount(uart->rx_dma_channel); uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; @@ -487,7 +496,11 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) x_pos = 0; pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; - if (pos != uart->rx_dma_buf.tail) { + /* Ignore receiving data if new position is in the same line of + * current buffer tail and small. + */ + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { uart->rx_dma_buf.head = pos; bfin_serial_dma_rx_chars(uart); uart->rx_dma_buf.tail = uart->rx_dma_buf.head; @@ -532,11 +545,25 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; unsigned short irqstat; + int pos; spin_lock(&uart->port.lock); irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); clear_dma_irqstat(uart->rx_dma_channel); - bfin_serial_dma_rx_chars(uart); + + uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); + uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; + if (uart->rx_dma_nrows == DMA_RX_YCOUNT) + uart->rx_dma_nrows = 0; + + pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { + uart->rx_dma_buf.head = pos; + bfin_serial_dma_rx_chars(uart); + uart->rx_dma_buf.tail = uart->rx_dma_buf.head; + } + spin_unlock(&uart->port.lock); return IRQ_HANDLED; -- cgit v1.2.3 From 7de7c55bf54dede2bd2262349fc7b558bcc8e413 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Thu, 11 Jun 2009 13:38:57 +0100 Subject: Blackfin Serial Driver: fix baudrate for early_printk Since we already setup the early console UART in arch/blackfin/kernel/early_printk.c, and common functions which are enabled from the .setup will override the proper settings later, don't fill in these structures. Otherwise we get mangled baudrate settings when using early_printk. Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_5xx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 65a4c07f619..dfae22d47bf 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -1272,12 +1272,17 @@ static __init void early_serial_write(struct console *con, const char *s, } } +/* + * This should have a .setup or .early_setup in it, but then things get called + * without the command line options, and the baud rate gets messed up - so + * don't let the common infrastructure play with things. (see calls to setup + * & earlysetup in ./kernel/printk.c:register_console() + */ static struct __initdata console bfin_early_serial_console = { .name = "early_BFuart", .write = early_serial_write, .device = uart_console_device, .flags = CON_PRINTBUFFER, - .setup = bfin_serial_console_setup, .index = -1, .data = &bfin_serial_reg, }; -- cgit v1.2.3 From f9d36da9cdc2504cd9bb6034cfaba0673ce2d6df Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Thu, 11 Jun 2009 13:42:17 +0100 Subject: Blackfin Serial Driver: fix missing new lines when under load Add a SSYNC() into bfin_serial_dma_tx_chars() to ensure DMA registers are written with new data otherwise we might miss a byte or two when the system is under load. PIO mode is OK though. Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_5xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index dfae22d47bf..676efdad371 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -415,6 +415,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); set_dma_x_count(uart->tx_dma_channel, uart->tx_count); set_dma_x_modify(uart->tx_dma_channel, 1); + SSYNC(); enable_dma(uart->tx_dma_channel); UART_SET_IER(uart, ETBEI); -- cgit v1.2.3 From 35ff69357949cfff5c3d8e3038b77146872e3bd3 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 11 Jun 2009 13:42:57 +0100 Subject: Blackfin Serial Driver: handle irregular DMA register status in auto start mode This bug is caused by irregular behavior of DMA register CURR_X_COUNT and CURR_Y_COUNT when an auto restart uart rx DMA run to last byte in DMA buffer, trigger the interrupt and stay at this possiton. The status of current x and y is 0:7 instead of 512:8 or 0:8. The driver doesn't take care of this case when calculating the position. URL: http://blackfin.uclinux.org/gf/tracker/5063 Reported-by: Tomasz Motylewski Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_5xx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 676efdad371..854e96dfb07 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -490,7 +490,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); x_pos = get_dma_curr_xcount(uart->rx_dma_channel); uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; - if (uart->rx_dma_nrows == DMA_RX_YCOUNT) + if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) uart->rx_dma_nrows = 0; x_pos = DMA_RX_XCOUNT - x_pos; if (x_pos == DMA_RX_XCOUNT) @@ -546,15 +546,16 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; unsigned short irqstat; - int pos; + int x_pos, pos; spin_lock(&uart->port.lock); irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); clear_dma_irqstat(uart->rx_dma_channel); uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); + x_pos = get_dma_curr_xcount(uart->rx_dma_channel); uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; - if (uart->rx_dma_nrows == DMA_RX_YCOUNT) + if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) uart->rx_dma_nrows = 0; pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; -- cgit v1.2.3 From 0efa4f2c944fabffc81918cc86d4d17dba39a021 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 11 Jun 2009 13:45:07 +0100 Subject: Blackfin Serial Driver: annotate anomalies 05000215 and 05000099 Add some comments for how these anomalies are addressed: 05000215 - UART TX Interrupt Masked Erroneously We always clear ETBEI within last UART TX interrupt to end a string. It is always set when starting a new tx transfer. 05000099 - UART Line Status Register (UART_LSR) Bits Are Not Updated at the Same Time This anomaly affects driver only in POLL code where multi bits of UART_LSR are checked. It doesn't affect current bfin_5xx.c driver. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_5xx.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 854e96dfb07..ab583ef3a30 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -330,6 +330,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) /* Clear TFI bit */ UART_PUT_LSR(uart, TFI); #endif + /* Anomaly notes: + * 05000215 - we always clear ETBEI within last UART TX + * interrupt to end a string. It is always set + * when start a new tx. + */ UART_CLEAR_IER(uart, ETBEI); return; } @@ -528,6 +533,11 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { disable_dma(uart->tx_dma_channel); clear_dma_irqstat(uart->tx_dma_channel); + /* Anomaly notes: + * 05000215 - we always clear ETBEI within last UART TX + * interrupt to end a string. It is always set + * when start a new tx. + */ UART_CLEAR_IER(uart, ETBEI); xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); uart->port.icount.tx += uart->tx_count; @@ -969,6 +979,10 @@ static void bfin_serial_reset_irda(struct uart_port *port) } #ifdef CONFIG_CONSOLE_POLL +/* Anomaly notes: + * 05000099 - Because we only use THRE in poll_put and DR in poll_get, + * losing other bits of UART_LSR is not a problem here. + */ static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -- cgit v1.2.3 From 84507794a9d5d4decd6bc9c111480076dba0d301 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 11 Jun 2009 13:50:20 +0100 Subject: Blackfin Serial Driver: handle anomaly 05000231 05000231 - UART STB Bit Incorrectly Affects Receiver Setting For processors affected by this, we cannot safely allow CSTOPB to be set as the UART will then be unable to properly clock in bytes. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_5xx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index ab583ef3a30..64603f5bb70 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -828,8 +828,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, __func__); } - if (termios->c_cflag & CSTOPB) - lcr |= STB; + /* Anomaly notes: + * 05000231 - STOP bit is always set to 1 whatever the user is set. + */ + if (termios->c_cflag & CSTOPB) { + if (ANOMALY_05000231) + printk(KERN_WARNING "STOP bits other than 1 is not " + "supported in case of anomaly 05000231.\n"); + else + lcr |= STB; + } if (termios->c_cflag & PARENB) lcr |= PEN; if (!(termios->c_cflag & PARODD)) -- cgit v1.2.3 From 2860b7911137eabb01c159abefb506e538ff3cb7 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 11 Jun 2009 13:51:33 +0100 Subject: Blackfin Serial Driver: disable dma rx interrupt only rather than all irqs The UART RX handling code isn't exactly speeding, so don't go disabling all interrupts when processing the buffer. Just disable the relevant DMA interrupt. This greatly improves latency of the system when utilizing the UART. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/bfin_5xx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 64603f5bb70..e2f6b1bfac9 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -479,9 +479,9 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) { int x_pos, pos; - unsigned long flags; - spin_lock_irqsave(&uart->port.lock, flags); + dma_disable_irq(uart->rx_dma_channel); + spin_lock_bh(&uart->port.lock); /* 2D DMA RX buffer ring is used. Because curr_y_count and * curr_x_count can't be read as an atomic operation, @@ -512,7 +512,8 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) uart->rx_dma_buf.tail = uart->rx_dma_buf.head; } - spin_unlock_irqrestore(&uart->port.lock, flags); + spin_unlock_bh(&uart->port.lock); + dma_enable_irq(uart->rx_dma_channel); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); } -- cgit v1.2.3 From 34aec591847c696339189b070cce2a11f901cfea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20R=C3=B6jfors?= Date: Thu, 11 Jun 2009 14:05:39 +0100 Subject: serial: Added Timberdale UART driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Driver for the UART found in the Timberdale FPGA Signed-off-by: Richard Röjfors Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/Kconfig | 7 + drivers/serial/Makefile | 1 + drivers/serial/timbuart.c | 520 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/serial/timbuart.h | 58 ++++++ 4 files changed, 586 insertions(+) create mode 100644 drivers/serial/timbuart.c create mode 100644 drivers/serial/timbuart.h (limited to 'drivers/serial') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 343e3a35b6a..3391ef0d761 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1433,4 +1433,11 @@ config SPORT_BAUD_RATE default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) +config SERIAL_TIMBERDALE + tristate "Support for timberdale UART" + depends on MFD_TIMBERDALE + select SERIAL_CORE + ---help--- + Add support for UART controller on timberdale. + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index d438eb2a73d..45a8658f54d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -77,3 +77,4 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o +obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c new file mode 100644 index 00000000000..30ba3c4cc18 --- /dev/null +++ b/drivers/serial/timbuart.c @@ -0,0 +1,520 @@ +/* + * timbuart.c timberdale FPGA UART driver + * Copyright (c) 2009 Intel Corporation + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * Timberdale FPGA UART + */ + +#include +#include +#include +#include +#include +#include + +#include "timbuart.h" + +struct timbuart_port { + struct uart_port port; + struct tasklet_struct tasklet; + int usedma; + u8 last_ier; + struct platform_device *dev; +}; + +static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, + 921600, 1843200, 3250000}; + +static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier); + +static irqreturn_t timbuart_handleinterrupt(int irq, void *devid); + +static void timbuart_stop_rx(struct uart_port *port) +{ + /* spin lock held by upper layer, disable all RX interrupts */ + u8 ier = ioread8(port->membase + TIMBUART_IER) & ~RXFLAGS; + iowrite8(ier, port->membase + TIMBUART_IER); +} + +static void timbuart_stop_tx(struct uart_port *port) +{ + /* spinlock held by upper layer, disable TX interrupt */ + u8 ier = ioread8(port->membase + TIMBUART_IER) & ~TXBAE; + iowrite8(ier, port->membase + TIMBUART_IER); +} + +static void timbuart_start_tx(struct uart_port *port) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + + /* do not transfer anything here -> fire off the tasklet */ + tasklet_schedule(&uart->tasklet); +} + +static void timbuart_flush_buffer(struct uart_port *port) +{ + u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | TIMBUART_CTRL_FLSHTX; + + iowrite8(ctl, port->membase + TIMBUART_CTRL); + iowrite8(TXBF, port->membase + TIMBUART_ISR); +} + +static void timbuart_rx_chars(struct uart_port *port) +{ + struct tty_struct *tty = port->info->port.tty; + + while (ioread8(port->membase + TIMBUART_ISR) & RXDP) { + u8 ch = ioread8(port->membase + TIMBUART_RXFIFO); + port->icount.rx++; + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(port->info->port.tty); + spin_lock(&port->lock); + + dev_dbg(port->dev, "%s - total read %d bytes\n", + __func__, port->icount.rx); +} + +static void timbuart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + while (!(ioread8(port->membase + TIMBUART_ISR) & TXBF) && + !uart_circ_empty(xmit)) { + iowrite8(xmit->buf[xmit->tail], + port->membase + TIMBUART_TXFIFO); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + dev_dbg(port->dev, + "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n", + __func__, + port->icount.tx, + ioread8(port->membase + TIMBUART_CTRL), + port->mctrl & TIOCM_RTS, + ioread8(port->membase + TIMBUART_BAUDRATE)); +} + +static void timbuart_handle_tx_port(struct uart_port *port, u8 isr, u8 *ier) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + struct circ_buf *xmit = &port->info->xmit; + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return; + + if (port->x_char) + return; + + if (isr & TXFLAGS) { + timbuart_tx_chars(port); + /* clear all TX interrupts */ + iowrite8(TXFLAGS, port->membase + TIMBUART_ISR); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + } else + /* Re-enable any tx interrupt */ + *ier |= uart->last_ier & TXFLAGS; + + /* enable interrupts if there are chars in the transmit buffer, + * Or if we delivered some bytes and want the almost empty interrupt + * we wake up the upper layer later when we got the interrupt + * to give it some time to go out... + */ + if (!uart_circ_empty(xmit)) + *ier |= TXBAE; + + dev_dbg(port->dev, "%s - leaving\n", __func__); +} + +void timbuart_handle_rx_port(struct uart_port *port, u8 isr, u8 *ier) +{ + if (isr & RXFLAGS) { + /* Some RX status is set */ + if (isr & RXBF) { + u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | + TIMBUART_CTRL_FLSHRX; + iowrite8(ctl, port->membase + TIMBUART_CTRL); + port->icount.overrun++; + } else if (isr & (RXDP)) + timbuart_rx_chars(port); + + /* ack all RX interrupts */ + iowrite8(RXFLAGS, port->membase + TIMBUART_ISR); + } + + /* always have the RX interrupts enabled */ + *ier |= RXBAF | RXBF | RXTT; + + dev_dbg(port->dev, "%s - leaving\n", __func__); +} + +void timbuart_tasklet(unsigned long arg) +{ + struct timbuart_port *uart = (struct timbuart_port *)arg; + u8 isr, ier = 0; + + spin_lock(&uart->port.lock); + + isr = ioread8(uart->port.membase + TIMBUART_ISR); + dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr); + + if (!uart->usedma) + timbuart_handle_tx_port(&uart->port, isr, &ier); + + timbuart_mctrl_check(&uart->port, isr, &ier); + + if (!uart->usedma) + timbuart_handle_rx_port(&uart->port, isr, &ier); + + iowrite8(ier, uart->port.membase + TIMBUART_IER); + + spin_unlock(&uart->port.lock); + dev_dbg(uart->port.dev, "%s leaving\n", __func__); +} + +static unsigned int timbuart_tx_empty(struct uart_port *port) +{ + u8 isr = ioread8(port->membase + TIMBUART_ISR); + + return (isr & TXBAE) ? TIOCSER_TEMT : 0; +} + +static unsigned int timbuart_get_mctrl(struct uart_port *port) +{ + u8 cts = ioread8(port->membase + TIMBUART_CTRL); + dev_dbg(port->dev, "%s - cts %x\n", __func__, cts); + + if (cts & TIMBUART_CTRL_CTS) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + else + return TIOCM_DSR | TIOCM_CAR; +} + +static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + dev_dbg(port->dev, "%s - %x\n", __func__, mctrl); + + if (mctrl & TIOCM_RTS) + iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); + else + iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); +} + +static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier) +{ + unsigned int cts; + + if (isr & CTS_DELTA) { + /* ack */ + iowrite8(CTS_DELTA, port->membase + TIMBUART_ISR); + cts = timbuart_get_mctrl(port); + uart_handle_cts_change(port, cts & TIOCM_CTS); + wake_up_interruptible(&port->info->delta_msr_wait); + } + + *ier |= CTS_DELTA; +} + +static void timbuart_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +static void timbuart_break_ctl(struct uart_port *port, int ctl) +{ + /* N/A */ +} + +static int timbuart_startup(struct uart_port *port) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + + dev_dbg(port->dev, "%s\n", __func__); + + iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL); + iowrite8(0xff, port->membase + TIMBUART_ISR); + /* Enable all but TX interrupts */ + iowrite8(RXBAF | RXBF | RXTT | CTS_DELTA, + port->membase + TIMBUART_IER); + + return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED, + "timb-uart", uart); +} + +static void timbuart_shutdown(struct uart_port *port) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + dev_dbg(port->dev, "%s\n", __func__); + free_irq(port->irq, uart); + iowrite8(0, port->membase + TIMBUART_IER); +} + +static int get_bindex(int baud) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(baudrates); i++) + if (baud == baudrates[i]) + return i; + + return -1; +} + +static void timbuart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud; + short bindex; + unsigned long flags; + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + bindex = get_bindex(baud); + dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex); + + if (bindex < 0) { + printk(KERN_ALERT "timbuart: Unsupported baud rate\n"); + } else { + spin_lock_irqsave(&port->lock, flags); + iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock_irqrestore(&port->lock, flags); + } +} + +static const char *timbuart_type(struct uart_port *port) +{ + return port->type == PORT_UNKNOWN ? "timbuart" : NULL; +} + +/* We do not request/release mappings of the registers here, + * currently it's done in the proble function. + */ +static void timbuart_release_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + int size = + resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); + + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, size); +} + +static int timbuart_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + int size = + resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); + + if (!request_mem_region(port->mapbase, size, "timb-uart")) + return -EBUSY; + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, size); + if (port->membase == NULL) { + release_mem_region(port->mapbase, size); + return -ENOMEM; + } + } + + return 0; +} + +static irqreturn_t timbuart_handleinterrupt(int irq, void *devid) +{ + struct timbuart_port *uart = (struct timbuart_port *)devid; + + if (ioread8(uart->port.membase + TIMBUART_IPR)) { + uart->last_ier = ioread8(uart->port.membase + TIMBUART_IER); + + /* disable interrupts, the tasklet enables them again */ + iowrite8(0, uart->port.membase + TIMBUART_IER); + + /* fire off bottom half */ + tasklet_schedule(&uart->tasklet); + + return IRQ_HANDLED; + } else + return IRQ_NONE; +} + +/* + * Configure/autoconfigure the port. + */ +static void timbuart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_TIMBUART; + timbuart_request_port(port); + } +} + +static int timbuart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + /* we don't want the core code to modify any port params */ + return -EINVAL; +} + +static struct uart_ops timbuart_ops = { + .tx_empty = timbuart_tx_empty, + .set_mctrl = timbuart_set_mctrl, + .get_mctrl = timbuart_get_mctrl, + .stop_tx = timbuart_stop_tx, + .start_tx = timbuart_start_tx, + .flush_buffer = timbuart_flush_buffer, + .stop_rx = timbuart_stop_rx, + .enable_ms = timbuart_enable_ms, + .break_ctl = timbuart_break_ctl, + .startup = timbuart_startup, + .shutdown = timbuart_shutdown, + .set_termios = timbuart_set_termios, + .type = timbuart_type, + .release_port = timbuart_release_port, + .request_port = timbuart_request_port, + .config_port = timbuart_config_port, + .verify_port = timbuart_verify_port +}; + +static struct uart_driver timbuart_driver = { + .owner = THIS_MODULE, + .driver_name = "timberdale_uart", + .dev_name = "ttyTU", + .major = TIMBUART_MAJOR, + .minor = TIMBUART_MINOR, + .nr = 1 +}; + +static int timbuart_probe(struct platform_device *dev) +{ + int err; + struct timbuart_port *uart; + struct resource *iomem; + + dev_dbg(&dev->dev, "%s\n", __func__); + + uart = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) { + err = -EINVAL; + goto err_mem; + } + + uart->usedma = 0; + + uart->port.uartclk = 3250000 * 16; + uart->port.fifosize = TIMBUART_FIFO_SIZE; + uart->port.regshift = 2; + uart->port.iotype = UPIO_MEM; + uart->port.ops = &timbuart_ops; + uart->port.irq = 0; + uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; + uart->port.line = 0; + uart->port.dev = &dev->dev; + + iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!iomem) { + err = -ENOMEM; + goto err_register; + } + uart->port.mapbase = iomem->start; + uart->port.membase = NULL; + + uart->port.irq = platform_get_irq(dev, 0); + if (uart->port.irq < 0) { + err = -EINVAL; + goto err_register; + } + + tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart); + + err = uart_register_driver(&timbuart_driver); + if (err) + goto err_register; + + err = uart_add_one_port(&timbuart_driver, &uart->port); + if (err) + goto err_add_port; + + platform_set_drvdata(dev, uart); + + return 0; + +err_add_port: + uart_unregister_driver(&timbuart_driver); +err_register: + kfree(uart); +err_mem: + printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n", + err); + + return err; +} + +static int timbuart_remove(struct platform_device *dev) +{ + struct timbuart_port *uart = platform_get_drvdata(dev); + + tasklet_kill(&uart->tasklet); + uart_remove_one_port(&timbuart_driver, &uart->port); + uart_unregister_driver(&timbuart_driver); + kfree(uart); + + return 0; +} + +static struct platform_driver timbuart_platform_driver = { + .driver = { + .name = "timb-uart", + .owner = THIS_MODULE, + }, + .probe = timbuart_probe, + .remove = timbuart_remove, +}; + +/*--------------------------------------------------------------------------*/ + +static int __init timbuart_init(void) +{ + return platform_driver_register(&timbuart_platform_driver); +} + +static void __exit timbuart_exit(void) +{ + platform_driver_unregister(&timbuart_platform_driver); +} + +module_init(timbuart_init); +module_exit(timbuart_exit); + +MODULE_DESCRIPTION("Timberdale UART driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:timb-uart"); + diff --git a/drivers/serial/timbuart.h b/drivers/serial/timbuart.h new file mode 100644 index 00000000000..7e566766bc4 --- /dev/null +++ b/drivers/serial/timbuart.h @@ -0,0 +1,58 @@ +/* + * timbuart.c timberdale FPGA GPIO driver + * Copyright (c) 2009 Intel Corporation + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * Timberdale FPGA UART + */ + +#ifndef _TIMBUART_H +#define _TIMBUART_H + +#define TIMBUART_FIFO_SIZE 2048 + +#define TIMBUART_RXFIFO 0x08 +#define TIMBUART_TXFIFO 0x0c +#define TIMBUART_IER 0x10 +#define TIMBUART_IPR 0x14 +#define TIMBUART_ISR 0x18 +#define TIMBUART_CTRL 0x1c +#define TIMBUART_BAUDRATE 0x20 + +#define TIMBUART_CTRL_RTS 0x01 +#define TIMBUART_CTRL_CTS 0x02 +#define TIMBUART_CTRL_FLSHTX 0x40 +#define TIMBUART_CTRL_FLSHRX 0x80 + +#define TXBF 0x01 +#define TXBAE 0x02 +#define CTS_DELTA 0x04 +#define RXDP 0x08 +#define RXBAF 0x10 +#define RXBF 0x20 +#define RXTT 0x40 +#define RXBNAE 0x80 +#define TXBE 0x100 + +#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE) +#define TXFLAGS (TXBF | TXBAE) + +#define TIMBUART_MAJOR 204 +#define TIMBUART_MINOR 192 + +#endif /* _TIMBUART_H */ + -- cgit v1.2.3 From 7d55deaf50182c47c1e805dc8cc85f2769f0673e Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 11 Jun 2009 14:27:13 +0100 Subject: timbuart: Fix the termios logic The driver only handles speeds but it fails to return the current values for the hardware features it does not support. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/timbuart.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c index 30ba3c4cc18..ac9e5d5f742 100644 --- a/drivers/serial/timbuart.c +++ b/drivers/serial/timbuart.c @@ -278,7 +278,7 @@ static int get_bindex(int baud) int i; for (i = 0; i < ARRAY_SIZE(baudrates); i++) - if (baud == baudrates[i]) + if (baud <= baudrates[i]) return i; return -1; @@ -296,14 +296,20 @@ static void timbuart_set_termios(struct uart_port *port, bindex = get_bindex(baud); dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex); - if (bindex < 0) { - printk(KERN_ALERT "timbuart: Unsupported baud rate\n"); - } else { - spin_lock_irqsave(&port->lock, flags); - iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); - uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); - } + if (bindex < 0) + bindex = 0; + baud = baudrates[bindex]; + + /* The serial layer calls into this once with old = NULL when setting + up initially */ + if (old) + tty_termios_copy_hw(termios, old); + tty_termios_encode_baud_rate(termios, baud, baud); + + spin_lock_irqsave(&port->lock, flags); + iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock_irqrestore(&port->lock, flags); } static const char *timbuart_type(struct uart_port *port) -- cgit v1.2.3 From d3810cd4d7064b109574374f73c41b11b481dbf2 Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Thu, 11 Jun 2009 14:35:01 +0100 Subject: imx: serial: fix whitespaces (no changes in functionality) Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 5f0be40dfda..76c8fa1884e 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -302,8 +302,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport) /* send xmit->buf[xmit->tail] * out the port here */ writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); - xmit->tail = (xmit->tail + 1) & - (UART_XMIT_SIZE - 1); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); sport->port.icount.tx++; if (uart_circ_empty(xmit)) break; @@ -395,8 +394,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) continue; } - if (uart_handle_sysrq_char - (&sport->port, (unsigned char)rx)) + if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) continue; if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { @@ -471,26 +469,26 @@ static unsigned int imx_tx_empty(struct uart_port *port) */ static unsigned int imx_get_mctrl(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; - unsigned int tmp = TIOCM_DSR | TIOCM_CAR; + struct imx_port *sport = (struct imx_port *)port; + unsigned int tmp = TIOCM_DSR | TIOCM_CAR; - if (readl(sport->port.membase + USR1) & USR1_RTSS) - tmp |= TIOCM_CTS; + if (readl(sport->port.membase + USR1) & USR1_RTSS) + tmp |= TIOCM_CTS; - if (readl(sport->port.membase + UCR2) & UCR2_CTS) - tmp |= TIOCM_RTS; + if (readl(sport->port.membase + UCR2) & UCR2_CTS) + tmp |= TIOCM_RTS; - return tmp; + return tmp; } static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = (struct imx_port *)port; unsigned long temp; temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; - if (mctrl & TIOCM_RTS) + if (mctrl & TIOCM_RTS) temp |= UCR2_CTS; writel(temp, sport->port.membase + UCR2); @@ -1072,22 +1070,22 @@ static struct uart_driver imx_reg = { static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) { - struct imx_port *sport = platform_get_drvdata(dev); + struct imx_port *sport = platform_get_drvdata(dev); - if (sport) - uart_suspend_port(&imx_reg, &sport->port); + if (sport) + uart_suspend_port(&imx_reg, &sport->port); - return 0; + return 0; } static int serial_imx_resume(struct platform_device *dev) { - struct imx_port *sport = platform_get_drvdata(dev); + struct imx_port *sport = platform_get_drvdata(dev); - if (sport) - uart_resume_port(&imx_reg, &sport->port); + if (sport) + uart_resume_port(&imx_reg, &sport->port); - return 0; + return 0; } static int serial_imx_probe(struct platform_device *pdev) @@ -1143,7 +1141,7 @@ static int serial_imx_probe(struct platform_device *pdev) imx_ports[pdev->id] = sport; pdata = pdev->dev.platform_data; - if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) + if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) sport->have_rtscts = 1; if (pdata->init) { @@ -1193,13 +1191,13 @@ static int serial_imx_remove(struct platform_device *pdev) } static struct platform_driver serial_imx_driver = { - .probe = serial_imx_probe, - .remove = serial_imx_remove, + .probe = serial_imx_probe, + .remove = serial_imx_remove, .suspend = serial_imx_suspend, .resume = serial_imx_resume, .driver = { - .name = "imx-uart", + .name = "imx-uart", .owner = THIS_MODULE, }, }; -- cgit v1.2.3 From 26bbb3ff1ff6163d6a233055766e26af8054a212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gl=C3=B6ckner?= Date: Thu, 11 Jun 2009 14:36:29 +0100 Subject: imx: serial: fix one bit field type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "have_rtscts" is assigned 1, while it is declared int:1, two's complement, which can hold 0 and -1 only. The code works, as the upper bits are cut off, and tests are done against 0 only. Nonetheless, correctly declaring the bit field as unsigned int:1 renders the code more robust. Signed-off-by: Daniel Glöckner Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 76c8fa1884e..6b8f12f4a70 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -211,7 +211,7 @@ struct imx_port { struct timer_list timer; unsigned int old_status; int txirq,rxirq,rtsirq; - int have_rtscts:1; + unsigned int have_rtscts:1; struct clk *clk; }; -- cgit v1.2.3 From 977757311e50dc5d832c9fef34e7555411f7ccd8 Mon Sep 17 00:00:00 2001 From: Fabian Godehardt Date: Thu, 11 Jun 2009 14:37:19 +0100 Subject: imx: serial: notify higher layers in case xmit IRQ was not called upper layers, namely line discipline, need to be notified when transmission of more data is possible. For spurious cases, where IRQ handling does not supply notification for sure, it is given additionally here, when data has just been transmitted and space in the buffer will most probably be available. Signed-off-by: Fabian Godehardt Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 6b8f12f4a70..49f2e12ba58 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -308,6 +308,9 @@ static inline void imx_transmit_buffer(struct imx_port *sport) break; } + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + if (uart_circ_empty(xmit)) imx_stop_tx(&sport->port); } -- cgit v1.2.3 From 2e1463922a35584c863f71d4021e1e71f76eaed0 Mon Sep 17 00:00:00 2001 From: Fabian Godehardt Date: Thu, 11 Jun 2009 14:38:38 +0100 Subject: imx: serial: be sure to stop xmit upon shutdown needed to avoid continued transmission by hardware while software already shuts down, which might cause dangling characters to show up in hardware queues when restarting the device. Signed-off-by: Fabian Godehardt Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 49f2e12ba58..e6c2ba26dcb 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -634,6 +634,10 @@ static void imx_shutdown(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_TXEN); + writel(temp, sport->port.membase + UCR2); + /* * Stop our timer. */ -- cgit v1.2.3 From 9f322ad064f9210e7d472dfe77e702274d5c9dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gl=C3=B6ckner?= Date: Thu, 11 Jun 2009 14:39:21 +0100 Subject: imx: serial: handle initialisation failure correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit correctly de-initialise device when setting up failed, call to pdata->exit() was missing. Signed-off-by: Daniel Glöckner Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index e6c2ba26dcb..cbd4f322464 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -1157,10 +1157,15 @@ static int serial_imx_probe(struct platform_device *pdev) goto clkput; } - uart_add_one_port(&imx_reg, &sport->port); + ret = uart_add_one_port(&imx_reg, &sport->port); + if (ret) + goto deinit; platform_set_drvdata(pdev, &sport->port); return 0; +deinit: + if (pdata->exit) + pdata->exit(pdev); clkput: clk_put(sport->clk); clk_disable(sport->clk); -- cgit v1.2.3 From 534fca068ec8063ec8b67626b3eb34ba6ec86967 Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Thu, 11 Jun 2009 14:52:23 +0100 Subject: imx: serial: use rational library function for calculation of numerator and denominator used in baud rate setting, use generic library function for optimum settings. Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/Kconfig | 1 + drivers/serial/imx.c | 30 ++++++++++-------------------- 2 files changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 3391ef0d761..641e800ed69 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -833,6 +833,7 @@ config SERIAL_IMX bool "IMX serial port support" depends on ARM && (ARCH_IMX || ARCH_MXC) select SERIAL_CORE + select RATIONAL help If you have a machine based on a Motorola IMX CPU you can enable its onboard serial port by enabling this option. diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index cbd4f322464..0de81f71f88 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -670,7 +671,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, unsigned long flags; unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - unsigned int div, num, denom, ufcr; + unsigned int div, ufcr; + unsigned long num, denom; /* * If we don't support modem control lines, don't allow @@ -772,32 +774,20 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, if (!div) div = 1; - num = baud; - denom = port->uartclk / div / 16; + rational_best_approximation(16 * div * baud, sport->port.uartclk, + 1 << 16, 1 << 16, &num, &denom); - /* shift num and denom right until they fit into 16 bits */ - while (num > 0x10000 || denom > 0x10000) { - num >>= 1; - denom >>= 1; - } - if (num > 0) - num -= 1; - if (denom > 0) - denom -= 1; - - writel(num, sport->port.membase + UBIR); - writel(denom, sport->port.membase + UBMR); - - if (div == 7) - div = 6; /* 6 in RFDIV means divide by 7 */ - else - div = 6 - div; + num -= 1; + denom -= 1; ufcr = readl(sport->port.membase + UFCR); ufcr = (ufcr & (~UFCR_RFDIV)) | (div << 7); writel(ufcr, sport->port.membase + UFCR); + writel(num, sport->port.membase + UBIR); + writel(denom, sport->port.membase + UBMR); + #ifdef ONEMS writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); #endif -- cgit v1.2.3 From b6e4913834cd032082e5c76dfade61050212dc98 Mon Sep 17 00:00:00 2001 From: Fabian Godehardt Date: Thu, 11 Jun 2009 14:53:18 +0100 Subject: imx: serial: add IrDA support to serial driver Using the iMX serial driver with an IrDA device needs extra peripheral settings and specific timing depending on the transmitter circuitry used. Signed-off-by: Fabian Godehardt Signed-off-by: Oskar Schirmer Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 176 insertions(+), 19 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 0de81f71f88..8c79e8c2fd4 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -8,6 +8,9 @@ * Author: Sascha Hauer * Copyright (C) 2004 Pengutronix * + * Copyright (C) 2009 emlix GmbH + * Author: Fabian Godehardt (added IrDA support for iMX) + * * 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 @@ -41,6 +44,7 @@ #include #include #include +#include #include #include @@ -149,6 +153,7 @@ #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ #define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ #define USR1_RTSS (1<<14) /* RTS pin status */ @@ -213,9 +218,19 @@ struct imx_port { unsigned int old_status; int txirq,rxirq,rtsirq; unsigned int have_rtscts:1; + unsigned int use_irda:1; + unsigned int irda_inv_rx:1; + unsigned int irda_inv_tx:1; + unsigned short trcv_delay; /* transceiver delay */ struct clk *clk; }; +#ifdef CONFIG_IRDA +#define USE_IRDA(sport) ((sport)->use_irda) +#else +#define USE_IRDA(sport) (0) +#endif + /* * Handle any change of modem status signal since we were last called. */ @@ -269,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + if (USE_IRDA(sport)) { + /* half duplex - wait for end of transmission */ + int n = 256; + while ((--n > 0) && + !(readl(sport->port.membase + USR2) & USR2_TXDC)) { + udelay(5); + barrier(); + } + /* + * irda transceiver - wait a bit more to avoid + * cutoff, hardware dependent + */ + udelay(sport->trcv_delay); + + /* + * half duplex - reactivate receive mode, + * flush receive pipe echo crap + */ + if (readl(sport->port.membase + USR2) & USR2_TXDC) { + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp &= ~(UCR4_TCEN); + writel(temp, sport->port.membase + UCR4); + + while (readl(sport->port.membase + URXD0) & + URXD_CHARRDY) + barrier(); + + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RRDYEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_DREN; + writel(temp, sport->port.membase + UCR4); + } + return; + } + temp = readl(sport->port.membase + UCR1); writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); } @@ -324,9 +381,30 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + if (USE_IRDA(sport)) { + /* half duplex in IrDA mode; have to disable receive mode */ + temp = readl(sport->port.membase + UCR4); + temp &= ~(UCR4_DREN); + writel(temp, sport->port.membase + UCR4); + + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_RRDYEN); + writel(temp, sport->port.membase + UCR1); + } + temp = readl(sport->port.membase + UCR1); writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); + if (USE_IRDA(sport)) { + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_TRDYEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_TCEN; + writel(temp, sport->port.membase + UCR4); + } + if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) imx_transmit_buffer(sport); } @@ -536,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) if(!ufcr_rfdiv) ufcr_rfdiv = 1; - if(ufcr_rfdiv >= 7) - ufcr_rfdiv = 6; - else - ufcr_rfdiv = 6 - ufcr_rfdiv; - - val |= UFCR_RFDIV & (ufcr_rfdiv << 7); + val |= UFCR_RFDIV_REG(ufcr_rfdiv); writel(val, sport->port.membase + UFCR); @@ -560,8 +633,24 @@ static int imx_startup(struct uart_port *port) * requesting IRQs */ temp = readl(sport->port.membase + UCR4); + + if (USE_IRDA(sport)) + temp |= UCR4_IRSC; + 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); + } + } + /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later * chips only have one interrupt. @@ -577,12 +666,16 @@ static int imx_startup(struct uart_port *port) if (retval) goto error_out2; - retval = request_irq(sport->rtsirq, imx_rtsint, - (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - DRIVER_NAME, sport); - if (retval) - goto error_out3; + /* do not use RTS IRQ on IrDA */ + if (!USE_IRDA(sport)) { + retval = request_irq(sport->rtsirq, imx_rtsint, + (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, + DRIVER_NAME, sport); + if (retval) + goto error_out3; + } } else { retval = request_irq(sport->port.irq, imx_int, 0, DRIVER_NAME, sport); @@ -599,18 +692,49 @@ static int imx_startup(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; + + if (USE_IRDA(sport)) { + temp |= UCR1_IREN; + temp &= ~(UCR1_RTSDEN); + } + writel(temp, sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR2); temp |= (UCR2_RXEN | UCR2_TXEN); 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 defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 temp = readl(sport->port.membase + UCR3); temp |= UCR3_RXDMUXSEL; writel(temp, sport->port.membase + UCR3); #endif + if (USE_IRDA(sport)) { + temp = readl(sport->port.membase + UCR4); + if (sport->irda_inv_rx) + temp |= UCR4_INVR; + else + temp &= ~(UCR4_INVR); + writel(temp | UCR4_DREN, sport->port.membase + UCR4); + + temp = readl(sport->port.membase + UCR3); + if (sport->irda_inv_tx) + temp |= UCR3_INVT; + else + temp &= ~(UCR3_INVT); + writel(temp, sport->port.membase + UCR3); + } + /* * Enable modem status interrupts */ @@ -618,6 +742,16 @@ static int imx_startup(struct uart_port *port) imx_enable_ms(&sport->port); spin_unlock_irqrestore(&sport->port.lock,flags); + if (USE_IRDA(sport)) { + struct imxuart_platform_data *pdata; + pdata = sport->port.dev->platform_data; + sport->irda_inv_rx = pdata->irda_inv_rx; + sport->irda_inv_tx = pdata->irda_inv_tx; + sport->trcv_delay = pdata->transceiver_delay; + if (pdata->irda_enable) + pdata->irda_enable(1); + } + return 0; error_out3: @@ -639,6 +773,13 @@ static void imx_shutdown(struct uart_port *port) temp &= ~(UCR2_TXEN); writel(temp, sport->port.membase + UCR2); + if (USE_IRDA(sport)) { + struct imxuart_platform_data *pdata; + pdata = sport->port.dev->platform_data; + if (pdata->irda_enable) + pdata->irda_enable(0); + } + /* * Stop our timer. */ @@ -648,7 +789,8 @@ static void imx_shutdown(struct uart_port *port) * Free the interrupts */ if (sport->txirq > 0) { - free_irq(sport->rtsirq, sport); + if (!USE_IRDA(sport)) + free_irq(sport->rtsirq, sport); free_irq(sport->txirq, sport); free_irq(sport->rxirq, sport); } else @@ -660,6 +802,9 @@ static void imx_shutdown(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + if (USE_IRDA(sport)) + temp &= ~(UCR1_IREN); + writel(temp, sport->port.membase + UCR1); } @@ -768,11 +913,19 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.membase + UCR2); old_txrxen &= (UCR2_TXEN | UCR2_RXEN); - div = sport->port.uartclk / (baud * 16); - if (div > 7) - div = 7; - if (!div) + if (USE_IRDA(sport)) { + /* + * use maximum available submodule frequency to + * avoid missing short pulses due to low sampling rate + */ div = 1; + } else { + div = sport->port.uartclk / (baud * 16); + if (div > 7) + div = 7; + if (!div) + div = 1; + } rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); @@ -781,8 +934,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, denom -= 1; ufcr = readl(sport->port.membase + UFCR); - ufcr = (ufcr & (~UFCR_RFDIV)) | - (div << 7); + ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); writel(ufcr, sport->port.membase + UFCR); writel(num, sport->port.membase + UBIR); @@ -1141,6 +1293,11 @@ static int serial_imx_probe(struct platform_device *pdev) if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) sport->have_rtscts = 1; +#ifdef CONFIG_IRDA + if (pdata && (pdata->flags & IMXUART_IRDA)) + sport->use_irda = 1; +#endif + if (pdata->init) { ret = pdata->init(pdev); if (ret) -- cgit v1.2.3 From d7f8d437bda0ec409e26cffb846bc28a40603ee3 Mon Sep 17 00:00:00 2001 From: Oskar Schirmer Date: Thu, 11 Jun 2009 14:55:22 +0100 Subject: imx: serial: use tty_encode_baud_rate to set true rate real baud rate may be different from the one requested. for upper layers, set the nearest value to the real rate in favour of the rate previously requested. Signed-off-by: Oskar Schirmer Signed-off-by: Linus Torvalds --- drivers/serial/imx.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 8c79e8c2fd4..7b5d1de9cfe 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -818,6 +818,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned int div, ufcr; unsigned long num, denom; + uint64_t tdiv64; /* * If we don't support modem control lines, don't allow @@ -930,6 +931,12 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); + tdiv64 = sport->port.uartclk; + tdiv64 *= num; + do_div(tdiv64, denom * 16 * div); + tty_encode_baud_rate(sport->port.info->port.tty, + (speed_t)tdiv64, (speed_t)tdiv64); + num -= 1; denom -= 1; -- cgit v1.2.3 From 4737f0978d6e64eae468e01fa181abf6499e6b84 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 5 Jun 2009 00:44:53 +0200 Subject: trivial: Kconfig: .ko is normally not included in module names .ko is normally not included in Kconfig help, make it consistent. Signed-off-by: Pavel Machek Signed-off-by: Jiri Kosina --- drivers/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 641e800ed69..1132c5cae7a 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -861,7 +861,7 @@ config SERIAL_UARTLITE Say Y here if you want to use the Xilinx uartlite serial controller. To compile this driver as a module, choose M here: the - module will be called uartlite.ko. + module will be called uartlite. config SERIAL_UARTLITE_CONSOLE bool "Support for console on Xilinx uartlite serial port" -- cgit v1.2.3