aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/sc16is7xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/sc16is7xx.c')
-rw-r--r--drivers/tty/serial/sc16is7xx.c47
1 files changed, 31 insertions, 16 deletions
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 8247bce5f4ad..f218e24463c9 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -301,10 +301,17 @@ struct sc16is7xx_devtype {
301 int nr_uart; 301 int nr_uart;
302}; 302};
303 303
304#define SC16IS7XX_RECONF_MD (1 << 0)
305
306struct sc16is7xx_one_config {
307 unsigned int flags;
308};
309
304struct sc16is7xx_one { 310struct sc16is7xx_one {
305 struct uart_port port; 311 struct uart_port port;
306 struct kthread_work tx_work; 312 struct kthread_work tx_work;
307 struct work_struct md_work; 313 struct kthread_work reg_work;
314 struct sc16is7xx_one_config config;
308}; 315};
309 316
310struct sc16is7xx_port { 317struct sc16is7xx_port {
@@ -659,6 +666,24 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)
659 sc16is7xx_handle_tx(port); 666 sc16is7xx_handle_tx(port);
660} 667}
661 668
669static void sc16is7xx_reg_proc(struct kthread_work *ws)
670{
671 struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work);
672 struct sc16is7xx_one_config config;
673 unsigned long irqflags;
674
675 spin_lock_irqsave(&one->port.lock, irqflags);
676 config = one->config;
677 memset(&one->config, 0, sizeof(one->config));
678 spin_unlock_irqrestore(&one->port.lock, irqflags);
679
680 if (config.flags & SC16IS7XX_RECONF_MD)
681 sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
682 SC16IS7XX_MCR_LOOP_BIT,
683 (one->port.mctrl & TIOCM_LOOP) ?
684 SC16IS7XX_MCR_LOOP_BIT : 0);
685}
686
662static void sc16is7xx_stop_tx(struct uart_port* port) 687static void sc16is7xx_stop_tx(struct uart_port* port)
663{ 688{
664 sc16is7xx_port_update(port, SC16IS7XX_IER_REG, 689 sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
@@ -701,21 +726,13 @@ static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
701 return TIOCM_DSR | TIOCM_CAR; 726 return TIOCM_DSR | TIOCM_CAR;
702} 727}
703 728
704static void sc16is7xx_md_proc(struct work_struct *ws)
705{
706 struct sc16is7xx_one *one = to_sc16is7xx_one(ws, md_work);
707
708 sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
709 SC16IS7XX_MCR_LOOP_BIT,
710 (one->port.mctrl & TIOCM_LOOP) ?
711 SC16IS7XX_MCR_LOOP_BIT : 0);
712}
713
714static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl) 729static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
715{ 730{
731 struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
716 struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); 732 struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
717 733
718 schedule_work(&one->md_work); 734 one->config.flags |= SC16IS7XX_RECONF_MD;
735 queue_kthread_work(&s->kworker, &one->reg_work);
719} 736}
720 737
721static void sc16is7xx_break_ctl(struct uart_port *port, int break_state) 738static void sc16is7xx_break_ctl(struct uart_port *port, int break_state)
@@ -1132,10 +1149,9 @@ static int sc16is7xx_probe(struct device *dev,
1132 sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG, 1149 sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG,
1133 SC16IS7XX_EFCR_RXDISABLE_BIT | 1150 SC16IS7XX_EFCR_RXDISABLE_BIT |
1134 SC16IS7XX_EFCR_TXDISABLE_BIT); 1151 SC16IS7XX_EFCR_TXDISABLE_BIT);
1135 /* Initialize queue for start TX */ 1152 /* Initialize kthread work structs */
1136 init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc); 1153 init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
1137 /* Initialize queue for changing mode */ 1154 init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
1138 INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc);
1139 /* Register port */ 1155 /* Register port */
1140 uart_add_one_port(&s->uart, &s->p[i].port); 1156 uart_add_one_port(&s->uart, &s->p[i].port);
1141 /* Go to suspend mode */ 1157 /* Go to suspend mode */
@@ -1180,7 +1196,6 @@ static int sc16is7xx_remove(struct device *dev)
1180#endif 1196#endif
1181 1197
1182 for (i = 0; i < s->uart.nr; i++) { 1198 for (i = 0; i < s->uart.nr; i++) {
1183 cancel_work_sync(&s->p[i].md_work);
1184 uart_remove_one_port(&s->uart, &s->p[i].port); 1199 uart_remove_one_port(&s->uart, &s->p[i].port);
1185 sc16is7xx_power(&s->p[i].port, 0); 1200 sc16is7xx_power(&s->p[i].port, 0);
1186 } 1201 }