diff options
Diffstat (limited to 'drivers/serial/sh-sci.c')
-rw-r--r-- | drivers/serial/sh-sci.c | 113 |
1 files changed, 49 insertions, 64 deletions
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 6498bd1fb6dd..68c7f6cfd728 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -50,7 +50,6 @@ #include <linux/list.h> #ifdef CONFIG_SUPERH -#include <asm/clock.h> #include <asm/sh_bios.h> #endif @@ -79,22 +78,18 @@ struct sci_port { struct timer_list break_timer; int break_flag; -#ifdef CONFIG_HAVE_CLK /* Interface clock */ struct clk *iclk; /* Data clock */ struct clk *dclk; -#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 }; /* Function prototypes */ @@ -156,32 +151,6 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ -#if defined(__H8300S__) -enum { sci_disable, sci_enable }; - -static void h8300_sci_config(struct uart_port *port, unsigned int ctrl) -{ - volatile unsigned char *mstpcrl = (volatile unsigned char *)MSTPCRL; - int ch = (port->mapbase - SMR0) >> 3; - unsigned char mask = 1 << (ch+1); - - if (ctrl == sci_disable) - *mstpcrl |= mask; - else - *mstpcrl &= ~mask; -} - -static void h8300_sci_enable(struct uart_port *port) -{ - h8300_sci_config(port, sci_enable); -} - -static void h8300_sci_disable(struct uart_port *port) -{ - h8300_sci_config(port, sci_disable); -} -#endif - #if defined(__H8300H__) || defined(__H8300S__) static void sci_init_pins(struct uart_port *port, unsigned int cflag) { @@ -733,7 +702,6 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) return ret; } -#ifdef CONFIG_HAVE_CLK /* * Here we define a transistion notifier so that we can update all of our * ports' baud rate when the peripheral clock changes. @@ -751,7 +719,6 @@ static int sci_notifier(struct notifier_block *self, spin_lock_irqsave(&priv->lock, flags); list_for_each_entry(sci_port, &priv->ports, node) sci_port->port.uartclk = clk_get_rate(sci_port->dclk); - spin_unlock_irqrestore(&priv->lock, flags); } @@ -778,7 +745,6 @@ static void sci_clk_disable(struct uart_port *port) clk_disable(sci_port->dclk); } -#endif static int sci_request_irq(struct sci_port *port) { @@ -833,8 +799,8 @@ static void sci_free_irq(struct sci_port *port) static unsigned int sci_tx_empty(struct uart_port *port) { - /* Can't detect */ - return TIOCSER_TEMT; + unsigned short status = sci_in(port, SCxSR); + return status & SCxSR_TEND(port) ? TIOCSER_TEMT : 0; } static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -1078,20 +1044,13 @@ static void __devinit sci_init_single(struct platform_device *dev, sci_port->port.line = index; sci_port->port.fifosize = 1; -#if defined(__H8300H__) || defined(__H8300S__) -#ifdef __H8300S__ - sci_port->enable = h8300_sci_enable; - sci_port->disable = h8300_sci_disable; -#endif - 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, "peripheral_clk"); - sci_port->enable = sci_clk_enable; - sci_port->disable = sci_clk_disable; -#else -#error "Need a valid uartclk" -#endif + if (dev) { + sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL; + sci_port->dclk = clk_get(&dev->dev, "peripheral_clk"); + sci_port->enable = sci_clk_enable; + sci_port->disable = sci_clk_disable; + sci_port->port.dev = &dev->dev; + } sci_port->break_timer.data = (unsigned long)sci_port; sci_port->break_timer.function = sci_break_timer; @@ -1102,11 +1061,9 @@ static void __devinit sci_init_single(struct platform_device *dev, 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 @@ -1147,7 +1104,7 @@ static void serial_console_write(struct console *co, const char *s, sci_port->disable(port); } -static int __init serial_console_setup(struct console *co, char *options) +static int __devinit serial_console_setup(struct console *co, char *options) { struct sci_port *sci_port; struct uart_port *port; @@ -1165,9 +1122,14 @@ static int __init serial_console_setup(struct console *co, char *options) if (co->index >= SCI_NPORTS) co->index = 0; - sci_port = &sci_ports[co->index]; - port = &sci_port->port; - co->data = port; + if (co->data) { + port = co->data; + sci_port = to_sci_port(port); + } else { + 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 @@ -1211,6 +1173,15 @@ static int __init sci_console_init(void) return 0; } console_initcall(sci_console_init); + +static struct sci_port early_serial_port; +static struct console early_serial_console = { + .name = "early_ttySC", + .write = serial_console_write, + .flags = CON_PRINTBUFFER, +}; +static char early_serial_buf[32]; + #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) @@ -1239,14 +1210,11 @@ static int sci_remove(struct platform_device *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); @@ -1299,6 +1267,21 @@ static int __devinit sci_probe(struct platform_device *dev) struct sh_sci_priv *priv; int i, ret = -EINVAL; +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE + if (is_early_platform_device(dev)) { + if (dev->id == -1) + return -ENOTSUPP; + early_serial_console.index = dev->id; + early_serial_console.data = &early_serial_port.port; + sci_init_single(NULL, &early_serial_port, dev->id, p); + serial_console_setup(&early_serial_console, early_serial_buf); + if (!strstr(early_serial_buf, "keep")) + early_serial_console.flags |= CON_BOOT; + register_console(&early_serial_console); + return 0; + } +#endif + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -1307,10 +1290,8 @@ static int __devinit sci_probe(struct platform_device *dev) 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 if (dev->id != -1) { ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]); @@ -1363,14 +1344,14 @@ static int sci_resume(struct device *dev) return 0; } -static struct dev_pm_ops sci_dev_pm_ops = { +static const struct dev_pm_ops sci_dev_pm_ops = { .suspend = sci_suspend, .resume = sci_resume, }; static struct platform_driver sci_driver = { .probe = sci_probe, - .remove = __devexit_p(sci_remove), + .remove = sci_remove, .driver = { .name = "sh-sci", .owner = THIS_MODULE, @@ -1400,6 +1381,10 @@ static void __exit sci_exit(void) uart_unregister_driver(&sci_uart_driver); } +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +early_platform_init_buffer("earlyprintk", &sci_driver, + early_serial_buf, ARRAY_SIZE(early_serial_buf)); +#endif module_init(sci_init); module_exit(sci_exit); |