This patch enables ACPI power domain on UART user devices. With this patch, Linux can achieve open/close based ACPI power manageability for UART tty ports. Signed-off-by: Lv Zheng <lv.zheng@xxxxxxxxx> --- drivers/acpi/acpi_uart.c | 40 ++++++++++++++++++++++++++++++++++++++ drivers/tty/serial/serial_core.c | 5 +++++ include/linux/tty.h | 4 ++++ 3 files changed, 49 insertions(+) diff --git a/drivers/acpi/acpi_uart.c b/drivers/acpi/acpi_uart.c index c27fc7c..a6735b1 100644 --- a/drivers/acpi/acpi_uart.c +++ b/drivers/acpi/acpi_uart.c @@ -163,3 +163,43 @@ void acpi_uart_register_user_device(struct device *parent, } } EXPORT_SYMBOL_GPL(acpi_uart_register_user_device); + +/** + * acpi_uart_user_change_pm - change pm for tty port + * @port: the tty port + * @power_on: whether or not power on the device + * + * Change PM for tty user device. + */ +void acpi_uart_user_change_pm(struct tty_port *port, bool power_on) +{ + acpi_handle handle; + struct acpi_device *adev; + struct acpi_device_physical_node *entry; + struct device *ldev; + + BUG_ON(!port); + handle = ACPI_NODE_GET(port->acpi_node); + if (!handle) + return; + if (acpi_bus_get_device(handle, &adev)) + return; + if (acpi_bus_get_status(adev) || !adev->status.present) + return; + + list_for_each_entry(entry, &adev->physical_node_list, node) { + ldev = get_device(entry->dev); + if (!ldev) + continue; + if (ldev->class == tty_class) { + if (power_on) + acpi_dev_pm_attach(ldev, true); + else + acpi_dev_pm_detach(ldev, false); + put_device(ldev); + return; + } + put_device(ldev); + } +} +EXPORT_SYMBOL_GPL(acpi_uart_user_change_pm); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index c10bb4c..6ca4a5c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1901,10 +1901,15 @@ static void uart_change_pm(struct uart_state *state, enum uart_pm_state pm_state) { struct uart_port *port = state->uart_port; + struct tty_port *tport = &state->port; if (state->pm_state != pm_state) { + if (pm_state == UART_PM_STATE_ON) + acpi_uart_user_change_pm(tport, true); if (port->ops->pm) port->ops->pm(port, pm_state, state->pm_state); + if (pm_state == UART_PM_STATE_OFF) + acpi_uart_user_change_pm(tport, false); state->pm_state = pm_state; } } diff --git a/include/linux/tty.h b/include/linux/tty.h index 5f17ab5..fbf8def 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -687,11 +687,15 @@ void acpi_uart_register_user_device(struct device *parent, struct device *dev, struct tty_driver *driver, unsigned int index); +extern void acpi_uart_user_change_pm(struct tty_port *port, + bool power_on); #else static inline void acpi_uart_register_user_device(struct device *parent, struct device *dev, struct tty_driver *driver, unsigned int index) {} +static inline void acpi_uart_user_change_pm(struct tty_port *port, + bool power_on) {} #endif #endif -- 1.7.10 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html