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 spin_lock_irqsave(&port->lock, flags); 39 if (!port_dev->tx_enabled) 40 goto unlock; 41 if (__serial_port_busy(port)) 42 port->ops->start_tx(port); 43 44 unlock: 45 spin_unlock_irqrestore(&port->lock, flags); 46 47 out: 48 pm_runtime_mark_last_busy(dev); 49 50 return 0; 51 } 52 53 static int serial_port_runtime_suspend(struct device *dev) 54 { 55 struct serial_port_device *port_dev = to_serial_base_port_device(dev); 56 struct uart_port *port = port_dev->port; 57 unsigned long flags; 58 bool busy; 59 60 if (port->flags & UPF_DEAD) 61 return 0; 62 63 uart_port_lock_irqsave(port, &flags); 64 if (!port_dev->tx_enabled) { 65 uart_port_unlock_irqrestore(port, flags); 66 return 0; 67 } 68 69 busy = __serial_port_busy(port); 70 if (busy) 71 port->ops->start_tx(port); 72 uart_port_unlock_irqrestore(port, flags); 73 74 if (busy) 75 pm_runtime_mark_last_busy(dev); 76 77 return busy ? -EBUSY : 0; 78 } 79 80 static void serial_base_port_set_tx(struct uart_port *port, 81 struct serial_port_device *port_dev, 82 bool enabled) 83 { 84 unsigned long flags; 85 86 uart_port_lock_irqsave(port, &flags); 87 port_dev->tx_enabled = enabled; 88 uart_port_unlock_irqrestore(port, flags); 89 } 90 91 void serial_base_port_startup(struct uart_port *port) 92 { 93 struct serial_port_device *port_dev = port->port_dev; 94 95 serial_base_port_set_tx(port, port_dev, true); 96 } 97 98 void serial_base_port_shutdown(struct uart_port *port) 99 { 100 struct serial_port_device *port_dev = port->port_dev; 101 102 serial_base_port_set_tx(port, port_dev, false); 103 } 104 105 static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm, 106 serial_port_runtime_suspend, 107 serial_port_runtime_resume, NULL); 108 109 static int serial_port_probe(struct device *dev) 110 { 111 pm_runtime_enable(dev); 112 pm_runtime_set_autosuspend_delay(dev, SERIAL_PORT_AUTOSUSPEND_DELAY_MS); 113 pm_runtime_use_autosuspend(dev); 114 115 return 0; 116 } 117 118 static int serial_port_remove(struct device *dev) 119 { 120 pm_runtime_dont_use_autosuspend(dev); 121 pm_runtime_disable(dev); 122 123 return 0; 124 } 125 126 /* 127 * Serial core port device init functions. Note that the physical serial 128 * port device driver may not have completed probe at this point. 129 */ 130 int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) 131 { 132 return serial_ctrl_register_port(drv, port); 133 } 134 EXPORT_SYMBOL(uart_add_one_port); 135 136 void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) 137 { 138 serial_ctrl_unregister_port(drv, port); 139 } 140 EXPORT_SYMBOL(uart_remove_one_port); 141 142 static struct device_driver serial_port_driver = { 143 .name = "port", 144 .suppress_bind_attrs = true, 145 .probe = serial_port_probe, 146 .remove = serial_port_remove, 147 .pm = pm_ptr(&serial_port_pm), 148 }; 149 150 int serial_base_port_init(void) 151 { 152 return serial_base_driver_register(&serial_port_driver); 153 } 154 155 void serial_base_port_exit(void) 156 { 157 serial_base_driver_unregister(&serial_port_driver); 158 } 159 160 MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); 161 MODULE_DESCRIPTION("Serial controller port driver"); 162 MODULE_LICENSE("GPL"); 163