[PATCH v2 09/30] clk: ti: add gate clock driver

Dario Binacchi dariobin at libero.it
Sun Sep 6 14:11:39 CEST 2020


The patch adds support for TI gate clock binding. The code is based on
the drivers/clk/ti/gate.c driver of the Linux kernel.

Signed-off-by: Dario Binacchi <dariobin at libero.it>
---

(no changes since v1)

 .../clock/gpio-gate-clock.txt                 |  21 ++++
 .../clock/ti,clockdomain.txt                  |  24 ++++
 doc/device-tree-bindings/clock/ti,gate.txt    | 106 ++++++++++++++++++
 drivers/clk/Kconfig                           |   6 +
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-ti-gate.c                     |  92 +++++++++++++++
 6 files changed, 250 insertions(+)
 create mode 100644 doc/device-tree-bindings/clock/gpio-gate-clock.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,clockdomain.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,gate.txt
 create mode 100644 drivers/clk/clk-ti-gate.c

diff --git a/doc/device-tree-bindings/clock/gpio-gate-clock.txt b/doc/device-tree-bindings/clock/gpio-gate-clock.txt
new file mode 100644
index 0000000000..7cba766cbe
--- /dev/null
+++ b/doc/device-tree-bindings/clock/gpio-gate-clock.txt
@@ -0,0 +1,21 @@
+Binding for simple gpio gated clock.
+
+This binding uses the common clock binding[1].
+
+[1] doc/device-tree-bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "gpio-gate-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- enable-gpios : GPIO reference for enabling and disabling the clock.
+
+Optional properties:
+- clocks: Maximum of one parent clock is supported.
+
+Example:
+	clock {
+		compatible = "gpio-gate-clock";
+		clocks = <&parentclk>;
+		#clock-cells = <0>;
+		enable-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
+	};
diff --git a/doc/device-tree-bindings/clock/ti,clockdomain.txt b/doc/device-tree-bindings/clock/ti,clockdomain.txt
new file mode 100644
index 0000000000..cf05ee8bb9
--- /dev/null
+++ b/doc/device-tree-bindings/clock/ti,clockdomain.txt
@@ -0,0 +1,24 @@
+Binding for Texas Instruments clockdomain.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1] in consumer role.
+Every clock on TI SoC belongs to one clockdomain, but software
+only needs this information for specific clocks which require
+their parent clockdomain to be controlled when the clock is
+enabled/disabled. This binding doesn't define a new clock
+binding type, it is used to group existing clock nodes under
+hardware hierarchy.
+
+[1] doc/device-tree-bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "ti,clockdomain"
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of clocks within this domain
+
+Examples:
+	dss_clkdm: dss_clkdm {
+		compatible = "ti,clockdomain";
+		clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>;
+	};
diff --git a/doc/device-tree-bindings/clock/ti,gate.txt b/doc/device-tree-bindings/clock/ti,gate.txt
new file mode 100644
index 0000000000..792e2033c0
--- /dev/null
+++ b/doc/device-tree-bindings/clock/ti,gate.txt
@@ -0,0 +1,106 @@
+Binding for Texas Instruments gate clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1]. This clock is
+quite much similar to the basic gate-clock [2], however,
+it supports a number of additional features. If no register
+is provided for this clock, the code assumes that a clockdomain
+will be controlled instead and the corresponding hw-ops for
+that is used.
+
+[1] doc/device-tree-bindings/clock/clock-bindings.txt
+[2] doc/device-tree-bindings/clock/gpio-gate-clock.txt
+[3] doc/device-tree-bindings/clock/ti,clockdomain.txt
+
+Required properties:
+- compatible : shall be one of:
+  "ti,gate-clock" - basic gate clock
+  "ti,wait-gate-clock" - gate clock which waits until clock is active before
+			 returning from clk_enable()
+  "ti,dss-gate-clock" - gate clock with DSS specific hardware handling
+  "ti,am35xx-gate-clock" - gate clock with AM35xx specific hardware handling
+  "ti,clkdm-gate-clock" - clockdomain gate clock, which derives its functional
+			  clock directly from a clockdomain, see [3] how
+			  to map clockdomains properly
+  "ti,hsdiv-gate-clock" - gate clock with OMAP36xx specific hardware handling,
+			  required for a hardware errata
+  "ti,composite-gate-clock" - composite gate clock, to be part of composite
+			      clock
+  "ti,composite-no-wait-gate-clock" - composite gate clock that does not wait
+				      for clock to be active before returning
+				      from clk_enable()
+- #clock-cells : from common clock binding; shall be set to 0
+- clocks : link to phandle of parent clock
+- reg : offset for register controlling adjustable gate, not needed for
+	ti,clkdm-gate-clock type
+
+Optional properties:
+- ti,bit-shift : bit shift for programming the clock gate, invalid for
+		 ti,clkdm-gate-clock type
+- ti,set-bit-to-disable : inverts default gate programming. Setting the bit
+  gates the clock and clearing the bit ungates the clock.
+
+Examples:
+	mmchs2_fck: mmchs2_fck at 48004a00 {
+		#clock-cells = <0>;
+		compatible = "ti,gate-clock";
+		clocks = <&core_96m_fck>;
+		reg = <0x0a00>;
+		ti,bit-shift = <25>;
+	};
+
+	uart4_fck_am35xx: uart4_fck_am35xx {
+		#clock-cells = <0>;
+		compatible = "ti,wait-gate-clock";
+		clocks = <&core_48m_fck>;
+		reg = <0x0a00>;
+		ti,bit-shift = <23>;
+	};
+
+	dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2 at 48004e00 {
+		#clock-cells = <0>;
+		compatible = "ti,dss-gate-clock";
+		clocks = <&dpll4_m4x2_ck>;
+		reg = <0x0e00>;
+		ti,bit-shift = <0>;
+	};
+
+	emac_ick: emac_ick at 4800259c {
+		#clock-cells = <0>;
+		compatible = "ti,am35xx-gate-clock";
+		clocks = <&ipss_ick>;
+		reg = <0x059c>;
+		ti,bit-shift = <1>;
+	};
+
+	emu_src_ck: emu_src_ck {
+		#clock-cells = <0>;
+		compatible = "ti,clkdm-gate-clock";
+		clocks = <&emu_src_mux_ck>;
+	};
+
+	dpll4_m2x2_ck: dpll4_m2x2_ck at 48004d00 {
+		#clock-cells = <0>;
+		compatible = "ti,hsdiv-gate-clock";
+		clocks = <&dpll4_m2x2_mul_ck>;
+		ti,bit-shift = <0x1b>;
+		reg = <0x0d00>;
+		ti,set-bit-to-disable;
+	};
+
+	vlynq_gate_fck: vlynq_gate_fck {
+		#clock-cells = <0>;
+		compatible = "ti,composite-gate-clock";
+		clocks = <&core_ck>;
+		ti,bit-shift = <3>;
+		reg = <0x0200>;
+	};
+
+	sys_clkout2_src_gate: sys_clkout2_src_gate {
+		#clock-cells = <0>;
+		compatible = "ti,composite-no-wait-gate-clock";
+		clocks = <&core_ck>;
+		ti,bit-shift = <15>;
+		reg = <0x0070>;
+	};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index d7b546d9db..c0528c2aeb 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -111,6 +111,12 @@ config CLK_TI_DIVIDER
 	help
 	  This enables the divider clock driver support on TI's SoCs.
 
+config CLK_TI_GATE
+	bool "TI gate clock driver"
+	depends on CLK && OF_CONTROL
+	help
+	  This enables the gate clock driver support on TI's SoCs.
+
 config CLK_TI_MUX
 	bool "TI mux clock driver"
 	depends on CLK && OF_CONTROL && CLK_CCF
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 21b1e9c364..4d16fb7a50 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_STM32H7) += clk_stm32h7.o
 obj-$(CONFIG_CLK_TI_AM3_DPLL) += clk-ti-am3-dpll.o clk-ti-am3-dpll-x2.o
 obj-$(CONFIG_CLK_TI_DIVIDER) += clk-ti-divider.o
+obj-$(CONFIG_CLK_TI_GATE) += clk-ti-gate.o
 obj-$(CONFIG_CLK_TI_MUX) += clk-ti-mux.o
 obj-$(CONFIG_CLK_TI_SCI) += clk-ti-sci.o
 obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
diff --git a/drivers/clk/clk-ti-gate.c b/drivers/clk/clk-ti-gate.c
new file mode 100644
index 0000000000..0f86b8a4b3
--- /dev/null
+++ b/drivers/clk/clk-ti-gate.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI gate clock support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin at libero.it>
+ *
+ * Loosely based on Linux kernel drivers/clk/ti/gate.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk-uclass.h>
+#include <asm/io.h>
+#include <linux/clk-provider.h>
+
+struct clk_ti_gate_priv {
+	fdt_addr_t reg;
+	u8 enable_bit;
+	u32 flags;
+	bool invert_enable;
+};
+
+static int clk_ti_gate_disable(struct clk *clk)
+{
+	struct clk_ti_gate_priv *priv = dev_get_priv(clk->dev);
+	u32 v;
+
+	v = readl(priv->reg);
+	if (priv->invert_enable)
+		v |= (1 << priv->enable_bit);
+	else
+		v &= ~(1 << priv->enable_bit);
+
+	writel(v, priv->reg);
+	/* No OCP barrier needed here since it is a disable operation */
+	return 0;
+}
+
+static int clk_ti_gate_enable(struct clk *clk)
+{
+	struct clk_ti_gate_priv *priv = dev_get_priv(clk->dev);
+	u32 v;
+
+	v = readl(priv->reg);
+	if (priv->invert_enable)
+		v &= ~(1 << priv->enable_bit);
+	else
+		v |= (1 << priv->enable_bit);
+
+	writel(v, priv->reg);
+	/* OCP barrier */
+	v = readl(priv->reg);
+	return 0;
+}
+
+static int clk_ti_gate_ofdata_to_platdata(struct udevice *dev)
+{
+	struct clk_ti_gate_priv *priv = dev_get_priv(dev);
+
+	priv->reg = dev_read_addr(dev);
+	if (priv->reg == FDT_ADDR_T_NONE) {
+		dev_err(dev, "failed to get control register\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "reg=0x%08lx\n", priv->reg);
+	priv->enable_bit = dev_read_u32_default(dev, "ti,bit-shift", 0);
+	if (dev_read_bool(dev, "ti,set-rate-parent"))
+		priv->flags |= CLK_SET_RATE_PARENT;
+
+	priv->invert_enable = dev_read_bool(dev, "ti,set-bit-to-disable");
+	return 0;
+}
+
+static struct clk_ops clk_ti_gate_ops = {
+	.enable = clk_ti_gate_enable,
+	.disable = clk_ti_gate_disable,
+};
+
+static const struct udevice_id clk_ti_gate_of_match[] = {
+	{ .compatible = "ti,gate-clock" },
+	{ },
+};
+
+U_BOOT_DRIVER(clk_ti_gate) = {
+	.name = "ti_gate_clock",
+	.id = UCLASS_CLK,
+	.of_match = clk_ti_gate_of_match,
+	.ofdata_to_platdata = clk_ti_gate_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct clk_ti_gate_priv),
+	.ops = &clk_ti_gate_ops,
+};
-- 
2.17.1



More information about the U-Boot mailing list