diff --git a/MAINTAINERS b/MAINTAINERS
index b17e90363262..8667b05b73f5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4133,6 +4133,16 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/aspeed,ast2600-pcie.yaml
F: drivers/pci/controller/pcie-aspeed.c
+ASPEED UART ROUTING DRIVER
+M: Chia-Wei Wang <chiawei_wang@aspeedtech.com>
+M: Oskar Senft <osk@google.com>
+L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
+L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/ABI/testing/sysfs-driver-aspeed-uart-routing
+F: Documentation/devicetree/bindings/soc/aspeed/uart-routing.yaml
+F: drivers/uart-routing/aspeed-uart-routing.c
+
ASUS EC HARDWARE MONITOR DRIVER
M: Eugene Shalygin <eugene.shalygin@gmail.com>
L: linux-hwmon@vger.kernel.org
diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
index 63a656449a1a..e27623a94fd2 100644
--- a/drivers/soc/aspeed/Kconfig
+++ b/drivers/soc/aspeed/Kconfig
@@ -24,16 +24,6 @@ config ASPEED_LPC_SNOOP
allows the BMC to listen on and save the data written by
the host to an arbitrary LPC I/O port.
-config ASPEED_UART_ROUTING
- tristate "ASPEED uart routing control"
- select REGMAP
- select MFD_SYSCON
- default ARCH_ASPEED
- help
- Provides a driver to control the UART routing paths, allowing
- users to perform runtime configuration of the RX muxes among
- the UART controllers and I/O pins.
-
config ASPEED_P2A_CTRL
tristate "ASPEED P2A (VGA MMIO to BMC) bridge control"
select REGMAP
diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
index b5188dcde37a..ace038b6ff22 100644
--- a/drivers/soc/aspeed/Makefile
+++ b/drivers/soc/aspeed/Makefile
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
-obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o
CONTEXT_ANALYSIS_aspeed-lpc-snoop.o := y
diff --git a/drivers/soc/aspeed/aspeed-uart-routing.c b/drivers/soc/aspeed/aspeed-uart-routing.c
deleted file mode 100644
index b4b521b5ddf1..000000000000
--- a/drivers/soc/aspeed/aspeed-uart-routing.c
+++ /dev/null
@@ -1,601 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2018 Google LLC
- * Copyright (c) 2021 Aspeed Technology Inc.
- */
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
-#include <linux/platform_device.h>
-
-/* register offsets */
-#define HICR9 0x98
-#define HICRA 0x9c
-
-/* attributes options */
-#define UART_ROUTING_IO1 "io1"
-#define UART_ROUTING_IO2 "io2"
-#define UART_ROUTING_IO3 "io3"
-#define UART_ROUTING_IO4 "io4"
-#define UART_ROUTING_IO5 "io5"
-#define UART_ROUTING_IO6 "io6"
-#define UART_ROUTING_IO10 "io10"
-#define UART_ROUTING_UART1 "uart1"
-#define UART_ROUTING_UART2 "uart2"
-#define UART_ROUTING_UART3 "uart3"
-#define UART_ROUTING_UART4 "uart4"
-#define UART_ROUTING_UART5 "uart5"
-#define UART_ROUTING_UART6 "uart6"
-#define UART_ROUTING_UART10 "uart10"
-#define UART_ROUTING_RES "reserved"
-
-struct aspeed_uart_routing {
- struct regmap *map;
- struct attribute_group const *attr_grp;
-};
-
-struct aspeed_uart_routing_selector {
- struct device_attribute dev_attr;
- uint8_t reg;
- uint8_t mask;
- uint8_t shift;
- const char *const options[];
-};
-
-#define to_routing_selector(_dev_attr) \
- container_of(_dev_attr, struct aspeed_uart_routing_selector, dev_attr)
-
-static ssize_t aspeed_uart_routing_show(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-static ssize_t aspeed_uart_routing_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
-
-#define ROUTING_ATTR(_name) { \
- .attr = {.name = _name, \
- .mode = VERIFY_OCTAL_PERMISSIONS(0644) }, \
- .show = aspeed_uart_routing_show, \
- .store = aspeed_uart_routing_store, \
-}
-
-/* routing selector for AST25xx */
-static struct aspeed_uart_routing_selector ast2500_io6_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO6),
- .reg = HICR9,
- .shift = 8,
- .mask = 0xf,
- .options = {
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_UART5,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_IO5,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_uart5_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART5),
- .reg = HICRA,
- .shift = 28,
- .mask = 0xf,
- .options = {
- UART_ROUTING_IO5,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_uart4_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART4),
- .reg = HICRA,
- .shift = 25,
- .mask = 0x7,
- .options = {
- UART_ROUTING_IO4,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_uart3_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART3),
- .reg = HICRA,
- .shift = 22,
- .mask = 0x7,
- .options = {
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_UART4,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_uart2_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART2),
- .reg = HICRA,
- .shift = 19,
- .mask = 0x7,
- .options = {
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_IO1,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_UART1,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_uart1_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART1),
- .reg = HICRA,
- .shift = 16,
- .mask = 0x7,
- .options = {
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_io5_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO5),
- .reg = HICRA,
- .shift = 12,
- .mask = 0x7,
- .options = {
- UART_ROUTING_UART5,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_IO1,
- UART_ROUTING_IO3,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_io4_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO4),
- .reg = HICRA,
- .shift = 9,
- .mask = 0x7,
- .options = {
- UART_ROUTING_UART4,
- UART_ROUTING_UART5,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_io3_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO3),
- .reg = HICRA,
- .shift = 6,
- .mask = 0x7,
- .options = {
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_UART5,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_io2_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO2),
- .reg = HICRA,
- .shift = 3,
- .mask = 0x7,
- .options = {
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_UART5,
- UART_ROUTING_UART1,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2500_io1_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO1),
- .reg = HICRA,
- .shift = 0,
- .mask = 0x7,
- .options = {
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_UART5,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_IO6,
- NULL,
- },
-};
-
-static struct attribute *ast2500_uart_routing_attrs[] = {
- &ast2500_io6_sel.dev_attr.attr,
- &ast2500_uart5_sel.dev_attr.attr,
- &ast2500_uart4_sel.dev_attr.attr,
- &ast2500_uart3_sel.dev_attr.attr,
- &ast2500_uart2_sel.dev_attr.attr,
- &ast2500_uart1_sel.dev_attr.attr,
- &ast2500_io5_sel.dev_attr.attr,
- &ast2500_io4_sel.dev_attr.attr,
- &ast2500_io3_sel.dev_attr.attr,
- &ast2500_io2_sel.dev_attr.attr,
- &ast2500_io1_sel.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ast2500_uart_routing_attr_group = {
- .attrs = ast2500_uart_routing_attrs,
-};
-
-/* routing selector for AST26xx */
-static struct aspeed_uart_routing_selector ast2600_uart10_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART10),
- .reg = HICR9,
- .shift = 12,
- .mask = 0xf,
- .options = {
- UART_ROUTING_IO10,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_RES,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2600_io10_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO10),
- .reg = HICR9,
- .shift = 8,
- .mask = 0xf,
- .options = {
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_RES,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_RES,
- UART_ROUTING_UART10,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2600_uart4_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART4),
- .reg = HICRA,
- .shift = 25,
- .mask = 0x7,
- .options = {
- UART_ROUTING_IO4,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_IO10,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2600_uart3_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART3),
- .reg = HICRA,
- .shift = 22,
- .mask = 0x7,
- .options = {
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_UART4,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_IO10,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2600_uart2_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART2),
- .reg = HICRA,
- .shift = 19,
- .mask = 0x7,
- .options = {
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_IO1,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_UART1,
- UART_ROUTING_IO10,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2600_uart1_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_UART1),
- .reg = HICRA,
- .shift = 16,
- .mask = 0x7,
- .options = {
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_IO10,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2600_io4_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO4),
- .reg = HICRA,
- .shift = 9,
- .mask = 0x7,
- .options = {
- UART_ROUTING_UART4,
- UART_ROUTING_UART10,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO10,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2600_io3_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO3),
- .reg = HICRA,
- .shift = 6,
- .mask = 0x7,
- .options = {
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_UART10,
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_IO1,
- UART_ROUTING_IO2,
- UART_ROUTING_IO10,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2600_io2_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO2),
- .reg = HICRA,
- .shift = 3,
- .mask = 0x7,
- .options = {
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_UART10,
- UART_ROUTING_UART1,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_IO10,
- NULL,
- },
-};
-
-static struct aspeed_uart_routing_selector ast2600_io1_sel = {
- .dev_attr = ROUTING_ATTR(UART_ROUTING_IO1),
- .reg = HICRA,
- .shift = 0,
- .mask = 0x7,
- .options = {
- UART_ROUTING_UART1,
- UART_ROUTING_UART2,
- UART_ROUTING_UART3,
- UART_ROUTING_UART4,
- UART_ROUTING_UART10,
- UART_ROUTING_IO3,
- UART_ROUTING_IO4,
- UART_ROUTING_IO10,
- NULL,
- },
-};
-
-static struct attribute *ast2600_uart_routing_attrs[] = {
- &ast2600_uart10_sel.dev_attr.attr,
- &ast2600_io10_sel.dev_attr.attr,
- &ast2600_uart4_sel.dev_attr.attr,
- &ast2600_uart3_sel.dev_attr.attr,
- &ast2600_uart2_sel.dev_attr.attr,
- &ast2600_uart1_sel.dev_attr.attr,
- &ast2600_io4_sel.dev_attr.attr,
- &ast2600_io3_sel.dev_attr.attr,
- &ast2600_io2_sel.dev_attr.attr,
- &ast2600_io1_sel.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ast2600_uart_routing_attr_group = {
- .attrs = ast2600_uart_routing_attrs,
-};
-
-static ssize_t aspeed_uart_routing_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev);
- struct aspeed_uart_routing_selector *sel = to_routing_selector(attr);
- int val, pos, len;
-
- regmap_read(uart_routing->map, sel->reg, &val);
- val = (val >> sel->shift) & sel->mask;
-
- len = 0;
- for (pos = 0; sel->options[pos] != NULL; ++pos) {
- if (pos == val)
- len += sysfs_emit_at(buf, len, "[%s] ", sel->options[pos]);
- else
- len += sysfs_emit_at(buf, len, "%s ", sel->options[pos]);
- }
-
- if (val >= pos)
- len += sysfs_emit_at(buf, len, "[unknown(%d)]", val);
-
- len += sysfs_emit_at(buf, len, "\n");
-
- return len;
-}
-
-static ssize_t aspeed_uart_routing_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev);
- struct aspeed_uart_routing_selector *sel = to_routing_selector(attr);
- int val;
-
- val = __sysfs_match_string(sel->options, -1, buf);
- if (val < 0) {
- dev_err(dev, "invalid value \"%s\"\n", buf);
- return -EINVAL;
- }
-
- regmap_update_bits(uart_routing->map, sel->reg,
- (sel->mask << sel->shift),
- (val & sel->mask) << sel->shift);
-
- return count;
-}
-
-static int aspeed_uart_routing_probe(struct platform_device *pdev)
-{
- int rc;
- struct device *dev = &pdev->dev;
- struct aspeed_uart_routing *uart_routing;
-
- uart_routing = devm_kzalloc(&pdev->dev, sizeof(*uart_routing), GFP_KERNEL);
- if (!uart_routing)
- return -ENOMEM;
-
- uart_routing->map = syscon_node_to_regmap(dev->parent->of_node);
- if (IS_ERR(uart_routing->map)) {
- dev_err(dev, "cannot get regmap\n");
- return PTR_ERR(uart_routing->map);
- }
-
- uart_routing->attr_grp = of_device_get_match_data(dev);
-
- rc = sysfs_create_group(&dev->kobj, uart_routing->attr_grp);
- if (rc < 0)
- return rc;
-
- dev_set_drvdata(dev, uart_routing);
-
- dev_info(dev, "module loaded\n");
-
- return 0;
-}
-
-static void aspeed_uart_routing_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct aspeed_uart_routing *uart_routing = platform_get_drvdata(pdev);
-
- sysfs_remove_group(&dev->kobj, uart_routing->attr_grp);
-}
-
-static const struct of_device_id aspeed_uart_routing_table[] = {
- { .compatible = "aspeed,ast2400-uart-routing",
- .data = &ast2500_uart_routing_attr_group },
- { .compatible = "aspeed,ast2500-uart-routing",
- .data = &ast2500_uart_routing_attr_group },
- { .compatible = "aspeed,ast2600-uart-routing",
- .data = &ast2600_uart_routing_attr_group },
- { },
-};
-MODULE_DEVICE_TABLE(of, aspeed_uart_routing_table);
-
-static struct platform_driver aspeed_uart_routing_driver = {
- .driver = {
- .name = "aspeed-uart-routing",
- .of_match_table = aspeed_uart_routing_table,
- },
- .probe = aspeed_uart_routing_probe,
- .remove = aspeed_uart_routing_remove,
-};
-
-module_platform_driver(aspeed_uart_routing_driver);
-
-MODULE_AUTHOR("Oskar Senft <osk@google.com>");
-MODULE_AUTHOR("Chia-Wei Wang <chiawei_wang@aspeedtech.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Driver to configure Aspeed UART routing");diff --git a/drivers/uart-routing/Kconfig b/drivers/uart-routing/Kconfig
index a0c45a7bba47..983e7fbd1bc4 100644
--- a/drivers/uart-routing/Kconfig
+++ b/drivers/uart-routing/Kconfig
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "UART routing drivers"
+ depends on ARCH_ASPEED || COMPILE_TEST
config UART_ROUTING
tristate
@@ -13,4 +14,19 @@ config UART_ROUTING
This symbol is selected by the SoC specific drivers below and is
not meant to be enabled on its own.
+config ASPEED_UART_ROUTING
+ tristate "ASPEED uart routing control"
+ depends on ARCH_ASPEED || COMPILE_TEST
+ select UART_ROUTING
+ select REGMAP
+ select MFD_SYSCON
+ default ARCH_ASPEED
+ help
+ Provides a driver to control the UART routing paths, allowing
+ users to perform runtime configuration of the RX muxes among
+ the UART controllers and I/O pins.
+
+ If M is selected, the module will be called
+ aspeed-uart-routing.
+
endmenu
diff --git a/drivers/uart-routing/Makefile b/drivers/uart-routing/Makefile
index 975165f070a5..226980c639a4 100644
--- a/drivers/uart-routing/Makefile
+++ b/drivers/uart-routing/Makefile
@@ -1,2 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_UART_ROUTING) += uart-routing.o
+
+obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
diff --git a/drivers/uart-routing/aspeed-uart-routing.c b/drivers/uart-routing/aspeed-uart-routing.c
new file mode 100644
index 000000000000..7286ecd87bea
--- /dev/null
+++ b/drivers/uart-routing/aspeed-uart-routing.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Google LLC
+ * Copyright (c) 2021 Aspeed Technology Inc.
+ */
+#include <linux/device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#include "uart-routing.h"
+
+/* register offsets */
+#define HICR9 0x98
+#define HICRA 0x9c
+
+/* attributes options */
+#define UART_ROUTING_IO1 "io1"
+#define UART_ROUTING_IO2 "io2"
+#define UART_ROUTING_IO3 "io3"
+#define UART_ROUTING_IO4 "io4"
+#define UART_ROUTING_IO5 "io5"
+#define UART_ROUTING_IO6 "io6"
+#define UART_ROUTING_IO10 "io10"
+#define UART_ROUTING_UART1 "uart1"
+#define UART_ROUTING_UART2 "uart2"
+#define UART_ROUTING_UART3 "uart3"
+#define UART_ROUTING_UART4 "uart4"
+#define UART_ROUTING_UART5 "uart5"
+#define UART_ROUTING_UART6 "uart6"
+#define UART_ROUTING_UART10 "uart10"
+#define UART_ROUTING_RES "reserved"
+
+/* routing selector for AST25xx */
+static const char *const ast2500_io6_options[] = {
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART5,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO5,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_io6_sel, io6, HICR9, 8, 0xf, ast2500_io6_options);
+
+static const char *const ast2500_uart5_options[] = {
+ UART_ROUTING_IO5,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_uart5_sel, uart5, HICRA, 28, 0xf, ast2500_uart5_options);
+
+static const char *const ast2500_uart4_options[] = {
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_uart4_sel, uart4, HICRA, 25, 0x7, ast2500_uart4_options);
+
+static const char *const ast2500_uart3_options[] = {
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_uart3_sel, uart3, HICRA, 22, 0x7, ast2500_uart3_options);
+
+static const char *const ast2500_uart2_options[] = {
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO1,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART1,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_uart2_sel, uart2, HICRA, 19, 0x7, ast2500_uart2_options);
+
+static const char *const ast2500_uart1_options[] = {
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_uart1_sel, uart1, HICRA, 16, 0x7, ast2500_uart1_options);
+
+static const char *const ast2500_io5_options[] = {
+ UART_ROUTING_UART5,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_io5_sel, io5, HICRA, 12, 0x7, ast2500_io5_options);
+
+static const char *const ast2500_io4_options[] = {
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART5,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_io4_sel, io4, HICRA, 9, 0x7, ast2500_io4_options);
+
+static const char *const ast2500_io3_options[] = {
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART5,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_io3_sel, io3, HICRA, 6, 0x7, ast2500_io3_options);
+
+static const char *const ast2500_io2_options[] = {
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART5,
+ UART_ROUTING_UART1,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_io2_sel, io2, HICRA, 3, 0x7, ast2500_io2_options);
+
+static const char *const ast2500_io1_options[] = {
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART5,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO6,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2500_io1_sel, io1, HICRA, 0, 0x7, ast2500_io1_options);
+
+static struct attribute *ast2500_uart_routing_attrs[] = {
+ UART_ROUTING_SELECTOR_ATTR(ast2500_io6_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_uart5_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_uart4_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_uart3_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_uart2_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_uart1_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_io5_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_io4_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_io3_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_io2_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2500_io1_sel),
+ NULL,
+};
+
+static const struct attribute_group ast2500_uart_routing_attr_group = {
+ .attrs = ast2500_uart_routing_attrs,
+};
+
+/* routing selector for AST26xx */
+static const char *const ast2600_uart10_options[] = {
+ UART_ROUTING_IO10,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_RES,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_uart10_sel, uart10, HICR9, 12, 0xf, ast2600_uart10_options);
+
+static const char *const ast2600_io10_options[] = {
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_RES,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_RES,
+ UART_ROUTING_UART10,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_io10_sel, io10, HICR9, 8, 0xf, ast2600_io10_options);
+
+static const char *const ast2600_uart4_options[] = {
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_IO10,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_uart4_sel, uart4, HICRA, 25, 0x7, ast2600_uart4_options);
+
+static const char *const ast2600_uart3_options[] = {
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_IO10,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_uart3_sel, uart3, HICRA, 22, 0x7, ast2600_uart3_options);
+
+static const char *const ast2600_uart2_options[] = {
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO1,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART1,
+ UART_ROUTING_IO10,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_uart2_sel, uart2, HICRA, 19, 0x7, ast2600_uart2_options);
+
+static const char *const ast2600_uart1_options[] = {
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_IO10,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_uart1_sel, uart1, HICRA, 16, 0x7, ast2600_uart1_options);
+
+static const char *const ast2600_io4_options[] = {
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART10,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO10,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_io4_sel, io4, HICRA, 9, 0x7, ast2600_io4_options);
+
+static const char *const ast2600_io3_options[] = {
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART10,
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_IO1,
+ UART_ROUTING_IO2,
+ UART_ROUTING_IO10,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_io3_sel, io3, HICRA, 6, 0x7, ast2600_io3_options);
+
+static const char *const ast2600_io2_options[] = {
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART10,
+ UART_ROUTING_UART1,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO10,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_io2_sel, io2, HICRA, 3, 0x7, ast2600_io2_options);
+
+static const char *const ast2600_io1_options[] = {
+ UART_ROUTING_UART1,
+ UART_ROUTING_UART2,
+ UART_ROUTING_UART3,
+ UART_ROUTING_UART4,
+ UART_ROUTING_UART10,
+ UART_ROUTING_IO3,
+ UART_ROUTING_IO4,
+ UART_ROUTING_IO10,
+ NULL,
+};
+
+UART_ROUTING_SELECTOR(ast2600_io1_sel, io1, HICRA, 0, 0x7, ast2600_io1_options);
+
+static struct attribute *ast2600_uart_routing_attrs[] = {
+ UART_ROUTING_SELECTOR_ATTR(ast2600_uart10_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2600_io10_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2600_uart4_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2600_uart3_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2600_uart2_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2600_uart1_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2600_io4_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2600_io3_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2600_io2_sel),
+ UART_ROUTING_SELECTOR_ATTR(ast2600_io1_sel),
+ NULL,
+};
+
+static const struct attribute_group ast2600_uart_routing_attr_group = {
+ .attrs = ast2600_uart_routing_attrs,
+};
+
+static int aspeed_uart_routing_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct regmap *map;
+
+ map = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map), "cannot get regmap\n");
+
+ return devm_uart_routing_register(dev, map,
+ of_device_get_match_data(dev));
+}
+
+static const struct of_device_id aspeed_uart_routing_table[] = {
+ { .compatible = "aspeed,ast2400-uart-routing",
+ .data = &ast2500_uart_routing_attr_group },
+ { .compatible = "aspeed,ast2500-uart-routing",
+ .data = &ast2500_uart_routing_attr_group },
+ { .compatible = "aspeed,ast2600-uart-routing",
+ .data = &ast2600_uart_routing_attr_group },
+ { },
+};
+MODULE_DEVICE_TABLE(of, aspeed_uart_routing_table);
+
+static struct platform_driver aspeed_uart_routing_driver = {
+ .driver = {
+ .name = "aspeed-uart-routing",
+ .of_match_table = aspeed_uart_routing_table,
+ },
+ .probe = aspeed_uart_routing_probe,
+};
+
+module_platform_driver(aspeed_uart_routing_driver);
+
+MODULE_AUTHOR("Oskar Senft <osk@google.com>");
+MODULE_AUTHOR("Chia-Wei Wang <chiawei_wang@aspeedtech.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Driver to configure Aspeed UART routing");--
2.25.1