summaryrefslogtreecommitdiffstats
path: root/drivers/clk/ti/clk-am3-dpll-x2.c
diff options
context:
space:
mode:
authorDario Binacchi <dariobin@libero.it>2020-12-30 00:06:34 +0100
committerLokesh Vutla <lokeshvutla@ti.com>2021-01-12 10:58:04 +0530
commit756d64e43e20be558e6e49f2ccee2f747feb4a4d (patch)
treedc99960e80d3e24ac13cd44af16fec3f570745fa /drivers/clk/ti/clk-am3-dpll-x2.c
parent9d76120083131cf087bbc028249bf88a91208504 (diff)
downloadu-boot-756d64e43e20be558e6e49f2ccee2f747feb4a4d.tar.gz
u-boot-756d64e43e20be558e6e49f2ccee2f747feb4a4d.tar.xz
u-boot-756d64e43e20be558e6e49f2ccee2f747feb4a4d.zip
clk: ti: am33xx: add DPLL clock drivers
The digital phase-locked loop (DPLL) provides all interface clocks and functional clocks to the processor of the AM33xx device. The AM33xx device integrates five different DPLLs: * Core DPLL * Per DPLL * LCD DPLL * DDR DPLL * MPU DPLL The patch adds support for the compatible strings: * "ti,am3-dpll-core-clock" * "ti,am3-dpll-no-gate-clock" * "ti,am3-dpll-no-gate-j-type-clock" * "ti,am3-dpll-x2-clock" The code is loosely based on the drivers/clk/ti/dpll.c drivers of the Linux kernel version 5.9-rc7. For DT binding details see: - Documentation/devicetree/bindings/clock/ti/dpll.txt Signed-off-by: Dario Binacchi <dariobin@libero.it>
Diffstat (limited to 'drivers/clk/ti/clk-am3-dpll-x2.c')
-rw-r--r--drivers/clk/ti/clk-am3-dpll-x2.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/drivers/clk/ti/clk-am3-dpll-x2.c b/drivers/clk/ti/clk-am3-dpll-x2.c
new file mode 100644
index 0000000000..3cf279d6a3
--- /dev/null
+++ b/drivers/clk/ti/clk-am3-dpll-x2.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI DPLL x2 clock support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ *
+ * Loosely based on Linux kernel drivers/clk/ti/dpll.c
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/clk-provider.h>
+
+struct clk_ti_am3_dpll_x2_priv {
+ struct clk parent;
+};
+
+static ulong clk_ti_am3_dpll_x2_get_rate(struct clk *clk)
+{
+ struct clk_ti_am3_dpll_x2_priv *priv = dev_get_priv(clk->dev);
+ unsigned long rate;
+
+ rate = clk_get_rate(&priv->parent);
+ if (IS_ERR_VALUE(rate))
+ return rate;
+
+ rate *= 2;
+ dev_dbg(clk->dev, "rate=%ld\n", rate);
+ return rate;
+}
+
+const struct clk_ops clk_ti_am3_dpll_x2_ops = {
+ .get_rate = clk_ti_am3_dpll_x2_get_rate,
+};
+
+static int clk_ti_am3_dpll_x2_remove(struct udevice *dev)
+{
+ struct clk_ti_am3_dpll_x2_priv *priv = dev_get_priv(dev);
+ int err;
+
+ err = clk_release_all(&priv->parent, 1);
+ if (err) {
+ dev_err(dev, "failed to release parent clock\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int clk_ti_am3_dpll_x2_probe(struct udevice *dev)
+{
+ struct clk_ti_am3_dpll_x2_priv *priv = dev_get_priv(dev);
+ int err;
+
+ err = clk_get_by_index(dev, 0, &priv->parent);
+ if (err) {
+ dev_err(dev, "%s: failed to get parent clock\n", __func__);
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id clk_ti_am3_dpll_x2_of_match[] = {
+ {.compatible = "ti,am3-dpll-x2-clock"},
+ {}
+};
+
+U_BOOT_DRIVER(clk_ti_am3_dpll_x2) = {
+ .name = "ti_am3_dpll_x2_clock",
+ .id = UCLASS_CLK,
+ .of_match = clk_ti_am3_dpll_x2_of_match,
+ .probe = clk_ti_am3_dpll_x2_probe,
+ .remove = clk_ti_am3_dpll_x2_remove,
+ .priv_auto = sizeof(struct clk_ti_am3_dpll_x2_priv),
+ .ops = &clk_ti_am3_dpll_x2_ops,
+};