diff options
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 81 |
1 files changed, 53 insertions, 28 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index fdbbff547106..b46b146524ce 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c | |||
@@ -160,6 +160,7 @@ struct sci_port { | |||
160 | #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS | 160 | #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS |
161 | 161 | ||
162 | static struct sci_port sci_ports[SCI_NPORTS]; | 162 | static struct sci_port sci_ports[SCI_NPORTS]; |
163 | static unsigned long sci_ports_in_use; | ||
163 | static struct uart_driver sci_uart_driver; | 164 | static struct uart_driver sci_uart_driver; |
164 | 165 | ||
165 | static inline struct sci_port * | 166 | static inline struct sci_port * |
@@ -2390,6 +2391,27 @@ done: | |||
2390 | 2391 | ||
2391 | uart_update_timeout(port, termios->c_cflag, baud); | 2392 | uart_update_timeout(port, termios->c_cflag, baud); |
2392 | 2393 | ||
2394 | /* byte size and parity */ | ||
2395 | switch (termios->c_cflag & CSIZE) { | ||
2396 | case CS5: | ||
2397 | bits = 7; | ||
2398 | break; | ||
2399 | case CS6: | ||
2400 | bits = 8; | ||
2401 | break; | ||
2402 | case CS7: | ||
2403 | bits = 9; | ||
2404 | break; | ||
2405 | default: | ||
2406 | bits = 10; | ||
2407 | break; | ||
2408 | } | ||
2409 | |||
2410 | if (termios->c_cflag & CSTOPB) | ||
2411 | bits++; | ||
2412 | if (termios->c_cflag & PARENB) | ||
2413 | bits++; | ||
2414 | |||
2393 | if (best_clk >= 0) { | 2415 | if (best_clk >= 0) { |
2394 | if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) | 2416 | if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) |
2395 | switch (srr + 1) { | 2417 | switch (srr + 1) { |
@@ -2406,8 +2428,27 @@ done: | |||
2406 | serial_port_out(port, SCSCR, scr_val | s->hscif_tot); | 2428 | serial_port_out(port, SCSCR, scr_val | s->hscif_tot); |
2407 | serial_port_out(port, SCSMR, smr_val); | 2429 | serial_port_out(port, SCSMR, smr_val); |
2408 | serial_port_out(port, SCBRR, brr); | 2430 | serial_port_out(port, SCBRR, brr); |
2409 | if (sci_getreg(port, HSSRR)->size) | 2431 | if (sci_getreg(port, HSSRR)->size) { |
2410 | serial_port_out(port, HSSRR, srr | HSCIF_SRE); | 2432 | unsigned int hssrr = srr | HSCIF_SRE; |
2433 | /* Calculate deviation from intended rate at the | ||
2434 | * center of the last stop bit in sampling clocks. | ||
2435 | */ | ||
2436 | int last_stop = bits * 2 - 1; | ||
2437 | int deviation = min_err * srr * last_stop / 2 / baud; | ||
2438 | |||
2439 | if (abs(deviation) >= 2) { | ||
2440 | /* At least two sampling clocks off at the | ||
2441 | * last stop bit; we can increase the error | ||
2442 | * margin by shifting the sampling point. | ||
2443 | */ | ||
2444 | int shift = min(-8, max(7, deviation / 2)); | ||
2445 | |||
2446 | hssrr |= (shift << HSCIF_SRHP_SHIFT) & | ||
2447 | HSCIF_SRHP_MASK; | ||
2448 | hssrr |= HSCIF_SRDE; | ||
2449 | } | ||
2450 | serial_port_out(port, HSSRR, hssrr); | ||
2451 | } | ||
2411 | 2452 | ||
2412 | /* Wait one bit interval */ | 2453 | /* Wait one bit interval */ |
2413 | udelay((1000000 + (baud - 1)) / baud); | 2454 | udelay((1000000 + (baud - 1)) / baud); |
@@ -2474,27 +2515,6 @@ done: | |||
2474 | * value obtained by this formula is too small. Therefore, if the value | 2515 | * value obtained by this formula is too small. Therefore, if the value |
2475 | * is smaller than 20ms, use 20ms as the timeout value for DMA. | 2516 | * is smaller than 20ms, use 20ms as the timeout value for DMA. |
2476 | */ | 2517 | */ |
2477 | /* byte size and parity */ | ||
2478 | switch (termios->c_cflag & CSIZE) { | ||
2479 | case CS5: | ||
2480 | bits = 7; | ||
2481 | break; | ||
2482 | case CS6: | ||
2483 | bits = 8; | ||
2484 | break; | ||
2485 | case CS7: | ||
2486 | bits = 9; | ||
2487 | break; | ||
2488 | default: | ||
2489 | bits = 10; | ||
2490 | break; | ||
2491 | } | ||
2492 | |||
2493 | if (termios->c_cflag & CSTOPB) | ||
2494 | bits++; | ||
2495 | if (termios->c_cflag & PARENB) | ||
2496 | bits++; | ||
2497 | |||
2498 | s->rx_frame = (10000 * bits) / (baud / 100); | 2518 | s->rx_frame = (10000 * bits) / (baud / 100); |
2499 | #ifdef CONFIG_SERIAL_SH_SCI_DMA | 2519 | #ifdef CONFIG_SERIAL_SH_SCI_DMA |
2500 | s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame; | 2520 | s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame; |
@@ -2890,16 +2910,15 @@ static void serial_console_write(struct console *co, const char *s, | |||
2890 | unsigned long flags; | 2910 | unsigned long flags; |
2891 | int locked = 1; | 2911 | int locked = 1; |
2892 | 2912 | ||
2893 | local_irq_save(flags); | ||
2894 | #if defined(SUPPORT_SYSRQ) | 2913 | #if defined(SUPPORT_SYSRQ) |
2895 | if (port->sysrq) | 2914 | if (port->sysrq) |
2896 | locked = 0; | 2915 | locked = 0; |
2897 | else | 2916 | else |
2898 | #endif | 2917 | #endif |
2899 | if (oops_in_progress) | 2918 | if (oops_in_progress) |
2900 | locked = spin_trylock(&port->lock); | 2919 | locked = spin_trylock_irqsave(&port->lock, flags); |
2901 | else | 2920 | else |
2902 | spin_lock(&port->lock); | 2921 | spin_lock_irqsave(&port->lock, flags); |
2903 | 2922 | ||
2904 | /* first save SCSCR then disable interrupts, keep clock source */ | 2923 | /* first save SCSCR then disable interrupts, keep clock source */ |
2905 | ctrl = serial_port_in(port, SCSCR); | 2924 | ctrl = serial_port_in(port, SCSCR); |
@@ -2919,8 +2938,7 @@ static void serial_console_write(struct console *co, const char *s, | |||
2919 | serial_port_out(port, SCSCR, ctrl); | 2938 | serial_port_out(port, SCSCR, ctrl); |
2920 | 2939 | ||
2921 | if (locked) | 2940 | if (locked) |
2922 | spin_unlock(&port->lock); | 2941 | spin_unlock_irqrestore(&port->lock, flags); |
2923 | local_irq_restore(flags); | ||
2924 | } | 2942 | } |
2925 | 2943 | ||
2926 | static int serial_console_setup(struct console *co, char *options) | 2944 | static int serial_console_setup(struct console *co, char *options) |
@@ -3026,6 +3044,7 @@ static int sci_remove(struct platform_device *dev) | |||
3026 | { | 3044 | { |
3027 | struct sci_port *port = platform_get_drvdata(dev); | 3045 | struct sci_port *port = platform_get_drvdata(dev); |
3028 | 3046 | ||
3047 | sci_ports_in_use &= ~BIT(port->port.line); | ||
3029 | uart_remove_one_port(&sci_uart_driver, &port->port); | 3048 | uart_remove_one_port(&sci_uart_driver, &port->port); |
3030 | 3049 | ||
3031 | sci_cleanup_single(port); | 3050 | sci_cleanup_single(port); |
@@ -3107,6 +3126,8 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, | |||
3107 | 3126 | ||
3108 | /* Get the line number from the aliases node. */ | 3127 | /* Get the line number from the aliases node. */ |
3109 | id = of_alias_get_id(np, "serial"); | 3128 | id = of_alias_get_id(np, "serial"); |
3129 | if (id < 0 && ~sci_ports_in_use) | ||
3130 | id = ffz(sci_ports_in_use); | ||
3110 | if (id < 0) { | 3131 | if (id < 0) { |
3111 | dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); | 3132 | dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); |
3112 | return NULL; | 3133 | return NULL; |
@@ -3141,6 +3162,9 @@ static int sci_probe_single(struct platform_device *dev, | |||
3141 | dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); | 3162 | dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); |
3142 | return -EINVAL; | 3163 | return -EINVAL; |
3143 | } | 3164 | } |
3165 | BUILD_BUG_ON(SCI_NPORTS > sizeof(sci_ports_in_use) * 8); | ||
3166 | if (sci_ports_in_use & BIT(index)) | ||
3167 | return -EBUSY; | ||
3144 | 3168 | ||
3145 | mutex_lock(&sci_uart_registration_lock); | 3169 | mutex_lock(&sci_uart_registration_lock); |
3146 | if (!sci_uart_driver.state) { | 3170 | if (!sci_uart_driver.state) { |
@@ -3239,6 +3263,7 @@ static int sci_probe(struct platform_device *dev) | |||
3239 | sh_bios_gdb_detach(); | 3263 | sh_bios_gdb_detach(); |
3240 | #endif | 3264 | #endif |
3241 | 3265 | ||
3266 | sci_ports_in_use |= BIT(dev_id); | ||
3242 | return 0; | 3267 | return 0; |
3243 | } | 3268 | } |
3244 | 3269 | ||