brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · 60a80d0 Raw
193 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 *  Serial Port driver for Tegra devices4 *5 *  Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.6 */7 8#include <linux/acpi.h>9#include <linux/clk.h>10#include <linux/console.h>11#include <linux/delay.h>12#include <linux/io.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/reset.h>16#include <linux/slab.h>17 18#include "8250.h"19 20struct tegra_uart {21	struct clk *clk;22	struct reset_control *rst;23	int line;24};25 26static void tegra_uart_handle_break(struct uart_port *p)27{28	unsigned int status, tmout = 10000;29 30	while (1) {31		status = p->serial_in(p, UART_LSR);32		if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)))33			break;34 35		p->serial_in(p, UART_RX);36 37		if (--tmout == 0)38			break;39		udelay(1);40	}41}42 43static int tegra_uart_probe(struct platform_device *pdev)44{45	struct uart_8250_port port8250;46	struct tegra_uart *uart;47	struct uart_port *port;48	struct resource *res;49	int ret;50 51	uart = devm_kzalloc(&pdev->dev, sizeof(*uart), GFP_KERNEL);52	if (!uart)53		return -ENOMEM;54 55	memset(&port8250, 0, sizeof(port8250));56 57	port = &port8250.port;58	spin_lock_init(&port->lock);59 60	port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;61	port->type = PORT_TEGRA;62	port->dev = &pdev->dev;63	port->handle_break = tegra_uart_handle_break;64 65	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);66	if (!res)67		return -ENODEV;68 69	port->membase = devm_ioremap(&pdev->dev, res->start,70				     resource_size(res));71	if (!port->membase)72		return -ENOMEM;73 74	port->mapbase = res->start;75	port->mapsize = resource_size(res);76 77	ret = uart_read_port_properties(port);78	if (ret)79		return ret;80 81	port->iotype = UPIO_MEM32;82	port->regshift = 2;83 84	uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);85	if (IS_ERR(uart->rst))86		return PTR_ERR(uart->rst);87 88	if (!port->uartclk) {89		uart->clk = devm_clk_get(&pdev->dev, NULL);90		if (IS_ERR(uart->clk)) {91			dev_err(&pdev->dev, "failed to get clock!\n");92			return -ENODEV;93		}94 95		ret = clk_prepare_enable(uart->clk);96		if (ret < 0)97			return ret;98 99		port->uartclk = clk_get_rate(uart->clk);100	}101 102	ret = reset_control_deassert(uart->rst);103	if (ret)104		goto err_clkdisable;105 106	ret = serial8250_register_8250_port(&port8250);107	if (ret < 0)108		goto err_ctrl_assert;109 110	platform_set_drvdata(pdev, uart);111	uart->line = ret;112 113	return 0;114 115err_ctrl_assert:116	reset_control_assert(uart->rst);117err_clkdisable:118	clk_disable_unprepare(uart->clk);119 120	return ret;121}122 123static void tegra_uart_remove(struct platform_device *pdev)124{125	struct tegra_uart *uart = platform_get_drvdata(pdev);126 127	serial8250_unregister_port(uart->line);128	reset_control_assert(uart->rst);129	clk_disable_unprepare(uart->clk);130}131 132#ifdef CONFIG_PM_SLEEP133static int tegra_uart_suspend(struct device *dev)134{135	struct tegra_uart *uart = dev_get_drvdata(dev);136	struct uart_8250_port *port8250 = serial8250_get_port(uart->line);137	struct uart_port *port = &port8250->port;138 139	serial8250_suspend_port(uart->line);140 141	if (!uart_console(port) || console_suspend_enabled)142		clk_disable_unprepare(uart->clk);143 144	return 0;145}146 147static int tegra_uart_resume(struct device *dev)148{149	struct tegra_uart *uart = dev_get_drvdata(dev);150	struct uart_8250_port *port8250 = serial8250_get_port(uart->line);151	struct uart_port *port = &port8250->port;152 153	if (!uart_console(port) || console_suspend_enabled)154		clk_prepare_enable(uart->clk);155 156	serial8250_resume_port(uart->line);157 158	return 0;159}160#endif161 162static SIMPLE_DEV_PM_OPS(tegra_uart_pm_ops, tegra_uart_suspend,163			 tegra_uart_resume);164 165static const struct of_device_id tegra_uart_of_match[] = {166	{ .compatible = "nvidia,tegra20-uart", },167	{ },168};169MODULE_DEVICE_TABLE(of, tegra_uart_of_match);170 171static const struct acpi_device_id tegra_uart_acpi_match[] __maybe_unused = {172	{ "NVDA0100", 0 },173	{ },174};175MODULE_DEVICE_TABLE(acpi, tegra_uart_acpi_match);176 177static struct platform_driver tegra_uart_driver = {178	.driver = {179		.name = "tegra-uart",180		.pm = &tegra_uart_pm_ops,181		.of_match_table = tegra_uart_of_match,182		.acpi_match_table = ACPI_PTR(tegra_uart_acpi_match),183	},184	.probe = tegra_uart_probe,185	.remove_new = tegra_uart_remove,186};187 188module_platform_driver(tegra_uart_driver);189 190MODULE_AUTHOR("Jeff Brasen <jbrasen@nvidia.com>");191MODULE_DESCRIPTION("NVIDIA Tegra 8250 Driver");192MODULE_LICENSE("GPL v2");193