diff options
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
| -rw-r--r-- | drivers/tty/serial/sh-sci.c | 431 | 
1 files changed, 212 insertions, 219 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 92c91c83edd..eb7958c675a 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -47,7 +47,6 @@  #include <linux/clk.h>  #include <linux/ctype.h>  #include <linux/err.h> -#include <linux/list.h>  #include <linux/dmaengine.h>  #include <linux/scatterlist.h>  #include <linux/slab.h> @@ -65,11 +64,8 @@  struct sci_port {  	struct uart_port	port; -	/* Port type */ -	unsigned int		type; - -	/* Port IRQs: ERI, RXI, TXI, BRI (optional) */ -	unsigned int		irqs[SCIx_NR_IRQS]; +	/* Platform configuration */ +	struct plat_sci_port	*cfg;  	/* Port enable callback */  	void			(*enable)(struct uart_port *port); @@ -81,26 +77,15 @@ struct sci_port {  	struct timer_list	break_timer;  	int			break_flag; -	/* SCSCR initialization */ -	unsigned int		scscr; - -	/* SCBRR calculation algo */ -	unsigned int		scbrr_algo_id; -  	/* Interface clock */  	struct clk		*iclk;  	/* Function clock */  	struct clk		*fclk; -	struct list_head	node; -  	struct dma_chan			*chan_tx;  	struct dma_chan			*chan_rx;  #ifdef CONFIG_SERIAL_SH_SCI_DMA -	struct device			*dma_dev; -	unsigned int			slave_tx; -	unsigned int			slave_rx;  	struct dma_async_tx_descriptor	*desc_tx;  	struct dma_async_tx_descriptor	*desc_rx[2];  	dma_cookie_t			cookie_tx; @@ -117,16 +102,14 @@ struct sci_port {  	struct timer_list		rx_timer;  	unsigned int			rx_timeout;  #endif -}; -struct sh_sci_priv { -	spinlock_t lock; -	struct list_head ports; -	struct notifier_block clk_nb; +	struct notifier_block		freq_transition;  };  /* Function prototypes */ +static void sci_start_tx(struct uart_port *port);  static void sci_stop_tx(struct uart_port *port); +static void sci_start_rx(struct uart_port *port);  #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS @@ -142,12 +125,6 @@ to_sci_port(struct uart_port *uart)  #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)  #ifdef CONFIG_CONSOLE_POLL -static inline void handle_error(struct uart_port *port) -{ -	/* Clear error flags */ -	sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); -} -  static int sci_poll_get_char(struct uart_port *port)  {  	unsigned short status; @@ -156,7 +133,7 @@ static int sci_poll_get_char(struct uart_port *port)  	do {  		status = sci_in(port, SCxSR);  		if (status & SCxSR_ERRORS(port)) { -			handle_error(port); +			sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));  			continue;  		}  		break; @@ -475,7 +452,7 @@ static void sci_transmit_chars(struct uart_port *port)  /* On SH3, SCIF may read end-of-break as a space->mark char */  #define STEPFN(c)  ({int __c = (c); (((__c-1)|(__c)) == -1); }) -static inline void sci_receive_chars(struct uart_port *port) +static void sci_receive_chars(struct uart_port *port)  {  	struct sci_port *sci_port = to_sci_port(port);  	struct tty_struct *tty = port->state->port.tty; @@ -566,18 +543,20 @@ static inline void sci_receive_chars(struct uart_port *port)  }  #define SCI_BREAK_JIFFIES (HZ/20) -/* The sci generates interrupts during the break, + +/* + * The sci generates interrupts during the break,   * 1 per millisecond or so during the break period, for 9600 baud.   * So dont bother disabling interrupts.   * But dont want more than 1 break event.   * Use a kernel timer to periodically poll the rx line until   * the break is finished.   */ -static void sci_schedule_break_timer(struct sci_port *port) +static inline void sci_schedule_break_timer(struct sci_port *port)  { -	port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES; -	add_timer(&port->break_timer); +	mod_timer(&port->break_timer, jiffies + SCI_BREAK_JIFFIES);  } +  /* Ensure that two consecutive samples find the break over. */  static void sci_break_timer(unsigned long data)  { @@ -594,7 +573,7 @@ static void sci_break_timer(unsigned long data)  		port->break_flag = 0;  } -static inline int sci_handle_errors(struct uart_port *port) +static int sci_handle_errors(struct uart_port *port)  {  	int copied = 0;  	unsigned short status = sci_in(port, SCxSR); @@ -650,7 +629,7 @@ static inline int sci_handle_errors(struct uart_port *port)  	return copied;  } -static inline int sci_handle_fifo_overrun(struct uart_port *port) +static int sci_handle_fifo_overrun(struct uart_port *port)  {  	struct tty_struct *tty = port->state->port.tty;  	int copied = 0; @@ -671,7 +650,7 @@ static inline int sci_handle_fifo_overrun(struct uart_port *port)  	return copied;  } -static inline int sci_handle_breaks(struct uart_port *port) +static int sci_handle_breaks(struct uart_port *port)  {  	int copied = 0;  	unsigned short status = sci_in(port, SCxSR); @@ -794,7 +773,7 @@ static inline unsigned long port_rx_irq_mask(struct uart_port *port)  	 * it's unset, it's logically inferred that there's no point in  	 * testing for it.  	 */ -	return SCSCR_RIE | (to_sci_port(port)->scscr & SCSCR_REIE); +	return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE);  }  static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) @@ -839,17 +818,18 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)  static int sci_notifier(struct notifier_block *self,  			unsigned long phase, void *p)  { -	struct sh_sci_priv *priv = container_of(self, -						struct sh_sci_priv, clk_nb);  	struct sci_port *sci_port;  	unsigned long flags; +	sci_port = container_of(self, struct sci_port, freq_transition); +  	if ((phase == CPUFREQ_POSTCHANGE) ||  	    (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->iclk); -		spin_unlock_irqrestore(&priv->lock, flags); +		struct uart_port *port = &sci_port->port; + +		spin_lock_irqsave(&port->lock, flags); +		port->uartclk = clk_get_rate(sci_port->iclk); +		spin_unlock_irqrestore(&port->lock, flags);  	}  	return NOTIFY_OK; @@ -882,21 +862,21 @@ static int sci_request_irq(struct sci_port *port)  	const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",  			       "SCI Transmit Data Empty", "SCI Break" }; -	if (port->irqs[0] == port->irqs[1]) { -		if (unlikely(!port->irqs[0])) +	if (port->cfg->irqs[0] == port->cfg->irqs[1]) { +		if (unlikely(!port->cfg->irqs[0]))  			return -ENODEV; -		if (request_irq(port->irqs[0], sci_mpxed_interrupt, +		if (request_irq(port->cfg->irqs[0], sci_mpxed_interrupt,  				IRQF_DISABLED, "sci", port)) {  			dev_err(port->port.dev, "Can't allocate IRQ\n");  			return -ENODEV;  		}  	} else {  		for (i = 0; i < ARRAY_SIZE(handlers); i++) { -			if (unlikely(!port->irqs[i])) +			if (unlikely(!port->cfg->irqs[i]))  				continue; -			if (request_irq(port->irqs[i], handlers[i], +			if (request_irq(port->cfg->irqs[i], handlers[i],  					IRQF_DISABLED, desc[i], port)) {  				dev_err(port->port.dev, "Can't allocate IRQ\n");  				return -ENODEV; @@ -911,14 +891,14 @@ static void sci_free_irq(struct sci_port *port)  {  	int i; -	if (port->irqs[0] == port->irqs[1]) -		free_irq(port->irqs[0], port); +	if (port->cfg->irqs[0] == port->cfg->irqs[1]) +		free_irq(port->cfg->irqs[0], port);  	else { -		for (i = 0; i < ARRAY_SIZE(port->irqs); i++) { -			if (!port->irqs[i]) +		for (i = 0; i < ARRAY_SIZE(port->cfg->irqs); i++) { +			if (!port->cfg->irqs[i])  				continue; -			free_irq(port->irqs[i], port); +			free_irq(port->cfg->irqs[i], port);  		}  	}  } @@ -1037,9 +1017,6 @@ static void sci_dma_rx_complete(void *arg)  	schedule_work(&s->work_rx);  } -static void sci_start_rx(struct uart_port *port); -static void sci_start_tx(struct uart_port *port); -  static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)  {  	struct dma_chan *chan = s->chan_rx; @@ -1325,7 +1302,7 @@ static void rx_timer_fn(unsigned long arg)  	if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {  		scr &= ~0x4000; -		enable_irq(s->irqs[1]); +		enable_irq(s->cfg->irqs[1]);  	}  	sci_out(port, SCSCR, scr | SCSCR_RIE);  	dev_dbg(port->dev, "DMA Rx timed out\n"); @@ -1341,9 +1318,9 @@ static void sci_request_dma(struct uart_port *port)  	int nent;  	dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__, -		port->line, s->dma_dev); +		port->line, s->cfg->dma_dev); -	if (!s->dma_dev) +	if (!s->cfg->dma_dev)  		return;  	dma_cap_zero(mask); @@ -1352,8 +1329,8 @@ static void sci_request_dma(struct uart_port *port)  	param = &s->param_tx;  	/* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ -	param->slave_id = s->slave_tx; -	param->dma_dev = s->dma_dev; +	param->slave_id = s->cfg->dma_slave_tx; +	param->dma_dev = s->cfg->dma_dev;  	s->cookie_tx = -EINVAL;  	chan = dma_request_channel(mask, filter, param); @@ -1381,8 +1358,8 @@ static void sci_request_dma(struct uart_port *port)  	param = &s->param_rx;  	/* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ -	param->slave_id = s->slave_rx; -	param->dma_dev = s->dma_dev; +	param->slave_id = s->cfg->dma_slave_rx; +	param->dma_dev = s->cfg->dma_dev;  	chan = dma_request_channel(mask, filter, param);  	dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); @@ -1427,7 +1404,7 @@ static void sci_free_dma(struct uart_port *port)  {  	struct sci_port *s = to_sci_port(port); -	if (!s->dma_dev) +	if (!s->cfg->dma_dev)  		return;  	if (s->chan_tx) @@ -1435,21 +1412,32 @@ static void sci_free_dma(struct uart_port *port)  	if (s->chan_rx)  		sci_rx_dma_release(s, false);  } +#else +static inline void sci_request_dma(struct uart_port *port) +{ +} + +static inline void sci_free_dma(struct uart_port *port) +{ +}  #endif  static int sci_startup(struct uart_port *port)  {  	struct sci_port *s = to_sci_port(port); +	int ret;  	dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);  	if (s->enable)  		s->enable(port); -	sci_request_irq(s); -#ifdef CONFIG_SERIAL_SH_SCI_DMA +	ret = sci_request_irq(s); +	if (unlikely(ret < 0)) +		return ret; +  	sci_request_dma(port); -#endif +  	sci_start_tx(port);  	sci_start_rx(port); @@ -1464,9 +1452,8 @@ static void sci_shutdown(struct uart_port *port)  	sci_stop_rx(port);  	sci_stop_tx(port); -#ifdef CONFIG_SERIAL_SH_SCI_DMA +  	sci_free_dma(port); -#endif  	sci_free_irq(s);  	if (s->disable) @@ -1491,6 +1478,7 @@ static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,  	/* Warn, but use a safe default */  	WARN_ON(1); +  	return ((freq + 16 * bps) / (32 * bps) - 1);  } @@ -1514,7 +1502,10 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,  	baud = uart_get_baud_rate(port, termios, old, 0, max_baud);  	if (likely(baud && port->uartclk)) -		t = sci_scbrr_calc(s->scbrr_algo_id, baud, port->uartclk); +		t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, port->uartclk); + +	if (s->enable) +		s->enable(port);  	do {  		status = sci_in(port, SCxSR); @@ -1526,6 +1517,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,  		sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);  	smr_val = sci_in(port, SCSMR) & 3; +  	if ((termios->c_cflag & CSIZE) == CS7)  		smr_val |= 0x40;  	if (termios->c_cflag & PARENB) @@ -1540,7 +1532,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,  	sci_out(port, SCSMR, smr_val);  	dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t, -		s->scscr); +		s->cfg->scscr);  	if (t > 0) {  		if (t >= 256) { @@ -1556,7 +1548,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,  	sci_init_pins(port, termios->c_cflag);  	sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0)); -	sci_out(port, SCSCR, s->scscr); +	sci_out(port, SCSCR, s->cfg->scscr);  #ifdef CONFIG_SERIAL_SH_SCI_DMA  	/* @@ -1582,6 +1574,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,  	if ((termios->c_cflag & CREAD) != 0)  		sci_start_rx(port); + +	if (s->disable) +		s->disable(port);  }  static const char *sci_type(struct uart_port *port) @@ -1602,31 +1597,33 @@ static const char *sci_type(struct uart_port *port)  	return NULL;  } -static void sci_release_port(struct uart_port *port) +static inline unsigned long sci_port_size(struct uart_port *port)  { -	/* Nothing here yet .. */ -} - -static int sci_request_port(struct uart_port *port) -{ -	/* Nothing here yet .. */ -	return 0; +	/* +	 * Pick an arbitrary size that encapsulates all of the base +	 * registers by default. This can be optimized later, or derived +	 * from platform resource data at such a time that ports begin to +	 * behave more erratically. +	 */ +	return 64;  } -static void sci_config_port(struct uart_port *port, int flags) +static int sci_remap_port(struct uart_port *port)  { -	struct sci_port *s = to_sci_port(port); - -	port->type = s->type; +	unsigned long size = sci_port_size(port); +	/* +	 * Nothing to do if there's already an established membase. +	 */  	if (port->membase) -		return; +		return 0;  	if (port->flags & UPF_IOREMAP) { -		port->membase = ioremap_nocache(port->mapbase, 0x40); - -		if (IS_ERR(port->membase)) +		port->membase = ioremap_nocache(port->mapbase, size); +		if (unlikely(!port->membase)) {  			dev_err(port->dev, "can't remap port#%d\n", port->line); +			return -ENXIO; +		}  	} else {  		/*  		 * For the simple (and majority of) cases where we don't @@ -1635,13 +1632,54 @@ static void sci_config_port(struct uart_port *port, int flags)  		 */  		port->membase = (void __iomem *)port->mapbase;  	} + +	return 0; +} + +static void sci_release_port(struct uart_port *port) +{ +	if (port->flags & UPF_IOREMAP) { +		iounmap(port->membase); +		port->membase = NULL; +	} + +	release_mem_region(port->mapbase, sci_port_size(port)); +} + +static int sci_request_port(struct uart_port *port) +{ +	unsigned long size = sci_port_size(port); +	struct resource *res; +	int ret; + +	res = request_mem_region(port->mapbase, size, dev_name(port->dev)); +	if (unlikely(res == NULL)) +		return -EBUSY; + +	ret = sci_remap_port(port); +	if (unlikely(ret != 0)) { +		release_resource(res); +		return ret; +	} + +	return 0; +} + +static void sci_config_port(struct uart_port *port, int flags) +{ +	if (flags & UART_CONFIG_TYPE) { +		struct sci_port *sport = to_sci_port(port); + +		port->type = sport->cfg->type; +		sci_request_port(port); +	}  }  static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)  {  	struct sci_port *s = to_sci_port(port); -	if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) +	if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)  		return -EINVAL;  	if (ser->baud_base < 2400)  		/* No paper tape reader for Mitch.. */ @@ -1726,36 +1764,29 @@ static int __devinit sci_init_single(struct platform_device *dev,  	sci_port->break_timer.function = sci_break_timer;  	init_timer(&sci_port->break_timer); -	port->mapbase	= p->mapbase; -	port->membase	= p->membase; +	sci_port->cfg		= p; -	port->irq		= p->irqs[SCIx_TXI_IRQ]; +	port->mapbase		= p->mapbase; +	port->type		= p->type;  	port->flags		= p->flags; -	sci_port->type		= port->type = p->type; -	sci_port->scscr		= p->scscr; -	sci_port->scbrr_algo_id	= p->scbrr_algo_id; -#ifdef CONFIG_SERIAL_SH_SCI_DMA -	sci_port->dma_dev	= p->dma_dev; -	sci_port->slave_tx	= p->dma_slave_tx; -	sci_port->slave_rx	= p->dma_slave_rx; +	/* +	 * The UART port needs an IRQ value, so we peg this to the TX IRQ +	 * for the multi-IRQ ports, which is where we are primarily +	 * concerned with the shutdown path synchronization. +	 * +	 * For the muxed case there's nothing more to do. +	 */ +	port->irq		= p->irqs[SCIx_TXI_IRQ]; -	dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__, -		p->dma_dev, p->dma_slave_tx, p->dma_slave_rx); -#endif +	if (p->dma_dev) +		dev_dbg(port->dev, "DMA device %p, tx %d, rx %d\n", +			p->dma_dev, p->dma_slave_tx, p->dma_slave_rx); -	memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));  	return 0;  }  #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); @@ -1768,8 +1799,8 @@ static void serial_console_putchar(struct uart_port *port, int ch)  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); +	struct sci_port *sci_port = &sci_ports[co->index]; +	struct uart_port *port = &sci_port->port;  	unsigned short bits;  	if (sci_port->enable) @@ -1797,32 +1828,17 @@ static int __devinit serial_console_setup(struct console *co, char *options)  	int ret;  	/* -	 * Check whether an invalid uart number has been specified, and -	 * if so, search for the first available port that does have -	 * console support. -	 */ -	if (co->index >= SCI_NPORTS) -		co->index = 0; - -	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 -	 * UPIO_PORT ports, but uart_report_port() handily misreports -	 * it anyways if we don't have a port available by the time this is -	 * called. +	 * Refuse to handle any bogus ports.  	 */ -	if (!port->type) +	if (co->index < 0 || co->index >= SCI_NPORTS)  		return -ENODEV; -	sci_config_port(port, 0); +	sci_port = &sci_ports[co->index]; +	port = &sci_port->port; + +	ret = sci_remap_port(port); +	if (unlikely(ret != 0)) +		return ret;  	if (sci_port->enable)  		sci_port->enable(port); @@ -1842,11 +1858,12 @@ static int __devinit serial_console_setup(struct console *co, char *options)  static struct console serial_console = {  	.name		= "ttySC", -	.device		= serial_console_device, +	.device		= uart_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) @@ -1856,14 +1873,39 @@ static int __init sci_console_init(void)  }  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, +	.index		= -1,  }; +  static char early_serial_buf[32]; +static int __devinit sci_probe_earlyprintk(struct platform_device *pdev) +{ +	struct plat_sci_port *cfg = pdev->dev.platform_data; + +	if (early_serial_console.data) +		return -EEXIST; + +	early_serial_console.index = pdev->id; + +	sci_init_single(NULL, &sci_ports[pdev->id], pdev->id, cfg); + +	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; +} +#else +static inline int __devinit sci_probe_earlyprintk(struct platform_device *pdev) +{ +	return -EINVAL; +}  #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */  #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) @@ -1885,24 +1927,18 @@ static struct uart_driver sci_uart_driver = {  	.cons		= SCI_CONSOLE,  }; -  static int sci_remove(struct platform_device *dev)  { -	struct sh_sci_priv *priv = platform_get_drvdata(dev); -	struct sci_port *p; -	unsigned long flags; +	struct sci_port *port = platform_get_drvdata(dev); -	cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); +	cpufreq_unregister_notifier(&port->freq_transition, +				    CPUFREQ_TRANSITION_NOTIFIER); -	spin_lock_irqsave(&priv->lock, flags); -	list_for_each_entry(p, &priv->ports, node) { -		uart_remove_one_port(&sci_uart_driver, &p->port); -		clk_put(p->iclk); -		clk_put(p->fclk); -	} -	spin_unlock_irqrestore(&priv->lock, flags); +	uart_remove_one_port(&sci_uart_driver, &port->port); + +	clk_put(port->iclk); +	clk_put(port->fclk); -	kfree(priv);  	return 0;  } @@ -1911,8 +1947,6 @@ static int __devinit sci_probe_single(struct platform_device *dev,  				      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 */ @@ -1929,68 +1963,35 @@ static int __devinit sci_probe_single(struct platform_device *dev,  	if (ret)  		return ret; -	ret = uart_add_one_port(&sci_uart_driver, &sciport->port); -	if (ret) -		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; +	return uart_add_one_port(&sci_uart_driver, &sciport->port);  } -/* - * Register a set of serial devices attached to a platform device.  The - * list is terminated with a zero flags entry, which means we expect - * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need - * remapping (such as sh64) should also set UPF_IOREMAP. - */  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; +	struct sci_port *sp = &sci_ports[dev->id]; +	int ret; -#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 +	/* +	 * If we've come here via earlyprintk initialization, head off to +	 * the special early probe. We don't have sufficient device state +	 * to make it beyond this yet. +	 */ +	if (is_early_platform_device(dev)) +		return sci_probe_earlyprintk(dev); -	priv = kzalloc(sizeof(*priv), GFP_KERNEL); -	if (!priv) -		return -ENOMEM; +	platform_set_drvdata(dev, sp); -	INIT_LIST_HEAD(&priv->ports); -	spin_lock_init(&priv->lock); -	platform_set_drvdata(dev, priv); +	ret = sci_probe_single(dev, dev->id, p, sp); +	if (ret) +		goto err_unreg; -	priv->clk_nb.notifier_call = sci_notifier; -	cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); +	sp->freq_transition.notifier_call = sci_notifier; -	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; -		} -	} +	ret = cpufreq_register_notifier(&sp->freq_transition, +					CPUFREQ_TRANSITION_NOTIFIER); +	if (unlikely(ret < 0)) +		goto err_unreg;  #ifdef CONFIG_SH_STANDARD_BIOS  	sh_bios_gdb_detach(); @@ -2005,28 +2006,20 @@ err_unreg:  static int sci_suspend(struct device *dev)  { -	struct sh_sci_priv *priv = dev_get_drvdata(dev); -	struct sci_port *p; -	unsigned long flags; +	struct sci_port *sport = dev_get_drvdata(dev); -	spin_lock_irqsave(&priv->lock, flags); -	list_for_each_entry(p, &priv->ports, node) -		uart_suspend_port(&sci_uart_driver, &p->port); -	spin_unlock_irqrestore(&priv->lock, flags); +	if (sport) +		uart_suspend_port(&sci_uart_driver, &sport->port);  	return 0;  }  static int sci_resume(struct device *dev)  { -	struct sh_sci_priv *priv = dev_get_drvdata(dev); -	struct sci_port *p; -	unsigned long flags; +	struct sci_port *sport = dev_get_drvdata(dev); -	spin_lock_irqsave(&priv->lock, flags); -	list_for_each_entry(p, &priv->ports, node) -		uart_resume_port(&sci_uart_driver, &p->port); -	spin_unlock_irqrestore(&priv->lock, flags); +	if (sport) +		uart_resume_port(&sci_uart_driver, &sport->port);  	return 0;  }  |