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 */ 20 static 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 26 static 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 uart_port_lock_irqsave(port, &flags); 39 if (__serial_port_busy(port)) 40 port->ops->start_tx(port); 41 uart_port_unlock_irqrestore(port, flags); 42 43 out: 44 pm_runtime_mark_last_busy(dev); 45 46 return 0; 47 } 48 49 static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm, 50 NULL, serial_port_runtime_resume, NULL); 51 52 static 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 61 static 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 */ 73 int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) 74 { 75 return serial_ctrl_register_port(drv, port); 76 } 77 EXPORT_SYMBOL(uart_add_one_port); 78 79 void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) 80 { 81 serial_ctrl_unregister_port(drv, port); 82 } 83 EXPORT_SYMBOL(uart_remove_one_port); 84 85 static 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 93 int serial_base_port_init(void) 94 { 95 return serial_base_driver_register(&serial_port_driver); 96 } 97 98 void serial_base_port_exit(void) 99 { 100 serial_base_driver_unregister(&serial_port_driver); 101 } 102 103 MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); 104 MODULE_DESCRIPTION("Serial controller port driver"); 105 MODULE_LICENSE("GPL"); 106