1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Serial core port device driver 4 * 5 * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ 6 * Author: Tony Lindgren <tony@atomide.com> 7 */ 8 9#include <linux/device.h> 10#include <linux/module.h> 11#include <linux/pm_runtime.h> 12#include <linux/serial_core.h> 13#include <linux/spinlock.h> 14 15#include "serial_base.h" 16 17#define SERIAL_PORT_AUTOSUSPEND_DELAY_MS 500 18 19/* Only considers pending TX for now. Caller must take care of locking */ 20static int __serial_port_busy(struct uart_port *port) 21{ 22 return !uart_tx_stopped(port) && 23 uart_circ_chars_pending(&port->state->xmit); 24} 25 26static int serial_port_runtime_resume(struct device *dev) 27{ 28 struct serial_port_device *port_dev = to_serial_base_port_device(dev); 29 struct uart_port *port; 30 unsigned long flags; 31 32 port = port_dev->port; 33 34 if (port->flags & UPF_DEAD) 35 goto out; 36 37 /* Flush any pending TX for the port */ 38 spin_lock_irqsave(&port->lock, flags); 39 if (__serial_port_busy(port)) 40 port->ops->start_tx(port); 41 spin_unlock_irqrestore(&port->lock, flags); 42 43out: 44 pm_runtime_mark_last_busy(dev); 45 46 return 0; 47} 48 49static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm, 50 NULL, serial_port_runtime_resume, NULL); 51 52static int serial_port_probe(struct device *dev) 53{ 54 pm_runtime_enable(dev); 55 pm_runtime_set_autosuspend_delay(dev, SERIAL_PORT_AUTOSUSPEND_DELAY_MS); 56 pm_runtime_use_autosuspend(dev); 57 58 return 0; 59} 60 61static int serial_port_remove(struct device *dev) 62{ 63 pm_runtime_dont_use_autosuspend(dev); 64 pm_runtime_disable(dev); 65 66 return 0; 67} 68 69/* 70 * Serial core port device init functions. Note that the physical serial 71 * port device driver may not have completed probe at this point. 72 */ 73int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) 74{ 75 return serial_ctrl_register_port(drv, port); 76} 77EXPORT_SYMBOL(uart_add_one_port); 78 79void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) 80{ 81 serial_ctrl_unregister_port(drv, port); 82} 83EXPORT_SYMBOL(uart_remove_one_port); 84 85static struct device_driver serial_port_driver = { 86 .name = "port", 87 .suppress_bind_attrs = true, 88 .probe = serial_port_probe, 89 .remove = serial_port_remove, 90 .pm = pm_ptr(&serial_port_pm), 91}; 92 93int serial_base_port_init(void) 94{ 95 return serial_base_driver_register(&serial_port_driver); 96} 97 98void serial_base_port_exit(void) 99{ 100 serial_base_driver_unregister(&serial_port_driver); 101} 102 103MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); 104MODULE_DESCRIPTION("Serial controller port driver"); 105MODULE_LICENSE("GPL"); 106