Skip to content

Commit

Permalink
serial: 8250_mtk: track busclk state to avoid bus error
Browse files Browse the repository at this point in the history
Commit e32a83c ("serial: 8250-mtk: modify mtk uart power and
clock management") introduced polling a debug register to make sure
the UART is idle before disabling the bus clock. However, at least on
some MediaTek SoCs access to that very debug register requires the bus
clock being enabled. Hence calling the suspend function while already
in suspended state results in that register access triggering a bus
error. In order to avoid that, track the state of the bus clock and
only poll the debug register if not already in suspended state.

Fixes: e32a83c ("serial: 8250-mtk: modify mtk uart power and clock management")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  • Loading branch information
dangowrt authored and frank-w committed Jul 30, 2024
1 parent 8e06ade commit ce40b6c
Showing 1 changed file with 9 additions and 1 deletion.
10 changes: 9 additions & 1 deletion drivers/tty/serial/8250/8250_mtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */
#define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */
#define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */
#define MTK_UART_DEBUG0 0x18
#define MTK_UART_DEBUG0 0x18
#define MTK_UART_IER_XOFFI 0x20 /* Enable XOFF character interrupt */
#define MTK_UART_IER_RTSI 0x40 /* Enable RTS Modem status interrupt */
#define MTK_UART_IER_CTSI 0x80 /* Enable CTS Modem status interrupt */
Expand Down Expand Up @@ -65,6 +65,7 @@ enum dma_rx_status {
};
#endif

#define MTK_UART_STATE_BIT_BUSCLK_EN BIT(0)
struct mtk8250_data {
int line;
unsigned int rx_pos;
Expand All @@ -76,6 +77,7 @@ struct mtk8250_data {
enum dma_rx_status rx_status;
#endif
int rx_wakeup_irq;
unsigned long state; /* MTK_UART_STATE_BIT_xxx */
};

/* flow control mode */
Expand Down Expand Up @@ -431,6 +433,9 @@ static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
struct mtk8250_data *data = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(data->line);

if (!test_and_clear_bit(MTK_UART_STATE_BIT_BUSCLK_EN, &data->state))
return 0;

/* wait until UART in idle status */
while
(serial_in(up, MTK_UART_DEBUG0));
Expand All @@ -444,6 +449,9 @@ static int __maybe_unused mtk8250_runtime_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);

if (test_and_set_bit(MTK_UART_STATE_BIT_BUSCLK_EN, &data->state))
return 0;

clk_prepare_enable(data->bus_clk);

return 0;
Expand Down

0 comments on commit ce40b6c

Please sign in to comment.