Devicetree
 help / color / mirror / Atom feed
From: Navid Ghahremani <ghahramani.navid@gmail.com>
To: linux-arm-kernel@lists.infradead.org
Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	arnd@arndb.de, linux@armlinux.org.uk, stefandoesinger@gmail.com,
	robh@kernel.org, krzk@kernel.org,
	Navid Ghahremani <ghahramani.navid@gmail.com>
Subject: [PATCH 07/24] clk: zte: Add ZX279128S CRM clock and reset driver
Date: Sat, 10 Oct 2026 13:59:45 +0100	[thread overview]
Message-ID: <20261010130024.177503-8-ghahramani.navid@gmail.com> (raw)
In-Reply-To: <20261010130024.177503-1-ghahramani.navid@gmail.com>

Read the bootloader PLL and bus setup and provide peripheral gates,
muxes, dividers and USB resets. Preserve the parked CPU memory clocks
and use managed registration for platform clocks.

Assisted-by: LLM
Signed-off-by: Navid Ghahremani <ghahramani.navid@gmail.com>
---
 drivers/clk/Kconfig             |   1 +
 drivers/clk/Makefile            |   1 +
 drivers/clk/zte/Kconfig         |  14 +
 drivers/clk/zte/Makefile        |   2 +
 drivers/clk/zte/clk-zx279128s.c | 460 ++++++++++++++++++++++++++++++++
 5 files changed, 478 insertions(+)
 create mode 100644 drivers/clk/zte/Kconfig
 create mode 100644 drivers/clk/zte/Makefile
 create mode 100644 drivers/clk/zte/clk-zx279128s.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index f9592fd9ec..5200de26c0 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -547,6 +547,7 @@ source "drivers/clk/uniphier/Kconfig"
 source "drivers/clk/visconti/Kconfig"
 source "drivers/clk/x86/Kconfig"
 source "drivers/clk/xilinx/Kconfig"
+source "drivers/clk/zte/Kconfig"
 source "drivers/clk/zynqmp/Kconfig"
 
 # Kunit test cases
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index b18af485d7..07393019c3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -181,5 +181,6 @@ ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_X86)			+= x86/
 endif
 obj-y					+= xilinx/
+obj-y					+= zte/
 obj-$(CONFIG_ARCH_ZYNQ)			+= zynq/
 obj-$(CONFIG_COMMON_CLK_ZYNQMP)         += zynqmp/
diff --git a/drivers/clk/zte/Kconfig b/drivers/clk/zte/Kconfig
new file mode 100644
index 0000000000..92fd27ea42
--- /dev/null
+++ b/drivers/clk/zte/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config CLK_ZX279128S
+	bool "ZTE zx279128s clock driver"
+	depends on SOC_ZX279128S || COMPILE_TEST
+	depends on OF
+	default SOC_ZX279128S
+	select RESET_CONTROLLER
+	select RESET_SIMPLE
+	help
+	  This driver supports the clocks of the ZTE zx279128s SoC: the
+	  top clock and reset module (CRM) with the PLLs, the CPU, bus and
+	  peripheral group clocks, and the CRPMs of the two groups of low
+	  speed peripherals (UARTs, SPI flash controller, GPIO, MDIO).
+	  Say Y if you build a kernel for a board with this SoC.
diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile
new file mode 100644
index 0000000000..a55ffbfaf1
--- /dev/null
+++ b/drivers/clk/zte/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_CLK_ZX279128S)	+= clk-zx279128s.o
diff --git a/drivers/clk/zte/clk-zx279128s.c b/drivers/clk/zte/clk-zx279128s.c
new file mode 100644
index 0000000000..1282d17fcf
--- /dev/null
+++ b/drivers/clk/zte/clk-zx279128s.c
@@ -0,0 +1,460 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ZTE zx279128s clocks: the top CRM and the CRPMs of the two groups of low
+ * speed peripherals
+ *
+ * Copyright (C) 2026 Navid Ghahremani <ghahramani.navid@gmail.com>
+ *
+ * The boot loader sets up the PLLs and the CPU and bus clocks, and the driver
+ * leaves them as they are: it reads them once and registers their rates. The
+ * gates, and the muxes and dividers of the peripherals, are under its
+ * control.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/reset-controller.h>
+#include <linux/reset/reset-simple.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/clock/zte,zx279128s-crm.h>
+
+/* Top CRM */
+#define TOP_CLK_SEL		0x0c
+#define  TOP_MATRIX_SEL_SHIFT	15
+#define  TOP_CPU_SEL_SHIFT	13
+#define TOP_CLK_EN		0x14
+#define TOP_PLL_A9		0x18
+#define TOP_PLL_AUDIO		0x28
+#define TOP_USB_EN		0x48
+#define TOP_RST_LAST		0x4c	/* the last register with resets */
+
+#define TOP_NUM_CLKS		(ZX279128S_TOP_USB_REF + 1)
+#define TOP_NUM_RESETS		((TOP_RST_LAST / 4 + 1) * 32)
+
+/*
+ * A PLL has two registers. The output is
+ * osc * (fbdiv + frac / 2^24) / pd1 / pd2.
+ */
+#define PLL_FBDIV		GENMASK(17, 6)
+#define PLL_PD1			GENMASK(5, 3)
+#define PLL_PD2			GENMASK(2, 0)
+#define PLL_FRAC		GENMASK(23, 0)	/* second register */
+#define PLL_FRAC_BITS		24
+
+/* The LSP CRPMs: one register per peripheral */
+#define LSP_PCLK_EN		0	/* bit of the register clock gate */
+#define LSP_WCLK_EN		1	/* bit of the work clock gate */
+#define LSP_WCLK_SEL_SHIFT	9
+#define LSP_WCLK_DIV_SHIFT	11
+
+static DEFINE_SPINLOCK(zx_top_lock);
+
+/*
+ * Register a PLL as a fixed factor of the crystal, from the setting the boot
+ * loader left in it.
+ */
+static struct clk_hw * __init zx_top_pll(struct device_node *np,
+					 const char *name, void __iomem *reg)
+{
+	u32 cfg0 = readl(reg), cfg1 = readl(reg + 4);
+	unsigned int pd = FIELD_GET(PLL_PD1, cfg0) * FIELD_GET(PLL_PD2, cfg0);
+	u64 mult = ((u64)FIELD_GET(PLL_FBDIV, cfg0) << PLL_FRAC_BITS) |
+		   FIELD_GET(PLL_FRAC, cfg1);
+	u64 div = (u64)pd << PLL_FRAC_BITS;
+	unsigned int shift;
+
+	if (!mult || !pd)
+		return ERR_PTR(-EINVAL);
+
+	/* Fit both into 32 bits: drop trailing zeroes, then fraction bits */
+	shift = min(__ffs64(mult), PLL_FRAC_BITS);
+	mult >>= shift;
+	div >>= shift;
+	while (mult > UINT_MAX) {
+		mult >>= 1;
+		div >>= 1;
+	}
+
+	return clk_hw_register_fixed_factor_fwname(NULL, np, name, "osc", 0,
+						   mult, div);
+}
+
+static struct clk_hw * __init zx_top_gate(void __iomem *reg,
+					  const char *name,
+					  const struct clk_hw *parent, u8 bit,
+					  unsigned long flags)
+{
+	return clk_hw_register_gate_parent_hw(NULL, name, parent, flags, reg,
+					      bit, 0, &zx_top_lock);
+}
+
+/*
+ * Reset bits are cleared to hold the reset. The registers also hold other
+ * controls, but no other driver writes the reset registers.
+ */
+static int __init zx_top_reset_init(struct device_node *np,
+				    void __iomem *base)
+{
+	struct reset_simple_data *rst;
+
+	rst = kzalloc_obj(*rst);
+	if (!rst)
+		return -ENOMEM;
+
+	spin_lock_init(&rst->lock);
+	rst->membase = base;
+	rst->active_low = true;
+	rst->status_active_low = true;
+	rst->rcdev.ops = &reset_simple_ops;
+	rst->rcdev.owner = THIS_MODULE;
+	rst->rcdev.nr_resets = TOP_NUM_RESETS;
+	rst->rcdev.of_node = np;
+
+	return reset_controller_register(&rst->rcdev);
+}
+
+static void __init zx279128s_topcrm_init(struct device_node *np)
+{
+	const struct clk_hw *cpu_parents[4], *matrix_parents[4];
+	struct clk_hw *osc, *lsp, *lsp_500m, *lsp_250m, *lsp_125m, *lsp_100m;
+	struct clk_hw *audio, *audio_32k, *matrix, *hclk, *pclk, *m200, *m20;
+	struct clk_hw_onecell_data *data;
+	struct clk_hw **hws;
+	void __iomem *base, *en;
+	int i;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%pOF: no registers\n", np);
+		return;
+	}
+
+	data = kzalloc(struct_size(data, hws, TOP_NUM_CLKS), GFP_KERNEL);
+	if (!data)
+		return;
+	data->num = TOP_NUM_CLKS;
+	hws = data->hws;
+
+	hws[ZX279128S_TOP_PLL_A9] = zx_top_pll(np, "pll_a9", base + TOP_PLL_A9);
+	if (IS_ERR(hws[ZX279128S_TOP_PLL_A9]))
+		goto err;
+	osc = clk_hw_get_parent(hws[ZX279128S_TOP_PLL_A9]);
+	if (!osc)
+		goto err;
+
+	/*
+	 * The formula above gives 200 MHz for the LSP PLL, but the vendor
+	 * kernel has it at 1 GHz, with fixed taps for the bus (250 MHz) and
+	 * the peripherals (100 MHz). Until that is measured, it is registered
+	 * with the vendor's rate.
+	 */
+	lsp = clk_hw_register_fixed_factor_parent_hw(NULL, "pll_lsp", osc, 0,
+						     40, 1);
+	if (IS_ERR(lsp))
+		goto err;
+	hws[ZX279128S_TOP_PLL_LSP] = lsp;
+	lsp_500m = clk_hw_register_fixed_factor_parent_hw(NULL, "lsp_500m", lsp,
+							  0, 1, 2);
+	lsp_250m = clk_hw_register_fixed_factor_parent_hw(NULL, "lsp_250m", lsp,
+							  0, 1, 4);
+	lsp_125m = clk_hw_register_fixed_factor_parent_hw(NULL, "lsp_125m", lsp,
+							  0, 1, 8);
+	lsp_100m = clk_hw_register_fixed_factor_parent_hw(NULL, "lsp_100m", lsp,
+							  0, 1, 10);
+	if (IS_ERR(lsp_500m) || IS_ERR(lsp_250m) || IS_ERR(lsp_125m) ||
+	    IS_ERR(lsp_100m))
+		goto err;
+
+	/* 49.152 MHz, and the 32.768 kHz derived from it */
+	audio = zx_top_pll(np, "pll_audio", base + TOP_PLL_AUDIO);
+	if (IS_ERR(audio))
+		goto err;
+	audio_32k = clk_hw_register_fixed_factor_parent_hw(NULL, "audio_32k",
+							   audio, 0, 1, 1500);
+	if (IS_ERR(audio_32k))
+		goto err;
+
+	cpu_parents[0] = osc;
+	cpu_parents[1] = lsp_250m;
+	cpu_parents[2] = lsp_500m;
+	cpu_parents[3] = hws[ZX279128S_TOP_PLL_A9];
+	hws[ZX279128S_TOP_CPU] =
+		clk_hw_register_mux_hws(NULL, "cpu", cpu_parents, 4, 0,
+					base + TOP_CLK_SEL, TOP_CPU_SEL_SHIFT,
+					2, CLK_MUX_READ_ONLY, &zx_top_lock);
+	if (IS_ERR(hws[ZX279128S_TOP_CPU]))
+		goto err;
+	hws[ZX279128S_TOP_A9_PERIPH] =
+		clk_hw_register_fixed_factor_parent_hw(NULL, "a9_periph",
+						       hws[ZX279128S_TOP_CPU],
+						       0, 1, 2);
+
+	/*
+	 * A 200 MHz clock of unknown source; the vendor kernel declares it at
+	 * this rate. It feeds the bus select and, divided, the USB reference.
+	 */
+	m200 = clk_hw_register_fixed_rate(NULL, "clk_200m", NULL, 0,
+					  200000000);
+	if (IS_ERR(m200))
+		goto err;
+	m20 = clk_hw_register_fixed_factor_parent_hw(NULL, "clk_20m", m200, 0,
+						     1, 10);
+	if (IS_ERR(m20))
+		goto err;
+
+	matrix_parents[0] = osc;
+	matrix_parents[1] = m200;
+	matrix_parents[2] = lsp_250m;
+	matrix_parents[3] = lsp_125m;
+	matrix = clk_hw_register_mux_hws(NULL, "matrix_aclk", matrix_parents,
+					 4, 0, base + TOP_CLK_SEL,
+					 TOP_MATRIX_SEL_SHIFT, 2,
+					 CLK_MUX_READ_ONLY, &zx_top_lock);
+	if (IS_ERR(matrix))
+		goto err;
+	hws[ZX279128S_TOP_MATRIX_ACLK] = matrix;
+	hclk = clk_hw_register_fixed_factor_parent_hw(NULL, "matrix_hclk",
+						      matrix, 0, 1, 2);
+	hws[ZX279128S_TOP_MATRIX_HCLK] = hclk;
+	pclk = clk_hw_register_fixed_factor_parent_hw(NULL, "matrix_pclk",
+						      matrix, 0, 1, 2);
+	if (IS_ERR(pclk))
+		goto err;
+	hws[ZX279128S_TOP_MATRIX_PCLK] = pclk;
+
+	en = base + TOP_CLK_EN;
+	hws[ZX279128S_TOP_LSP0_100M] = zx_top_gate(en, "lsp0_100m", lsp_100m,
+						   13, 0);
+	hws[ZX279128S_TOP_LSP0_32K] = zx_top_gate(en, "lsp0_32k", audio_32k,
+						  12, 0);
+	hws[ZX279128S_TOP_LSP0_PCLK] = zx_top_gate(en, "lsp0_pclk", pclk, 11, 0);
+	hws[ZX279128S_TOP_LSP0_25M] = zx_top_gate(en, "lsp0_25m", osc, 9, 0);
+	hws[ZX279128S_TOP_LSP1_ACLK] = zx_top_gate(en, "lsp1_aclk", matrix, 8, 0);
+	hws[ZX279128S_TOP_LSP1_100M] = zx_top_gate(en, "lsp1_100m", lsp_100m,
+						   7, 0);
+	hws[ZX279128S_TOP_LSP1_49M] = zx_top_gate(en, "lsp1_49m", audio, 6, 0);
+	hws[ZX279128S_TOP_LSP1_PCLK] = zx_top_gate(en, "lsp1_pclk", pclk, 5, 0);
+	hws[ZX279128S_TOP_LSP1_25M] = zx_top_gate(en, "lsp1_25m", osc, 4, 0);
+	/* the parked second CPU waits in the IRAM */
+	hws[ZX279128S_TOP_IRAM_ACLK] = zx_top_gate(en, "iram_aclk", matrix, 2,
+						   CLK_IS_CRITICAL);
+	hws[ZX279128S_TOP_IROM_ACLK] = zx_top_gate(en, "irom_aclk", matrix, 1,
+						   CLK_IS_CRITICAL);
+	hws[ZX279128S_TOP_SYS_CTRL_PCLK] = zx_top_gate(en, "sys_ctrl_pclk", pclk,
+						       0, CLK_IS_CRITICAL);
+
+	/* The USB 3.0 controller's bus, suspend and reference clocks */
+	en = base + TOP_USB_EN;
+	hws[ZX279128S_TOP_USB_ACLK] = zx_top_gate(en, "usb_aclk", matrix, 21, 0);
+	hws[ZX279128S_TOP_USB_SUSPEND] = zx_top_gate(en, "usb_suspend",
+						     audio_32k, 20, 0);
+	hws[ZX279128S_TOP_USB_REF] = zx_top_gate(en, "usb_ref", m20, 19, 0);
+
+	for (i = 0; i < TOP_NUM_CLKS; i++)
+		if (IS_ERR_OR_NULL(hws[i]))
+			goto err;
+
+	if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, data))
+		goto err;
+
+	if (zx_top_reset_init(np, base))
+		pr_err("%pOF: failed to register the resets\n", np);
+	return;
+
+err:
+	/* Without its timer and bus clocks the system won't boot anyway */
+	pr_err("%pOF: failed to register the clocks\n", np);
+}
+
+CLK_OF_DECLARE(zx279128s_topcrm, "zte,zx279128s-topcrm",
+	       zx279128s_topcrm_init);
+
+/*
+ * A peripheral of an LSP group: its work clock, optionally behind a mux of
+ * two inputs or a divider, and its register clock.
+ */
+struct zx_lsp_periph {
+	const char *name;
+	unsigned int reg;
+	int wclk;			/* index of the work clock, or -1 */
+	int pclk;			/* index of the register clock */
+	const char *parents[2];		/* the mux inputs, or one parent */
+	u8 div_width;			/* 0: no divider */
+};
+
+struct zx_lsp_data {
+	const struct zx_lsp_periph *periphs;
+	unsigned int num_periphs;
+	unsigned int num_clks;
+	bool aclk;			/* the group has an AXI clock */
+};
+
+/* The work clock: an optional mux or divider, then the gate */
+static struct clk_hw *zx_lsp_wclk(struct device *dev, void __iomem *reg,
+				  spinlock_t *lock,
+				  const struct zx_lsp_periph *p)
+{
+	struct clk_parent_data pd[2] = {
+		{ .fw_name = p->parents[0] },
+		{ .fw_name = p->parents[1] },
+	};
+	struct clk_hw *src = NULL;
+	const char *name;
+
+	if (p->parents[1]) {
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s_wsel", p->name);
+		if (!name)
+			return ERR_PTR(-ENOMEM);
+		src = devm_clk_hw_register_mux_parent_data_table(dev, name, pd,
+								 2, 0, reg,
+								 LSP_WCLK_SEL_SHIFT,
+								 1, 0, NULL,
+								 lock);
+	} else if (p->div_width) {
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s_wdiv", p->name);
+		if (!name)
+			return ERR_PTR(-ENOMEM);
+		src = __devm_clk_hw_register_divider(dev, NULL, name, NULL,
+						     NULL, pd, 0, reg,
+						     LSP_WCLK_DIV_SHIFT,
+						     p->div_width, 0, NULL,
+						     lock);
+	}
+	if (IS_ERR(src))
+		return src;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s_wclk", p->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+	if (src)
+		return devm_clk_hw_register_gate_parent_hw(dev, name, src,
+							   CLK_SET_RATE_PARENT,
+							   reg, LSP_WCLK_EN, 0,
+							   lock);
+	return devm_clk_hw_register_gate_parent_data(dev, name, pd, 0, reg,
+						     LSP_WCLK_EN, 0, lock);
+}
+
+/* The register clock */
+static struct clk_hw *zx_lsp_pclk(struct device *dev, void __iomem *reg,
+				  spinlock_t *lock,
+				  const struct zx_lsp_periph *p)
+{
+	struct clk_parent_data pclk = { .fw_name = "pclk" };
+	const char *name;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s_pclk", p->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+	return devm_clk_hw_register_gate_parent_data(dev, name, &pclk, 0, reg,
+						     LSP_PCLK_EN, 0, lock);
+}
+
+static int zx279128s_lsp_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct zx_lsp_data *match = device_get_match_data(dev);
+	struct clk_hw_onecell_data *data;
+	void __iomem *base;
+	spinlock_t *lock;	/* serializes the group's clock registers */
+	struct clk *clk;
+	unsigned int i;
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	/* The group's own registers need these */
+	clk = devm_clk_get_enabled(dev, "pclk");
+	if (IS_ERR(clk))
+		return dev_err_probe(dev, PTR_ERR(clk), "no register clock\n");
+	if (match->aclk) {
+		clk = devm_clk_get_enabled(dev, "aclk");
+		if (IS_ERR(clk))
+			return dev_err_probe(dev, PTR_ERR(clk),
+					     "no AXI clock\n");
+	}
+
+	lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
+	data = devm_kzalloc(dev, struct_size(data, hws, match->num_clks),
+			    GFP_KERNEL);
+	if (!lock || !data)
+		return -ENOMEM;
+	spin_lock_init(lock);
+	data->num = match->num_clks;
+
+	for (i = 0; i < match->num_periphs; i++) {
+		const struct zx_lsp_periph *p = &match->periphs[i];
+		void __iomem *reg = base + p->reg;
+		struct clk_hw *hw;
+
+		if (p->wclk >= 0) {
+			hw = zx_lsp_wclk(dev, reg, lock, p);
+			if (IS_ERR(hw))
+				return dev_err_probe(dev, PTR_ERR(hw),
+						     "failed to register %s\n",
+						     p->name);
+			data->hws[p->wclk] = hw;
+		}
+
+		hw = zx_lsp_pclk(dev, reg, lock, p);
+		if (IS_ERR(hw))
+			return dev_err_probe(dev, PTR_ERR(hw),
+					     "failed to register %s\n", p->name);
+		data->hws[p->pclk] = hw;
+	}
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data);
+}
+
+static const struct zx_lsp_periph zx_lsp0_periphs[] = {
+	{ "uart0", 0x10, ZX279128S_LSP0_UART0_WCLK, ZX279128S_LSP0_UART0_PCLK,
+	  { "wclk25m", "wclk100m" } },
+	{ "uart1", 0x14, ZX279128S_LSP0_UART1_WCLK, ZX279128S_LSP0_UART1_PCLK,
+	  { "wclk25m", "wclk100m" } },
+	{ "spi", 0x18, ZX279128S_LSP0_SPI_WCLK, ZX279128S_LSP0_SPI_PCLK,
+	  { "wclk100m" }, 6 },
+	{ "gpio", 0x1c, -1, ZX279128S_LSP0_GPIO_PCLK },
+};
+
+static const struct zx_lsp_data zx_lsp0_data = {
+	.periphs = zx_lsp0_periphs,
+	.num_periphs = ARRAY_SIZE(zx_lsp0_periphs),
+	.num_clks = ZX279128S_LSP0_GPIO_PCLK + 1,
+};
+
+static const struct zx_lsp_periph zx_lsp1_periphs[] = {
+	{ "mdio", 0x04, ZX279128S_LSP1_MDIO_WCLK, ZX279128S_LSP1_MDIO_PCLK,
+	  { "wclk100m" }, 7 },
+};
+
+static const struct zx_lsp_data zx_lsp1_data = {
+	.periphs = zx_lsp1_periphs,
+	.num_periphs = ARRAY_SIZE(zx_lsp1_periphs),
+	.num_clks = ZX279128S_LSP1_MDIO_PCLK + 1,
+	.aclk = true,
+};
+
+static const struct of_device_id zx279128s_lsp_of_match[] = {
+	{ .compatible = "zte,zx279128s-lsp0crpm", .data = &zx_lsp0_data },
+	{ .compatible = "zte,zx279128s-lsp1crpm", .data = &zx_lsp1_data },
+	{ }
+};
+
+static struct platform_driver zx279128s_lsp_driver = {
+	.probe = zx279128s_lsp_probe,
+	.driver = {
+		.name = "zx279128s-lspcrpm",
+		.of_match_table = zx279128s_lsp_of_match,
+		.suppress_bind_attrs = true,
+	},
+};
+builtin_platform_driver(zx279128s_lsp_driver);
-- 
2.55.0


  parent reply	other threads:[~2026-10-10 13:00 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-10 12:59 [PATCH RFC 00/24] ARM: zte: Add support for Sanechips ZX279128S and ZTE ZXHN H3600 Navid Ghahremani
2026-10-10 12:59 ` [PATCH 01/24] dt-bindings: cache: l2c2x0: Describe ZTE device-read serialization Navid Ghahremani
2026-10-12  9:43   ` Krzysztof Kozlowski
2026-10-10 12:59 ` [PATCH 02/24] ARM: l2c: Serialize device reads with cache maintenance when requested Navid Ghahremani
2026-10-10 13:10   ` sashiko-bot
2026-10-10 14:28   ` Arnd Bergmann
2026-10-10 21:41     ` Navid Ghahremani
2026-10-11  1:02     ` Navid Ghahremani
2026-10-11 14:48       ` Arnd Bergmann
2026-10-10 12:59 ` [PATCH 03/24] wifi: mt76: Serialize MMIO reads with outer cache maintenance Navid Ghahremani
2026-10-10 12:59 ` [PATCH 04/24] dt-bindings: arm: Add ZTE ZX279128S platform descriptions Navid Ghahremani
2026-10-10 12:59 ` [PATCH 05/24] ARM: zte: Add ZX279128S platform and CPU hotplug support Navid Ghahremani
2026-10-10 14:13   ` Arnd Bergmann
2026-10-10 17:34     ` Stefan Dösinger
2026-10-10 21:26       ` Navid Ghahremani
2026-10-10 12:59 ` [PATCH 06/24] dt-bindings: clock: Add ZTE ZX279128S CRM clocks and resets Navid Ghahremani
2026-10-10 13:08   ` sashiko-bot
2026-10-11  9:13   ` Stefan Dösinger
2026-10-10 12:59 ` Navid Ghahremani [this message]
2026-10-10 13:15   ` [PATCH 07/24] clk: zte: Add ZX279128S CRM clock and reset driver sashiko-bot
2026-10-11 11:10   ` Stefan Dösinger
2026-10-10 12:59 ` [PATCH 08/24] dt-bindings: gpio: Add ZTE ZX279128S GPIO controller Navid Ghahremani
2026-10-10 12:59 ` [PATCH 09/24] gpio: Add ZTE ZX279128S GPIO driver Navid Ghahremani
2026-10-10 13:14   ` sashiko-bot
2026-10-11 11:19   ` Stefan Dösinger
2026-10-12 10:59   ` Uwe Kleine-König
2026-10-10 12:59 ` [PATCH 10/24] dt-bindings: pinctrl: pinctrl-single: Add ZTE ZX279128S pin mux Navid Ghahremani
2026-10-10 12:59 ` [PATCH 11/24] dt-bindings: mfd: syscon: Add ZX279128S system controller Navid Ghahremani
2026-10-10 13:08   ` sashiko-bot
2026-10-10 12:59 ` [PATCH 12/24] dt-bindings: PCI: Add ZTE ZX279128S host controller Navid Ghahremani
2026-10-10 13:12   ` sashiko-bot
2026-10-10 12:59 ` [PATCH 13/24] PCI: dwc: Add ZTE ZX279128S host controller driver Navid Ghahremani
2026-10-10 13:14   ` sashiko-bot
2026-10-11 13:03   ` Stefan Dösinger
2026-10-10 12:59 ` [PATCH 14/24] dt-bindings: net: Add ZTE ZX279128S MDIO controller Navid Ghahremani
2026-10-10 13:06   ` sashiko-bot
2026-10-10 12:59 ` [PATCH 15/24] net: mdio: " Navid Ghahremani
2026-10-10 13:11   ` sashiko-bot
2026-10-10 12:59 ` [PATCH 16/24] net: phy: Add Sanechips ZX5201 PHY support Navid Ghahremani
2026-10-10 12:59 ` [PATCH 17/24] dt-bindings: net: Add ZTE ZX279128S Ethernet switch Navid Ghahremani
2026-10-10 13:08   ` sashiko-bot
2026-10-10 12:59 ` [PATCH 18/24] net: ethernet: zte: Add ZX279128S Ethernet switch driver Navid Ghahremani
2026-10-10 13:19   ` sashiko-bot
2026-10-10 12:59 ` [PATCH 19/24] dt-bindings: spi: Add ZTE ZX279128S SPI flash controller Navid Ghahremani
2026-10-10 12:59 ` [PATCH 20/24] " Navid Ghahremani
2026-10-10 13:11   ` sashiko-bot
2026-10-11 16:32   ` Stefan Dösinger
2026-10-10 12:59 ` [PATCH 21/24] dt-bindings: usb: Add ZTE ZX279128S DWC3 controller Navid Ghahremani
2026-10-10 13:11   ` sashiko-bot
2026-10-10 13:00 ` [PATCH 22/24] usb: dwc3: generic-plat: Add ZTE ZX279128S Navid Ghahremani
2026-10-10 13:14   ` sashiko-bot
2026-10-10 13:00 ` [PATCH 23/24] ARM: dts: zte: Add ZX279128S SoC description Navid Ghahremani
2026-10-10 13:14   ` sashiko-bot
2026-10-10 13:00 ` [PATCH 24/24] ARM: dts: zte: Add ZTE ZXHN H3600 board Navid Ghahremani

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261010130024.177503-8-ghahramani.navid@gmail.com \
    --to=ghahramani.navid@gmail.com \
    --cc=arnd@arndb.de \
    --cc=devicetree@vger.kernel.org \
    --cc=krzk@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=robh@kernel.org \
    --cc=stefandoesinger@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox