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