summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorYe Li <[email protected]>2025-09-11 18:56:06 +0800
committerFabio Estevam <[email protected]>2025-09-20 17:46:15 -0300
commitd680ac6cfd052ced54f51d7cfe081ad291550e44 (patch)
treeaae800e8852d0642ef41edda7bb8d17b9e573f0b /drivers
parentf8b188350815df2e0436eb113e7c9300ca9cd02e (diff)
clk: imx: Add imx95 blkctrl clock driver
Add iMX95 blkctrl clock driver which implements clocks for HSIOMIX blkctrl and LVDS blkctrl. Since multiple blkctrl device for different blkctrl may be enabled, and each has dedicated clock id from 0. We must enable CLK_AUTO_ID to avoid conflict on clock id. Signed-off-by: Ye Li <[email protected]>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/imx/Kconfig9
-rw-r--r--drivers/clk/imx/Makefile1
-rw-r--r--drivers/clk/imx/clk-imx95-blkctrl.c170
3 files changed, 180 insertions, 0 deletions
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
index 74d5fe73f94..644ab162af4 100644
--- a/drivers/clk/imx/Kconfig
+++ b/drivers/clk/imx/Kconfig
@@ -167,3 +167,12 @@ config CLK_IMXRT1170
select CLK_CCF
help
This enables support clock driver for i.MXRT1170 platforms.
+
+config CLK_IMX95_BLKCTRL
+ bool "Enable i.MX95 blkctrl clock driver"
+ depends on IMX95 || IMX94
+ select CLK
+ select CLK_CCF
+ select CLK_AUTO_ID
+ help
+ Enable support for clocks in i.MX95 MIX blkctrl like HSIO and LVDS.
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index b10221a195c..f2fd6ff8ca0 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_$(PHASE_)CLK_IMX93) += clk-imx93.o clk-fracn-gppll.o \
obj-$(CONFIG_$(PHASE_)CLK_IMXRT1020) += clk-imxrt1020.o
obj-$(CONFIG_$(PHASE_)CLK_IMXRT1050) += clk-imxrt1050.o
obj-$(CONFIG_$(PHASE_)CLK_IMXRT1170) += clk-imxrt1170.o
+obj-$(CONFIG_CLK_IMX95_BLKCTRL) += clk-imx95-blkctrl.o
diff --git a/drivers/clk/imx/clk-imx95-blkctrl.c b/drivers/clk/imx/clk-imx95-blkctrl.c
new file mode 100644
index 00000000000..3bf6f9415e2
--- /dev/null
+++ b/drivers/clk/imx/clk-imx95-blkctrl.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2023-2025 NXP
+ *
+ */
+
+#include <asm/io.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dt-bindings/clock/nxp,imx95-clock.h>
+#include <linux/clk-provider.h>
+
+#include "clk.h"
+
+enum {
+ CLK_GATE,
+ CLK_DIVIDER,
+ CLK_MUX,
+};
+
+struct imx95_blk_ctl_clk_dev_data {
+ const char *name;
+ const char * const *parent_names;
+ u32 num_parents;
+ u32 reg;
+ u32 bit_idx;
+ u32 clk_type;
+ u32 flags;
+ u32 flags2;
+ u32 type;
+};
+
+struct imx95_blk_ctl_dev_data {
+ const struct imx95_blk_ctl_clk_dev_data *clk_dev_data;
+ u32 num_clks;
+ u32 clk_reg_offset;
+};
+
+static const struct imx95_blk_ctl_clk_dev_data hsio_blk_ctl_clk_dev_data[] = {
+ [0] = {
+ .name = "hsio_blk_ctl_clk",
+ .parent_names = (const char *[]){ "hsiopll", },
+ .num_parents = 1,
+ .reg = 0,
+ .bit_idx = 6,
+ .type = CLK_GATE,
+ .flags = CLK_SET_RATE_PARENT,
+ }
+};
+
+static const struct imx95_blk_ctl_dev_data hsio_blk_ctl_dev_data = {
+ .num_clks = 1,
+ .clk_dev_data = hsio_blk_ctl_clk_dev_data,
+ .clk_reg_offset = 0,
+};
+
+static const struct imx95_blk_ctl_clk_dev_data imx95_lvds_clk_dev_data[] = {
+ [IMX95_CLK_DISPMIX_LVDS_PHY_DIV] = {
+ .name = "ldb_phy_div",
+ .parent_names = (const char *[]){ "ldbpll", },
+ .num_parents = 1,
+ .reg = 0,
+ .bit_idx = 0,
+ .type = CLK_DIVIDER,
+ .flags2 = CLK_DIVIDER_POWER_OF_TWO,
+ },
+
+ [IMX95_CLK_DISPMIX_LVDS_CH0_GATE] = {
+ .name = "lvds_ch0_gate",
+ .parent_names = (const char *[]){ "ldb_phy_div", },
+ .num_parents = 1,
+ .reg = 0,
+ .bit_idx = 1,
+ .type = CLK_GATE,
+ .flags = CLK_SET_RATE_PARENT,
+ .flags2 = CLK_GATE_SET_TO_DISABLE,
+ },
+ [IMX95_CLK_DISPMIX_LVDS_CH1_GATE] = {
+ .name = "lvds_ch1_gate",
+ .parent_names = (const char *[]){ "ldb_phy_div", },
+ .num_parents = 1,
+ .reg = 0,
+ .bit_idx = 2,
+ .type = CLK_GATE,
+ .flags = CLK_SET_RATE_PARENT,
+ .flags2 = CLK_GATE_SET_TO_DISABLE,
+ },
+ [IMX95_CLK_DISPMIX_PIX_DI0_GATE] = {
+ .name = "lvds_di0_gate",
+ .parent_names = (const char *[]){ "ldb_pll_div7", },
+ .num_parents = 1,
+ .reg = 0,
+ .bit_idx = 3,
+ .type = CLK_GATE,
+ .flags = CLK_SET_RATE_PARENT,
+ .flags2 = CLK_GATE_SET_TO_DISABLE,
+ },
+ [IMX95_CLK_DISPMIX_PIX_DI1_GATE] = {
+ .name = "lvds_di1_gate",
+ .parent_names = (const char *[]){ "ldb_pll_div7", },
+ .num_parents = 1,
+ .reg = 0,
+ .bit_idx = 4,
+ .type = CLK_GATE,
+ .flags = CLK_SET_RATE_PARENT,
+ .flags2 = CLK_GATE_SET_TO_DISABLE,
+ },
+};
+
+static const struct imx95_blk_ctl_dev_data imx95_lvds_csr_dev_data = {
+ .num_clks = ARRAY_SIZE(imx95_lvds_clk_dev_data),
+ .clk_dev_data = imx95_lvds_clk_dev_data,
+ .clk_reg_offset = 0,
+};
+
+static int imx95_blkctrl_clk_probe(struct udevice *dev)
+{
+ int i;
+ void __iomem *addr;
+ struct imx95_blk_ctl_dev_data *dev_data = (void *)dev_get_driver_data(dev);
+ const struct imx95_blk_ctl_clk_dev_data *clk_dev_data;
+
+ addr = dev_read_addr_ptr(dev);
+ if (addr == (void *)FDT_ADDR_T_NONE) {
+ dev_err(dev, "No blkctrl register base address\n");
+ return -EINVAL;
+ }
+
+ if (!dev_data) {
+ dev_err(dev, "driver data is NULL\n");
+ return -EINVAL;
+ }
+
+ clk_dev_data = dev_data->clk_dev_data;
+ for (i = 0; i < dev_data->num_clks; i++) {
+ if (clk_dev_data[i].clk_type == CLK_GATE) {
+ dev_clk_dm(dev, i, clk_register_gate(dev, clk_dev_data[i].name, clk_dev_data[i].parent_names[0],
+ clk_dev_data[i].flags, addr + dev_data->clk_reg_offset, clk_dev_data[i].bit_idx,
+ clk_dev_data[i].flags2, NULL));
+ } else if (clk_dev_data[i].clk_type == CLK_DIVIDER) {
+ dev_clk_dm(dev, i,
+ clk_register_divider(dev, clk_dev_data[i].name, clk_dev_data[i].parent_names[0],
+ clk_dev_data[i].flags, addr + dev_data->clk_reg_offset, clk_dev_data[i].bit_idx, 1,
+ clk_dev_data[i].flags2));
+ } else if (clk_dev_data[i].clk_type == CLK_MUX) {
+ dev_clk_dm(dev, i,
+ clk_register_mux(dev, clk_dev_data[i].name, clk_dev_data[i].parent_names,
+ clk_dev_data[i].num_parents, clk_dev_data[i].flags, addr + dev_data->clk_reg_offset,
+ clk_dev_data[i].bit_idx, 1, clk_dev_data[i].flags2));
+ }
+ }
+
+ return 0;
+}
+
+static const struct udevice_id imx95_blkctrl_clk_ids[] = {
+ { .compatible = "nxp,imx95-lvds-csr", .data = (ulong)&imx95_lvds_csr_dev_data, },
+ { .compatible = "nxp,imx95-hsio-blk-ctl", .data = (ulong)&hsio_blk_ctl_dev_data, },
+ { },
+};
+
+U_BOOT_DRIVER(imx95_blkctrl_clk) = {
+ .name = "imx95_blkctrl_clk",
+ .id = UCLASS_CLK,
+ .of_match = imx95_blkctrl_clk_ids,
+ .ops = &ccf_clk_ops,
+ .probe = imx95_blkctrl_clk_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};