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 int serial_port_runtime_suspend(struct device *dev) 50 { 51 struct serial_port_device *port_dev = to_serial_base_port_device(dev); 52 struct uart_port *port = port_dev->port; 53 unsigned long flags; 54 bool busy; 55 56 if (port->flags & UPF_DEAD) 57 return 0; 58 59 uart_port_lock_irqsave(port, &flags); 60 busy = __serial_port_busy(port); 61 if (busy) 62 port->ops->start_tx(port); 63 uart_port_unlock_irqrestore(port, flags); 64 65 if (busy) 66 pm_runtime_mark_last_busy(dev); 67 68 return busy ? -EBUSY : 0; 69 } 70 71 static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm, 72 serial_port_runtime_suspend, 73 serial_port_runtime_resume, NULL); 74 75 static int serial_port_probe(struct device *dev) 76 { 77 pm_runtime_enable(dev); 78 pm_runtime_set_autosuspend_delay(dev, SERIAL_PORT_AUTOSUSPEND_DELAY_MS); 79 pm_runtime_use_autosuspend(dev); 80 81 return 0; 82 } 83 84 static int serial_port_remove(struct device *dev) 85 { 86 pm_runtime_dont_use_autosuspend(dev); 87 pm_runtime_disable(dev); 88 89 return 0; 90 } 91 92 /* 93 * Serial core port device init functions. Note that the physical serial 94 * port device driver may not have completed probe at this point. 95 */ 96 int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) 97 { 98 return serial_ctrl_register_port(drv, port); 99 } 100 EXPORT_SYMBOL(uart_add_one_port); 101 102 void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) 103 { 104 serial_ctrl_unregister_port(drv, port); 105 } 106 EXPORT_SYMBOL(uart_remove_one_port); 107 108 static struct device_driver serial_port_driver = { 109 .name = "port", 110 .suppress_bind_attrs = true, 111 .probe = serial_port_probe, 112 .remove = serial_port_remove, 113 .pm = pm_ptr(&serial_port_pm), 114 }; 115 116 int serial_base_port_init(void) 117 { 118 return serial_base_driver_register(&serial_port_driver); 119 } 120 121 void serial_base_port_exit(void) 122 { 123 serial_base_driver_unregister(&serial_port_driver); 124 } 125 126 MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); 127 MODULE_DESCRIPTION("Serial controller port driver"); 128 MODULE_LICENSE("GPL"); 129