Skip to content

Commit b5b82df

Browse files
dwmw2Linus Torvalds
authored andcommitted
NS16550A: Restore HS settings in EXCR2 on resume
After a suspend/resume cycle, the UART may have been reset into low-speed mode -- either because it's actually been reset, or because the firmware pokes at the old-style divisor registers. If we detected it as a NS16550A SuperIO chip in the first place and set baud_base to 921600, then we should do so again in the resume path. This patch adds that code to serial8250_resume_port(), and also makes serial8250_resume() actually call serial8250_resume_port() for each port instead of just calling uart_resume_port() directly. And thus fixes serial port operation after suspend/resume. It also fixes a bogus comment where we write the EXCR2 register with a comment saying /* EXCR1 */ Signed-off-by: David Woodhouse <[email protected]> Acked-by: Alan Cox <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent c97a9e1 commit b5b82df

File tree

1 file changed

+18
-3
lines changed

1 file changed

+18
-3
lines changed

drivers/serial/8250.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
894894
quot = serial_dl_read(up);
895895
quot <<= 3;
896896

897-
status1 = serial_in(up, 0x04); /* EXCR1 */
897+
status1 = serial_in(up, 0x04); /* EXCR2 */
898898
status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
899899
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
900900
serial_outp(up, 0x04, status1);
@@ -2617,7 +2617,22 @@ void serial8250_suspend_port(int line)
26172617
*/
26182618
void serial8250_resume_port(int line)
26192619
{
2620-
uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
2620+
struct uart_8250_port *up = &serial8250_ports[line];
2621+
2622+
if (up->capabilities & UART_NATSEMI) {
2623+
unsigned char tmp;
2624+
2625+
/* Ensure it's still in high speed mode */
2626+
serial_outp(up, UART_LCR, 0xE0);
2627+
2628+
tmp = serial_in(up, 0x04); /* EXCR2 */
2629+
tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
2630+
tmp |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
2631+
serial_outp(up, 0x04, tmp);
2632+
2633+
serial_outp(up, UART_LCR, 0);
2634+
}
2635+
uart_resume_port(&serial8250_reg, &up->port);
26212636
}
26222637

26232638
/*
@@ -2694,7 +2709,7 @@ static int serial8250_resume(struct platform_device *dev)
26942709
struct uart_8250_port *up = &serial8250_ports[i];
26952710

26962711
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
2697-
uart_resume_port(&serial8250_reg, &up->port);
2712+
serial8250_resume_port(i);
26982713
}
26992714

27002715
return 0;

0 commit comments

Comments
 (0)