File Index
Files and directories
Sign in
FILE

tegra-utc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/tty/serial/tegra-utc.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  3// NVIDIA Tegra UTC (UART Trace Controller) driver.
  4
  5#include <linux/bits.h>
  6#include <linux/console.h>
  7#include <linux/container_of.h>
  8#include <linux/device.h>
  9#include <linux/err.h>
 10#include <linux/iopoll.h>
 11#include <linux/kfifo.h>
 12#include <linux/module.h>
 13#include <linux/mod_devicetable.h>
 14#include <linux/property.h>
 15#include <linux/platform_device.h>
 16#include <linux/serial.h>
 17#include <linux/serial_core.h>
 18#include <linux/slab.h>
 19#include <linux/tty.h>
 20#include <linux/tty_flip.h>
 21#include <linux/types.h>
 22
 23#define TEGRA_UTC_ENABLE			0x000
 24#define TEGRA_UTC_ENABLE_CLIENT_ENABLE		BIT(0)
 25
 26#define TEGRA_UTC_FIFO_THRESHOLD		0x008
 27
 28#define TEGRA_UTC_COMMAND			0x00c
 29#define TEGRA_UTC_COMMAND_RESET			BIT(0)
 30#define TEGRA_UTC_COMMAND_FLUSH			BIT(1)
 31
 32#define TEGRA_UTC_DATA				0x020
 33
 34#define TEGRA_UTC_FIFO_STATUS			0x100
 35#define TEGRA_UTC_FIFO_EMPTY			BIT(0)
 36#define TEGRA_UTC_FIFO_FULL			BIT(1)
 37#define TEGRA_UTC_FIFO_REQ			BIT(2)
 38#define TEGRA_UTC_FIFO_OVERFLOW			BIT(3)
 39#define TEGRA_UTC_FIFO_TIMEOUT			BIT(4)
 40
 41#define TEGRA_UTC_FIFO_OCCUPANCY		0x104
 42
 43#define TEGRA_UTC_INTR_STATUS			0x108
 44#define TEGRA_UTC_INTR_SET			0x10c
 45#define TEGRA_UTC_INTR_MASK			0x110
 46#define TEGRA_UTC_INTR_CLEAR			0x114
 47#define TEGRA_UTC_INTR_EMPTY			BIT(0)
 48#define TEGRA_UTC_INTR_FULL			BIT(1)
 49#define TEGRA_UTC_INTR_REQ			BIT(2)
 50#define TEGRA_UTC_INTR_OVERFLOW			BIT(3)
 51#define TEGRA_UTC_INTR_TIMEOUT			BIT(4)
 52
 53#define TEGRA_UTC_UART_NR			16
 54
 55#define TEGRA_UTC_INTR_COMMON	(TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_FULL | TEGRA_UTC_INTR_EMPTY)
 56
 57struct tegra_utc_port {
 58#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
 59	struct console console;
 60#endif
 61	struct uart_port port;
 62
 63	void __iomem *rx_base;
 64	void __iomem *tx_base;
 65
 66	u32 tx_irqmask;
 67	u32 rx_irqmask;
 68
 69	unsigned int fifosize;
 70	u32 tx_threshold;
 71	u32 rx_threshold;
 72};
 73
 74static u32 tegra_utc_rx_readl(struct tegra_utc_port *tup, unsigned int offset)
 75{
 76	void __iomem *addr = tup->rx_base + offset;
 77
 78	return readl_relaxed(addr);
 79}
 80
 81static void tegra_utc_rx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
 82{
 83	void __iomem *addr = tup->rx_base + offset;
 84
 85	writel_relaxed(val, addr);
 86}
 87
 88static u32 tegra_utc_tx_readl(struct tegra_utc_port *tup, unsigned int offset)
 89{
 90	void __iomem *addr = tup->tx_base + offset;
 91
 92	return readl_relaxed(addr);
 93}
 94
 95static void tegra_utc_tx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
 96{
 97	void __iomem *addr = tup->tx_base + offset;
 98
 99	writel_relaxed(val, addr);
100}
101
102static void tegra_utc_enable_tx_irq(struct tegra_utc_port *tup)
103{
104	tup->tx_irqmask = TEGRA_UTC_INTR_REQ;
105
106	tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
107	tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
108}
109
110static void tegra_utc_disable_tx_irq(struct tegra_utc_port *tup)
111{
112	tup->tx_irqmask = 0x0;
113
114	tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
115	tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
116}
117
118static void tegra_utc_stop_tx(struct uart_port *port)
119{
120	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
121
122	tegra_utc_disable_tx_irq(tup);
123}
124
125static void tegra_utc_init_tx(struct tegra_utc_port *tup)
126{
127	/* Disable TX. */
128	tegra_utc_tx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
129
130	/* Update the FIFO Threshold. */
131	tegra_utc_tx_writel(tup, tup->tx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
132
133	/* Clear and mask all the interrupts. */
134	tegra_utc_tx_writel(tup, TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
135	tegra_utc_disable_tx_irq(tup);
136
137	/* Enable TX. */
138	tegra_utc_tx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
139}
140
141static void tegra_utc_init_rx(struct tegra_utc_port *tup)
142{
143	tup->rx_irqmask = TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_TIMEOUT;
144
145	tegra_utc_rx_writel(tup, TEGRA_UTC_COMMAND_RESET, TEGRA_UTC_COMMAND);
146	tegra_utc_rx_writel(tup, tup->rx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
147
148	/* Clear all the pending interrupts. */
149	tegra_utc_rx_writel(tup, TEGRA_UTC_INTR_TIMEOUT | TEGRA_UTC_INTR_OVERFLOW |
150			    TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
151	tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
152	tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
153
154	/* Enable RX. */
155	tegra_utc_rx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
156}
157
158static bool tegra_utc_tx_chars(struct tegra_utc_port *tup)
159{
160	struct uart_port *port = &tup->port;
161	unsigned int pending;
162	u8 c;
163
164	pending = uart_port_tx(port, c,
165		     !(tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_FULL),
166		     tegra_utc_tx_writel(tup, c, TEGRA_UTC_DATA));
167
168	return pending;
169}
170
171static void tegra_utc_rx_chars(struct tegra_utc_port *tup)
172{
173	struct tty_port *port = &tup->port.state->port;
174	unsigned int max_chars = 256;
175	u32 status;
176	int sysrq;
177	u32 ch;
178
179	while (max_chars--) {
180		status = tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS);
181		if (status & TEGRA_UTC_FIFO_EMPTY)
182			break;
183
184		ch = tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
185		tup->port.icount.rx++;
186
187		if (status & TEGRA_UTC_FIFO_OVERFLOW)
188			tup->port.icount.overrun++;
189
190		uart_port_unlock(&tup->port);
191		sysrq = uart_handle_sysrq_char(&tup->port, ch);
192		uart_port_lock(&tup->port);
193
194		if (!sysrq)
195			tty_insert_flip_char(port, ch, TTY_NORMAL);
196	}
197
198	tty_flip_buffer_push(port);
199}
200
201static irqreturn_t tegra_utc_isr(int irq, void *dev_id)
202{
203	struct tegra_utc_port *tup = dev_id;
204	unsigned int handled = 0;
205	u32 status;
206
207	uart_port_lock(&tup->port);
208
209	/* Process RX_REQ and RX_TIMEOUT interrupts. */
210	do {
211		status = tegra_utc_rx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->rx_irqmask;
212		if (status) {
213			tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_CLEAR);
214			tegra_utc_rx_chars(tup);
215			handled = 1;
216		}
217	} while (status);
218
219	/* Process TX_REQ interrupt. */
220	do {
221		status = tegra_utc_tx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->tx_irqmask;
222		if (status) {
223			tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_CLEAR);
224			tegra_utc_tx_chars(tup);
225			handled = 1;
226		}
227	} while (status);
228
229	uart_port_unlock(&tup->port);
230
231	return IRQ_RETVAL(handled);
232}
233
234static unsigned int tegra_utc_tx_empty(struct uart_port *port)
235{
236	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
237
238	return tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY) ? 0 : TIOCSER_TEMT;
239}
240
241static void tegra_utc_set_mctrl(struct uart_port *port, unsigned int mctrl)
242{
243}
244
245static unsigned int tegra_utc_get_mctrl(struct uart_port *port)
246{
247	return 0;
248}
249
250static void tegra_utc_start_tx(struct uart_port *port)
251{
252	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
253
254	if (tegra_utc_tx_chars(tup))
255		tegra_utc_enable_tx_irq(tup);
256}
257
258static void tegra_utc_stop_rx(struct uart_port *port)
259{
260	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
261
262	tup->rx_irqmask = 0x0;
263	tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
264	tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
265}
266
267static void tegra_utc_hw_init(struct tegra_utc_port *tup)
268{
269	tegra_utc_init_tx(tup);
270	tegra_utc_init_rx(tup);
271}
272
273static int tegra_utc_startup(struct uart_port *port)
274{
275	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
276	int ret;
277
278	tegra_utc_hw_init(tup);
279
280	/* Interrupt is dedicated to this UTC client. */
281	ret = request_irq(port->irq, tegra_utc_isr, 0, dev_name(port->dev), tup);
282	if (ret < 0)
283		dev_err(port->dev, "failed to register interrupt handler\n");
284
285	return ret;
286}
287
288static void tegra_utc_shutdown(struct uart_port *port)
289{
290	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
291
292	tegra_utc_rx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
293	free_irq(port->irq, tup);
294}
295
296static void tegra_utc_set_termios(struct uart_port *port, struct ktermios *termios,
297				  const struct ktermios *old)
298{
299	/* The Tegra UTC clients supports only 8-N-1 configuration without HW flow control */
300	termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
301	termios->c_cflag &= ~(CMSPAR | CRTSCTS);
302	termios->c_cflag |= CS8 | CLOCAL;
303}
304
305#ifdef CONFIG_CONSOLE_POLL
306
307static int tegra_utc_poll_init(struct uart_port *port)
308{
309	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
310
311	tegra_utc_hw_init(tup);
312	return 0;
313}
314
315static int tegra_utc_get_poll_char(struct uart_port *port)
316{
317	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
318
319	if (tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_EMPTY)
320		return NO_POLL_CHAR;
321
322	return tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
323}
324
325static void tegra_utc_put_poll_char(struct uart_port *port, unsigned char ch)
326{
327	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
328	u32 val;
329
330	read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
331				 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
332
333	tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
334}
335
336#endif
337
338static const struct uart_ops tegra_utc_uart_ops = {
339	.tx_empty = tegra_utc_tx_empty,
340	.set_mctrl = tegra_utc_set_mctrl,
341	.get_mctrl = tegra_utc_get_mctrl,
342	.stop_tx = tegra_utc_stop_tx,
343	.start_tx = tegra_utc_start_tx,
344	.stop_rx = tegra_utc_stop_rx,
345	.startup = tegra_utc_startup,
346	.shutdown = tegra_utc_shutdown,
347	.set_termios = tegra_utc_set_termios,
348#ifdef CONFIG_CONSOLE_POLL
349	.poll_init = tegra_utc_poll_init,
350	.poll_get_char = tegra_utc_get_poll_char,
351	.poll_put_char = tegra_utc_put_poll_char,
352#endif
353};
354
355#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
356#define TEGRA_UTC_DEFAULT_FIFO_THRESHOLD	4
357#define TEGRA_UTC_EARLYCON_MAX_BURST_SIZE	128
358
359static void tegra_utc_putc(struct uart_port *port, unsigned char c)
360{
361	writel(c, port->membase + TEGRA_UTC_DATA);
362}
363
364static void tegra_utc_early_write(struct console *con, const char *s, unsigned int n)
365{
366	struct earlycon_device *dev = con->data;
367
368	while (n) {
369		u32 burst_size = TEGRA_UTC_EARLYCON_MAX_BURST_SIZE;
370
371		burst_size -= readl(dev->port.membase + TEGRA_UTC_FIFO_OCCUPANCY);
372		if (n < burst_size)
373			burst_size = n;
374
375		uart_console_write(&dev->port, s, burst_size, tegra_utc_putc);
376
377		n -= burst_size;
378		s += burst_size;
379	}
380}
381
382static int __init tegra_utc_early_console_setup(struct earlycon_device *device, const char *opt)
383{
384	if (!device->port.membase)
385		return -ENODEV;
386
387	/* Configure TX */
388	writel(TEGRA_UTC_COMMAND_FLUSH | TEGRA_UTC_COMMAND_RESET,
389		device->port.membase + TEGRA_UTC_COMMAND);
390	writel(TEGRA_UTC_DEFAULT_FIFO_THRESHOLD, device->port.membase + TEGRA_UTC_FIFO_THRESHOLD);
391
392	/* Clear and mask all the interrupts. */
393	writel(TEGRA_UTC_INTR_COMMON, device->port.membase + TEGRA_UTC_INTR_CLEAR);
394
395	writel(0x0, device->port.membase + TEGRA_UTC_INTR_MASK);
396	writel(0x0, device->port.membase + TEGRA_UTC_INTR_SET);
397
398	/* Enable TX. */
399	writel(TEGRA_UTC_ENABLE_CLIENT_ENABLE, device->port.membase + TEGRA_UTC_ENABLE);
400
401	device->con->write = tegra_utc_early_write;
402
403	return 0;
404}
405OF_EARLYCON_DECLARE(tegra_utc, "nvidia,tegra264-utc", tegra_utc_early_console_setup);
406
407static void tegra_utc_console_putchar(struct uart_port *port, unsigned char ch)
408{
409	struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
410
411	tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
412}
413
414static void tegra_utc_console_write_atomic(struct console *cons, struct nbcon_write_context *wctxt)
415{
416	struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
417	unsigned int len;
418	char *outbuf;
419
420	if (!nbcon_enter_unsafe(wctxt))
421		return;
422
423	outbuf = wctxt->outbuf;
424	len = wctxt->len;
425
426	while (len) {
427		u32 burst_size = tup->fifosize;
428
429		burst_size -= tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY);
430		if (len < burst_size)
431			burst_size = len;
432
433		uart_console_write(&tup->port, outbuf, burst_size, tegra_utc_console_putchar);
434
435		outbuf += burst_size;
436		len -= burst_size;
437	}
438
439	nbcon_exit_unsafe(wctxt);
440}
441
442static void tegra_utc_console_write_thread(struct console *cons, struct nbcon_write_context *wctxt)
443{
444	struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
445	unsigned int len = READ_ONCE(wctxt->len);
446	unsigned int i;
447	u32 val;
448
449	for (i = 0; i < len; i++) {
450		if (!nbcon_enter_unsafe(wctxt))
451			break;
452
453		read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
454					 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
455		uart_console_write(&tup->port, wctxt->outbuf + i, 1, tegra_utc_console_putchar);
456
457		if (!nbcon_exit_unsafe(wctxt))
458			break;
459	}
460}
461
462static void tegra_utc_console_device_lock(struct console *cons, unsigned long *flags)
463{
464	struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
465	struct uart_port *port = &tup->port;
466
467	__uart_port_lock_irqsave(port, flags);
468}
469
470static void tegra_utc_console_device_unlock(struct console *cons, unsigned long flags)
471{
472	struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
473	struct uart_port *port = &tup->port;
474
475	__uart_port_unlock_irqrestore(port, flags);
476}
477
478static int tegra_utc_console_setup(struct console *cons, char *options)
479{
480	struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
481
482	tegra_utc_init_tx(tup);
483
484	return 0;
485}
486#endif
487
488static struct uart_driver tegra_utc_driver = {
489	.driver_name	= "tegra-utc",
490	.dev_name	= "ttyUTC",
491	.nr		= TEGRA_UTC_UART_NR,
492};
493
494static int tegra_utc_setup_port(struct device *dev, struct tegra_utc_port *tup)
495{
496	tup->port.dev			= dev;
497	tup->port.fifosize		= tup->fifosize;
498	tup->port.flags			= UPF_BOOT_AUTOCONF;
499	tup->port.iotype		= UPIO_MEM;
500	tup->port.ops			= &tegra_utc_uart_ops;
501	tup->port.type			= PORT_TEGRA_TCU;
502	tup->port.private_data		= tup;
503
504#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
505	strscpy(tup->console.name, "ttyUTC", sizeof(tup->console.name));
506	tup->console.write_atomic	= tegra_utc_console_write_atomic;
507	tup->console.write_thread	= tegra_utc_console_write_thread;
508	tup->console.device_lock	= tegra_utc_console_device_lock;
509	tup->console.device_unlock	= tegra_utc_console_device_unlock;
510	tup->console.device		= uart_console_device;
511	tup->console.setup		= tegra_utc_console_setup;
512	tup->console.flags		= CON_PRINTBUFFER | CON_NBCON;
513	tup->console.data		= &tegra_utc_driver;
514#endif
515
516	return uart_read_port_properties(&tup->port);
517}
518
519static int tegra_utc_register_port(struct tegra_utc_port *tup)
520{
521	int ret;
522
523	ret = uart_add_one_port(&tegra_utc_driver, &tup->port);
524	if (ret)
525		return ret;
526
527#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
528	register_console(&tup->console);
529#endif
530
531	return 0;
532}
533
534static int tegra_utc_probe(struct platform_device *pdev)
535{
536	const unsigned int *soc_fifosize;
537	struct device *dev = &pdev->dev;
538	struct tegra_utc_port *tup;
539	int ret;
540
541	tup = devm_kzalloc(dev, sizeof(*tup), GFP_KERNEL);
542	if (!tup)
543		return -ENOMEM;
544
545	ret = device_property_read_u32(dev, "tx-threshold", &tup->tx_threshold);
546	if (ret)
547		return dev_err_probe(dev, ret, "missing %s property\n", "tx-threshold");
548
549	ret = device_property_read_u32(dev, "rx-threshold", &tup->rx_threshold);
550	if (ret)
551		return dev_err_probe(dev, ret, "missing %s property\n", "rx-threshold");
552
553	soc_fifosize = device_get_match_data(dev);
554	tup->fifosize = *soc_fifosize;
555
556	tup->tx_base = devm_platform_ioremap_resource_byname(pdev, "tx");
557	if (IS_ERR(tup->tx_base))
558		return PTR_ERR(tup->tx_base);
559
560	tup->rx_base = devm_platform_ioremap_resource_byname(pdev, "rx");
561	if (IS_ERR(tup->rx_base))
562		return PTR_ERR(tup->rx_base);
563
564	ret = tegra_utc_setup_port(dev, tup);
565	if (ret)
566		dev_err_probe(dev, ret, "failed to setup uart port\n");
567
568	platform_set_drvdata(pdev, tup);
569
570	return tegra_utc_register_port(tup);
571}
572
573static void tegra_utc_remove(struct platform_device *pdev)
574{
575	struct tegra_utc_port *tup = platform_get_drvdata(pdev);
576
577#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
578	unregister_console(&tup->console);
579#endif
580	uart_remove_one_port(&tegra_utc_driver, &tup->port);
581}
582
583static const unsigned int tegra264_utc_soc = 128;
584
585static const struct of_device_id tegra_utc_of_match[] = {
586	{ .compatible = "nvidia,tegra264-utc", .data = &tegra264_utc_soc },
587	{}
588};
589MODULE_DEVICE_TABLE(of, tegra_utc_of_match);
590
591static struct platform_driver tegra_utc_platform_driver = {
592	.probe = tegra_utc_probe,
593	.remove = tegra_utc_remove,
594	.driver = {
595		.name = "tegra-utc",
596		.of_match_table = tegra_utc_of_match,
597	},
598};
599
600static int __init tegra_utc_init(void)
601{
602	int ret;
603
604	ret = uart_register_driver(&tegra_utc_driver);
605	if (ret)
606		return ret;
607
608	ret = platform_driver_register(&tegra_utc_platform_driver);
609	if (ret)
610		uart_unregister_driver(&tegra_utc_driver);
611
612	return ret;
613}
614module_init(tegra_utc_init);
615
616static void __exit tegra_utc_exit(void)
617{
618	platform_driver_unregister(&tegra_utc_platform_driver);
619	uart_unregister_driver(&tegra_utc_driver);
620}
621module_exit(tegra_utc_exit);
622
623MODULE_AUTHOR("Kartik Rajput <kkartik@nvidia.com>");
624MODULE_DESCRIPTION("Tegra UART Trace Controller");
625MODULE_LICENSE("GPL");
~/ Read-only file preview.