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 <dario...@libero.it>
---

 .../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@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@48004e00 {
+               #clock-cells = <0>;
+               compatible = "ti,dss-gate-clock";
+               clocks = <&dpll4_m4x2_ck>;
+               reg = <0x0e00>;
+               ti,bit-shift = <0>;
+       };
+
+       emac_ick: emac_ick@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@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 <dario...@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

Reply via email to