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/of.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/pm_runtime.h> |
14 | #include <linux/property.h> |
15 | #include <linux/serial_core.h> |
16 | #include <linux/spinlock.h> |
17 | |
18 | #include "serial_base.h" |
19 | |
20 | #define SERIAL_PORT_AUTOSUSPEND_DELAY_MS 500 |
21 | |
22 | /* Only considers pending TX for now. Caller must take care of locking */ |
23 | static int __serial_port_busy(struct uart_port *port) |
24 | { |
25 | return !uart_tx_stopped(port) && |
26 | uart_circ_chars_pending(&port->state->xmit); |
27 | } |
28 | |
29 | static int serial_port_runtime_resume(struct device *dev) |
30 | { |
31 | struct serial_port_device *port_dev = to_serial_base_port_device(dev); |
32 | struct uart_port *port; |
33 | unsigned long flags; |
34 | |
35 | port = port_dev->port; |
36 | |
37 | if (port->flags & UPF_DEAD) |
38 | goto out; |
39 | |
40 | /* Flush any pending TX for the port */ |
41 | uart_port_lock_irqsave(up: port, flags: &flags); |
42 | if (!port_dev->tx_enabled) |
43 | goto unlock; |
44 | if (__serial_port_busy(port)) |
45 | port->ops->start_tx(port); |
46 | |
47 | unlock: |
48 | uart_port_unlock_irqrestore(up: port, flags); |
49 | |
50 | out: |
51 | pm_runtime_mark_last_busy(dev); |
52 | |
53 | return 0; |
54 | } |
55 | |
56 | static int serial_port_runtime_suspend(struct device *dev) |
57 | { |
58 | struct serial_port_device *port_dev = to_serial_base_port_device(dev); |
59 | struct uart_port *port = port_dev->port; |
60 | unsigned long flags; |
61 | bool busy; |
62 | |
63 | if (port->flags & UPF_DEAD) |
64 | return 0; |
65 | |
66 | uart_port_lock_irqsave(up: port, flags: &flags); |
67 | if (!port_dev->tx_enabled) { |
68 | uart_port_unlock_irqrestore(up: port, flags); |
69 | return 0; |
70 | } |
71 | |
72 | busy = __serial_port_busy(port); |
73 | if (busy) |
74 | port->ops->start_tx(port); |
75 | uart_port_unlock_irqrestore(up: port, flags); |
76 | |
77 | if (busy) |
78 | pm_runtime_mark_last_busy(dev); |
79 | |
80 | return busy ? -EBUSY : 0; |
81 | } |
82 | |
83 | static void serial_base_port_set_tx(struct uart_port *port, |
84 | struct serial_port_device *port_dev, |
85 | bool enabled) |
86 | { |
87 | unsigned long flags; |
88 | |
89 | uart_port_lock_irqsave(up: port, flags: &flags); |
90 | port_dev->tx_enabled = enabled; |
91 | uart_port_unlock_irqrestore(up: port, flags); |
92 | } |
93 | |
94 | void serial_base_port_startup(struct uart_port *port) |
95 | { |
96 | struct serial_port_device *port_dev = port->port_dev; |
97 | |
98 | serial_base_port_set_tx(port, port_dev, enabled: true); |
99 | } |
100 | |
101 | void serial_base_port_shutdown(struct uart_port *port) |
102 | { |
103 | struct serial_port_device *port_dev = port->port_dev; |
104 | |
105 | serial_base_port_set_tx(port, port_dev, enabled: false); |
106 | } |
107 | |
108 | static DEFINE_RUNTIME_DEV_PM_OPS(serial_port_pm, |
109 | serial_port_runtime_suspend, |
110 | serial_port_runtime_resume, NULL); |
111 | |
112 | static int serial_port_probe(struct device *dev) |
113 | { |
114 | pm_runtime_enable(dev); |
115 | pm_runtime_set_autosuspend_delay(dev, SERIAL_PORT_AUTOSUSPEND_DELAY_MS); |
116 | pm_runtime_use_autosuspend(dev); |
117 | |
118 | return 0; |
119 | } |
120 | |
121 | static int serial_port_remove(struct device *dev) |
122 | { |
123 | pm_runtime_dont_use_autosuspend(dev); |
124 | pm_runtime_disable(dev); |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | /* |
130 | * Serial core port device init functions. Note that the physical serial |
131 | * port device driver may not have completed probe at this point. |
132 | */ |
133 | int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) |
134 | { |
135 | return serial_ctrl_register_port(drv, port); |
136 | } |
137 | EXPORT_SYMBOL(uart_add_one_port); |
138 | |
139 | void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) |
140 | { |
141 | serial_ctrl_unregister_port(drv, port); |
142 | } |
143 | EXPORT_SYMBOL(uart_remove_one_port); |
144 | |
145 | /** |
146 | * __uart_read_properties - read firmware properties of the given UART port |
147 | * @port: corresponding port |
148 | * @use_defaults: apply defaults (when %true) or validate the values (when %false) |
149 | * |
150 | * The following device properties are supported: |
151 | * - clock-frequency (optional) |
152 | * - fifo-size (optional) |
153 | * - no-loopback-test (optional) |
154 | * - reg-shift (defaults may apply) |
155 | * - reg-offset (value may be validated) |
156 | * - reg-io-width (defaults may apply or value may be validated) |
157 | * - interrupts (OF only) |
158 | * - serial [alias ID] (OF only) |
159 | * |
160 | * If the port->dev is of struct platform_device type the interrupt line |
161 | * will be retrieved via platform_get_irq() call against that device. |
162 | * Otherwise it will be assigned by fwnode_irq_get() call. In both cases |
163 | * the index 0 of the resource is used. |
164 | * |
165 | * The caller is responsible to initialize the following fields of the @port |
166 | * ->dev (must be valid) |
167 | * ->flags |
168 | * ->mapbase |
169 | * ->mapsize |
170 | * ->regshift (if @use_defaults is false) |
171 | * before calling this function. Alternatively the above mentioned fields |
172 | * may be zeroed, in such case the only ones, that have associated properties |
173 | * found, will be set to the respective values. |
174 | * |
175 | * If no error happened, the ->irq, ->mapbase, ->mapsize will be altered. |
176 | * The ->iotype is always altered. |
177 | * |
178 | * When @use_defaults is true and the respective property is not found |
179 | * the following values will be applied: |
180 | * ->regshift = 0 |
181 | * In this case IRQ must be provided, otherwise an error will be returned. |
182 | * |
183 | * When @use_defaults is false and the respective property is found |
184 | * the following values will be validated: |
185 | * - reg-io-width (->iotype) |
186 | * - reg-offset (->mapsize against ->mapbase) |
187 | * |
188 | * Returns: 0 on success or negative errno on failure |
189 | */ |
190 | static int __uart_read_properties(struct uart_port *port, bool use_defaults) |
191 | { |
192 | struct device *dev = port->dev; |
193 | u32 value; |
194 | int ret; |
195 | |
196 | /* Read optional UART functional clock frequency */ |
197 | device_property_read_u32(dev, propname: "clock-frequency" , val: &port->uartclk); |
198 | |
199 | /* Read the registers alignment (default: 8-bit) */ |
200 | ret = device_property_read_u32(dev, propname: "reg-shift" , val: &value); |
201 | if (ret) |
202 | port->regshift = use_defaults ? 0 : port->regshift; |
203 | else |
204 | port->regshift = value; |
205 | |
206 | /* Read the registers I/O access type (default: MMIO 8-bit) */ |
207 | ret = device_property_read_u32(dev, propname: "reg-io-width" , val: &value); |
208 | if (ret) { |
209 | port->iotype = UPIO_MEM; |
210 | } else { |
211 | switch (value) { |
212 | case 1: |
213 | port->iotype = UPIO_MEM; |
214 | break; |
215 | case 2: |
216 | port->iotype = UPIO_MEM16; |
217 | break; |
218 | case 4: |
219 | port->iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32; |
220 | break; |
221 | default: |
222 | if (!use_defaults) { |
223 | dev_err(dev, "Unsupported reg-io-width (%u)\n" , value); |
224 | return -EINVAL; |
225 | } |
226 | port->iotype = UPIO_UNKNOWN; |
227 | break; |
228 | } |
229 | } |
230 | |
231 | /* Read the address mapping base offset (default: no offset) */ |
232 | ret = device_property_read_u32(dev, propname: "reg-offset" , val: &value); |
233 | if (ret) |
234 | value = 0; |
235 | |
236 | /* Check for shifted address mapping overflow */ |
237 | if (!use_defaults && port->mapsize < value) { |
238 | dev_err(dev, "reg-offset %u exceeds region size %pa\n" , value, &port->mapsize); |
239 | return -EINVAL; |
240 | } |
241 | |
242 | port->mapbase += value; |
243 | port->mapsize -= value; |
244 | |
245 | /* Read optional FIFO size */ |
246 | device_property_read_u32(dev, propname: "fifo-size" , val: &port->fifosize); |
247 | |
248 | if (device_property_read_bool(dev, propname: "no-loopback-test" )) |
249 | port->flags |= UPF_SKIP_TEST; |
250 | |
251 | /* Get index of serial line, if found in DT aliases */ |
252 | ret = of_alias_get_id(np: dev_of_node(dev), stem: "serial" ); |
253 | if (ret >= 0) |
254 | port->line = ret; |
255 | |
256 | if (dev_is_platform(dev)) |
257 | ret = platform_get_irq(to_platform_device(dev), 0); |
258 | else |
259 | ret = fwnode_irq_get(dev_fwnode(dev), index: 0); |
260 | if (ret == -EPROBE_DEFER) |
261 | return ret; |
262 | if (ret > 0) |
263 | port->irq = ret; |
264 | else if (use_defaults) |
265 | /* By default IRQ support is mandatory */ |
266 | return ret; |
267 | else |
268 | port->irq = 0; |
269 | |
270 | port->flags |= UPF_SHARE_IRQ; |
271 | |
272 | return 0; |
273 | } |
274 | |
275 | int uart_read_port_properties(struct uart_port *port) |
276 | { |
277 | return __uart_read_properties(port, use_defaults: true); |
278 | } |
279 | EXPORT_SYMBOL_GPL(uart_read_port_properties); |
280 | |
281 | int uart_read_and_validate_port_properties(struct uart_port *port) |
282 | { |
283 | return __uart_read_properties(port, use_defaults: false); |
284 | } |
285 | EXPORT_SYMBOL_GPL(uart_read_and_validate_port_properties); |
286 | |
287 | static struct device_driver serial_port_driver = { |
288 | .name = "port" , |
289 | .suppress_bind_attrs = true, |
290 | .probe = serial_port_probe, |
291 | .remove = serial_port_remove, |
292 | .pm = pm_ptr(&serial_port_pm), |
293 | }; |
294 | |
295 | int serial_base_port_init(void) |
296 | { |
297 | return serial_base_driver_register(driver: &serial_port_driver); |
298 | } |
299 | |
300 | void serial_base_port_exit(void) |
301 | { |
302 | serial_base_driver_unregister(driver: &serial_port_driver); |
303 | } |
304 | |
305 | MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>" ); |
306 | MODULE_DESCRIPTION("Serial controller port driver" ); |
307 | MODULE_LICENSE("GPL" ); |
308 | |