mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
serial: qcom-geni: add force suspend/resume to system sleep callbacks
During system sleep the hardware resources (clocks, interconnect) are not gated because the runtime-suspend callback is never invoked from the system sleep path. This prevents the platform from reaching its lowest idle state. The system sleep callbacks qcom_geni_serial_suspend() and qcom_geni_serial_resume() rely solely on uart_suspend_port() / uart_resume_port() to manage power. uart_suspend_port() drives the UART PM state machine to UART_PM_STATE_OFF, which in turn calls pm_runtime_put_sync() and eventually the runtime-suspend callback. However, if the runtime-PM usage count is still elevated at the time of system sleep (e.g. the port is held active by an open file descriptor), the runtime-suspend callback is never invoked and the hardware resources (clocks, interconnect) remain enabled across suspend, preventing the platform from reaching its lowest idle state. Fix this by calling pm_runtime_force_suspend() at the end of qcom_geni_serial_suspend() so that the runtime-suspend callback is always executed regardless of the usage count, and by calling pm_runtime_force_resume() at the start of qcom_geni_serial_resume() to restore those resources before uart_resume_port() re-opens the port. Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com> Link: https://patch.msgid.link/20260702-add_force_suspend_resume_to_system_sleep_callbacks-v2-1-b79e254a7015@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
bafe277d6c
commit
d0cd9c8d0f
|
|
@ -1985,6 +1985,7 @@ static int qcom_geni_serial_suspend(struct device *dev)
|
||||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||||
struct uart_port *uport = &port->uport;
|
struct uart_port *uport = &port->uport;
|
||||||
struct qcom_geni_private_data *private_data = uport->private_data;
|
struct qcom_geni_private_data *private_data = uport->private_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is done so we can hit the lowest possible state in suspend
|
* This is done so we can hit the lowest possible state in suspend
|
||||||
|
|
@ -1994,7 +1995,19 @@ static int qcom_geni_serial_suspend(struct device *dev)
|
||||||
geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ACTIVE_ONLY);
|
geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ACTIVE_ONLY);
|
||||||
geni_icc_set_bw(&port->se);
|
geni_icc_set_bw(&port->se);
|
||||||
}
|
}
|
||||||
return uart_suspend_port(private_data->drv, uport);
|
|
||||||
|
ret = uart_suspend_port(private_data->drv, uport);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When no_console_suspend is set the console must remain active
|
||||||
|
* across system sleep, so skip the force suspend path.
|
||||||
|
*/
|
||||||
|
if (!console_suspend_enabled && uart_console(uport))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return pm_runtime_force_suspend(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcom_geni_serial_resume(struct device *dev)
|
static int qcom_geni_serial_resume(struct device *dev)
|
||||||
|
|
@ -2004,6 +2017,10 @@ static int qcom_geni_serial_resume(struct device *dev)
|
||||||
struct uart_port *uport = &port->uport;
|
struct uart_port *uport = &port->uport;
|
||||||
struct qcom_geni_private_data *private_data = uport->private_data;
|
struct qcom_geni_private_data *private_data = uport->private_data;
|
||||||
|
|
||||||
|
ret = pm_runtime_force_resume(dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
ret = uart_resume_port(private_data->drv, uport);
|
ret = uart_resume_port(private_data->drv, uport);
|
||||||
if (uart_console(uport)) {
|
if (uart_console(uport)) {
|
||||||
geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS);
|
geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user