Skip to content

Commit 21144ba

Browse files
Tomasz Mońgregkh
authored andcommitted
sc16is7xx: Handle modem status lines
The uart_handle_cts_change() and uart_handle_dcd_change() must be called with port lock being held. Acquire the lock after reading MSR register. Do not acquire spin lock when reading MSR register because I2C/SPI port functions cannot be called with spinlocks held. Update rng and dsr counters. Wake up delta_msr_wait to allow tty notice modem status change. Co-developed-by: Lech Perczak <l.perczak@camlintechnologies.com> Co-developed-by: Tomasz Moń <tomasz.mon@camlingroup.com> Signed-off-by: Lech Perczak <l.perczak@camlintechnologies.com> Signed-off-by: Tomasz Moń <tomasz.mon@camlingroup.com> Link: https://lore.kernel.org/r/20220301060332.2561851-3-tomasz.mon@camlingroup.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent cc4c1d0 commit 21144ba

1 file changed

Lines changed: 114 additions & 6 deletions

File tree

drivers/tty/serial/sc16is7xx.c

Lines changed: 114 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,10 @@ struct sc16is7xx_one {
324324
u8 line;
325325
struct kthread_work tx_work;
326326
struct kthread_work reg_work;
327+
struct kthread_delayed_work ms_work;
327328
struct sc16is7xx_one_config config;
328329
bool irda_mode;
330+
unsigned int old_mctrl;
329331
};
330332

331333
struct sc16is7xx_port {
@@ -705,12 +707,56 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
705707
spin_unlock_irqrestore(&port->lock, flags);
706708
}
707709

710+
static unsigned int sc16is7xx_get_hwmctrl(struct uart_port *port)
711+
{
712+
u8 msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
713+
unsigned int mctrl = 0;
714+
715+
mctrl |= (msr & SC16IS7XX_MSR_CTS_BIT) ? TIOCM_CTS : 0;
716+
mctrl |= (msr & SC16IS7XX_MSR_DSR_BIT) ? TIOCM_DSR : 0;
717+
mctrl |= (msr & SC16IS7XX_MSR_CD_BIT) ? TIOCM_CAR : 0;
718+
mctrl |= (msr & SC16IS7XX_MSR_RI_BIT) ? TIOCM_RNG : 0;
719+
return mctrl;
720+
}
721+
722+
static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)
723+
{
724+
struct uart_port *port = &one->port;
725+
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
726+
unsigned long flags;
727+
unsigned int status, changed;
728+
729+
lockdep_assert_held_once(&s->efr_lock);
730+
731+
status = sc16is7xx_get_hwmctrl(port);
732+
changed = status ^ one->old_mctrl;
733+
734+
if (changed == 0)
735+
return;
736+
737+
one->old_mctrl = status;
738+
739+
spin_lock_irqsave(&port->lock, flags);
740+
if ((changed & TIOCM_RNG) && (status & TIOCM_RNG))
741+
port->icount.rng++;
742+
if (changed & TIOCM_DSR)
743+
port->icount.dsr++;
744+
if (changed & TIOCM_CAR)
745+
uart_handle_dcd_change(port, status & TIOCM_CAR);
746+
if (changed & TIOCM_CTS)
747+
uart_handle_cts_change(port, status & TIOCM_CTS);
748+
749+
wake_up_interruptible(&port->state->port.delta_msr_wait);
750+
spin_unlock_irqrestore(&port->lock, flags);
751+
}
752+
708753
static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
709754
{
710755
struct uart_port *port = &s->p[portno].port;
711756

712757
do {
713758
unsigned int iir, rxlen;
759+
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
714760

715761
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
716762
if (iir & SC16IS7XX_IIR_NO_INT_BIT)
@@ -727,6 +773,11 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
727773
if (rxlen)
728774
sc16is7xx_handle_rx(port, rxlen, iir);
729775
break;
776+
/* CTSRTS interrupt comes only when CTS goes inactive */
777+
case SC16IS7XX_IIR_CTSRTS_SRC:
778+
case SC16IS7XX_IIR_MSI_SRC:
779+
sc16is7xx_update_mlines(one);
780+
break;
730781
case SC16IS7XX_IIR_THRI_SRC:
731782
sc16is7xx_handle_tx(port);
732783
break;
@@ -874,6 +925,30 @@ static void sc16is7xx_stop_rx(struct uart_port *port)
874925
sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
875926
}
876927

928+
static void sc16is7xx_ms_proc(struct kthread_work *ws)
929+
{
930+
struct sc16is7xx_one *one = to_sc16is7xx_one(ws, ms_work.work);
931+
struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
932+
933+
if (one->port.state) {
934+
mutex_lock(&s->efr_lock);
935+
sc16is7xx_update_mlines(one);
936+
mutex_unlock(&s->efr_lock);
937+
938+
kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ);
939+
}
940+
}
941+
942+
static void sc16is7xx_enable_ms(struct uart_port *port)
943+
{
944+
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
945+
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
946+
947+
lockdep_assert_held_once(&port->lock);
948+
949+
kthread_queue_delayed_work(&s->kworker, &one->ms_work, 0);
950+
}
951+
877952
static void sc16is7xx_start_tx(struct uart_port *port)
878953
{
879954
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
@@ -893,10 +968,10 @@ static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
893968

894969
static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
895970
{
896-
/* DCD and DSR are not wired and CTS/RTS is handled automatically
897-
* so just indicate DSR and CAR asserted
898-
*/
899-
return TIOCM_DSR | TIOCM_CAR;
971+
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
972+
973+
/* Called with port lock taken so we can only return cached value */
974+
return one->old_mctrl;
900975
}
901976

902977
static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
@@ -920,8 +995,12 @@ static void sc16is7xx_set_termios(struct uart_port *port,
920995
struct ktermios *old)
921996
{
922997
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
998+
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
923999
unsigned int lcr, flow = 0;
9241000
int baud;
1001+
unsigned long flags;
1002+
1003+
kthread_cancel_delayed_work_sync(&one->ms_work);
9251004

9261005
/* Mask termios capabilities we don't support */
9271006
termios->c_cflag &= ~CMSPAR;
@@ -1010,8 +1089,15 @@ static void sc16is7xx_set_termios(struct uart_port *port,
10101089
/* Setup baudrate generator */
10111090
baud = sc16is7xx_set_baud(port, baud);
10121091

1092+
spin_lock_irqsave(&port->lock, flags);
1093+
10131094
/* Update timeout according to new baud rate */
10141095
uart_update_timeout(port, termios->c_cflag, baud);
1096+
1097+
if (UART_ENABLE_MS(port, termios->c_cflag))
1098+
sc16is7xx_enable_ms(port);
1099+
1100+
spin_unlock_irqrestore(&port->lock, flags);
10151101
}
10161102

10171103
static int sc16is7xx_config_rs485(struct uart_port *port,
@@ -1052,6 +1138,7 @@ static int sc16is7xx_startup(struct uart_port *port)
10521138
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
10531139
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
10541140
unsigned int val;
1141+
unsigned long flags;
10551142

10561143
sc16is7xx_power(port, 1);
10571144

@@ -1102,16 +1189,25 @@ static int sc16is7xx_startup(struct uart_port *port)
11021189
SC16IS7XX_EFCR_TXDISABLE_BIT,
11031190
0);
11041191

1105-
/* Enable RX interrupt */
1106-
val = SC16IS7XX_IER_RDI_BIT;
1192+
/* Enable RX, CTS change and modem lines interrupts */
1193+
val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_CTSI_BIT |
1194+
SC16IS7XX_IER_MSI_BIT;
11071195
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val);
11081196

1197+
/* Enable modem status polling */
1198+
spin_lock_irqsave(&port->lock, flags);
1199+
sc16is7xx_enable_ms(port);
1200+
spin_unlock_irqrestore(&port->lock, flags);
1201+
11091202
return 0;
11101203
}
11111204

11121205
static void sc16is7xx_shutdown(struct uart_port *port)
11131206
{
11141207
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
1208+
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
1209+
1210+
kthread_cancel_delayed_work_sync(&one->ms_work);
11151211

11161212
/* Disable all interrupts */
11171213
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
@@ -1175,6 +1271,7 @@ static const struct uart_ops sc16is7xx_ops = {
11751271
.stop_tx = sc16is7xx_stop_tx,
11761272
.start_tx = sc16is7xx_start_tx,
11771273
.stop_rx = sc16is7xx_stop_rx,
1274+
.enable_ms = sc16is7xx_enable_ms,
11781275
.break_ctl = sc16is7xx_break_ctl,
11791276
.startup = sc16is7xx_startup,
11801277
.shutdown = sc16is7xx_shutdown,
@@ -1341,7 +1438,9 @@ static int sc16is7xx_probe(struct device *dev,
13411438
s->p[i].port.uartclk = freq;
13421439
s->p[i].port.rs485_config = sc16is7xx_config_rs485;
13431440
s->p[i].port.ops = &sc16is7xx_ops;
1441+
s->p[i].old_mctrl = 0;
13441442
s->p[i].port.line = sc16is7xx_alloc_line();
1443+
13451444
if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) {
13461445
ret = -ENOMEM;
13471446
goto out_ports;
@@ -1353,9 +1452,17 @@ static int sc16is7xx_probe(struct device *dev,
13531452
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG,
13541453
SC16IS7XX_EFCR_RXDISABLE_BIT |
13551454
SC16IS7XX_EFCR_TXDISABLE_BIT);
1455+
1456+
/* Use GPIO lines as modem status registers */
1457+
if (devtype->has_mctrl)
1458+
sc16is7xx_port_write(&s->p[i].port,
1459+
SC16IS7XX_IOCONTROL_REG,
1460+
SC16IS7XX_IOCONTROL_MODEM_BIT);
1461+
13561462
/* Initialize kthread work structs */
13571463
kthread_init_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
13581464
kthread_init_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
1465+
kthread_init_delayed_work(&s->p[i].ms_work, sc16is7xx_ms_proc);
13591466
/* Register port */
13601467
uart_add_one_port(&sc16is7xx_uart, &s->p[i].port);
13611468

@@ -1439,6 +1546,7 @@ static void sc16is7xx_remove(struct device *dev)
14391546
#endif
14401547

14411548
for (i = 0; i < s->devtype->nr_uart; i++) {
1549+
kthread_cancel_delayed_work_sync(&s->p[i].ms_work);
14421550
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
14431551
clear_bit(s->p[i].port.line, &sc16is7xx_lines);
14441552
sc16is7xx_power(&s->p[i].port, 0);

0 commit comments

Comments
 (0)