[PATCH v2 05/13] soc: samsung: Add Exynos PMU driver
Sam Protsenko
semen.protsenko at linaro.org
Thu Jan 11 04:09:01 CET 2024
Add basic Power Management Unit (PMU) driver for Exynos SoCs. For now
it's only capable of changing UART path in PMU, which is needed for
E850-96 board. The driver's structure resembles the exynos-pmu driver
from Linux kernel, and although it's very basic and slim at the moment,
it can be easily extended in future if the need arises.
UCLASS_NOP is used, as there are no benefits in using more elaborate
classes like UCLASS_MISC in this case. The DM_FLAG_PROBE_AFTER_BIND flag
is added in bind function, as the probe function must be always called
for this driver.
Signed-off-by: Sam Protsenko <semen.protsenko at linaro.org>
Reviewed-by: Chanho Park <chanho61.park at samsung.com>
---
Changes in v2:
- Added R-b tag
drivers/soc/samsung/Kconfig | 10 +++
drivers/soc/samsung/Makefile | 1 +
drivers/soc/samsung/exynos-pmu.c | 102 +++++++++++++++++++++++++++++++
3 files changed, 113 insertions(+)
create mode 100644 drivers/soc/samsung/exynos-pmu.c
diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
index ffb87fe79316..737b7ca8cd19 100644
--- a/drivers/soc/samsung/Kconfig
+++ b/drivers/soc/samsung/Kconfig
@@ -5,6 +5,16 @@ menuconfig SOC_SAMSUNG
if SOC_SAMSUNG
+config EXYNOS_PMU
+ bool "Exynos PMU controller driver"
+ depends on ARCH_EXYNOS
+ select REGMAP
+ select SYSCON
+ help
+ Enable support for system controller configuration driver. It allows
+ one to configure system controller registers (e.g. some register in
+ PMU syscon) by providing register's offset, mask and value.
+
config EXYNOS_USI
bool "Exynos USI (Universal Serial Interface) driver"
depends on ARCH_EXYNOS
diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
index 833ac073fbfa..0eb3ed8353b0 100644
--- a/drivers/soc/samsung/Makefile
+++ b/drivers/soc/samsung/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
+obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o
obj-$(CONFIG_EXYNOS_USI) += exynos-usi.o
diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
new file mode 100644
index 000000000000..233ad4a908f5
--- /dev/null
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Linaro Ltd.
+ * Author: Sam Protsenko <semen.protsenko at linaro.org>
+ *
+ * Exynos PMU (Power Management Unit) driver.
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+#define EXYNOS850_UART_IO_SHARE_CTRL 0x0760
+#define SEL_RXD_AP_UART_SHIFT 16
+#define SEL_RXD_AP_UART_MASK GENMASK(17, 16)
+#define SEL_TXD_GPIO_1_SHIFT 20
+#define SEL_TXD_GPIO_1_MASK GENMASK(21, 20)
+#define RXD_GPIO_1 0x3
+#define TXD_AP_UART 0x0
+
+struct exynos_pmu {
+ struct udevice *dev;
+ const struct exynos_pmu_data *pmu_data;
+ struct regmap *regmap;
+};
+
+struct exynos_pmu_data {
+ int (*pmu_init)(struct exynos_pmu *priv);
+};
+
+static int exynos850_pmu_init(struct exynos_pmu *priv)
+{
+ ofnode node;
+ bool uart_debug_1;
+ unsigned int offset, mask, value;
+
+ node = dev_ofnode(priv->dev);
+ uart_debug_1 = ofnode_read_bool(node, "samsung,uart-debug-1");
+ if (!uart_debug_1)
+ return 0;
+
+ /*
+ * If uart1_pins are used for serial, AP UART lines have to be muxed
+ * in PMU block to UART_DEBUG_1 path (GPIO_1). By default (reset value)
+ * UART_DEBUG_0 path (uart0_pins) is connected to AP UART lines.
+ */
+ offset = EXYNOS850_UART_IO_SHARE_CTRL;
+ mask = SEL_RXD_AP_UART_MASK | SEL_TXD_GPIO_1_MASK;
+ value = RXD_GPIO_1 << SEL_RXD_AP_UART_SHIFT |
+ TXD_AP_UART << SEL_TXD_GPIO_1_SHIFT;
+ return regmap_update_bits(priv->regmap, offset, mask, value);
+}
+
+static const struct exynos_pmu_data exynos850_pmu_data = {
+ .pmu_init = exynos850_pmu_init,
+};
+
+static int exynos_pmu_bind(struct udevice *dev)
+{
+ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
+ return 0;
+}
+
+static int exynos_pmu_probe(struct udevice *dev)
+{
+ ofnode node;
+ struct exynos_pmu *priv;
+
+ priv = dev_get_priv(dev);
+ priv->dev = dev;
+
+ node = dev_ofnode(dev);
+ priv->regmap = syscon_node_to_regmap(node);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ priv->pmu_data = (struct exynos_pmu_data *)dev_get_driver_data(dev);
+ if (priv->pmu_data && priv->pmu_data->pmu_init)
+ return priv->pmu_data->pmu_init(priv);
+
+ return 0;
+}
+
+static const struct udevice_id exynos_pmu_ids[] = {
+ {
+ .compatible = "samsung,exynos850-pmu",
+ .data = (ulong)&exynos850_pmu_data
+ },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(exynos_pmu) = {
+ .name = "exynos-pmu",
+ .id = UCLASS_NOP,
+ .of_match = exynos_pmu_ids,
+ .bind = exynos_pmu_bind,
+ .probe = exynos_pmu_probe,
+ .priv_auto = sizeof(struct exynos_pmu),
+};
--
2.39.2
More information about the U-Boot
mailing list