diff mbox

[v6,03/11] clk: bcm: Add clocks for Stingray SOC

Message ID 1496385275-6899-4-git-send-email-anup.patel@broadcom.com (mailing list archive)
State New, archived
Headers show

Commit Message

Anup Patel June 2, 2017, 6:34 a.m. UTC
From: Sandeep Tripathy <sandeep.tripathy@broadcom.com>

This patch adds support for Stingray clocks in iproc
ccf. The Stingray SOC has various plls based on iproc
pll architecture.

Signed-off-by: Sandeep Tripathy <sandeep.tripathy@broadcom.com>
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
---
 drivers/clk/bcm/Kconfig  |   8 ++
 drivers/clk/bcm/Makefile |   1 +
 drivers/clk/bcm/clk-sr.c | 320 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 329 insertions(+)
 create mode 100644 drivers/clk/bcm/clk-sr.c

Comments

Stephen Boyd June 2, 2017, 10:10 p.m. UTC | #1
On 06/02, Anup Patel wrote:
> diff --git a/drivers/clk/bcm/clk-sr.c b/drivers/clk/bcm/clk-sr.c
> new file mode 100644
> index 0000000..342f702
> --- /dev/null
> +++ b/drivers/clk/bcm/clk-sr.c
> @@ -0,0 +1,320 @@
> +
> +static const struct iproc_clk_ctrl lcpll_pcie_clk[] = {
> +	[BCM_SR_LCPLL_PCIE_PHY_REF_CLK] = {
> +		.channel = BCM_SR_LCPLL_PCIE_PHY_REF_CLK,
> +		.flags = IPROC_CLK_AON,
> +		.enable = ENABLE_VAL(0x0, 7, 1, 13),
> +		.mdiv = REG_VAL(0x14, 0, 9),
> +	},
> +};
> +
> +static void __init sr_lcpll_pcie_clk_init(struct device_node *node)

Drop __init usage throughout this patch please.

> +{
> +	iproc_pll_clk_setup(node, &lcpll_pcie, NULL, 0, lcpll_pcie_clk,
> +		ARRAY_SIZE(lcpll_pcie_clk));
> +}
> +
> +static const struct of_device_id sr_clk_dt_ids[] = {
> +{ .compatible = "brcm,sr-genpll0", .data = sr_genpll0_clk_init, },
> +{ .compatible = "brcm,sr-genpll4", .data = sr_genpll4_clk_init, },
> +{ .compatible = "brcm,sr-genpll5", .data = sr_genpll5_clk_init, },
> +{ .compatible = "brcm,sr-lcpll0", .data = sr_lcpll0_clk_init, },
> +{ .compatible = "brcm,sr-lcpll1", .data = sr_lcpll1_clk_init, },
> +{ .compatible = "brcm,sr-lcpll-pcie", .data = sr_lcpll_pcie_clk_init, },
> +{ /* sentinel */ }

Please tab these out properly And also leave off the , after the
init function.

> +};
> +
> +static int sr_clk_probe(struct platform_device *pdev)
> +{
> +	const struct of_device_id *device;
> +	void (*init_func)(struct device_node *);

Let's keep this taking the platform device pointer. That way in
the future devm could be used as well as other platform device
APIs without having to change all init signatures.

> +
> +	device = of_match_device(sr_clk_dt_ids, &pdev->dev);
> +	if (!device)
> +		return -ENODEV;
> +	init_func = device->data;

Can use of_device_get_match_data() instead

> +
> +	init_func(pdev->dev.of_node);
> +
> +	return 0;
> +}

It would be pretty nice if we could have some platform driver
common function for this where we want to call different probe
functions for different compatible ids and put them all in the
same driver file. Like platform_driver_of_probe() or something
that then calls a int (*init_func)(struct platform_device *pdev)
directly from the of match table for you.

> +
> +static struct platform_driver sr_clk_driver = {

iproc_sr_* throughout this file?

> +	.driver = {
> +		.name = "sr-clk",
> +		.of_match_table = sr_clk_dt_ids,
> +	},
> +	.probe = sr_clk_probe,
> +};
> +builtin_platform_driver(sr_clk_driver);
Anup Patel June 6, 2017, 4:21 a.m. UTC | #2
On Sat, Jun 3, 2017 at 3:40 AM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> On 06/02, Anup Patel wrote:
>> diff --git a/drivers/clk/bcm/clk-sr.c b/drivers/clk/bcm/clk-sr.c
>> new file mode 100644
>> index 0000000..342f702
>> --- /dev/null
>> +++ b/drivers/clk/bcm/clk-sr.c
>> @@ -0,0 +1,320 @@
>> +
>> +static const struct iproc_clk_ctrl lcpll_pcie_clk[] = {
>> +     [BCM_SR_LCPLL_PCIE_PHY_REF_CLK] = {
>> +             .channel = BCM_SR_LCPLL_PCIE_PHY_REF_CLK,
>> +             .flags = IPROC_CLK_AON,
>> +             .enable = ENABLE_VAL(0x0, 7, 1, 13),
>> +             .mdiv = REG_VAL(0x14, 0, 9),
>> +     },
>> +};
>> +
>> +static void __init sr_lcpll_pcie_clk_init(struct device_node *node)
>
> Drop __init usage throughout this patch please.

Sure, will do.

>
>> +{
>> +     iproc_pll_clk_setup(node, &lcpll_pcie, NULL, 0, lcpll_pcie_clk,
>> +             ARRAY_SIZE(lcpll_pcie_clk));
>> +}
>> +
>> +static const struct of_device_id sr_clk_dt_ids[] = {
>> +{ .compatible = "brcm,sr-genpll0", .data = sr_genpll0_clk_init, },
>> +{ .compatible = "brcm,sr-genpll4", .data = sr_genpll4_clk_init, },
>> +{ .compatible = "brcm,sr-genpll5", .data = sr_genpll5_clk_init, },
>> +{ .compatible = "brcm,sr-lcpll0", .data = sr_lcpll0_clk_init, },
>> +{ .compatible = "brcm,sr-lcpll1", .data = sr_lcpll1_clk_init, },
>> +{ .compatible = "brcm,sr-lcpll-pcie", .data = sr_lcpll_pcie_clk_init, },
>> +{ /* sentinel */ }
>
> Please tab these out properly And also leave off the , after the
> init function.

Sure, will do.

>
>> +};
>> +
>> +static int sr_clk_probe(struct platform_device *pdev)
>> +{
>> +     const struct of_device_id *device;
>> +     void (*init_func)(struct device_node *);
>
> Let's keep this taking the platform device pointer. That way in
> the future devm could be used as well as other platform device
> APIs without having to change all init signatures.

Sounds good, I will make init_func prototype similar to
platform driver probe function.

>
>> +
>> +     device = of_match_device(sr_clk_dt_ids, &pdev->dev);
>> +     if (!device)
>> +             return -ENODEV;
>> +     init_func = device->data;
>
> Can use of_device_get_match_data() instead
>
>> +
>> +     init_func(pdev->dev.of_node);
>> +
>> +     return 0;
>> +}
>
> It would be pretty nice if we could have some platform driver
> common function for this where we want to call different probe
> functions for different compatible ids and put them all in the
> same driver file. Like platform_driver_of_probe() or something
> that then calls a int (*init_func)(struct platform_device *pdev)
> directly from the of match table for you.

Yes, in-future we can have some API in OF
such as:
int of_platform_nested_probe(struct platform_device *pdev)

This API can be directly set a probe function of
some platform driver. It will expect that match data
is another platform driver probe function and will
call that.

IMHO, having nested probe API for OF will certainly
help simplify probe functions of quite a few drivers.

>
>> +
>> +static struct platform_driver sr_clk_driver = {
>
> iproc_sr_* throughout this file?

Actually, clk drivers for other iProc SOCs (namely,
ns2 and nsp) have only "<soc_name>_" prefix
so we are trying to be consistent with these
drivers by using "sr_" prefix.

Regards,
A nup
diff mbox

Patch

diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
index b5ae531..1d9187d 100644
--- a/drivers/clk/bcm/Kconfig
+++ b/drivers/clk/bcm/Kconfig
@@ -46,3 +46,11 @@  config CLK_BCM_NS2
 	default ARCH_BCM_IPROC
 	help
 	  Enable common clock framework support for the Broadcom Northstar 2 SoC
+
+config CLK_BCM_SR
+	bool "Broadcom Stingray clock support"
+	depends on ARCH_BCM_IPROC || COMPILE_TEST
+	select COMMON_CLK_IPROC
+	default ARCH_BCM_IPROC
+	help
+	  Enable common clock framework support for the Broadcom Stingray SoC
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index d9dc848..a0c14fa 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -10,3 +10,4 @@  obj-$(CONFIG_ARCH_BCM_53573)	+= clk-bcm53573-ilp.o
 obj-$(CONFIG_CLK_BCM_CYGNUS)	+= clk-cygnus.o
 obj-$(CONFIG_CLK_BCM_NSP)	+= clk-nsp.o
 obj-$(CONFIG_CLK_BCM_NS2)	+= clk-ns2.o
+obj-$(CONFIG_CLK_BCM_SR)	+= clk-sr.o
diff --git a/drivers/clk/bcm/clk-sr.c b/drivers/clk/bcm/clk-sr.c
new file mode 100644
index 0000000..342f702
--- /dev/null
+++ b/drivers/clk/bcm/clk-sr.c
@@ -0,0 +1,320 @@ 
+/*
+ * Copyright 2017 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation (the "GPL").
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <dt-bindings/clock/bcm-sr.h>
+#include "clk-iproc.h"
+
+#define REG_VAL(o, s, w) { .offset = o, .shift = s, .width = w, }
+
+#define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \
+	.pwr_shift = ps, .iso_shift = is }
+
+#define SW_CTRL_VAL(o, s) { .offset = o, .shift = s, }
+
+#define RESET_VAL(o, rs, prs) { .offset = o, .reset_shift = rs, \
+	.p_reset_shift = prs }
+
+#define DF_VAL(o, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \
+	.ki_shift = kis, .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, \
+	.ka_shift = kas, .ka_width = kaw }
+
+#define VCO_CTRL_VAL(uo, lo) { .u_offset = uo, .l_offset = lo }
+
+#define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \
+	.hold_shift = hs, .bypass_shift = bs }
+
+
+static const struct iproc_pll_ctrl genpll0 = {
+	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+		IPROC_CLK_PLL_NEEDS_SW_CFG,
+	.aon = AON_VAL(0x0, 5, 1, 0),
+	.reset = RESET_VAL(0x0, 12, 11),
+	.dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
+	.sw_ctrl = SW_CTRL_VAL(0x10, 31),
+	.ndiv_int = REG_VAL(0x10, 20, 10),
+	.ndiv_frac = REG_VAL(0x10, 0, 20),
+	.pdiv = REG_VAL(0x14, 0, 4),
+	.status = REG_VAL(0x30, 12, 1),
+};
+
+static const struct iproc_clk_ctrl genpll0_clk[] = {
+	[BCM_SR_GENPLL0_SATA_CLK] = {
+		.channel = BCM_SR_GENPLL0_SATA_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 6, 0, 12),
+		.mdiv = REG_VAL(0x18, 0, 9),
+	},
+	[BCM_SR_GENPLL0_SCR_CLK] = {
+		.channel = BCM_SR_GENPLL0_SCR_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 7, 1, 13),
+		.mdiv = REG_VAL(0x18, 10, 9),
+	},
+	[BCM_SR_GENPLL0_250M_CLK] = {
+		.channel = BCM_SR_GENPLL0_250M_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 8, 2, 14),
+		.mdiv = REG_VAL(0x18, 20, 9),
+	},
+	[BCM_SR_GENPLL0_PCIE_AXI_CLK] = {
+		.channel = BCM_SR_GENPLL0_PCIE_AXI_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 9, 3, 15),
+		.mdiv = REG_VAL(0x1c, 0, 9),
+	},
+	[BCM_SR_GENPLL0_PAXC_AXI_X2_CLK] = {
+		.channel = BCM_SR_GENPLL0_PAXC_AXI_X2_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 10, 4, 16),
+		.mdiv = REG_VAL(0x1c, 10, 9),
+	},
+	[BCM_SR_GENPLL0_PAXC_AXI_CLK] = {
+		.channel = BCM_SR_GENPLL0_PAXC_AXI_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 11, 5, 17),
+		.mdiv = REG_VAL(0x1c, 20, 9),
+	},
+};
+
+static void __init sr_genpll0_clk_init(struct device_node *node)
+{
+	iproc_pll_clk_setup(node, &genpll0, NULL, 0, genpll0_clk,
+				ARRAY_SIZE(genpll0_clk));
+}
+
+static const struct iproc_pll_ctrl genpll3 = {
+	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+		IPROC_CLK_PLL_NEEDS_SW_CFG,
+	.aon = AON_VAL(0x0, 1, 19, 18),
+	.reset = RESET_VAL(0x0, 12, 11),
+	.dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
+	.sw_ctrl = SW_CTRL_VAL(0x10, 31),
+	.ndiv_int = REG_VAL(0x10, 20, 10),
+	.ndiv_frac = REG_VAL(0x10, 0, 20),
+	.pdiv = REG_VAL(0x14, 0, 4),
+	.status = REG_VAL(0x30, 12, 1),
+};
+
+static const struct iproc_clk_ctrl genpll3_clk[] = {
+	[BCM_SR_GENPLL3_HSLS_CLK] = {
+		.channel = BCM_SR_GENPLL3_HSLS_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 6, 0, 12),
+		.mdiv = REG_VAL(0x18, 0, 9),
+	},
+	[BCM_SR_GENPLL3_SDIO_CLK] = {
+		.channel = BCM_SR_GENPLL3_SDIO_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 7, 1, 13),
+		.mdiv = REG_VAL(0x18, 10, 9),
+	},
+};
+
+static void __init sr_genpll3_clk_init(struct device_node *node)
+{
+	iproc_pll_clk_setup(node, &genpll3, NULL, 0, genpll3_clk,
+				ARRAY_SIZE(genpll3_clk));
+}
+CLK_OF_DECLARE(sr_genpll3_clk, "brcm,sr-genpll3",
+			sr_genpll3_clk_init);
+
+static const struct iproc_pll_ctrl genpll4 = {
+	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+		IPROC_CLK_PLL_NEEDS_SW_CFG,
+	.aon = AON_VAL(0x0, 1, 25, 24),
+	.reset = RESET_VAL(0x0, 12, 11),
+	.dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
+	.sw_ctrl = SW_CTRL_VAL(0x10, 31),
+	.ndiv_int = REG_VAL(0x10, 20, 10),
+	.ndiv_frac = REG_VAL(0x10, 0, 20),
+	.pdiv = REG_VAL(0x14, 0, 4),
+	.status = REG_VAL(0x30, 12, 1),
+};
+
+static const struct iproc_clk_ctrl genpll4_clk[] = {
+	[BCM_SR_GENPLL4_CCN_CLK] = {
+		.channel = BCM_SR_GENPLL4_CCN_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 6, 0, 12),
+		.mdiv = REG_VAL(0x18, 0, 9),
+	},
+};
+
+static void __init sr_genpll4_clk_init(struct device_node *node)
+{
+	iproc_pll_clk_setup(node, &genpll4, NULL, 0, genpll4_clk,
+				ARRAY_SIZE(genpll4_clk));
+}
+
+static const struct iproc_pll_ctrl genpll5 = {
+	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+		IPROC_CLK_PLL_NEEDS_SW_CFG,
+	.aon = AON_VAL(0x0, 1, 1, 0),
+	.reset = RESET_VAL(0x0, 12, 11),
+	.dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
+	.sw_ctrl = SW_CTRL_VAL(0x10, 31),
+	.ndiv_int = REG_VAL(0x10, 20, 10),
+	.ndiv_frac = REG_VAL(0x10, 0, 20),
+	.pdiv = REG_VAL(0x14, 0, 4),
+	.status = REG_VAL(0x30, 12, 1),
+};
+
+static const struct iproc_clk_ctrl genpll5_clk[] = {
+	[BCM_SR_GENPLL5_FS_CLK] = {
+		.channel = BCM_SR_GENPLL5_FS_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 6, 0, 12),
+		.mdiv = REG_VAL(0x18, 0, 9),
+	},
+	[BCM_SR_GENPLL5_SPU_CLK] = {
+		.channel = BCM_SR_GENPLL5_SPU_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x4, 6, 0, 12),
+		.mdiv = REG_VAL(0x18, 10, 9),
+	},
+};
+
+static void __init sr_genpll5_clk_init(struct device_node *node)
+{
+	iproc_pll_clk_setup(node, &genpll5, NULL, 0, genpll5_clk,
+				ARRAY_SIZE(genpll5_clk));
+}
+
+static const struct iproc_pll_ctrl lcpll0 = {
+	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG,
+	.aon = AON_VAL(0x0, 2, 19, 18),
+	.reset = RESET_VAL(0x0, 31, 30),
+	.sw_ctrl = SW_CTRL_VAL(0x4, 31),
+	.ndiv_int = REG_VAL(0x4, 16, 10),
+	.pdiv = REG_VAL(0x4, 26, 4),
+	.status = REG_VAL(0x38, 12, 1),
+};
+
+static const struct iproc_clk_ctrl lcpll0_clk[] = {
+	[BCM_SR_LCPLL0_SATA_REF_CLK] = {
+		.channel = BCM_SR_LCPLL0_SATA_REF_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x0, 7, 1, 13),
+		.mdiv = REG_VAL(0x14, 0, 9),
+	},
+	[BCM_SR_LCPLL0_USB_REF_CLK] = {
+		.channel = BCM_SR_LCPLL0_USB_REF_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x0, 8, 2, 14),
+		.mdiv = REG_VAL(0x14, 10, 9),
+	},
+	[BCM_SR_LCPLL0_SATA_REFPN_CLK] = {
+		.channel = BCM_SR_LCPLL0_SATA_REFPN_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x0, 9, 3, 15),
+		.mdiv = REG_VAL(0x14, 20, 9),
+	},
+};
+
+static void __init sr_lcpll0_clk_init(struct device_node *node)
+{
+	iproc_pll_clk_setup(node, &lcpll0, NULL, 0, lcpll0_clk,
+				ARRAY_SIZE(lcpll0_clk));
+}
+
+static const struct iproc_pll_ctrl lcpll1 = {
+	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG,
+	.aon = AON_VAL(0x0, 2, 22, 21),
+	.reset = RESET_VAL(0x0, 31, 30),
+	.sw_ctrl = SW_CTRL_VAL(0x4, 31),
+	.ndiv_int = REG_VAL(0x4, 16, 10),
+	.pdiv = REG_VAL(0x4, 26, 4),
+	.status = REG_VAL(0x38, 12, 1),
+};
+
+static const struct iproc_clk_ctrl lcpll1_clk[] = {
+	[BCM_SR_LCPLL1_WAN_CLK] = {
+		.channel = BCM_SR_LCPLL1_WAN_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x0, 7, 1, 13),
+		.mdiv = REG_VAL(0x14, 0, 9),
+	},
+};
+
+static void __init sr_lcpll1_clk_init(struct device_node *node)
+{
+	iproc_pll_clk_setup(node, &lcpll1, NULL, 0, lcpll1_clk,
+				ARRAY_SIZE(lcpll1_clk));
+}
+
+static const struct iproc_pll_ctrl lcpll_pcie = {
+	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG,
+	.aon = AON_VAL(0x0, 2, 25, 24),
+	.reset = RESET_VAL(0x0, 31, 30),
+	.sw_ctrl = SW_CTRL_VAL(0x4, 31),
+	.ndiv_int = REG_VAL(0x4, 16, 10),
+	.pdiv = REG_VAL(0x4, 26, 4),
+	.status = REG_VAL(0x38, 12, 1),
+};
+
+static const struct iproc_clk_ctrl lcpll_pcie_clk[] = {
+	[BCM_SR_LCPLL_PCIE_PHY_REF_CLK] = {
+		.channel = BCM_SR_LCPLL_PCIE_PHY_REF_CLK,
+		.flags = IPROC_CLK_AON,
+		.enable = ENABLE_VAL(0x0, 7, 1, 13),
+		.mdiv = REG_VAL(0x14, 0, 9),
+	},
+};
+
+static void __init sr_lcpll_pcie_clk_init(struct device_node *node)
+{
+	iproc_pll_clk_setup(node, &lcpll_pcie, NULL, 0, lcpll_pcie_clk,
+		ARRAY_SIZE(lcpll_pcie_clk));
+}
+
+static const struct of_device_id sr_clk_dt_ids[] = {
+{ .compatible = "brcm,sr-genpll0", .data = sr_genpll0_clk_init, },
+{ .compatible = "brcm,sr-genpll4", .data = sr_genpll4_clk_init, },
+{ .compatible = "brcm,sr-genpll5", .data = sr_genpll5_clk_init, },
+{ .compatible = "brcm,sr-lcpll0", .data = sr_lcpll0_clk_init, },
+{ .compatible = "brcm,sr-lcpll1", .data = sr_lcpll1_clk_init, },
+{ .compatible = "brcm,sr-lcpll-pcie", .data = sr_lcpll_pcie_clk_init, },
+{ /* sentinel */ }
+};
+
+static int sr_clk_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *device;
+	void (*init_func)(struct device_node *);
+
+	device = of_match_device(sr_clk_dt_ids, &pdev->dev);
+	if (!device)
+		return -ENODEV;
+	init_func = device->data;
+
+	init_func(pdev->dev.of_node);
+
+	return 0;
+}
+
+static struct platform_driver sr_clk_driver = {
+	.driver = {
+		.name = "sr-clk",
+		.of_match_table = sr_clk_dt_ids,
+	},
+	.probe = sr_clk_probe,
+};
+builtin_platform_driver(sr_clk_driver);