clk: meson: add triple phase clock driver
authorJerome Brunet <jbrunet@baylibre.com>
Tue, 22 May 2018 16:34:54 +0000 (18:34 +0200)
committerJerome Brunet <jbrunet@baylibre.com>
Mon, 9 Jul 2018 11:47:22 +0000 (13:47 +0200)
Add a driver to control the output of the sample clock generator found
in the axg audio clock controller.

The goal of this driver is to coherently control the phase provided to
the different element using the sample clock generator. This simplify
the usage of the sample clock generator a lot, without comprising the
ability of the SoC.

Acked-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
drivers/clk/meson/Kconfig
drivers/clk/meson/Makefile
drivers/clk/meson/clk-triphase.c [new file with mode: 0644]
drivers/clk/meson/clkc-audio.h [new file with mode: 0644]

index 9d00809..9ad9596 100644 (file)
@@ -3,6 +3,11 @@ config COMMON_CLK_AMLOGIC
        depends on ARCH_MESON || COMPILE_TEST
        select COMMON_CLK_REGMAP_MESON
 
+config COMMON_CLK_AMLOGIC_AUDIO
+       bool
+       depends on ARCH_MESON || COMPILE_TEST
+       select COMMON_CLK_AMLOGIC
+
 config COMMON_CLK_MESON_AO
        bool
        depends on OF
index 162e4a6..74ec070 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o
 obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-phase.o
+obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o
 obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
 obj-$(CONFIG_COMMON_CLK_GXBB)   += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c
new file mode 100644 (file)
index 0000000..4a59936
--- /dev/null
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#include <linux/clk-provider.h>
+#include "clkc-audio.h"
+
+/*
+ * This is a special clock for the audio controller.
+ * The phase of mst_sclk clock output can be controlled independently
+ * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2).
+ * Controlling these 3 phases as just one makes things simpler and
+ * give the same clock view to all the element on the i2s bus.
+ * If necessary, we can still control the phase in the tdm block
+ * which makes these independent control redundant.
+ */
+static inline struct meson_clk_triphase_data *
+meson_clk_triphase_data(struct clk_regmap *clk)
+{
+       return (struct meson_clk_triphase_data *)clk->data;
+}
+
+static void meson_clk_triphase_sync(struct clk_hw *hw)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
+       unsigned int val;
+
+       /* Get phase 0 and sync it to phase 1 and 2 */
+       val = meson_parm_read(clk->map, &tph->ph0);
+       meson_parm_write(clk->map, &tph->ph1, val);
+       meson_parm_write(clk->map, &tph->ph2, val);
+}
+
+static int meson_clk_triphase_get_phase(struct clk_hw *hw)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
+       unsigned int val;
+
+       /* Phase are in sync, reading phase 0 is enough */
+       val = meson_parm_read(clk->map, &tph->ph0);
+
+       return meson_clk_degrees_from_val(val, tph->ph0.width);
+}
+
+static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
+       unsigned int val;
+
+       val = meson_clk_degrees_to_val(degrees, tph->ph0.width);
+       meson_parm_write(clk->map, &tph->ph0, val);
+       meson_parm_write(clk->map, &tph->ph1, val);
+       meson_parm_write(clk->map, &tph->ph2, val);
+
+       return 0;
+}
+
+const struct clk_ops meson_clk_triphase_ops = {
+       .init           = meson_clk_triphase_sync,
+       .get_phase      = meson_clk_triphase_get_phase,
+       .set_phase      = meson_clk_triphase_set_phase,
+};
+EXPORT_SYMBOL_GPL(meson_clk_triphase_ops);
diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h
new file mode 100644 (file)
index 0000000..286ff12
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_CLKC_AUDIO_H
+#define __MESON_CLKC_AUDIO_H
+
+#include "clkc.h"
+
+struct meson_clk_triphase_data {
+       struct parm ph0;
+       struct parm ph1;
+       struct parm ph2;
+};
+
+extern const struct clk_ops meson_clk_triphase_ops;
+
+#endif /* __MESON_CLKC_AUDIO_H */