On 04/08/2024 08:38,zhenghaowei@xxxxxxxxxxx wrote:
From: Haowei Zheng<zhenghaowei@xxxxxxxxxxx>How is this used?
Due to certain hardware design challenges, we have opted to
utilize a dedicated UART driver to probe the UART interface.
Presently, we have defined four parameters — 'fractional-division',
'invert-rts', 'invert-dtr', 'invert-cts', and 'invert-dsr' — which
will be employed as needed.
Signed-off-by: Haowei Zheng<zhenghaowei@xxxxxxxxxxx>
---
drivers/tty/serial/8250/8250_loongson.c | 208 ++++++++++++++++++++++++
drivers/tty/serial/8250/8250_port.c | 8 +
drivers/tty/serial/8250/Kconfig | 9 +
drivers/tty/serial/8250/Makefile | 1 +
include/uapi/linux/serial_core.h | 1 +
5 files changed, 227 insertions(+)
create mode 100644 drivers/tty/serial/8250/8250_loongson.c
diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c
new file mode 100644
index 000000000000..eb16677f1dde
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_loongson.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020-2024 Loongson Technology Corporation Limited
+ */
+
+#include <linux/acpi.h>
Currently, it doesn't seem to serve much purpose, and I will remove it in the next version.+#include <linux/clk.h>And this?
+#include <linux/console.h>...
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/reset.h>
+
+#include "8250.h"
+
+struct loongson_uart_data {
+ struct reset_control *rst;
+ int line;
+ int mcr_invert;
+ int msr_invert;
+};
+static int loongson_uart_probe(struct platform_device *pdev)Use wrapper combining both calls.
+{
+ struct uart_8250_port uart = {};
+ struct loongson_uart_data *data;
+ struct uart_port *port;
+ struct resource *res;
+ int ret;
+
+ port = &uart.port;
+ spin_lock_init(&port->lock);
+
+ port->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ port->iotype = UPIO_MEM;
+ port->regshift = 0;
+ port->dev = &pdev->dev;
+ port->type = (unsigned long)device_get_match_data(&pdev->dev);
+ port->serial_in = loongson_serial_in;
+ port->serial_out = loongson_serial_out;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!port->membase)
+ return -ENOMEM;
+
+ port->mapbase = res->start;Why do you need match data if there is no choice?
+ port->mapsize = resource_size(res);
+
+ port->irq = platform_get_irq(pdev, 0);
+ if (port->irq < 0)
+ return -EINVAL;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ port->private_data = data;
+
+ if (device_property_read_bool(&pdev->dev, "fractional-division")) {
+ port->get_divisor = loongson_frac_get_divisor;
+ port->set_divisor = loongson_frac_set_divisor;
+ }
+
+ if (device_property_read_bool(&pdev->dev, "rts-invert"))
+ data->mcr_invert |= UART_MCR_RTS;
+
+ if (device_property_read_bool(&pdev->dev, "dtr-invert"))
+ data->mcr_invert |= UART_MCR_DTR;
+
+ if (device_property_read_bool(&pdev->dev, "cts-invert"))
+ data->msr_invert |= UART_MSR_CTS;
+
+ if (device_property_read_bool(&pdev->dev, "dsr-invert"))
+ data->msr_invert |= UART_MSR_DSR;
+
+ data->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
+ if (IS_ERR(data->rst))
+ return PTR_ERR(data->rst);
+
+ device_property_read_u32(&pdev->dev, "clock-frequency", &port->uartclk);
+
+ ret = reset_control_deassert(data->rst);
+ if (ret)
+ goto err_unprepare;
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0)
+ goto err_unprepare;
+
+ platform_set_drvdata(pdev, data);
+ data->line = ret;
+
+ return 0;
+
+err_unprepare:
+
+ return ret;
+}
+
+static void loongson_uart_remove(struct platform_device *pdev)
+{
+ struct loongson_uart_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ reset_control_assert(data->rst);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int loongson_uart_suspend(struct device *dev)
+{
+ struct loongson_uart_data *data = dev_get_drvdata(dev);
+
+ serial8250_suspend_port(data->line);
+
+ return 0;
+}
+
+static int loongson_uart_resume(struct device *dev)
+{
+ struct loongson_uart_data *data = dev_get_drvdata(dev);
+
+ serial8250_resume_port(data->line);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops loongson_uart_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(loongson_uart_suspend, loongson_uart_resume)
+};
+
+static const struct of_device_id of_platform_serial_table[] = {
+ {.compatible = "loongson,ls7a-uart", .data = (void *)PORT_LOONGSON},
Ok, I got it.+ {},Except that this does not build... drop of_match_ptr(), not needed and
+};
+MODULE_DEVICE_TABLE(of, of_platform_serial_table);
+
+static struct platform_driver loongson_uart_driver = {
+ .probe = loongson_uart_probe,
+ .remove = loongson_uart_remove,
+ .driver = {
+ .name = "ls7a-uart",
+ .pm = &loongson_uart_pm_ops,
+ .of_match_table = of_match_ptr(of_platform_serial_table),
causes warnings.
+ },MIPS? Why?
+};
+
+module_platform_driver(loongson_uart_driver);
+
+MODULE_DESCRIPTION("LOONGSON 8250 Driver");
+MODULE_AUTHOR("Haowei Zheng<zhenghaowei@xxxxxxxxxxx>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 2786918aea98..60b72c785028 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -319,6 +319,14 @@ static const struct serial8250_config uart_config[] = {
.rxtrig_bytes = {1, 8, 16, 30},
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
+ [PORT_LOONGSON] = {
+ .name = "Loongson",
+ .fifo_size = 16,
+ .tx_loadsz = 16,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+ .rxtrig_bytes = {1, 4, 8, 14},
+ .flags = UART_CAP_FIFO,
+ },
};
/* Uart divisor latch read */
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 47ff50763c04..a696afc4f8a8 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -568,6 +568,15 @@ config SERIAL_8250_BCM7271
including DMA support and high accuracy BAUD rates, say
Y to this option. If unsure, say N.
+config SERIAL_8250_LOONGSON
+ tristate "Loongson 8250 serial port support"
+ default SERIAL_8250
+ depends on SERIAL_8250
+ depends on LOONGARCH || MIPS
You also miss COMPILE_TEST.
Best regards,
Krzysztof