diff options
Diffstat (limited to 'drivers/tty/serial/samsung.c')
-rw-r--r-- | drivers/tty/serial/samsung.c | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 7f04717176aa..fb0e0f0bed0e 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c | |||
@@ -223,8 +223,11 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id) | |||
223 | struct uart_port *port = &ourport->port; | 223 | struct uart_port *port = &ourport->port; |
224 | struct tty_struct *tty = port->state->port.tty; | 224 | struct tty_struct *tty = port->state->port.tty; |
225 | unsigned int ufcon, ch, flag, ufstat, uerstat; | 225 | unsigned int ufcon, ch, flag, ufstat, uerstat; |
226 | unsigned long flags; | ||
226 | int max_count = 64; | 227 | int max_count = 64; |
227 | 228 | ||
229 | spin_lock_irqsave(&port->lock, flags); | ||
230 | |||
228 | while (max_count-- > 0) { | 231 | while (max_count-- > 0) { |
229 | ufcon = rd_regl(port, S3C2410_UFCON); | 232 | ufcon = rd_regl(port, S3C2410_UFCON); |
230 | ufstat = rd_regl(port, S3C2410_UFSTAT); | 233 | ufstat = rd_regl(port, S3C2410_UFSTAT); |
@@ -299,6 +302,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id) | |||
299 | tty_flip_buffer_push(tty); | 302 | tty_flip_buffer_push(tty); |
300 | 303 | ||
301 | out: | 304 | out: |
305 | spin_unlock_irqrestore(&port->lock, flags); | ||
302 | return IRQ_HANDLED; | 306 | return IRQ_HANDLED; |
303 | } | 307 | } |
304 | 308 | ||
@@ -307,8 +311,11 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) | |||
307 | struct s3c24xx_uart_port *ourport = id; | 311 | struct s3c24xx_uart_port *ourport = id; |
308 | struct uart_port *port = &ourport->port; | 312 | struct uart_port *port = &ourport->port; |
309 | struct circ_buf *xmit = &port->state->xmit; | 313 | struct circ_buf *xmit = &port->state->xmit; |
314 | unsigned long flags; | ||
310 | int count = 256; | 315 | int count = 256; |
311 | 316 | ||
317 | spin_lock_irqsave(&port->lock, flags); | ||
318 | |||
312 | if (port->x_char) { | 319 | if (port->x_char) { |
313 | wr_regb(port, S3C2410_UTXH, port->x_char); | 320 | wr_regb(port, S3C2410_UTXH, port->x_char); |
314 | port->icount.tx++; | 321 | port->icount.tx++; |
@@ -336,13 +343,17 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) | |||
336 | port->icount.tx++; | 343 | port->icount.tx++; |
337 | } | 344 | } |
338 | 345 | ||
339 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | 346 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { |
347 | spin_unlock(&port->lock); | ||
340 | uart_write_wakeup(port); | 348 | uart_write_wakeup(port); |
349 | spin_lock(&port->lock); | ||
350 | } | ||
341 | 351 | ||
342 | if (uart_circ_empty(xmit)) | 352 | if (uart_circ_empty(xmit)) |
343 | s3c24xx_serial_stop_tx(port); | 353 | s3c24xx_serial_stop_tx(port); |
344 | 354 | ||
345 | out: | 355 | out: |
356 | spin_unlock_irqrestore(&port->lock, flags); | ||
346 | return IRQ_HANDLED; | 357 | return IRQ_HANDLED; |
347 | } | 358 | } |
348 | 359 | ||
@@ -352,10 +363,8 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) | |||
352 | struct s3c24xx_uart_port *ourport = id; | 363 | struct s3c24xx_uart_port *ourport = id; |
353 | struct uart_port *port = &ourport->port; | 364 | struct uart_port *port = &ourport->port; |
354 | unsigned int pend = rd_regl(port, S3C64XX_UINTP); | 365 | unsigned int pend = rd_regl(port, S3C64XX_UINTP); |
355 | unsigned long flags; | ||
356 | irqreturn_t ret = IRQ_HANDLED; | 366 | irqreturn_t ret = IRQ_HANDLED; |
357 | 367 | ||
358 | spin_lock_irqsave(&port->lock, flags); | ||
359 | if (pend & S3C64XX_UINTM_RXD_MSK) { | 368 | if (pend & S3C64XX_UINTM_RXD_MSK) { |
360 | ret = s3c24xx_serial_rx_chars(irq, id); | 369 | ret = s3c24xx_serial_rx_chars(irq, id); |
361 | wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK); | 370 | wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK); |
@@ -364,7 +373,6 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) | |||
364 | ret = s3c24xx_serial_tx_chars(irq, id); | 373 | ret = s3c24xx_serial_tx_chars(irq, id); |
365 | wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK); | 374 | wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK); |
366 | } | 375 | } |
367 | spin_unlock_irqrestore(&port->lock, flags); | ||
368 | return ret; | 376 | return ret; |
369 | } | 377 | } |
370 | 378 | ||
@@ -530,16 +538,16 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, | |||
530 | switch (level) { | 538 | switch (level) { |
531 | case 3: | 539 | case 3: |
532 | if (!IS_ERR(ourport->baudclk)) | 540 | if (!IS_ERR(ourport->baudclk)) |
533 | clk_disable(ourport->baudclk); | 541 | clk_disable_unprepare(ourport->baudclk); |
534 | 542 | ||
535 | clk_disable(ourport->clk); | 543 | clk_disable_unprepare(ourport->clk); |
536 | break; | 544 | break; |
537 | 545 | ||
538 | case 0: | 546 | case 0: |
539 | clk_enable(ourport->clk); | 547 | clk_prepare_enable(ourport->clk); |
540 | 548 | ||
541 | if (!IS_ERR(ourport->baudclk)) | 549 | if (!IS_ERR(ourport->baudclk)) |
542 | clk_enable(ourport->baudclk); | 550 | clk_prepare_enable(ourport->baudclk); |
543 | 551 | ||
544 | break; | 552 | break; |
545 | default: | 553 | default: |
@@ -713,11 +721,11 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, | |||
713 | s3c24xx_serial_setsource(port, clk_sel); | 721 | s3c24xx_serial_setsource(port, clk_sel); |
714 | 722 | ||
715 | if (!IS_ERR(ourport->baudclk)) { | 723 | if (!IS_ERR(ourport->baudclk)) { |
716 | clk_disable(ourport->baudclk); | 724 | clk_disable_unprepare(ourport->baudclk); |
717 | ourport->baudclk = ERR_PTR(-EINVAL); | 725 | ourport->baudclk = ERR_PTR(-EINVAL); |
718 | } | 726 | } |
719 | 727 | ||
720 | clk_enable(clk); | 728 | clk_prepare_enable(clk); |
721 | 729 | ||
722 | ourport->baudclk = clk; | 730 | ourport->baudclk = clk; |
723 | ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; | 731 | ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; |
@@ -1256,7 +1264,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) | |||
1256 | return ret; | 1264 | return ret; |
1257 | } | 1265 | } |
1258 | 1266 | ||
1259 | static int __devexit s3c24xx_serial_remove(struct platform_device *dev) | 1267 | static int s3c24xx_serial_remove(struct platform_device *dev) |
1260 | { | 1268 | { |
1261 | struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); | 1269 | struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); |
1262 | 1270 | ||
@@ -1287,9 +1295,9 @@ static int s3c24xx_serial_resume(struct device *dev) | |||
1287 | struct s3c24xx_uart_port *ourport = to_ourport(port); | 1295 | struct s3c24xx_uart_port *ourport = to_ourport(port); |
1288 | 1296 | ||
1289 | if (port) { | 1297 | if (port) { |
1290 | clk_enable(ourport->clk); | 1298 | clk_prepare_enable(ourport->clk); |
1291 | s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); | 1299 | s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); |
1292 | clk_disable(ourport->clk); | 1300 | clk_disable_unprepare(ourport->clk); |
1293 | 1301 | ||
1294 | uart_resume_port(&s3c24xx_uart_drv, port); | 1302 | uart_resume_port(&s3c24xx_uart_drv, port); |
1295 | } | 1303 | } |
@@ -1701,6 +1709,16 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids); | |||
1701 | 1709 | ||
1702 | #ifdef CONFIG_OF | 1710 | #ifdef CONFIG_OF |
1703 | static const struct of_device_id s3c24xx_uart_dt_match[] = { | 1711 | static const struct of_device_id s3c24xx_uart_dt_match[] = { |
1712 | { .compatible = "samsung,s3c2410-uart", | ||
1713 | .data = (void *)S3C2410_SERIAL_DRV_DATA }, | ||
1714 | { .compatible = "samsung,s3c2412-uart", | ||
1715 | .data = (void *)S3C2412_SERIAL_DRV_DATA }, | ||
1716 | { .compatible = "samsung,s3c2440-uart", | ||
1717 | .data = (void *)S3C2440_SERIAL_DRV_DATA }, | ||
1718 | { .compatible = "samsung,s3c6400-uart", | ||
1719 | .data = (void *)S3C6400_SERIAL_DRV_DATA }, | ||
1720 | { .compatible = "samsung,s5pv210-uart", | ||
1721 | .data = (void *)S5PV210_SERIAL_DRV_DATA }, | ||
1704 | { .compatible = "samsung,exynos4210-uart", | 1722 | { .compatible = "samsung,exynos4210-uart", |
1705 | .data = (void *)EXYNOS4210_SERIAL_DRV_DATA }, | 1723 | .data = (void *)EXYNOS4210_SERIAL_DRV_DATA }, |
1706 | {}, | 1724 | {}, |
@@ -1712,7 +1730,7 @@ MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); | |||
1712 | 1730 | ||
1713 | static struct platform_driver samsung_serial_driver = { | 1731 | static struct platform_driver samsung_serial_driver = { |
1714 | .probe = s3c24xx_serial_probe, | 1732 | .probe = s3c24xx_serial_probe, |
1715 | .remove = __devexit_p(s3c24xx_serial_remove), | 1733 | .remove = s3c24xx_serial_remove, |
1716 | .id_table = s3c24xx_serial_driver_ids, | 1734 | .id_table = s3c24xx_serial_driver_ids, |
1717 | .driver = { | 1735 | .driver = { |
1718 | .name = "samsung-uart", | 1736 | .name = "samsung-uart", |