diff options
| author | Jakub Kicinski <kubakici@wp.pl> | 2015-05-29 15:20:33 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-05-31 17:47:27 -0400 |
| commit | 478d1051a0293b8a8857267bb0f768ebcb05cfde (patch) | |
| tree | 7a35b87afbb87cdbb27f878a2d1d046707315fc2 /drivers/tty | |
| parent | 059d5815304bdbe440d0ffc957d832aebf076ca3 (diff) | |
sc16is7xx: use kworker for RS-485 configuration
RS-485 configuration is also done under the spinlock
so no blocking I/O allowed.
Signed-off-by: Jakub Kicinski <kubakici@wp.pl>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
| -rw-r--r-- | drivers/tty/serial/sc16is7xx.c | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 86a679a5870b..9e6576004a42 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c | |||
| @@ -303,6 +303,7 @@ struct sc16is7xx_devtype { | |||
| 303 | 303 | ||
| 304 | #define SC16IS7XX_RECONF_MD (1 << 0) | 304 | #define SC16IS7XX_RECONF_MD (1 << 0) |
| 305 | #define SC16IS7XX_RECONF_IER (1 << 1) | 305 | #define SC16IS7XX_RECONF_IER (1 << 1) |
| 306 | #define SC16IS7XX_RECONF_RS485 (1 << 2) | ||
| 306 | 307 | ||
| 307 | struct sc16is7xx_one_config { | 308 | struct sc16is7xx_one_config { |
| 308 | unsigned int flags; | 309 | unsigned int flags; |
| @@ -668,6 +669,26 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws) | |||
| 668 | sc16is7xx_handle_tx(port); | 669 | sc16is7xx_handle_tx(port); |
| 669 | } | 670 | } |
| 670 | 671 | ||
| 672 | static void sc16is7xx_reconf_rs485(struct uart_port *port) | ||
| 673 | { | ||
| 674 | const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT | | ||
| 675 | SC16IS7XX_EFCR_RTS_INVERT_BIT; | ||
| 676 | u32 efcr = 0; | ||
| 677 | struct serial_rs485 *rs485 = &port->rs485; | ||
| 678 | unsigned long irqflags; | ||
| 679 | |||
| 680 | spin_lock_irqsave(&port->lock, irqflags); | ||
| 681 | if (rs485->flags & SER_RS485_ENABLED) { | ||
| 682 | efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT; | ||
| 683 | |||
| 684 | if (rs485->flags & SER_RS485_RTS_AFTER_SEND) | ||
| 685 | efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT; | ||
| 686 | } | ||
| 687 | spin_unlock_irqrestore(&port->lock, irqflags); | ||
| 688 | |||
| 689 | sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr); | ||
| 690 | } | ||
| 691 | |||
| 671 | static void sc16is7xx_reg_proc(struct kthread_work *ws) | 692 | static void sc16is7xx_reg_proc(struct kthread_work *ws) |
| 672 | { | 693 | { |
| 673 | struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work); | 694 | struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work); |
| @@ -688,6 +709,9 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws) | |||
| 688 | if (config.flags & SC16IS7XX_RECONF_IER) | 709 | if (config.flags & SC16IS7XX_RECONF_IER) |
| 689 | sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG, | 710 | sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG, |
| 690 | config.ier_clear, 0); | 711 | config.ier_clear, 0); |
| 712 | |||
| 713 | if (config.flags & SC16IS7XX_RECONF_RS485) | ||
| 714 | sc16is7xx_reconf_rs485(&one->port); | ||
| 691 | } | 715 | } |
| 692 | 716 | ||
| 693 | static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit) | 717 | static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit) |
| @@ -845,9 +869,8 @@ static void sc16is7xx_set_termios(struct uart_port *port, | |||
| 845 | static int sc16is7xx_config_rs485(struct uart_port *port, | 869 | static int sc16is7xx_config_rs485(struct uart_port *port, |
| 846 | struct serial_rs485 *rs485) | 870 | struct serial_rs485 *rs485) |
| 847 | { | 871 | { |
| 848 | const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT | | 872 | struct sc16is7xx_port *s = dev_get_drvdata(port->dev); |
| 849 | SC16IS7XX_EFCR_RTS_INVERT_BIT; | 873 | struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); |
| 850 | u32 efcr = 0; | ||
| 851 | 874 | ||
| 852 | if (rs485->flags & SER_RS485_ENABLED) { | 875 | if (rs485->flags & SER_RS485_ENABLED) { |
| 853 | bool rts_during_rx, rts_during_tx; | 876 | bool rts_during_rx, rts_during_tx; |
| @@ -855,13 +878,7 @@ static int sc16is7xx_config_rs485(struct uart_port *port, | |||
| 855 | rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND; | 878 | rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND; |
| 856 | rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND; | 879 | rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND; |
| 857 | 880 | ||
| 858 | efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT; | 881 | if (rts_during_rx == rts_during_tx) |
| 859 | |||
| 860 | if (!rts_during_rx && rts_during_tx) | ||
| 861 | /* default */; | ||
| 862 | else if (rts_during_rx && !rts_during_tx) | ||
| 863 | efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT; | ||
| 864 | else | ||
| 865 | dev_err(port->dev, | 882 | dev_err(port->dev, |
| 866 | "unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n", | 883 | "unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n", |
| 867 | rts_during_tx, rts_during_rx); | 884 | rts_during_tx, rts_during_rx); |
| @@ -875,9 +892,9 @@ static int sc16is7xx_config_rs485(struct uart_port *port, | |||
| 875 | return -EINVAL; | 892 | return -EINVAL; |
| 876 | } | 893 | } |
| 877 | 894 | ||
| 878 | sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr); | ||
| 879 | |||
| 880 | port->rs485 = *rs485; | 895 | port->rs485 = *rs485; |
| 896 | one->config.flags |= SC16IS7XX_RECONF_RS485; | ||
| 897 | queue_kthread_work(&s->kworker, &one->reg_work); | ||
| 881 | 898 | ||
| 882 | return 0; | 899 | return 0; |
| 883 | } | 900 | } |
