All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] clk: meson: axg: add audio clock controller support
@ 2018-04-25 16:32 ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:32 UTC (permalink / raw)
  To: Neil Armstrong, Carlo Caione, Kevin Hilman
  Cc: Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

The purpose of this patchset is to add support for the clock controller
dedicated to the audio subsystem found on A113 based SoCs

The series depends on the CLK_MUX_ROUND_CLOSEST fixes [0] and the duty
cycle support [1] making their way into CCF.

First patch is a clean-up of the meson clk Kconfig.
Then, there is 3 clock provider drivers for clocks found in the audio
The last 3 are for the clock controller itself.

[0]: https://lkml.kernel.org/r/152389589448.51482.15489333464741262913@swboyd.mtv.corp.google.com
[1]: https://lkml.kernel.org/r/20180420211141.28929-1-jbrunet@baylibre.com

Jerome Brunet (7):
  clk: meson: clean-up meson clock configuration
  clk: meson: add clk-phase clock driver
  clk: meson: add triple phase clock driver
  clk: meson: add axg audio sclk divider driver
  clk: meson: axg: export audio clock controller id bindings
  clk: meson: axg: document bindings for the audio clock controller
  clk: meson: axg: add the audio clock controller driver

 .../bindings/clock/amlogic,axg-audio-clkc.txt      |  56 ++
 drivers/clk/meson/Kconfig                          |  25 +-
 drivers/clk/meson/Makefile                         |   3 +
 drivers/clk/meson/axg-audio.c                      | 845 +++++++++++++++++++++
 drivers/clk/meson/axg-audio.h                      | 127 ++++
 drivers/clk/meson/clk-phase.c                      |  63 ++
 drivers/clk/meson/clk-triphase.c                   |  68 ++
 drivers/clk/meson/clkc-audio.h                     |  28 +
 drivers/clk/meson/clkc.h                           |   8 +
 drivers/clk/meson/sclk-div.c                       | 243 ++++++
 include/dt-bindings/clock/axg-audio-clkc.h         |  94 +++
 11 files changed, 1553 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
 create mode 100644 drivers/clk/meson/axg-audio.c
 create mode 100644 drivers/clk/meson/axg-audio.h
 create mode 100644 drivers/clk/meson/clk-phase.c
 create mode 100644 drivers/clk/meson/clk-triphase.c
 create mode 100644 drivers/clk/meson/clkc-audio.h
 create mode 100644 drivers/clk/meson/sclk-div.c
 create mode 100644 include/dt-bindings/clock/axg-audio-clkc.h

-- 
2.14.3

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 0/7] clk: meson: axg: add audio clock controller support
@ 2018-04-25 16:32 ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:32 UTC (permalink / raw)
  To: linus-amlogic

The purpose of this patchset is to add support for the clock controller
dedicated to the audio subsystem found on A113 based SoCs

The series depends on the CLK_MUX_ROUND_CLOSEST fixes [0] and the duty
cycle support [1] making their way into CCF.

First patch is a clean-up of the meson clk Kconfig.
Then, there is 3 clock provider drivers for clocks found in the audio
The last 3 are for the clock controller itself.

[0]: https://lkml.kernel.org/r/152389589448.51482.15489333464741262913 at swboyd.mtv.corp.google.com
[1]: https://lkml.kernel.org/r/20180420211141.28929-1-jbrunet at baylibre.com

Jerome Brunet (7):
  clk: meson: clean-up meson clock configuration
  clk: meson: add clk-phase clock driver
  clk: meson: add triple phase clock driver
  clk: meson: add axg audio sclk divider driver
  clk: meson: axg: export audio clock controller id bindings
  clk: meson: axg: document bindings for the audio clock controller
  clk: meson: axg: add the audio clock controller driver

 .../bindings/clock/amlogic,axg-audio-clkc.txt      |  56 ++
 drivers/clk/meson/Kconfig                          |  25 +-
 drivers/clk/meson/Makefile                         |   3 +
 drivers/clk/meson/axg-audio.c                      | 845 +++++++++++++++++++++
 drivers/clk/meson/axg-audio.h                      | 127 ++++
 drivers/clk/meson/clk-phase.c                      |  63 ++
 drivers/clk/meson/clk-triphase.c                   |  68 ++
 drivers/clk/meson/clkc-audio.h                     |  28 +
 drivers/clk/meson/clkc.h                           |   8 +
 drivers/clk/meson/sclk-div.c                       | 243 ++++++
 include/dt-bindings/clock/axg-audio-clkc.h         |  94 +++
 11 files changed, 1553 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
 create mode 100644 drivers/clk/meson/axg-audio.c
 create mode 100644 drivers/clk/meson/axg-audio.h
 create mode 100644 drivers/clk/meson/clk-phase.c
 create mode 100644 drivers/clk/meson/clk-triphase.c
 create mode 100644 drivers/clk/meson/clkc-audio.h
 create mode 100644 drivers/clk/meson/sclk-div.c
 create mode 100644 include/dt-bindings/clock/axg-audio-clkc.h

-- 
2.14.3

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 1/7] clk: meson: clean-up meson clock configuration
  2018-04-25 16:32 ` Jerome Brunet
@ 2018-04-25 16:32   ` Jerome Brunet
  -1 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:32 UTC (permalink / raw)
  To: Neil Armstrong, Carlo Caione, Kevin Hilman
  Cc: Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

Clean the dependencies in meson clock Kconfig.
CLK_AMLOGIC should actually select CLK_REGMAP_MESON which it uses. Also,
each platform should select CLK_AMLOGIC, so everything is properly turned
on when the platform Kconfig enable each configuration flag

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Kconfig | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index d5cbec522aec..87d69573e172 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -1,7 +1,7 @@
 config COMMON_CLK_AMLOGIC
 	bool
-	depends on OF
 	depends on ARCH_MESON || COMPILE_TEST
+	select COMMON_CLK_REGMAP_MESON
 
 config COMMON_CLK_REGMAP_MESON
 	bool
@@ -9,9 +9,8 @@ config COMMON_CLK_REGMAP_MESON
 
 config COMMON_CLK_MESON8B
 	bool
-	depends on COMMON_CLK_AMLOGIC
+	select COMMON_CLK_AMLOGIC
 	select RESET_CONTROLLER
-	select COMMON_CLK_REGMAP_MESON
 	help
 	  Support for the clock controller on AmLogic S802 (Meson8),
 	  S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
@@ -19,9 +18,8 @@ config COMMON_CLK_MESON8B
 
 config COMMON_CLK_GXBB
 	bool
-	depends on COMMON_CLK_AMLOGIC
+	select COMMON_CLK_AMLOGIC
 	select RESET_CONTROLLER
-	select COMMON_CLK_REGMAP_MESON
 	select MFD_SYSCON
 	help
 	  Support for the clock controller on AmLogic S905 devices, aka gxbb.
@@ -29,9 +27,8 @@ config COMMON_CLK_GXBB
 
 config COMMON_CLK_AXG
 	bool
-	depends on COMMON_CLK_AMLOGIC
+	select COMMON_CLK_AMLOGIC
 	select RESET_CONTROLLER
-	select COMMON_CLK_REGMAP_MESON
 	select MFD_SYSCON
 	help
 	  Support for the clock controller on AmLogic A113D devices, aka axg.
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 1/7] clk: meson: clean-up meson clock configuration
@ 2018-04-25 16:32   ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:32 UTC (permalink / raw)
  To: linus-amlogic

Clean the dependencies in meson clock Kconfig.
CLK_AMLOGIC should actually select CLK_REGMAP_MESON which it uses. Also,
each platform should select CLK_AMLOGIC, so everything is properly turned
on when the platform Kconfig enable each configuration flag

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Kconfig | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index d5cbec522aec..87d69573e172 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -1,7 +1,7 @@
 config COMMON_CLK_AMLOGIC
 	bool
-	depends on OF
 	depends on ARCH_MESON || COMPILE_TEST
+	select COMMON_CLK_REGMAP_MESON
 
 config COMMON_CLK_REGMAP_MESON
 	bool
@@ -9,9 +9,8 @@ config COMMON_CLK_REGMAP_MESON
 
 config COMMON_CLK_MESON8B
 	bool
-	depends on COMMON_CLK_AMLOGIC
+	select COMMON_CLK_AMLOGIC
 	select RESET_CONTROLLER
-	select COMMON_CLK_REGMAP_MESON
 	help
 	  Support for the clock controller on AmLogic S802 (Meson8),
 	  S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
@@ -19,9 +18,8 @@ config COMMON_CLK_MESON8B
 
 config COMMON_CLK_GXBB
 	bool
-	depends on COMMON_CLK_AMLOGIC
+	select COMMON_CLK_AMLOGIC
 	select RESET_CONTROLLER
-	select COMMON_CLK_REGMAP_MESON
 	select MFD_SYSCON
 	help
 	  Support for the clock controller on AmLogic S905 devices, aka gxbb.
@@ -29,9 +27,8 @@ config COMMON_CLK_GXBB
 
 config COMMON_CLK_AXG
 	bool
-	depends on COMMON_CLK_AMLOGIC
+	select COMMON_CLK_AMLOGIC
 	select RESET_CONTROLLER
-	select COMMON_CLK_REGMAP_MESON
 	select MFD_SYSCON
 	help
 	  Support for the clock controller on AmLogic A113D devices, aka axg.
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 2/7] clk: meson: add clk-phase clock driver
  2018-04-25 16:32 ` Jerome Brunet
@ 2018-04-25 16:32   ` Jerome Brunet
  -1 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:32 UTC (permalink / raw)
  To: Neil Armstrong, Carlo Caione, Kevin Hilman
  Cc: Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

Add a driver based meson clk-regmap to control clock phase on
amlogic SoCs

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Makefile    |  1 +
 drivers/clk/meson/clk-phase.c | 63 +++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/meson/clkc.h      |  8 ++++++
 3 files changed, 72 insertions(+)
 create mode 100644 drivers/clk/meson/clk-phase.c

diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index ffee82e60b7a..352fb848c406 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -3,6 +3,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_MESON8B) += meson8b.o
 obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
 obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c
new file mode 100644
index 000000000000..96e70497ef1b
--- /dev/null
+++ b/drivers/clk/meson/clk-phase.c
@@ -0,0 +1,63 @@
+// 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.h"
+
+#define phase_step(_width) (360 / (1 << (_width)))
+
+static inline struct meson_clk_phase_data *
+meson_clk_phase_data(struct clk_regmap *clk)
+{
+	return (struct meson_clk_phase_data *)clk->data;
+}
+
+int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
+{
+	return phase_step(width) * val;
+}
+EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val);
+
+unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
+{
+	unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width));
+
+	/*
+	 * This last calculation is here for cases when degrees is rounded
+	 * to 360, in which case val == (1 << width).
+	 */
+	return val % (1 << width);
+}
+EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val);
+
+static int meson_clk_phase_get_phase(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
+	unsigned int val;
+
+	val = meson_parm_read(clk->map, &phase->ph);
+
+	return meson_clk_degrees_from_val(val, phase->ph.width);
+}
+
+static int meson_clk_phase_set_phase(struct clk_hw *hw, int degrees)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
+	unsigned int val;
+
+	val = meson_clk_degrees_to_val(degrees, phase->ph.width);
+	meson_parm_write(clk->map, &phase->ph, val);
+
+	return 0;
+}
+
+const struct clk_ops meson_clk_phase_ops = {
+	.get_phase	= meson_clk_phase_get_phase,
+	.set_phase	= meson_clk_phase_set_phase,
+};
+EXPORT_SYMBOL_GPL(meson_clk_phase_ops);
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
index 8fe73c4edca8..9a17d6705e0a 100644
--- a/drivers/clk/meson/clkc.h
+++ b/drivers/clk/meson/clkc.h
@@ -104,6 +104,13 @@ struct meson_clk_audio_div_data {
 	u8 flags;
 };
 
+struct meson_clk_phase_data {
+	struct parm ph;
+};
+
+int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
+unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
+
 #define MESON_GATE(_name, _reg, _bit)					\
 struct clk_regmap _name = {						\
 	.data = &(struct clk_regmap_gate_data){				\
@@ -127,5 +134,6 @@ extern const struct clk_ops meson_clk_mpll_ro_ops;
 extern const struct clk_ops meson_clk_mpll_ops;
 extern const struct clk_ops meson_clk_audio_divider_ro_ops;
 extern const struct clk_ops meson_clk_audio_divider_ops;
+extern const struct clk_ops meson_clk_phase_ops;
 
 #endif /* __CLKC_H */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 2/7] clk: meson: add clk-phase clock driver
@ 2018-04-25 16:32   ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:32 UTC (permalink / raw)
  To: linus-amlogic

Add a driver based meson clk-regmap to control clock phase on
amlogic SoCs

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Makefile    |  1 +
 drivers/clk/meson/clk-phase.c | 63 +++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/meson/clkc.h      |  8 ++++++
 3 files changed, 72 insertions(+)
 create mode 100644 drivers/clk/meson/clk-phase.c

diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index ffee82e60b7a..352fb848c406 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -3,6 +3,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_MESON8B) += meson8b.o
 obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
 obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c
new file mode 100644
index 000000000000..96e70497ef1b
--- /dev/null
+++ b/drivers/clk/meson/clk-phase.c
@@ -0,0 +1,63 @@
+// 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.h"
+
+#define phase_step(_width) (360 / (1 << (_width)))
+
+static inline struct meson_clk_phase_data *
+meson_clk_phase_data(struct clk_regmap *clk)
+{
+	return (struct meson_clk_phase_data *)clk->data;
+}
+
+int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
+{
+	return phase_step(width) * val;
+}
+EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val);
+
+unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
+{
+	unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width));
+
+	/*
+	 * This last calculation is here for cases when degrees is rounded
+	 * to 360, in which case val == (1 << width).
+	 */
+	return val % (1 << width);
+}
+EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val);
+
+static int meson_clk_phase_get_phase(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
+	unsigned int val;
+
+	val = meson_parm_read(clk->map, &phase->ph);
+
+	return meson_clk_degrees_from_val(val, phase->ph.width);
+}
+
+static int meson_clk_phase_set_phase(struct clk_hw *hw, int degrees)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
+	unsigned int val;
+
+	val = meson_clk_degrees_to_val(degrees, phase->ph.width);
+	meson_parm_write(clk->map, &phase->ph, val);
+
+	return 0;
+}
+
+const struct clk_ops meson_clk_phase_ops = {
+	.get_phase	= meson_clk_phase_get_phase,
+	.set_phase	= meson_clk_phase_set_phase,
+};
+EXPORT_SYMBOL_GPL(meson_clk_phase_ops);
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
index 8fe73c4edca8..9a17d6705e0a 100644
--- a/drivers/clk/meson/clkc.h
+++ b/drivers/clk/meson/clkc.h
@@ -104,6 +104,13 @@ struct meson_clk_audio_div_data {
 	u8 flags;
 };
 
+struct meson_clk_phase_data {
+	struct parm ph;
+};
+
+int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
+unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
+
 #define MESON_GATE(_name, _reg, _bit)					\
 struct clk_regmap _name = {						\
 	.data = &(struct clk_regmap_gate_data){				\
@@ -127,5 +134,6 @@ extern const struct clk_ops meson_clk_mpll_ro_ops;
 extern const struct clk_ops meson_clk_mpll_ops;
 extern const struct clk_ops meson_clk_audio_divider_ro_ops;
 extern const struct clk_ops meson_clk_audio_divider_ops;
+extern const struct clk_ops meson_clk_phase_ops;
 
 #endif /* __CLKC_H */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 3/7] clk: meson: add triple phase clock driver
  2018-04-25 16:32 ` Jerome Brunet
@ 2018-04-25 16:33   ` Jerome Brunet
  -1 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: Neil Armstrong, Carlo Caione, Kevin Hilman
  Cc: Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

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.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Kconfig        |  5 +++
 drivers/clk/meson/Makefile       |  1 +
 drivers/clk/meson/clk-triphase.c | 68 ++++++++++++++++++++++++++++++++++++++++
 drivers/clk/meson/clkc-audio.h   | 20 ++++++++++++
 4 files changed, 94 insertions(+)
 create mode 100644 drivers/clk/meson/clk-triphase.c
 create mode 100644 drivers/clk/meson/clkc-audio.h

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 87d69573e172..7f7fd6fb3809 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -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_REGMAP_MESON
 	bool
 	select REGMAP
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 352fb848c406..64bb917fe1f0 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -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_MESON8B) += meson8b.o
 obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
 obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c
new file mode 100644
index 000000000000..9508c03c73c1
--- /dev/null
+++ b/drivers/clk/meson/clk-triphase.c
@@ -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
index 000000000000..286ff1201258
--- /dev/null
+++ b/drivers/clk/meson/clkc-audio.h
@@ -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 */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 3/7] clk: meson: add triple phase clock driver
@ 2018-04-25 16:33   ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: linus-amlogic

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.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Kconfig        |  5 +++
 drivers/clk/meson/Makefile       |  1 +
 drivers/clk/meson/clk-triphase.c | 68 ++++++++++++++++++++++++++++++++++++++++
 drivers/clk/meson/clkc-audio.h   | 20 ++++++++++++
 4 files changed, 94 insertions(+)
 create mode 100644 drivers/clk/meson/clk-triphase.c
 create mode 100644 drivers/clk/meson/clkc-audio.h

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 87d69573e172..7f7fd6fb3809 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -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_REGMAP_MESON
 	bool
 	select REGMAP
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 352fb848c406..64bb917fe1f0 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -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_MESON8B) += meson8b.o
 obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
 obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c
new file mode 100644
index 000000000000..9508c03c73c1
--- /dev/null
+++ b/drivers/clk/meson/clk-triphase.c
@@ -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
index 000000000000..286ff1201258
--- /dev/null
+++ b/drivers/clk/meson/clkc-audio.h
@@ -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 */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 4/7] clk: meson: add axg audio sclk divider driver
  2018-04-25 16:32 ` Jerome Brunet
@ 2018-04-25 16:33   ` Jerome Brunet
  -1 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: Neil Armstrong, Carlo Caione, Kevin Hilman
  Cc: Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

Add a driver to control the clock divider found in the sample clock
generator of the axg audio clock controller.

The sclk divider accumulates specific features which make the generic
divider unsuitable to control it:
- zero based divider (div = val + 1), but zero value gates the clock,
  so minimum divider value is 2.
- lrclk variant may adjust the duty cycle depending the divider value
  and the 'hi' value.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Makefile     |   2 +-
 drivers/clk/meson/clkc-audio.h |   8 ++
 drivers/clk/meson/sclk-div.c   | 243 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 252 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/meson/sclk-div.c

diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 64bb917fe1f0..f51b4754c31b 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -4,7 +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_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
 obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
 obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h
index 286ff1201258..0a7c157ebf81 100644
--- a/drivers/clk/meson/clkc-audio.h
+++ b/drivers/clk/meson/clkc-audio.h
@@ -15,6 +15,14 @@ struct meson_clk_triphase_data {
 	struct parm ph2;
 };
 
+struct meson_sclk_div_data {
+	struct parm div;
+	struct parm hi;
+	unsigned int cached_div;
+	struct clk_duty cached_duty;
+};
+
 extern const struct clk_ops meson_clk_triphase_ops;
+extern const struct clk_ops meson_sclk_div_ops;
 
 #endif /* __MESON_CLKC_AUDIO_H */
diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c
new file mode 100644
index 000000000000..8c0bc914a6d7
--- /dev/null
+++ b/drivers/clk/meson/sclk-div.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * Sample clock generator divider:
+ * This HW divider gates with value 0 but is otherwise a zero based divider:
+ *
+ * val >= 1
+ * divider = val + 1
+ *
+ * The duty cycle may also be set for the LR clock variant. The duty cycle
+ * ratio is:
+ *
+ * hi = [0 - val]
+ * duty_cycle = (1 + hi) / (1 + val)
+ */
+
+#include "clkc-audio.h"
+
+static inline struct meson_sclk_div_data *
+meson_sclk_div_data(struct clk_regmap *clk)
+{
+	return (struct meson_sclk_div_data *)clk->data;
+}
+
+static int sclk_div_maxval(struct meson_sclk_div_data *sclk)
+{
+	return (1 << sclk->div.width) - 1;
+}
+
+static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk)
+{
+	return sclk_div_maxval(sclk) + 1;
+}
+
+static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate,
+			   unsigned long prate, int maxdiv)
+{
+	int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate);
+
+	return clamp(div, 2, maxdiv);
+}
+
+static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate,
+			    unsigned long *prate,
+			    struct meson_sclk_div_data *sclk)
+{
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	int bestdiv = 0, i;
+	unsigned long maxdiv, now, parent_now;
+	unsigned long best = 0, best_parent = 0;
+
+	if (!rate)
+		rate = 1;
+
+	maxdiv = sclk_div_maxdiv(sclk);
+
+	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
+		return sclk_div_getdiv(hw, rate, *prate, maxdiv);
+
+	/*
+	 * The maximum divider we can use without overflowing
+	 * unsigned long in rate * i below
+	 */
+	maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+	for (i = 2; i <= maxdiv; i++) {
+		/*
+		 * It's the most ideal case if the requested rate can be
+		 * divided from parent clock without needing to change
+		 * parent rate, so return the divider immediately.
+		 */
+		if (rate * i == *prate)
+			return i;
+
+		parent_now = clk_hw_round_rate(parent, rate * i);
+		now = DIV_ROUND_UP_ULL((u64)parent_now, i);
+
+		if (abs(rate - now) < abs(rate - best)) {
+			bestdiv = i;
+			best = now;
+			best_parent = parent_now;
+		}
+	}
+
+	if (!bestdiv)
+		bestdiv = sclk_div_maxdiv(sclk);
+	else
+		*prate = best_parent;
+
+	return bestdiv;
+}
+
+static long sclk_div_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+	int div;
+
+	div = sclk_div_bestdiv(hw, rate, prate, sclk);
+
+	return DIV_ROUND_UP_ULL((u64)*prate, div);
+}
+
+static void sclk_apply_ratio(struct clk_regmap *clk,
+			     struct meson_sclk_div_data *sclk)
+{
+	unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div *
+					    sclk->cached_duty.num,
+					    sclk->cached_duty.den);
+
+	if (hi)
+		hi -= 1;
+
+	meson_parm_write(clk->map, &sclk->hi, hi);
+}
+
+static int sclk_div_set_duty_cycle(struct clk_hw *hw,
+				   struct clk_duty *duty)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	if (MESON_PARM_APPLICABLE(&sclk->hi)) {
+		memcpy(&sclk->cached_duty, duty, sizeof(*duty));
+		sclk_apply_ratio(clk, sclk);
+	}
+
+	return 0;
+}
+
+static int sclk_div_get_duty_cycle(struct clk_hw *hw,
+				   struct clk_duty *duty)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+	int hi;
+
+	if (!MESON_PARM_APPLICABLE(&sclk->hi)) {
+		duty->num = 1;
+		duty->den = 2;
+		return 0;
+	}
+
+	hi = meson_parm_read(clk->map, &sclk->hi);
+	duty->num = hi + 1;
+	duty->den = sclk->cached_div;
+	return 0;
+}
+
+static void sclk_apply_divider(struct clk_regmap *clk,
+			       struct meson_sclk_div_data *sclk)
+{
+	if (MESON_PARM_APPLICABLE(&sclk->hi))
+		sclk_apply_ratio(clk, sclk);
+
+	meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1);
+}
+
+static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
+			     unsigned long prate)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+	unsigned long maxdiv = sclk_div_maxdiv(sclk);
+
+	sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv);
+
+	if (clk_hw_is_enabled(hw))
+		sclk_apply_divider(clk, sclk);
+
+	return 0;
+}
+
+static unsigned long sclk_div_recalc_rate(struct clk_hw *hw,
+					  unsigned long prate)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	return DIV_ROUND_UP_ULL((u64)prate, sclk->cached_div);
+}
+
+static int sclk_div_enable(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	sclk_apply_divider(clk, sclk);
+
+	return 0;
+}
+
+static void sclk_div_disable(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	meson_parm_write(clk->map, &sclk->div, 0);
+}
+
+static int sclk_div_is_enabled(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	if (meson_parm_read(clk->map, &sclk->div))
+		return 1;
+
+	return 0;
+}
+
+static void sclk_div_init(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+	unsigned int val;
+
+	val = meson_parm_read(clk->map, &sclk->div);
+
+	/* if the divider is initially disabled, assume max */
+	if (!val)
+		sclk->cached_div = sclk_div_maxdiv(sclk);
+	else
+		sclk->cached_div = val + 1;
+
+	sclk_div_get_duty_cycle(hw, &sclk->cached_duty);
+}
+
+const struct clk_ops meson_sclk_div_ops = {
+	.recalc_rate	= sclk_div_recalc_rate,
+	.round_rate	= sclk_div_round_rate,
+	.set_rate	= sclk_div_set_rate,
+	.enable		= sclk_div_enable,
+	.disable	= sclk_div_disable,
+	.is_enabled	= sclk_div_is_enabled,
+	.get_duty_cycle	= sclk_div_get_duty_cycle,
+	.set_duty_cycle = sclk_div_set_duty_cycle,
+	.init		= sclk_div_init,
+};
+EXPORT_SYMBOL_GPL(meson_sclk_div_ops);
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 4/7] clk: meson: add axg audio sclk divider driver
@ 2018-04-25 16:33   ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: linus-amlogic

Add a driver to control the clock divider found in the sample clock
generator of the axg audio clock controller.

The sclk divider accumulates specific features which make the generic
divider unsuitable to control it:
- zero based divider (div = val + 1), but zero value gates the clock,
  so minimum divider value is 2.
- lrclk variant may adjust the duty cycle depending the divider value
  and the 'hi' value.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Makefile     |   2 +-
 drivers/clk/meson/clkc-audio.h |   8 ++
 drivers/clk/meson/sclk-div.c   | 243 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 252 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/meson/sclk-div.c

diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 64bb917fe1f0..f51b4754c31b 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -4,7 +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_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
 obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
 obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h
index 286ff1201258..0a7c157ebf81 100644
--- a/drivers/clk/meson/clkc-audio.h
+++ b/drivers/clk/meson/clkc-audio.h
@@ -15,6 +15,14 @@ struct meson_clk_triphase_data {
 	struct parm ph2;
 };
 
+struct meson_sclk_div_data {
+	struct parm div;
+	struct parm hi;
+	unsigned int cached_div;
+	struct clk_duty cached_duty;
+};
+
 extern const struct clk_ops meson_clk_triphase_ops;
+extern const struct clk_ops meson_sclk_div_ops;
 
 #endif /* __MESON_CLKC_AUDIO_H */
diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c
new file mode 100644
index 000000000000..8c0bc914a6d7
--- /dev/null
+++ b/drivers/clk/meson/sclk-div.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * Sample clock generator divider:
+ * This HW divider gates with value 0 but is otherwise a zero based divider:
+ *
+ * val >= 1
+ * divider = val + 1
+ *
+ * The duty cycle may also be set for the LR clock variant. The duty cycle
+ * ratio is:
+ *
+ * hi = [0 - val]
+ * duty_cycle = (1 + hi) / (1 + val)
+ */
+
+#include "clkc-audio.h"
+
+static inline struct meson_sclk_div_data *
+meson_sclk_div_data(struct clk_regmap *clk)
+{
+	return (struct meson_sclk_div_data *)clk->data;
+}
+
+static int sclk_div_maxval(struct meson_sclk_div_data *sclk)
+{
+	return (1 << sclk->div.width) - 1;
+}
+
+static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk)
+{
+	return sclk_div_maxval(sclk) + 1;
+}
+
+static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate,
+			   unsigned long prate, int maxdiv)
+{
+	int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate);
+
+	return clamp(div, 2, maxdiv);
+}
+
+static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate,
+			    unsigned long *prate,
+			    struct meson_sclk_div_data *sclk)
+{
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	int bestdiv = 0, i;
+	unsigned long maxdiv, now, parent_now;
+	unsigned long best = 0, best_parent = 0;
+
+	if (!rate)
+		rate = 1;
+
+	maxdiv = sclk_div_maxdiv(sclk);
+
+	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
+		return sclk_div_getdiv(hw, rate, *prate, maxdiv);
+
+	/*
+	 * The maximum divider we can use without overflowing
+	 * unsigned long in rate * i below
+	 */
+	maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+	for (i = 2; i <= maxdiv; i++) {
+		/*
+		 * It's the most ideal case if the requested rate can be
+		 * divided from parent clock without needing to change
+		 * parent rate, so return the divider immediately.
+		 */
+		if (rate * i == *prate)
+			return i;
+
+		parent_now = clk_hw_round_rate(parent, rate * i);
+		now = DIV_ROUND_UP_ULL((u64)parent_now, i);
+
+		if (abs(rate - now) < abs(rate - best)) {
+			bestdiv = i;
+			best = now;
+			best_parent = parent_now;
+		}
+	}
+
+	if (!bestdiv)
+		bestdiv = sclk_div_maxdiv(sclk);
+	else
+		*prate = best_parent;
+
+	return bestdiv;
+}
+
+static long sclk_div_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+	int div;
+
+	div = sclk_div_bestdiv(hw, rate, prate, sclk);
+
+	return DIV_ROUND_UP_ULL((u64)*prate, div);
+}
+
+static void sclk_apply_ratio(struct clk_regmap *clk,
+			     struct meson_sclk_div_data *sclk)
+{
+	unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div *
+					    sclk->cached_duty.num,
+					    sclk->cached_duty.den);
+
+	if (hi)
+		hi -= 1;
+
+	meson_parm_write(clk->map, &sclk->hi, hi);
+}
+
+static int sclk_div_set_duty_cycle(struct clk_hw *hw,
+				   struct clk_duty *duty)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	if (MESON_PARM_APPLICABLE(&sclk->hi)) {
+		memcpy(&sclk->cached_duty, duty, sizeof(*duty));
+		sclk_apply_ratio(clk, sclk);
+	}
+
+	return 0;
+}
+
+static int sclk_div_get_duty_cycle(struct clk_hw *hw,
+				   struct clk_duty *duty)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+	int hi;
+
+	if (!MESON_PARM_APPLICABLE(&sclk->hi)) {
+		duty->num = 1;
+		duty->den = 2;
+		return 0;
+	}
+
+	hi = meson_parm_read(clk->map, &sclk->hi);
+	duty->num = hi + 1;
+	duty->den = sclk->cached_div;
+	return 0;
+}
+
+static void sclk_apply_divider(struct clk_regmap *clk,
+			       struct meson_sclk_div_data *sclk)
+{
+	if (MESON_PARM_APPLICABLE(&sclk->hi))
+		sclk_apply_ratio(clk, sclk);
+
+	meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1);
+}
+
+static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
+			     unsigned long prate)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+	unsigned long maxdiv = sclk_div_maxdiv(sclk);
+
+	sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv);
+
+	if (clk_hw_is_enabled(hw))
+		sclk_apply_divider(clk, sclk);
+
+	return 0;
+}
+
+static unsigned long sclk_div_recalc_rate(struct clk_hw *hw,
+					  unsigned long prate)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	return DIV_ROUND_UP_ULL((u64)prate, sclk->cached_div);
+}
+
+static int sclk_div_enable(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	sclk_apply_divider(clk, sclk);
+
+	return 0;
+}
+
+static void sclk_div_disable(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	meson_parm_write(clk->map, &sclk->div, 0);
+}
+
+static int sclk_div_is_enabled(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+
+	if (meson_parm_read(clk->map, &sclk->div))
+		return 1;
+
+	return 0;
+}
+
+static void sclk_div_init(struct clk_hw *hw)
+{
+	struct clk_regmap *clk = to_clk_regmap(hw);
+	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
+	unsigned int val;
+
+	val = meson_parm_read(clk->map, &sclk->div);
+
+	/* if the divider is initially disabled, assume max */
+	if (!val)
+		sclk->cached_div = sclk_div_maxdiv(sclk);
+	else
+		sclk->cached_div = val + 1;
+
+	sclk_div_get_duty_cycle(hw, &sclk->cached_duty);
+}
+
+const struct clk_ops meson_sclk_div_ops = {
+	.recalc_rate	= sclk_div_recalc_rate,
+	.round_rate	= sclk_div_round_rate,
+	.set_rate	= sclk_div_set_rate,
+	.enable		= sclk_div_enable,
+	.disable	= sclk_div_disable,
+	.is_enabled	= sclk_div_is_enabled,
+	.get_duty_cycle	= sclk_div_get_duty_cycle,
+	.set_duty_cycle = sclk_div_set_duty_cycle,
+	.init		= sclk_div_init,
+};
+EXPORT_SYMBOL_GPL(meson_sclk_div_ops);
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 5/7] clk: meson: axg: export audio clock controller id bindings
  2018-04-25 16:32 ` Jerome Brunet
@ 2018-04-25 16:33   ` Jerome Brunet
  -1 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: Neil Armstrong, Carlo Caione, Kevin Hilman
  Cc: Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

export the clock ids dt-bindings usable by the consumers of the axg
audio clock controller

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 include/dt-bindings/clock/axg-audio-clkc.h | 94 ++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 include/dt-bindings/clock/axg-audio-clkc.h

diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h
new file mode 100644
index 000000000000..4426ae655858
--- /dev/null
+++ b/include/dt-bindings/clock/axg-audio-clkc.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Baylibre SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __AXG_AUDIO_CLKC_BINDINGS_H
+#define __AXG_AUDIO_CLKC_BINDINGS_H
+
+#define AUD_CLKID_SLV_SCLK0		9
+#define AUD_CLKID_SLV_SCLK1		10
+#define AUD_CLKID_SLV_SCLK2		11
+#define AUD_CLKID_SLV_SCLK3		12
+#define AUD_CLKID_SLV_SCLK4		13
+#define AUD_CLKID_SLV_SCLK5		14
+#define AUD_CLKID_SLV_SCLK6		15
+#define AUD_CLKID_SLV_SCLK7		16
+#define AUD_CLKID_SLV_SCLK8		17
+#define AUD_CLKID_SLV_SCLK9		18
+#define AUD_CLKID_SLV_LRCLK0		19
+#define AUD_CLKID_SLV_LRCLK1		20
+#define AUD_CLKID_SLV_LRCLK2		21
+#define AUD_CLKID_SLV_LRCLK3		22
+#define AUD_CLKID_SLV_LRCLK4		23
+#define AUD_CLKID_SLV_LRCLK5		24
+#define AUD_CLKID_SLV_LRCLK6		25
+#define AUD_CLKID_SLV_LRCLK7		26
+#define AUD_CLKID_SLV_LRCLK8		27
+#define AUD_CLKID_SLV_LRCLK9		28
+#define AUD_CLKID_DDR_ARB		29
+#define AUD_CLKID_PDM			30
+#define AUD_CLKID_TDMIN_A		31
+#define AUD_CLKID_TDMIN_B		32
+#define AUD_CLKID_TDMIN_C		33
+#define AUD_CLKID_TDMIN_LB		34
+#define AUD_CLKID_TDMOUT_A		35
+#define AUD_CLKID_TDMOUT_B		36
+#define AUD_CLKID_TDMOUT_C		37
+#define AUD_CLKID_FRDDR_A		38
+#define AUD_CLKID_FRDDR_B		39
+#define AUD_CLKID_FRDDR_C		40
+#define AUD_CLKID_TODDR_A		41
+#define AUD_CLKID_TODDR_B		42
+#define AUD_CLKID_TODDR_C		43
+#define AUD_CLKID_LOOPBACK		44
+#define AUD_CLKID_SPDIFIN		45
+#define AUD_CLKID_SPDIFOUT		46
+#define AUD_CLKID_RESAMPLE		47
+#define AUD_CLKID_POWER_DETECT		48
+#define AUD_CLKID_MST_A_MCLK		49
+#define AUD_CLKID_MST_B_MCLK		50
+#define AUD_CLKID_MST_C_MCLK		51
+#define AUD_CLKID_MST_D_MCLK		52
+#define AUD_CLKID_MST_E_MCLK		53
+#define AUD_CLKID_MST_F_MCLK		54
+#define AUD_CLKID_SPDIFOUT_CLK		55
+#define AUD_CLKID_SPDIFIN_CLK		56
+#define AUD_CLKID_PDM_DCLK		57
+#define AUD_CLKID_PDM_SYSCLK		58
+#define AUD_CLKID_MST_A_SCLK		79
+#define AUD_CLKID_MST_B_SCLK		80
+#define AUD_CLKID_MST_C_SCLK		81
+#define AUD_CLKID_MST_D_SCLK		82
+#define AUD_CLKID_MST_E_SCLK		83
+#define AUD_CLKID_MST_F_SCLK		84
+#define AUD_CLKID_MST_A_LRCLK		86
+#define AUD_CLKID_MST_B_LRCLK		87
+#define AUD_CLKID_MST_C_LRCLK		88
+#define AUD_CLKID_MST_D_LRCLK		89
+#define AUD_CLKID_MST_E_LRCLK		90
+#define AUD_CLKID_MST_F_LRCLK		91
+#define AUD_CLKID_TDMIN_A_SCLK_SEL	116
+#define AUD_CLKID_TDMIN_B_SCLK_SEL	117
+#define AUD_CLKID_TDMIN_C_SCLK_SEL	118
+#define AUD_CLKID_TDMIN_LB_SCLK_SEL	119
+#define AUD_CLKID_TDMOUT_A_SCLK_SEL	120
+#define AUD_CLKID_TDMOUT_B_SCLK_SEL	121
+#define AUD_CLKID_TDMOUT_C_SCLK_SEL	122
+#define AUD_CLKID_TDMIN_A_SCLK		123
+#define AUD_CLKID_TDMIN_B_SCLK		124
+#define AUD_CLKID_TDMIN_C_SCLK		125
+#define AUD_CLKID_TDMIN_LB_SCLK		126
+#define AUD_CLKID_TDMOUT_A_SCLK		127
+#define AUD_CLKID_TDMOUT_B_SCLK		128
+#define AUD_CLKID_TDMOUT_C_SCLK		129
+#define AUD_CLKID_TDMIN_A_LRCLK		130
+#define AUD_CLKID_TDMIN_B_LRCLK		131
+#define AUD_CLKID_TDMIN_C_LRCLK		132
+#define AUD_CLKID_TDMIN_LB_LRCLK	133
+#define AUD_CLKID_TDMOUT_A_LRCLK	134
+#define AUD_CLKID_TDMOUT_B_LRCLK	135
+#define AUD_CLKID_TDMOUT_C_LRCLK	136
+
+#endif /* __AXG_AUDIO_CLKC_BINDINGS_H */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 5/7] clk: meson: axg: export audio clock controller id bindings
@ 2018-04-25 16:33   ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: linus-amlogic

export the clock ids dt-bindings usable by the consumers of the axg
audio clock controller

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 include/dt-bindings/clock/axg-audio-clkc.h | 94 ++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 include/dt-bindings/clock/axg-audio-clkc.h

diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h
new file mode 100644
index 000000000000..4426ae655858
--- /dev/null
+++ b/include/dt-bindings/clock/axg-audio-clkc.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Baylibre SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __AXG_AUDIO_CLKC_BINDINGS_H
+#define __AXG_AUDIO_CLKC_BINDINGS_H
+
+#define AUD_CLKID_SLV_SCLK0		9
+#define AUD_CLKID_SLV_SCLK1		10
+#define AUD_CLKID_SLV_SCLK2		11
+#define AUD_CLKID_SLV_SCLK3		12
+#define AUD_CLKID_SLV_SCLK4		13
+#define AUD_CLKID_SLV_SCLK5		14
+#define AUD_CLKID_SLV_SCLK6		15
+#define AUD_CLKID_SLV_SCLK7		16
+#define AUD_CLKID_SLV_SCLK8		17
+#define AUD_CLKID_SLV_SCLK9		18
+#define AUD_CLKID_SLV_LRCLK0		19
+#define AUD_CLKID_SLV_LRCLK1		20
+#define AUD_CLKID_SLV_LRCLK2		21
+#define AUD_CLKID_SLV_LRCLK3		22
+#define AUD_CLKID_SLV_LRCLK4		23
+#define AUD_CLKID_SLV_LRCLK5		24
+#define AUD_CLKID_SLV_LRCLK6		25
+#define AUD_CLKID_SLV_LRCLK7		26
+#define AUD_CLKID_SLV_LRCLK8		27
+#define AUD_CLKID_SLV_LRCLK9		28
+#define AUD_CLKID_DDR_ARB		29
+#define AUD_CLKID_PDM			30
+#define AUD_CLKID_TDMIN_A		31
+#define AUD_CLKID_TDMIN_B		32
+#define AUD_CLKID_TDMIN_C		33
+#define AUD_CLKID_TDMIN_LB		34
+#define AUD_CLKID_TDMOUT_A		35
+#define AUD_CLKID_TDMOUT_B		36
+#define AUD_CLKID_TDMOUT_C		37
+#define AUD_CLKID_FRDDR_A		38
+#define AUD_CLKID_FRDDR_B		39
+#define AUD_CLKID_FRDDR_C		40
+#define AUD_CLKID_TODDR_A		41
+#define AUD_CLKID_TODDR_B		42
+#define AUD_CLKID_TODDR_C		43
+#define AUD_CLKID_LOOPBACK		44
+#define AUD_CLKID_SPDIFIN		45
+#define AUD_CLKID_SPDIFOUT		46
+#define AUD_CLKID_RESAMPLE		47
+#define AUD_CLKID_POWER_DETECT		48
+#define AUD_CLKID_MST_A_MCLK		49
+#define AUD_CLKID_MST_B_MCLK		50
+#define AUD_CLKID_MST_C_MCLK		51
+#define AUD_CLKID_MST_D_MCLK		52
+#define AUD_CLKID_MST_E_MCLK		53
+#define AUD_CLKID_MST_F_MCLK		54
+#define AUD_CLKID_SPDIFOUT_CLK		55
+#define AUD_CLKID_SPDIFIN_CLK		56
+#define AUD_CLKID_PDM_DCLK		57
+#define AUD_CLKID_PDM_SYSCLK		58
+#define AUD_CLKID_MST_A_SCLK		79
+#define AUD_CLKID_MST_B_SCLK		80
+#define AUD_CLKID_MST_C_SCLK		81
+#define AUD_CLKID_MST_D_SCLK		82
+#define AUD_CLKID_MST_E_SCLK		83
+#define AUD_CLKID_MST_F_SCLK		84
+#define AUD_CLKID_MST_A_LRCLK		86
+#define AUD_CLKID_MST_B_LRCLK		87
+#define AUD_CLKID_MST_C_LRCLK		88
+#define AUD_CLKID_MST_D_LRCLK		89
+#define AUD_CLKID_MST_E_LRCLK		90
+#define AUD_CLKID_MST_F_LRCLK		91
+#define AUD_CLKID_TDMIN_A_SCLK_SEL	116
+#define AUD_CLKID_TDMIN_B_SCLK_SEL	117
+#define AUD_CLKID_TDMIN_C_SCLK_SEL	118
+#define AUD_CLKID_TDMIN_LB_SCLK_SEL	119
+#define AUD_CLKID_TDMOUT_A_SCLK_SEL	120
+#define AUD_CLKID_TDMOUT_B_SCLK_SEL	121
+#define AUD_CLKID_TDMOUT_C_SCLK_SEL	122
+#define AUD_CLKID_TDMIN_A_SCLK		123
+#define AUD_CLKID_TDMIN_B_SCLK		124
+#define AUD_CLKID_TDMIN_C_SCLK		125
+#define AUD_CLKID_TDMIN_LB_SCLK		126
+#define AUD_CLKID_TDMOUT_A_SCLK		127
+#define AUD_CLKID_TDMOUT_B_SCLK		128
+#define AUD_CLKID_TDMOUT_C_SCLK		129
+#define AUD_CLKID_TDMIN_A_LRCLK		130
+#define AUD_CLKID_TDMIN_B_LRCLK		131
+#define AUD_CLKID_TDMIN_C_LRCLK		132
+#define AUD_CLKID_TDMIN_LB_LRCLK	133
+#define AUD_CLKID_TDMOUT_A_LRCLK	134
+#define AUD_CLKID_TDMOUT_B_LRCLK	135
+#define AUD_CLKID_TDMOUT_C_LRCLK	136
+
+#endif /* __AXG_AUDIO_CLKC_BINDINGS_H */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 6/7] clk: meson: axg: document bindings for the audio clock controller
  2018-04-25 16:32 ` Jerome Brunet
@ 2018-04-25 16:33   ` Jerome Brunet
  -1 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: Neil Armstrong, Carlo Caione, Kevin Hilman
  Cc: Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

Add documentation for the device tree bindings of the audio clock
controller of the A113 based SoCs

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 .../bindings/clock/amlogic,axg-audio-clkc.txt      | 56 ++++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt

diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
new file mode 100644
index 000000000000..1b989ceda567
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
@@ -0,0 +1,56 @@
+* Amlogic AXG Audio Clock Controllers
+
+The Amlogic AXG audio clock controller generates and supplies clock to the
+other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
+devices.
+
+Required Properties:
+
+- compatible	: should be "amlogic,axg-audio-clkc" for the A113X and A113D
+- reg		: physical base address of the clock controller and length of
+		  memory mapped region.
+- clocks	: a list of phandle + clock-specifier pairs for the clocks listed
+		  in clock-names.
+- clock-names	: must contain the following:
+		  * "pclk" - Main peripheral bus clock
+		  may contain the following:
+		  * "mst_in[0-7]" - 8 input plls to generate clock signals
+		  * "slv_sclk[0-9]" - 10 slave bit clocks provided by external
+				      components.
+		  * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external
+				       components.
+- reset		: phandle of the internal reset line
+- #clock-cells	: should be 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
+used in device tree sources.
+
+Example:
+
+clkc_audio: clock-controller {
+	compatible = "amlogic,axg-audio-clkc";
+	reg = <0x0 0x0 0x0 0xb4>;
+	#clock-cells = <1>;
+
+	clocks = <&clkc CLKID_AUDIO>,
+		 <&clkc CLKID_MPLL0>,
+		 <&clkc CLKID_MPLL1>,
+		 <&clkc CLKID_MPLL2>,
+		 <&clkc CLKID_MPLL3>,
+		 <&clkc CLKID_HIFI_PLL>,
+		 <&clkc CLKID_FCLK_DIV3>,
+		 <&clkc CLKID_FCLK_DIV4>,
+		 <&clkc CLKID_GP0_PLL>;
+	clock-names = "pclk",
+		      "mst_in0",
+		      "mst_in1",
+		      "mst_in2",
+		      "mst_in3",
+		      "mst_in4",
+		      "mst_in5",
+		      "mst_in6",
+		      "mst_in7";
+	resets = <&reset RESET_AUDIO>;
+};
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 6/7] clk: meson: axg: document bindings for the audio clock controller
@ 2018-04-25 16:33   ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: linus-amlogic

Add documentation for the device tree bindings of the audio clock
controller of the A113 based SoCs

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 .../bindings/clock/amlogic,axg-audio-clkc.txt      | 56 ++++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt

diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
new file mode 100644
index 000000000000..1b989ceda567
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
@@ -0,0 +1,56 @@
+* Amlogic AXG Audio Clock Controllers
+
+The Amlogic AXG audio clock controller generates and supplies clock to the
+other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
+devices.
+
+Required Properties:
+
+- compatible	: should be "amlogic,axg-audio-clkc" for the A113X and A113D
+- reg		: physical base address of the clock controller and length of
+		  memory mapped region.
+- clocks	: a list of phandle + clock-specifier pairs for the clocks listed
+		  in clock-names.
+- clock-names	: must contain the following:
+		  * "pclk" - Main peripheral bus clock
+		  may contain the following:
+		  * "mst_in[0-7]" - 8 input plls to generate clock signals
+		  * "slv_sclk[0-9]" - 10 slave bit clocks provided by external
+				      components.
+		  * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external
+				       components.
+- reset		: phandle of the internal reset line
+- #clock-cells	: should be 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
+used in device tree sources.
+
+Example:
+
+clkc_audio: clock-controller {
+	compatible = "amlogic,axg-audio-clkc";
+	reg = <0x0 0x0 0x0 0xb4>;
+	#clock-cells = <1>;
+
+	clocks = <&clkc CLKID_AUDIO>,
+		 <&clkc CLKID_MPLL0>,
+		 <&clkc CLKID_MPLL1>,
+		 <&clkc CLKID_MPLL2>,
+		 <&clkc CLKID_MPLL3>,
+		 <&clkc CLKID_HIFI_PLL>,
+		 <&clkc CLKID_FCLK_DIV3>,
+		 <&clkc CLKID_FCLK_DIV4>,
+		 <&clkc CLKID_GP0_PLL>;
+	clock-names = "pclk",
+		      "mst_in0",
+		      "mst_in1",
+		      "mst_in2",
+		      "mst_in3",
+		      "mst_in4",
+		      "mst_in5",
+		      "mst_in6",
+		      "mst_in7";
+	resets = <&reset RESET_AUDIO>;
+};
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
  2018-04-25 16:32 ` Jerome Brunet
@ 2018-04-25 16:33   ` Jerome Brunet
  -1 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: Neil Armstrong, Carlo Caione, Kevin Hilman
  Cc: Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

The axg audio clock controller is the clock generation unit for the
amlogic audio subsystem of A113 based SoCs. It may be clocked by 8
different plls provided by the primary clock controller and also by
10 slave bit clocks and 10 slave sample clocks which may be provided
by external components, such as audio codecs, through the SoC pads.

It contains several muxes, dividers and gates which are fed into the
the different devices of the audio subsystem.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Kconfig     |   9 +
 drivers/clk/meson/Makefile    |   1 +
 drivers/clk/meson/axg-audio.c | 845 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/meson/axg-audio.h | 127 +++++++
 4 files changed, 982 insertions(+)
 create mode 100644 drivers/clk/meson/axg-audio.c
 create mode 100644 drivers/clk/meson/axg-audio.h

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 7f7fd6fb3809..006fa1204e5b 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -38,3 +38,12 @@ config COMMON_CLK_AXG
 	help
 	  Support for the clock controller on AmLogic A113D devices, aka axg.
 	  Say Y if you want peripherals and CPU frequency scaling to work.
+
+config COMMON_CLK_AXG_AUDIO
+	tristate "Meson AXG Audio Clock Controller Driver"
+	depends on COMMON_CLK_AXG
+	select COMMON_CLK_AMLOGIC_AUDIO
+	select MFD_SYSCON
+	help
+	  Support for the audio clock controller on AmLogic A113D devices,
+	  aka axg, Say Y if you want audio subsystem to work.
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index f51b4754c31b..1ab89b627586 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
 obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
 obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
+obj-$(CONFIG_COMMON_CLK_AXG_AUDIO)	+= axg-audio.o
 obj-$(CONFIG_COMMON_CLK_REGMAP_MESON)	+= clk-regmap.o
diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
new file mode 100644
index 000000000000..830c13ccd819
--- /dev/null
+++ b/drivers/clk/meson/axg-audio.c
@@ -0,0 +1,845 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#include "clkc-audio.h"
+#include "axg-audio.h"
+
+#define AXG_MST_IN_COUNT	8
+#define AXG_SLV_SCLK_COUNT	10
+#define AXG_SLV_LRCLK_COUNT	10
+
+#define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags)		\
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct clk_regmap_gate_data){				\
+		.offset = (_reg),					\
+		.bit_idx = (_bit),					\
+	},								\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = "axg_"#_name,					\
+		.ops = &clk_regmap_gate_ops,				\
+		.parent_names = (const char *[]){ _pname },		\
+		.num_parents = 1,					\
+		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
+	},								\
+}
+
+#define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct clk_regmap_mux_data){				\
+		.offset = (_reg),					\
+		.mask = (_mask),					\
+		.shift = (_shift),					\
+		.flags = (_dflags),					\
+	},								\
+	.hw.init = &(struct clk_init_data){				\
+		.name = "axg_"#_name,					\
+		.ops = &clk_regmap_mux_ops,				\
+		.parent_names = (_pnames),				\
+		.num_parents = ARRAY_SIZE(_pnames),			\
+		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
+	},								\
+}
+
+#define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct clk_regmap_div_data){				\
+		.offset = (_reg),					\
+		.shift = (_shift),					\
+		.width = (_width),					\
+		.flags = (_dflags),					\
+	},								\
+	.hw.init = &(struct clk_init_data){				\
+		.name = "axg_"#_name,					\
+		.ops = &clk_regmap_divider_ops,				\
+		.parent_names = (const char *[]) { _pname },		\
+		.num_parents = 1,					\
+		.flags = (_iflags),					\
+	},								\
+}
+
+#define AXG_PCLK_GATE(_name, _bit)				\
+	AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0)
+
+/* Audio peripheral clocks */
+static AXG_PCLK_GATE(ddr_arb,	   0);
+static AXG_PCLK_GATE(pdm,	   1);
+static AXG_PCLK_GATE(tdmin_a,	   2);
+static AXG_PCLK_GATE(tdmin_b,	   3);
+static AXG_PCLK_GATE(tdmin_c,	   4);
+static AXG_PCLK_GATE(tdmin_lb,	   5);
+static AXG_PCLK_GATE(tdmout_a,	   6);
+static AXG_PCLK_GATE(tdmout_b,	   7);
+static AXG_PCLK_GATE(tdmout_c,	   8);
+static AXG_PCLK_GATE(frddr_a,	   9);
+static AXG_PCLK_GATE(frddr_b,	   10);
+static AXG_PCLK_GATE(frddr_c,	   11);
+static AXG_PCLK_GATE(toddr_a,	   12);
+static AXG_PCLK_GATE(toddr_b,	   13);
+static AXG_PCLK_GATE(toddr_c,	   14);
+static AXG_PCLK_GATE(loopback,	   15);
+static AXG_PCLK_GATE(spdifin,	   16);
+static AXG_PCLK_GATE(spdifout,	   17);
+static AXG_PCLK_GATE(resample,	   18);
+static AXG_PCLK_GATE(power_detect, 19);
+
+/* Audio Master Clocks */
+static const char * const mst_mux_parent_names[] = {
+	"axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3",
+	"axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7",
+};
+
+#define AXG_MST_MCLK_MUX(_name, _reg)					\
+	AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
+		    mst_mux_parent_names, CLK_SET_RATE_PARENT)
+
+static AXG_MST_MCLK_MUX(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
+static AXG_MST_MCLK_MUX(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
+static AXG_MST_MCLK_MUX(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
+static AXG_MST_MCLK_MUX(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
+static AXG_MST_MCLK_MUX(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
+static AXG_MST_MCLK_MUX(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
+static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
+static AXG_MST_MCLK_MUX(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
+static AXG_MST_MCLK_MUX(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
+static AXG_MST_MCLK_MUX(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
+
+#define AXG_MST_MCLK_DIV(_name, _reg)					\
+	AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
+		    "axg_"#_name"_sel", CLK_SET_RATE_PARENT)		\
+
+static AXG_MST_MCLK_DIV(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
+static AXG_MST_MCLK_DIV(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
+static AXG_MST_MCLK_DIV(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
+static AXG_MST_MCLK_DIV(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
+static AXG_MST_MCLK_DIV(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
+static AXG_MST_MCLK_DIV(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
+static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
+static AXG_MST_MCLK_DIV(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
+static AXG_MST_MCLK_DIV(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
+static AXG_MST_MCLK_DIV(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
+
+#define AXG_MST_MCLK_GATE(_name, _reg)					\
+	AXG_AUD_GATE(_name, _reg, 31,  "axg_"#_name"_div",		\
+		     CLK_SET_RATE_PARENT)
+
+static AXG_MST_MCLK_GATE(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
+static AXG_MST_MCLK_GATE(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
+static AXG_MST_MCLK_GATE(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
+static AXG_MST_MCLK_GATE(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
+static AXG_MST_MCLK_GATE(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
+static AXG_MST_MCLK_GATE(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
+static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
+static AXG_MST_MCLK_GATE(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
+static AXG_MST_MCLK_GATE(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
+static AXG_MST_MCLK_GATE(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
+
+/* Sample Clocks */
+#define AXG_MST_SCLK_PRE_EN(_name, _reg)			\
+	AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31,	\
+		     "axg_mst_"#_name"_mclk", 0)
+
+static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0);
+
+#define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width,		\
+			 _hi_shift, _hi_width, _pname, _iflags)		\
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct meson_sclk_div_data) {				\
+		.div = {						\
+			.reg_off = (_reg),				\
+			.shift   = (_div_shift),			\
+			.width   = (_div_width),			\
+		},							\
+		.hi = {							\
+			.reg_off = (_reg),				\
+			.shift   = (_hi_shift),				\
+			.width   = (_hi_width),				\
+		},							\
+	},								\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = "axg_"#_name,					\
+		.ops = &meson_sclk_div_ops,				\
+		.parent_names = (const char *[]) { _pname },		\
+		.num_parents = 1,					\
+		.flags = (_iflags),					\
+	},								\
+}
+
+#define AXG_MST_SCLK_DIV(_name, _reg)					\
+	AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0,	\
+			 "axg_mst_"#_name"_sclk_pre_en",		\
+			 CLK_SET_RATE_PARENT)
+
+static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
+
+#define AXG_MST_SCLK_POST_EN(_name, _reg)				\
+	AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30,		\
+		     "axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT)
+
+static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0);
+
+#define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \
+			 _pname, _iflags)				\
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct meson_clk_triphase_data) {			\
+		.ph0 = {						\
+			.reg_off = (_reg),				\
+			.shift   = (_shift0),				\
+			.width   = (_width),				\
+		},							\
+		.ph1 = {						\
+			.reg_off = (_reg),				\
+			.shift   = (_shift1),				\
+			.width   = (_width),				\
+		},							\
+		.ph2 = {						\
+			.reg_off = (_reg),				\
+			.shift   = (_shift2),				\
+			.width   = (_width),				\
+		},							\
+	},								\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = "axg_"#_name,					\
+		.ops = &meson_clk_triphase_ops,				\
+		.parent_names = (const char *[]) { _pname },		\
+		.num_parents = 1,					\
+		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
+	},								\
+}
+
+#define AXG_MST_SCLK(_name, _reg)					\
+	AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4,		\
+			 "axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT)
+
+static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1);
+static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1);
+static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1);
+static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1);
+static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1);
+static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1);
+
+#define AXG_MST_LRCLK_DIV(_name, _reg)					\
+	AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10,	\
+		    "axg_mst_"#_name"_sclk_post_en", 0)			\
+
+static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
+
+#define AXG_MST_LRCLK(_name, _reg)					\
+	AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5,		\
+			 "axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT)
+
+static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1);
+static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1);
+static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1);
+static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1);
+static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1);
+static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1);
+
+static const char * const tdm_sclk_parent_names[] = {
+	"axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk",
+	"axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk",
+	"axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2",
+	"axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5",
+	"axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8",
+	"axg_slv_sclk9"
+};
+
+#define AXG_TDM_SCLK_MUX(_name, _reg)				\
+	AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24,	\
+		    CLK_MUX_ROUND_CLOSEST,			\
+		    tdm_sclk_parent_names, 0)
+
+static AXG_TDM_SCLK_MUX(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_SCLK_MUX(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_SCLK_MUX(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+#define AXG_TDM_SCLK_PRE_EN(_name, _reg)				\
+	AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31,		\
+		     "axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT)
+
+static AXG_TDM_SCLK_PRE_EN(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_SCLK_PRE_EN(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_SCLK_PRE_EN(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+#define AXG_TDM_SCLK_POST_EN(_name, _reg)				\
+	AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30,		\
+		     "axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT)
+
+static AXG_TDM_SCLK_POST_EN(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_SCLK_POST_EN(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_SCLK_POST_EN(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+#define AXG_TDM_SCLK(_name, _reg)					\
+	struct clk_regmap axg_tdm##_name##_sclk = {			\
+	.data = &(struct meson_clk_phase_data) {			\
+		.ph = {							\
+			.reg_off = (_reg),				\
+			.shift   = 29,					\
+			.width   = 1,					\
+		},							\
+	},								\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = "axg_tdm"#_name"_sclk",				\
+		.ops = &meson_clk_phase_ops,				\
+		.parent_names = (const char *[])			\
+		{ "axg_tdm"#_name"_sclk_post_en" },			\
+		.num_parents = 1,					\
+		.flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT,	\
+	},								\
+}
+
+static AXG_TDM_SCLK(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_SCLK(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_SCLK(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+static const char * const tdm_lrclk_parent_names[] = {
+	"axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk",
+	"axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk",
+	"axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2",
+	"axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5",
+	"axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8",
+	"axg_slv_lrclk9"
+};
+
+#define AXG_TDM_LRLCK(_name, _reg)		       \
+	AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \
+		    CLK_MUX_ROUND_CLOSEST,	       \
+		    tdm_lrclk_parent_names, 0)
+
+static AXG_TDM_LRLCK(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_LRLCK(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_LRLCK(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+/*
+ * Array of all clocks provided by this provider
+ * The input clocks of the controller will be populated at runtime
+ */
+static struct clk_hw_onecell_data axg_audio_hw_onecell_data = {
+	.hws = {
+		[AUD_CLKID_DDR_ARB]		= &axg_ddr_arb.hw,
+		[AUD_CLKID_PDM]			= &axg_pdm.hw,
+		[AUD_CLKID_TDMIN_A]		= &axg_tdmin_a.hw,
+		[AUD_CLKID_TDMIN_B]		= &axg_tdmin_b.hw,
+		[AUD_CLKID_TDMIN_C]		= &axg_tdmin_c.hw,
+		[AUD_CLKID_TDMIN_LB]		= &axg_tdmin_lb.hw,
+		[AUD_CLKID_TDMOUT_A]		= &axg_tdmout_a.hw,
+		[AUD_CLKID_TDMOUT_B]		= &axg_tdmout_b.hw,
+		[AUD_CLKID_TDMOUT_C]		= &axg_tdmout_c.hw,
+		[AUD_CLKID_FRDDR_A]		= &axg_frddr_a.hw,
+		[AUD_CLKID_FRDDR_B]		= &axg_frddr_b.hw,
+		[AUD_CLKID_FRDDR_C]		= &axg_frddr_c.hw,
+		[AUD_CLKID_TODDR_A]		= &axg_toddr_a.hw,
+		[AUD_CLKID_TODDR_B]		= &axg_toddr_b.hw,
+		[AUD_CLKID_TODDR_C]		= &axg_toddr_c.hw,
+		[AUD_CLKID_LOOPBACK]		= &axg_loopback.hw,
+		[AUD_CLKID_SPDIFIN]		= &axg_spdifin.hw,
+		[AUD_CLKID_SPDIFOUT]		= &axg_spdifout.hw,
+		[AUD_CLKID_RESAMPLE]		= &axg_resample.hw,
+		[AUD_CLKID_POWER_DETECT]	= &axg_power_detect.hw,
+		[AUD_CLKID_MST_A_MCLK_SEL]	= &axg_mst_a_mclk_sel.hw,
+		[AUD_CLKID_MST_B_MCLK_SEL]	= &axg_mst_b_mclk_sel.hw,
+		[AUD_CLKID_MST_C_MCLK_SEL]	= &axg_mst_c_mclk_sel.hw,
+		[AUD_CLKID_MST_D_MCLK_SEL]	= &axg_mst_d_mclk_sel.hw,
+		[AUD_CLKID_MST_E_MCLK_SEL]	= &axg_mst_e_mclk_sel.hw,
+		[AUD_CLKID_MST_F_MCLK_SEL]	= &axg_mst_f_mclk_sel.hw,
+		[AUD_CLKID_MST_A_MCLK_DIV]	= &axg_mst_a_mclk_div.hw,
+		[AUD_CLKID_MST_B_MCLK_DIV]	= &axg_mst_b_mclk_div.hw,
+		[AUD_CLKID_MST_C_MCLK_DIV]	= &axg_mst_c_mclk_div.hw,
+		[AUD_CLKID_MST_D_MCLK_DIV]	= &axg_mst_d_mclk_div.hw,
+		[AUD_CLKID_MST_E_MCLK_DIV]	= &axg_mst_e_mclk_div.hw,
+		[AUD_CLKID_MST_F_MCLK_DIV]	= &axg_mst_f_mclk_div.hw,
+		[AUD_CLKID_MST_A_MCLK]		= &axg_mst_a_mclk.hw,
+		[AUD_CLKID_MST_B_MCLK]		= &axg_mst_b_mclk.hw,
+		[AUD_CLKID_MST_C_MCLK]		= &axg_mst_c_mclk.hw,
+		[AUD_CLKID_MST_D_MCLK]		= &axg_mst_d_mclk.hw,
+		[AUD_CLKID_MST_E_MCLK]		= &axg_mst_e_mclk.hw,
+		[AUD_CLKID_MST_F_MCLK]		= &axg_mst_f_mclk.hw,
+		[AUD_CLKID_SPDIFOUT_CLK_SEL]	= &axg_spdifout_clk_sel.hw,
+		[AUD_CLKID_SPDIFOUT_CLK_DIV]	= &axg_spdifout_clk_div.hw,
+		[AUD_CLKID_SPDIFOUT_CLK]	= &axg_spdifout_clk.hw,
+		[AUD_CLKID_SPDIFIN_CLK_SEL]	= &axg_spdifin_clk_sel.hw,
+		[AUD_CLKID_SPDIFIN_CLK_DIV]	= &axg_spdifin_clk_div.hw,
+		[AUD_CLKID_SPDIFIN_CLK]		= &axg_spdifin_clk.hw,
+		[AUD_CLKID_PDM_DCLK_SEL]	= &axg_pdm_dclk_sel.hw,
+		[AUD_CLKID_PDM_DCLK_DIV]	= &axg_pdm_dclk_div.hw,
+		[AUD_CLKID_PDM_DCLK]		= &axg_pdm_dclk.hw,
+		[AUD_CLKID_PDM_SYSCLK_SEL]	= &axg_pdm_sysclk_sel.hw,
+		[AUD_CLKID_PDM_SYSCLK_DIV]	= &axg_pdm_sysclk_div.hw,
+		[AUD_CLKID_PDM_SYSCLK]		= &axg_pdm_sysclk.hw,
+		[AUD_CLKID_MST_A_SCLK_PRE_EN]	= &axg_mst_a_sclk_pre_en.hw,
+		[AUD_CLKID_MST_B_SCLK_PRE_EN]	= &axg_mst_b_sclk_pre_en.hw,
+		[AUD_CLKID_MST_C_SCLK_PRE_EN]	= &axg_mst_c_sclk_pre_en.hw,
+		[AUD_CLKID_MST_D_SCLK_PRE_EN]	= &axg_mst_d_sclk_pre_en.hw,
+		[AUD_CLKID_MST_E_SCLK_PRE_EN]	= &axg_mst_e_sclk_pre_en.hw,
+		[AUD_CLKID_MST_F_SCLK_PRE_EN]	= &axg_mst_f_sclk_pre_en.hw,
+		[AUD_CLKID_MST_A_SCLK_DIV]	= &axg_mst_a_sclk_div.hw,
+		[AUD_CLKID_MST_B_SCLK_DIV]	= &axg_mst_b_sclk_div.hw,
+		[AUD_CLKID_MST_C_SCLK_DIV]	= &axg_mst_c_sclk_div.hw,
+		[AUD_CLKID_MST_D_SCLK_DIV]	= &axg_mst_d_sclk_div.hw,
+		[AUD_CLKID_MST_E_SCLK_DIV]	= &axg_mst_e_sclk_div.hw,
+		[AUD_CLKID_MST_F_SCLK_DIV]	= &axg_mst_f_sclk_div.hw,
+		[AUD_CLKID_MST_A_SCLK_POST_EN]	= &axg_mst_a_sclk_post_en.hw,
+		[AUD_CLKID_MST_B_SCLK_POST_EN]	= &axg_mst_b_sclk_post_en.hw,
+		[AUD_CLKID_MST_C_SCLK_POST_EN]	= &axg_mst_c_sclk_post_en.hw,
+		[AUD_CLKID_MST_D_SCLK_POST_EN]	= &axg_mst_d_sclk_post_en.hw,
+		[AUD_CLKID_MST_E_SCLK_POST_EN]	= &axg_mst_e_sclk_post_en.hw,
+		[AUD_CLKID_MST_F_SCLK_POST_EN]	= &axg_mst_f_sclk_post_en.hw,
+		[AUD_CLKID_MST_A_SCLK]		= &axg_mst_a_sclk.hw,
+		[AUD_CLKID_MST_B_SCLK]		= &axg_mst_b_sclk.hw,
+		[AUD_CLKID_MST_C_SCLK]		= &axg_mst_c_sclk.hw,
+		[AUD_CLKID_MST_D_SCLK]		= &axg_mst_d_sclk.hw,
+		[AUD_CLKID_MST_E_SCLK]		= &axg_mst_e_sclk.hw,
+		[AUD_CLKID_MST_F_SCLK]		= &axg_mst_f_sclk.hw,
+		[AUD_CLKID_MST_A_LRCLK_DIV]	= &axg_mst_a_lrclk_div.hw,
+		[AUD_CLKID_MST_B_LRCLK_DIV]	= &axg_mst_b_lrclk_div.hw,
+		[AUD_CLKID_MST_C_LRCLK_DIV]	= &axg_mst_c_lrclk_div.hw,
+		[AUD_CLKID_MST_D_LRCLK_DIV]	= &axg_mst_d_lrclk_div.hw,
+		[AUD_CLKID_MST_E_LRCLK_DIV]	= &axg_mst_e_lrclk_div.hw,
+		[AUD_CLKID_MST_F_LRCLK_DIV]	= &axg_mst_f_lrclk_div.hw,
+		[AUD_CLKID_MST_A_LRCLK]		= &axg_mst_a_lrclk.hw,
+		[AUD_CLKID_MST_B_LRCLK]		= &axg_mst_b_lrclk.hw,
+		[AUD_CLKID_MST_C_LRCLK]		= &axg_mst_c_lrclk.hw,
+		[AUD_CLKID_MST_D_LRCLK]		= &axg_mst_d_lrclk.hw,
+		[AUD_CLKID_MST_E_LRCLK]		= &axg_mst_e_lrclk.hw,
+		[AUD_CLKID_MST_F_LRCLK]		= &axg_mst_f_lrclk.hw,
+		[AUD_CLKID_TDMIN_A_SCLK_SEL]	= &axg_tdmin_a_sclk_sel.hw,
+		[AUD_CLKID_TDMIN_B_SCLK_SEL]	= &axg_tdmin_b_sclk_sel.hw,
+		[AUD_CLKID_TDMIN_C_SCLK_SEL]	= &axg_tdmin_c_sclk_sel.hw,
+		[AUD_CLKID_TDMIN_LB_SCLK_SEL]	= &axg_tdmin_lb_sclk_sel.hw,
+		[AUD_CLKID_TDMOUT_A_SCLK_SEL]	= &axg_tdmout_a_sclk_sel.hw,
+		[AUD_CLKID_TDMOUT_B_SCLK_SEL]	= &axg_tdmout_b_sclk_sel.hw,
+		[AUD_CLKID_TDMOUT_C_SCLK_SEL]	= &axg_tdmout_c_sclk_sel.hw,
+		[AUD_CLKID_TDMIN_A_SCLK_PRE_EN]	= &axg_tdmin_a_sclk_pre_en.hw,
+		[AUD_CLKID_TDMIN_B_SCLK_PRE_EN]	= &axg_tdmin_b_sclk_pre_en.hw,
+		[AUD_CLKID_TDMIN_C_SCLK_PRE_EN]	= &axg_tdmin_c_sclk_pre_en.hw,
+		[AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw,
+		[AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw,
+		[AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw,
+		[AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw,
+		[AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw,
+		[AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw,
+		[AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw,
+		[AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw,
+		[AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw,
+		[AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw,
+		[AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw,
+		[AUD_CLKID_TDMIN_A_SCLK]	= &axg_tdmin_a_sclk.hw,
+		[AUD_CLKID_TDMIN_B_SCLK]	= &axg_tdmin_b_sclk.hw,
+		[AUD_CLKID_TDMIN_C_SCLK]	= &axg_tdmin_c_sclk.hw,
+		[AUD_CLKID_TDMIN_LB_SCLK]	= &axg_tdmin_lb_sclk.hw,
+		[AUD_CLKID_TDMOUT_A_SCLK]	= &axg_tdmout_a_sclk.hw,
+		[AUD_CLKID_TDMOUT_B_SCLK]	= &axg_tdmout_b_sclk.hw,
+		[AUD_CLKID_TDMOUT_C_SCLK]	= &axg_tdmout_c_sclk.hw,
+		[AUD_CLKID_TDMIN_A_LRCLK]	= &axg_tdmin_a_lrclk.hw,
+		[AUD_CLKID_TDMIN_B_LRCLK]	= &axg_tdmin_b_lrclk.hw,
+		[AUD_CLKID_TDMIN_C_LRCLK]	= &axg_tdmin_c_lrclk.hw,
+		[AUD_CLKID_TDMIN_LB_LRCLK]	= &axg_tdmin_lb_lrclk.hw,
+		[AUD_CLKID_TDMOUT_A_LRCLK]	= &axg_tdmout_a_lrclk.hw,
+		[AUD_CLKID_TDMOUT_B_LRCLK]	= &axg_tdmout_b_lrclk.hw,
+		[AUD_CLKID_TDMOUT_C_LRCLK]	= &axg_tdmout_c_lrclk.hw,
+		[NR_CLKS] = NULL,
+	},
+	.num = NR_CLKS,
+};
+
+/* Convenience table to populate regmap in .probe() */
+static struct clk_regmap *const axg_audio_clk_regmaps[] = {
+	&axg_ddr_arb,
+	&axg_pdm,
+	&axg_tdmin_a,
+	&axg_tdmin_b,
+	&axg_tdmin_c,
+	&axg_tdmin_lb,
+	&axg_tdmout_a,
+	&axg_tdmout_b,
+	&axg_tdmout_c,
+	&axg_frddr_a,
+	&axg_frddr_b,
+	&axg_frddr_c,
+	&axg_toddr_a,
+	&axg_toddr_b,
+	&axg_toddr_c,
+	&axg_loopback,
+	&axg_spdifin,
+	&axg_spdifout,
+	&axg_resample,
+	&axg_power_detect,
+	&axg_mst_a_mclk_sel,
+	&axg_mst_b_mclk_sel,
+	&axg_mst_c_mclk_sel,
+	&axg_mst_d_mclk_sel,
+	&axg_mst_e_mclk_sel,
+	&axg_mst_f_mclk_sel,
+	&axg_mst_a_mclk_div,
+	&axg_mst_b_mclk_div,
+	&axg_mst_c_mclk_div,
+	&axg_mst_d_mclk_div,
+	&axg_mst_e_mclk_div,
+	&axg_mst_f_mclk_div,
+	&axg_mst_a_mclk,
+	&axg_mst_b_mclk,
+	&axg_mst_c_mclk,
+	&axg_mst_d_mclk,
+	&axg_mst_e_mclk,
+	&axg_mst_f_mclk,
+	&axg_spdifout_clk_sel,
+	&axg_spdifout_clk_div,
+	&axg_spdifout_clk,
+	&axg_spdifin_clk_sel,
+	&axg_spdifin_clk_div,
+	&axg_spdifin_clk,
+	&axg_pdm_dclk_sel,
+	&axg_pdm_dclk_div,
+	&axg_pdm_dclk,
+	&axg_pdm_sysclk_sel,
+	&axg_pdm_sysclk_div,
+	&axg_pdm_sysclk,
+	&axg_mst_a_sclk_pre_en,
+	&axg_mst_b_sclk_pre_en,
+	&axg_mst_c_sclk_pre_en,
+	&axg_mst_d_sclk_pre_en,
+	&axg_mst_e_sclk_pre_en,
+	&axg_mst_f_sclk_pre_en,
+	&axg_mst_a_sclk_div,
+	&axg_mst_b_sclk_div,
+	&axg_mst_c_sclk_div,
+	&axg_mst_d_sclk_div,
+	&axg_mst_e_sclk_div,
+	&axg_mst_f_sclk_div,
+	&axg_mst_a_sclk_post_en,
+	&axg_mst_b_sclk_post_en,
+	&axg_mst_c_sclk_post_en,
+	&axg_mst_d_sclk_post_en,
+	&axg_mst_e_sclk_post_en,
+	&axg_mst_f_sclk_post_en,
+	&axg_mst_a_sclk,
+	&axg_mst_b_sclk,
+	&axg_mst_c_sclk,
+	&axg_mst_d_sclk,
+	&axg_mst_e_sclk,
+	&axg_mst_f_sclk,
+	&axg_mst_a_lrclk_div,
+	&axg_mst_b_lrclk_div,
+	&axg_mst_c_lrclk_div,
+	&axg_mst_d_lrclk_div,
+	&axg_mst_e_lrclk_div,
+	&axg_mst_f_lrclk_div,
+	&axg_mst_a_lrclk,
+	&axg_mst_b_lrclk,
+	&axg_mst_c_lrclk,
+	&axg_mst_d_lrclk,
+	&axg_mst_e_lrclk,
+	&axg_mst_f_lrclk,
+	&axg_tdmin_a_sclk_sel,
+	&axg_tdmin_b_sclk_sel,
+	&axg_tdmin_c_sclk_sel,
+	&axg_tdmin_lb_sclk_sel,
+	&axg_tdmout_a_sclk_sel,
+	&axg_tdmout_b_sclk_sel,
+	&axg_tdmout_c_sclk_sel,
+	&axg_tdmin_a_sclk_pre_en,
+	&axg_tdmin_b_sclk_pre_en,
+	&axg_tdmin_c_sclk_pre_en,
+	&axg_tdmin_lb_sclk_pre_en,
+	&axg_tdmout_a_sclk_pre_en,
+	&axg_tdmout_b_sclk_pre_en,
+	&axg_tdmout_c_sclk_pre_en,
+	&axg_tdmin_a_sclk_post_en,
+	&axg_tdmin_b_sclk_post_en,
+	&axg_tdmin_c_sclk_post_en,
+	&axg_tdmin_lb_sclk_post_en,
+	&axg_tdmout_a_sclk_post_en,
+	&axg_tdmout_b_sclk_post_en,
+	&axg_tdmout_c_sclk_post_en,
+	&axg_tdmin_a_sclk,
+	&axg_tdmin_b_sclk,
+	&axg_tdmin_c_sclk,
+	&axg_tdmin_lb_sclk,
+	&axg_tdmout_a_sclk,
+	&axg_tdmout_b_sclk,
+	&axg_tdmout_c_sclk,
+	&axg_tdmin_a_lrclk,
+	&axg_tdmin_b_lrclk,
+	&axg_tdmin_c_lrclk,
+	&axg_tdmin_lb_lrclk,
+	&axg_tdmout_a_lrclk,
+	&axg_tdmout_b_lrclk,
+	&axg_tdmout_c_lrclk,
+};
+
+static struct clk *devm_clk_get_enable(struct device *dev, char *id)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = devm_clk_get(dev, id);
+	if (IS_ERR(clk)) {
+		if (PTR_ERR(clk) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get %s", id);
+		return clk;
+	}
+
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		dev_err(dev, "failed to enable %s", id);
+		return ERR_PTR(ret);
+	}
+
+	ret = devm_add_action_or_reset(dev,
+				       (void(*)(void *))clk_disable_unprepare,
+				       clk);
+	if (ret) {
+		dev_err(dev, "failed to add reset action on %s", id);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+static const struct clk_ops axg_clk_no_ops = {};
+
+static struct clk_hw *axg_clk_hw_register_bypass(struct device *dev,
+						 const char *name,
+						 const char *parent_name)
+{
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	char *clk_name;
+	int ret;
+
+	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
+	if (!hw)
+		return ERR_PTR(-ENOMEM);
+
+	clk_name = kasprintf(GFP_KERNEL, "axg_%s", name);
+	if (!clk_name)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = clk_name;
+	init.ops = &axg_clk_no_ops;
+	init.flags = 0;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+	hw->init = &init;
+
+	ret = devm_clk_hw_register(dev, hw);
+	kfree(clk_name);
+
+	return ret ? ERR_PTR(ret) : hw;
+}
+
+static int axg_register_clk_hw_input(struct device *dev,
+				     const char *name,
+				     unsigned int clkid)
+{
+	struct clk *parent_clk = devm_clk_get(dev, name);
+	struct clk_hw *hw = NULL;
+
+	if (IS_ERR(parent_clk)) {
+		int err = PTR_ERR(parent_clk);
+
+		/* It is ok if an input clock is missing */
+		if (err == -ENOENT) {
+			dev_dbg(dev, "%s not provided", name);
+		} else {
+			if (err != -EPROBE_DEFER)
+				dev_err(dev, "failed to get %s clock", name);
+			return err;
+		}
+	} else {
+		hw = axg_clk_hw_register_bypass(dev, name,
+						__clk_get_name(parent_clk));
+	}
+
+	if (IS_ERR(hw)) {
+		dev_err(dev, "failed to register %s clock", name);
+		return PTR_ERR(hw);
+	}
+
+	axg_audio_hw_onecell_data.hws[clkid] = hw;
+	return 0;
+}
+
+static int axg_register_clk_hw_inputs(struct device *dev,
+				      const char *basename,
+				      unsigned int count,
+				      unsigned int clkid)
+{
+	char *name;
+	int i, ret;
+
+	for (i = 0; i < count; i++) {
+		name = kasprintf(GFP_KERNEL, "%s%d", basename, i);
+		if (!name)
+			return -ENOMEM;
+
+		ret = axg_register_clk_hw_input(dev, name, clkid + i);
+		kfree(name);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct regmap_config axg_audio_regmap_cfg = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= AUDIO_CLK_PDMIN_CTRL1,
+};
+
+static int axg_audio_clkc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct regmap *map;
+	struct resource *res;
+	void __iomem *regs;
+	struct clk *clk;
+	struct clk_hw *hw;
+	int ret, i;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	map = devm_regmap_init_mmio(dev, regs, &axg_audio_regmap_cfg);
+	if (IS_ERR(map)) {
+		dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(map));
+		return PTR_ERR(map);
+	}
+
+	/* Get the mandatory peripheral clock */
+	clk = devm_clk_get_enable(dev, "pclk");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	ret = device_reset(dev);
+	if (ret) {
+		dev_err(dev, "failed to reset device\n");
+		return ret;
+	}
+
+	/* Register the peripheral input clock */
+	hw = axg_clk_hw_register_bypass(dev, "audio_pclk",
+					__clk_get_name(clk));
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw;
+
+	/* Register optional input master clocks */
+	ret = axg_register_clk_hw_inputs(dev, "mst_in",
+					 AXG_MST_IN_COUNT,
+					 AUD_CLKID_MST0);
+	if (ret)
+		return ret;
+
+	/* Register optional input slave sclks */
+	ret = axg_register_clk_hw_inputs(dev, "slv_sclk",
+					 AXG_SLV_SCLK_COUNT,
+					 AUD_CLKID_SLV_SCLK0);
+	if (ret)
+		return ret;
+
+	/* Register optional input slave lrclks */
+	ret = axg_register_clk_hw_inputs(dev, "slv_lrclk",
+					 AXG_SLV_LRCLK_COUNT,
+					 AUD_CLKID_SLV_LRCLK0);
+	if (ret)
+		return ret;
+
+	/* Populate regmap for the regmap backed clocks */
+	for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++)
+		axg_audio_clk_regmaps[i]->map = map;
+
+	/* Take care to skip the registered input clocks */
+	for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) {
+		hw = axg_audio_hw_onecell_data.hws[i];
+		/* array might be sparse */
+		if (!hw)
+			continue;
+
+		ret = devm_clk_hw_register(dev, hw);
+		if (ret) {
+			dev_err(dev, "failed to register clock %s\n",
+				hw->init->name);
+			return ret;
+		}
+	}
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+					   &axg_audio_hw_onecell_data);
+}
+
+static const struct of_device_id clkc_match_table[] = {
+	{ .compatible = "amlogic,axg-audio-clkc" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, clkc_match_table);
+
+static struct platform_driver axg_audio_driver = {
+	.probe		= axg_audio_clkc_probe,
+	.driver		= {
+		.name	= "axg-audio-clkc",
+		.of_match_table = clkc_match_table,
+	},
+};
+module_platform_driver(axg_audio_driver);
+
+MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h
new file mode 100644
index 000000000000..e7a0efd12429
--- /dev/null
+++ b/drivers/clk/meson/axg-audio.h
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __AXG_AUDIO_CLKC_H
+#define __AXG_AUDIO_CLKC_H
+
+/*
+ * Audio Clock  register offsets
+ *
+ * Register offsets from the datasheet must be multiplied by 4 before
+ * to get the right offset
+ */
+#define AUDIO_CLK_GATE_EN	0x000
+#define AUDIO_MCLK_A_CTRL	0x004
+#define AUDIO_MCLK_B_CTRL	0x008
+#define AUDIO_MCLK_C_CTRL	0x00C
+#define AUDIO_MCLK_D_CTRL	0x010
+#define AUDIO_MCLK_E_CTRL	0x014
+#define AUDIO_MCLK_F_CTRL	0x018
+#define AUDIO_MST_A_SCLK_CTRL0	0x040
+#define AUDIO_MST_A_SCLK_CTRL1	0x044
+#define AUDIO_MST_B_SCLK_CTRL0	0x048
+#define AUDIO_MST_B_SCLK_CTRL1	0x04C
+#define AUDIO_MST_C_SCLK_CTRL0	0x050
+#define AUDIO_MST_C_SCLK_CTRL1	0x054
+#define AUDIO_MST_D_SCLK_CTRL0	0x058
+#define AUDIO_MST_D_SCLK_CTRL1	0x05C
+#define AUDIO_MST_E_SCLK_CTRL0	0x060
+#define AUDIO_MST_E_SCLK_CTRL1	0x064
+#define AUDIO_MST_F_SCLK_CTRL0	0x068
+#define AUDIO_MST_F_SCLK_CTRL1	0x06C
+#define AUDIO_CLK_TDMIN_A_CTRL	0x080
+#define AUDIO_CLK_TDMIN_B_CTRL	0x084
+#define AUDIO_CLK_TDMIN_C_CTRL	0x088
+#define AUDIO_CLK_TDMIN_LB_CTRL 0x08C
+#define AUDIO_CLK_TDMOUT_A_CTRL 0x090
+#define AUDIO_CLK_TDMOUT_B_CTRL 0x094
+#define AUDIO_CLK_TDMOUT_C_CTRL 0x098
+#define AUDIO_CLK_SPDIFIN_CTRL	0x09C
+#define AUDIO_CLK_SPDIFOUT_CTRL 0x0A0
+#define AUDIO_CLK_RESAMPLE_CTRL 0x0A4
+#define AUDIO_CLK_LOCKER_CTRL	0x0A8
+#define AUDIO_CLK_PDMIN_CTRL0	0x0AC
+#define AUDIO_CLK_PDMIN_CTRL1	0x0B0
+
+/*
+ * CLKID index values
+ * These indices are entirely contrived and do not map onto the hardware.
+ */
+
+#define AUD_CLKID_PCLK			0
+#define AUD_CLKID_MST0			1
+#define AUD_CLKID_MST1			2
+#define AUD_CLKID_MST2			3
+#define AUD_CLKID_MST3			4
+#define AUD_CLKID_MST4			5
+#define AUD_CLKID_MST5			6
+#define AUD_CLKID_MST6			7
+#define AUD_CLKID_MST7			8
+#define AUD_CLKID_MST_A_MCLK_SEL	59
+#define AUD_CLKID_MST_B_MCLK_SEL	60
+#define AUD_CLKID_MST_C_MCLK_SEL	61
+#define AUD_CLKID_MST_D_MCLK_SEL	62
+#define AUD_CLKID_MST_E_MCLK_SEL	63
+#define AUD_CLKID_MST_F_MCLK_SEL	64
+#define AUD_CLKID_MST_A_MCLK_DIV	65
+#define AUD_CLKID_MST_B_MCLK_DIV	66
+#define AUD_CLKID_MST_C_MCLK_DIV	67
+#define AUD_CLKID_MST_D_MCLK_DIV	68
+#define AUD_CLKID_MST_E_MCLK_DIV	69
+#define AUD_CLKID_MST_F_MCLK_DIV	70
+#define AUD_CLKID_SPDIFOUT_CLK_SEL	71
+#define AUD_CLKID_SPDIFOUT_CLK_DIV	72
+#define AUD_CLKID_SPDIFIN_CLK_SEL	73
+#define AUD_CLKID_SPDIFIN_CLK_DIV	74
+#define AUD_CLKID_PDM_DCLK_SEL		75
+#define AUD_CLKID_PDM_DCLK_DIV		76
+#define AUD_CLKID_PDM_SYSCLK_SEL	77
+#define AUD_CLKID_PDM_SYSCLK_DIV	78
+#define AUD_CLKID_MST_A_SCLK_PRE_EN	92
+#define AUD_CLKID_MST_B_SCLK_PRE_EN	93
+#define AUD_CLKID_MST_C_SCLK_PRE_EN	94
+#define AUD_CLKID_MST_D_SCLK_PRE_EN	95
+#define AUD_CLKID_MST_E_SCLK_PRE_EN	96
+#define AUD_CLKID_MST_F_SCLK_PRE_EN	97
+#define AUD_CLKID_MST_A_SCLK_DIV	98
+#define AUD_CLKID_MST_B_SCLK_DIV	99
+#define AUD_CLKID_MST_C_SCLK_DIV	100
+#define AUD_CLKID_MST_D_SCLK_DIV	101
+#define AUD_CLKID_MST_E_SCLK_DIV	102
+#define AUD_CLKID_MST_F_SCLK_DIV	103
+#define AUD_CLKID_MST_A_SCLK_POST_EN	104
+#define AUD_CLKID_MST_B_SCLK_POST_EN	105
+#define AUD_CLKID_MST_C_SCLK_POST_EN	106
+#define AUD_CLKID_MST_D_SCLK_POST_EN	107
+#define AUD_CLKID_MST_E_SCLK_POST_EN	108
+#define AUD_CLKID_MST_F_SCLK_POST_EN	109
+#define AUD_CLKID_MST_A_LRCLK_DIV	110
+#define AUD_CLKID_MST_B_LRCLK_DIV	111
+#define AUD_CLKID_MST_C_LRCLK_DIV	112
+#define AUD_CLKID_MST_D_LRCLK_DIV	113
+#define AUD_CLKID_MST_E_LRCLK_DIV	114
+#define AUD_CLKID_MST_F_LRCLK_DIV	115
+#define AUD_CLKID_TDMIN_A_SCLK_PRE_EN	137
+#define AUD_CLKID_TDMIN_B_SCLK_PRE_EN	138
+#define AUD_CLKID_TDMIN_C_SCLK_PRE_EN	139
+#define AUD_CLKID_TDMIN_LB_SCLK_PRE_EN	140
+#define AUD_CLKID_TDMOUT_A_SCLK_PRE_EN	141
+#define AUD_CLKID_TDMOUT_B_SCLK_PRE_EN	142
+#define AUD_CLKID_TDMOUT_C_SCLK_PRE_EN	143
+#define AUD_CLKID_TDMIN_A_SCLK_POST_EN	144
+#define AUD_CLKID_TDMIN_B_SCLK_POST_EN	145
+#define AUD_CLKID_TDMIN_C_SCLK_POST_EN	146
+#define AUD_CLKID_TDMIN_LB_SCLK_POST_EN	147
+#define AUD_CLKID_TDMOUT_A_SCLK_POST_EN	148
+#define AUD_CLKID_TDMOUT_B_SCLK_POST_EN	149
+#define AUD_CLKID_TDMOUT_C_SCLK_POST_EN	150
+
+/* include the CLKIDs which are part of the DT bindings */
+#include <dt-bindings/clock/axg-audio-clkc.h>
+
+#define NR_CLKS	151
+
+#endif /*__AXG_AUDIO_CLKC_H */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
@ 2018-04-25 16:33   ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-04-25 16:33 UTC (permalink / raw)
  To: linus-amlogic

The axg audio clock controller is the clock generation unit for the
amlogic audio subsystem of A113 based SoCs. It may be clocked by 8
different plls provided by the primary clock controller and also by
10 slave bit clocks and 10 slave sample clocks which may be provided
by external components, such as audio codecs, through the SoC pads.

It contains several muxes, dividers and gates which are fed into the
the different devices of the audio subsystem.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 drivers/clk/meson/Kconfig     |   9 +
 drivers/clk/meson/Makefile    |   1 +
 drivers/clk/meson/axg-audio.c | 845 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/meson/axg-audio.h | 127 +++++++
 4 files changed, 982 insertions(+)
 create mode 100644 drivers/clk/meson/axg-audio.c
 create mode 100644 drivers/clk/meson/axg-audio.h

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 7f7fd6fb3809..006fa1204e5b 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -38,3 +38,12 @@ config COMMON_CLK_AXG
 	help
 	  Support for the clock controller on AmLogic A113D devices, aka axg.
 	  Say Y if you want peripherals and CPU frequency scaling to work.
+
+config COMMON_CLK_AXG_AUDIO
+	tristate "Meson AXG Audio Clock Controller Driver"
+	depends on COMMON_CLK_AXG
+	select COMMON_CLK_AMLOGIC_AUDIO
+	select MFD_SYSCON
+	help
+	  Support for the audio clock controller on AmLogic A113D devices,
+	  aka axg, Say Y if you want audio subsystem to work.
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index f51b4754c31b..1ab89b627586 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
 obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
 obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
+obj-$(CONFIG_COMMON_CLK_AXG_AUDIO)	+= axg-audio.o
 obj-$(CONFIG_COMMON_CLK_REGMAP_MESON)	+= clk-regmap.o
diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
new file mode 100644
index 000000000000..830c13ccd819
--- /dev/null
+++ b/drivers/clk/meson/axg-audio.c
@@ -0,0 +1,845 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#include "clkc-audio.h"
+#include "axg-audio.h"
+
+#define AXG_MST_IN_COUNT	8
+#define AXG_SLV_SCLK_COUNT	10
+#define AXG_SLV_LRCLK_COUNT	10
+
+#define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags)		\
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct clk_regmap_gate_data){				\
+		.offset = (_reg),					\
+		.bit_idx = (_bit),					\
+	},								\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = "axg_"#_name,					\
+		.ops = &clk_regmap_gate_ops,				\
+		.parent_names = (const char *[]){ _pname },		\
+		.num_parents = 1,					\
+		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
+	},								\
+}
+
+#define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct clk_regmap_mux_data){				\
+		.offset = (_reg),					\
+		.mask = (_mask),					\
+		.shift = (_shift),					\
+		.flags = (_dflags),					\
+	},								\
+	.hw.init = &(struct clk_init_data){				\
+		.name = "axg_"#_name,					\
+		.ops = &clk_regmap_mux_ops,				\
+		.parent_names = (_pnames),				\
+		.num_parents = ARRAY_SIZE(_pnames),			\
+		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
+	},								\
+}
+
+#define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct clk_regmap_div_data){				\
+		.offset = (_reg),					\
+		.shift = (_shift),					\
+		.width = (_width),					\
+		.flags = (_dflags),					\
+	},								\
+	.hw.init = &(struct clk_init_data){				\
+		.name = "axg_"#_name,					\
+		.ops = &clk_regmap_divider_ops,				\
+		.parent_names = (const char *[]) { _pname },		\
+		.num_parents = 1,					\
+		.flags = (_iflags),					\
+	},								\
+}
+
+#define AXG_PCLK_GATE(_name, _bit)				\
+	AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0)
+
+/* Audio peripheral clocks */
+static AXG_PCLK_GATE(ddr_arb,	   0);
+static AXG_PCLK_GATE(pdm,	   1);
+static AXG_PCLK_GATE(tdmin_a,	   2);
+static AXG_PCLK_GATE(tdmin_b,	   3);
+static AXG_PCLK_GATE(tdmin_c,	   4);
+static AXG_PCLK_GATE(tdmin_lb,	   5);
+static AXG_PCLK_GATE(tdmout_a,	   6);
+static AXG_PCLK_GATE(tdmout_b,	   7);
+static AXG_PCLK_GATE(tdmout_c,	   8);
+static AXG_PCLK_GATE(frddr_a,	   9);
+static AXG_PCLK_GATE(frddr_b,	   10);
+static AXG_PCLK_GATE(frddr_c,	   11);
+static AXG_PCLK_GATE(toddr_a,	   12);
+static AXG_PCLK_GATE(toddr_b,	   13);
+static AXG_PCLK_GATE(toddr_c,	   14);
+static AXG_PCLK_GATE(loopback,	   15);
+static AXG_PCLK_GATE(spdifin,	   16);
+static AXG_PCLK_GATE(spdifout,	   17);
+static AXG_PCLK_GATE(resample,	   18);
+static AXG_PCLK_GATE(power_detect, 19);
+
+/* Audio Master Clocks */
+static const char * const mst_mux_parent_names[] = {
+	"axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3",
+	"axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7",
+};
+
+#define AXG_MST_MCLK_MUX(_name, _reg)					\
+	AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
+		    mst_mux_parent_names, CLK_SET_RATE_PARENT)
+
+static AXG_MST_MCLK_MUX(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
+static AXG_MST_MCLK_MUX(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
+static AXG_MST_MCLK_MUX(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
+static AXG_MST_MCLK_MUX(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
+static AXG_MST_MCLK_MUX(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
+static AXG_MST_MCLK_MUX(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
+static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
+static AXG_MST_MCLK_MUX(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
+static AXG_MST_MCLK_MUX(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
+static AXG_MST_MCLK_MUX(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
+
+#define AXG_MST_MCLK_DIV(_name, _reg)					\
+	AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
+		    "axg_"#_name"_sel", CLK_SET_RATE_PARENT)		\
+
+static AXG_MST_MCLK_DIV(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
+static AXG_MST_MCLK_DIV(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
+static AXG_MST_MCLK_DIV(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
+static AXG_MST_MCLK_DIV(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
+static AXG_MST_MCLK_DIV(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
+static AXG_MST_MCLK_DIV(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
+static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
+static AXG_MST_MCLK_DIV(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
+static AXG_MST_MCLK_DIV(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
+static AXG_MST_MCLK_DIV(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
+
+#define AXG_MST_MCLK_GATE(_name, _reg)					\
+	AXG_AUD_GATE(_name, _reg, 31,  "axg_"#_name"_div",		\
+		     CLK_SET_RATE_PARENT)
+
+static AXG_MST_MCLK_GATE(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
+static AXG_MST_MCLK_GATE(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
+static AXG_MST_MCLK_GATE(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
+static AXG_MST_MCLK_GATE(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
+static AXG_MST_MCLK_GATE(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
+static AXG_MST_MCLK_GATE(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
+static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
+static AXG_MST_MCLK_GATE(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
+static AXG_MST_MCLK_GATE(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
+static AXG_MST_MCLK_GATE(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
+
+/* Sample Clocks */
+#define AXG_MST_SCLK_PRE_EN(_name, _reg)			\
+	AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31,	\
+		     "axg_mst_"#_name"_mclk", 0)
+
+static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0);
+static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0);
+
+#define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width,		\
+			 _hi_shift, _hi_width, _pname, _iflags)		\
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct meson_sclk_div_data) {				\
+		.div = {						\
+			.reg_off = (_reg),				\
+			.shift   = (_div_shift),			\
+			.width   = (_div_width),			\
+		},							\
+		.hi = {							\
+			.reg_off = (_reg),				\
+			.shift   = (_hi_shift),				\
+			.width   = (_hi_width),				\
+		},							\
+	},								\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = "axg_"#_name,					\
+		.ops = &meson_sclk_div_ops,				\
+		.parent_names = (const char *[]) { _pname },		\
+		.num_parents = 1,					\
+		.flags = (_iflags),					\
+	},								\
+}
+
+#define AXG_MST_SCLK_DIV(_name, _reg)					\
+	AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0,	\
+			 "axg_mst_"#_name"_sclk_pre_en",		\
+			 CLK_SET_RATE_PARENT)
+
+static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
+static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
+
+#define AXG_MST_SCLK_POST_EN(_name, _reg)				\
+	AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30,		\
+		     "axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT)
+
+static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0);
+static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0);
+
+#define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \
+			 _pname, _iflags)				\
+struct clk_regmap axg_##_name = {					\
+	.data = &(struct meson_clk_triphase_data) {			\
+		.ph0 = {						\
+			.reg_off = (_reg),				\
+			.shift   = (_shift0),				\
+			.width   = (_width),				\
+		},							\
+		.ph1 = {						\
+			.reg_off = (_reg),				\
+			.shift   = (_shift1),				\
+			.width   = (_width),				\
+		},							\
+		.ph2 = {						\
+			.reg_off = (_reg),				\
+			.shift   = (_shift2),				\
+			.width   = (_width),				\
+		},							\
+	},								\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = "axg_"#_name,					\
+		.ops = &meson_clk_triphase_ops,				\
+		.parent_names = (const char *[]) { _pname },		\
+		.num_parents = 1,					\
+		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
+	},								\
+}
+
+#define AXG_MST_SCLK(_name, _reg)					\
+	AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4,		\
+			 "axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT)
+
+static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1);
+static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1);
+static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1);
+static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1);
+static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1);
+static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1);
+
+#define AXG_MST_LRCLK_DIV(_name, _reg)					\
+	AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10,	\
+		    "axg_mst_"#_name"_sclk_post_en", 0)			\
+
+static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
+static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
+
+#define AXG_MST_LRCLK(_name, _reg)					\
+	AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5,		\
+			 "axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT)
+
+static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1);
+static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1);
+static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1);
+static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1);
+static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1);
+static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1);
+
+static const char * const tdm_sclk_parent_names[] = {
+	"axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk",
+	"axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk",
+	"axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2",
+	"axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5",
+	"axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8",
+	"axg_slv_sclk9"
+};
+
+#define AXG_TDM_SCLK_MUX(_name, _reg)				\
+	AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24,	\
+		    CLK_MUX_ROUND_CLOSEST,			\
+		    tdm_sclk_parent_names, 0)
+
+static AXG_TDM_SCLK_MUX(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_SCLK_MUX(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_SCLK_MUX(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+#define AXG_TDM_SCLK_PRE_EN(_name, _reg)				\
+	AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31,		\
+		     "axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT)
+
+static AXG_TDM_SCLK_PRE_EN(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_SCLK_PRE_EN(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_SCLK_PRE_EN(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+#define AXG_TDM_SCLK_POST_EN(_name, _reg)				\
+	AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30,		\
+		     "axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT)
+
+static AXG_TDM_SCLK_POST_EN(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_SCLK_POST_EN(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_SCLK_POST_EN(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+#define AXG_TDM_SCLK(_name, _reg)					\
+	struct clk_regmap axg_tdm##_name##_sclk = {			\
+	.data = &(struct meson_clk_phase_data) {			\
+		.ph = {							\
+			.reg_off = (_reg),				\
+			.shift   = 29,					\
+			.width   = 1,					\
+		},							\
+	},								\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = "axg_tdm"#_name"_sclk",				\
+		.ops = &meson_clk_phase_ops,				\
+		.parent_names = (const char *[])			\
+		{ "axg_tdm"#_name"_sclk_post_en" },			\
+		.num_parents = 1,					\
+		.flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT,	\
+	},								\
+}
+
+static AXG_TDM_SCLK(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_SCLK(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_SCLK(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+static const char * const tdm_lrclk_parent_names[] = {
+	"axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk",
+	"axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk",
+	"axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2",
+	"axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5",
+	"axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8",
+	"axg_slv_lrclk9"
+};
+
+#define AXG_TDM_LRLCK(_name, _reg)		       \
+	AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \
+		    CLK_MUX_ROUND_CLOSEST,	       \
+		    tdm_lrclk_parent_names, 0)
+
+static AXG_TDM_LRLCK(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
+static AXG_TDM_LRLCK(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
+static AXG_TDM_LRLCK(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
+static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
+static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
+static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
+static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
+
+/*
+ * Array of all clocks provided by this provider
+ * The input clocks of the controller will be populated at runtime
+ */
+static struct clk_hw_onecell_data axg_audio_hw_onecell_data = {
+	.hws = {
+		[AUD_CLKID_DDR_ARB]		= &axg_ddr_arb.hw,
+		[AUD_CLKID_PDM]			= &axg_pdm.hw,
+		[AUD_CLKID_TDMIN_A]		= &axg_tdmin_a.hw,
+		[AUD_CLKID_TDMIN_B]		= &axg_tdmin_b.hw,
+		[AUD_CLKID_TDMIN_C]		= &axg_tdmin_c.hw,
+		[AUD_CLKID_TDMIN_LB]		= &axg_tdmin_lb.hw,
+		[AUD_CLKID_TDMOUT_A]		= &axg_tdmout_a.hw,
+		[AUD_CLKID_TDMOUT_B]		= &axg_tdmout_b.hw,
+		[AUD_CLKID_TDMOUT_C]		= &axg_tdmout_c.hw,
+		[AUD_CLKID_FRDDR_A]		= &axg_frddr_a.hw,
+		[AUD_CLKID_FRDDR_B]		= &axg_frddr_b.hw,
+		[AUD_CLKID_FRDDR_C]		= &axg_frddr_c.hw,
+		[AUD_CLKID_TODDR_A]		= &axg_toddr_a.hw,
+		[AUD_CLKID_TODDR_B]		= &axg_toddr_b.hw,
+		[AUD_CLKID_TODDR_C]		= &axg_toddr_c.hw,
+		[AUD_CLKID_LOOPBACK]		= &axg_loopback.hw,
+		[AUD_CLKID_SPDIFIN]		= &axg_spdifin.hw,
+		[AUD_CLKID_SPDIFOUT]		= &axg_spdifout.hw,
+		[AUD_CLKID_RESAMPLE]		= &axg_resample.hw,
+		[AUD_CLKID_POWER_DETECT]	= &axg_power_detect.hw,
+		[AUD_CLKID_MST_A_MCLK_SEL]	= &axg_mst_a_mclk_sel.hw,
+		[AUD_CLKID_MST_B_MCLK_SEL]	= &axg_mst_b_mclk_sel.hw,
+		[AUD_CLKID_MST_C_MCLK_SEL]	= &axg_mst_c_mclk_sel.hw,
+		[AUD_CLKID_MST_D_MCLK_SEL]	= &axg_mst_d_mclk_sel.hw,
+		[AUD_CLKID_MST_E_MCLK_SEL]	= &axg_mst_e_mclk_sel.hw,
+		[AUD_CLKID_MST_F_MCLK_SEL]	= &axg_mst_f_mclk_sel.hw,
+		[AUD_CLKID_MST_A_MCLK_DIV]	= &axg_mst_a_mclk_div.hw,
+		[AUD_CLKID_MST_B_MCLK_DIV]	= &axg_mst_b_mclk_div.hw,
+		[AUD_CLKID_MST_C_MCLK_DIV]	= &axg_mst_c_mclk_div.hw,
+		[AUD_CLKID_MST_D_MCLK_DIV]	= &axg_mst_d_mclk_div.hw,
+		[AUD_CLKID_MST_E_MCLK_DIV]	= &axg_mst_e_mclk_div.hw,
+		[AUD_CLKID_MST_F_MCLK_DIV]	= &axg_mst_f_mclk_div.hw,
+		[AUD_CLKID_MST_A_MCLK]		= &axg_mst_a_mclk.hw,
+		[AUD_CLKID_MST_B_MCLK]		= &axg_mst_b_mclk.hw,
+		[AUD_CLKID_MST_C_MCLK]		= &axg_mst_c_mclk.hw,
+		[AUD_CLKID_MST_D_MCLK]		= &axg_mst_d_mclk.hw,
+		[AUD_CLKID_MST_E_MCLK]		= &axg_mst_e_mclk.hw,
+		[AUD_CLKID_MST_F_MCLK]		= &axg_mst_f_mclk.hw,
+		[AUD_CLKID_SPDIFOUT_CLK_SEL]	= &axg_spdifout_clk_sel.hw,
+		[AUD_CLKID_SPDIFOUT_CLK_DIV]	= &axg_spdifout_clk_div.hw,
+		[AUD_CLKID_SPDIFOUT_CLK]	= &axg_spdifout_clk.hw,
+		[AUD_CLKID_SPDIFIN_CLK_SEL]	= &axg_spdifin_clk_sel.hw,
+		[AUD_CLKID_SPDIFIN_CLK_DIV]	= &axg_spdifin_clk_div.hw,
+		[AUD_CLKID_SPDIFIN_CLK]		= &axg_spdifin_clk.hw,
+		[AUD_CLKID_PDM_DCLK_SEL]	= &axg_pdm_dclk_sel.hw,
+		[AUD_CLKID_PDM_DCLK_DIV]	= &axg_pdm_dclk_div.hw,
+		[AUD_CLKID_PDM_DCLK]		= &axg_pdm_dclk.hw,
+		[AUD_CLKID_PDM_SYSCLK_SEL]	= &axg_pdm_sysclk_sel.hw,
+		[AUD_CLKID_PDM_SYSCLK_DIV]	= &axg_pdm_sysclk_div.hw,
+		[AUD_CLKID_PDM_SYSCLK]		= &axg_pdm_sysclk.hw,
+		[AUD_CLKID_MST_A_SCLK_PRE_EN]	= &axg_mst_a_sclk_pre_en.hw,
+		[AUD_CLKID_MST_B_SCLK_PRE_EN]	= &axg_mst_b_sclk_pre_en.hw,
+		[AUD_CLKID_MST_C_SCLK_PRE_EN]	= &axg_mst_c_sclk_pre_en.hw,
+		[AUD_CLKID_MST_D_SCLK_PRE_EN]	= &axg_mst_d_sclk_pre_en.hw,
+		[AUD_CLKID_MST_E_SCLK_PRE_EN]	= &axg_mst_e_sclk_pre_en.hw,
+		[AUD_CLKID_MST_F_SCLK_PRE_EN]	= &axg_mst_f_sclk_pre_en.hw,
+		[AUD_CLKID_MST_A_SCLK_DIV]	= &axg_mst_a_sclk_div.hw,
+		[AUD_CLKID_MST_B_SCLK_DIV]	= &axg_mst_b_sclk_div.hw,
+		[AUD_CLKID_MST_C_SCLK_DIV]	= &axg_mst_c_sclk_div.hw,
+		[AUD_CLKID_MST_D_SCLK_DIV]	= &axg_mst_d_sclk_div.hw,
+		[AUD_CLKID_MST_E_SCLK_DIV]	= &axg_mst_e_sclk_div.hw,
+		[AUD_CLKID_MST_F_SCLK_DIV]	= &axg_mst_f_sclk_div.hw,
+		[AUD_CLKID_MST_A_SCLK_POST_EN]	= &axg_mst_a_sclk_post_en.hw,
+		[AUD_CLKID_MST_B_SCLK_POST_EN]	= &axg_mst_b_sclk_post_en.hw,
+		[AUD_CLKID_MST_C_SCLK_POST_EN]	= &axg_mst_c_sclk_post_en.hw,
+		[AUD_CLKID_MST_D_SCLK_POST_EN]	= &axg_mst_d_sclk_post_en.hw,
+		[AUD_CLKID_MST_E_SCLK_POST_EN]	= &axg_mst_e_sclk_post_en.hw,
+		[AUD_CLKID_MST_F_SCLK_POST_EN]	= &axg_mst_f_sclk_post_en.hw,
+		[AUD_CLKID_MST_A_SCLK]		= &axg_mst_a_sclk.hw,
+		[AUD_CLKID_MST_B_SCLK]		= &axg_mst_b_sclk.hw,
+		[AUD_CLKID_MST_C_SCLK]		= &axg_mst_c_sclk.hw,
+		[AUD_CLKID_MST_D_SCLK]		= &axg_mst_d_sclk.hw,
+		[AUD_CLKID_MST_E_SCLK]		= &axg_mst_e_sclk.hw,
+		[AUD_CLKID_MST_F_SCLK]		= &axg_mst_f_sclk.hw,
+		[AUD_CLKID_MST_A_LRCLK_DIV]	= &axg_mst_a_lrclk_div.hw,
+		[AUD_CLKID_MST_B_LRCLK_DIV]	= &axg_mst_b_lrclk_div.hw,
+		[AUD_CLKID_MST_C_LRCLK_DIV]	= &axg_mst_c_lrclk_div.hw,
+		[AUD_CLKID_MST_D_LRCLK_DIV]	= &axg_mst_d_lrclk_div.hw,
+		[AUD_CLKID_MST_E_LRCLK_DIV]	= &axg_mst_e_lrclk_div.hw,
+		[AUD_CLKID_MST_F_LRCLK_DIV]	= &axg_mst_f_lrclk_div.hw,
+		[AUD_CLKID_MST_A_LRCLK]		= &axg_mst_a_lrclk.hw,
+		[AUD_CLKID_MST_B_LRCLK]		= &axg_mst_b_lrclk.hw,
+		[AUD_CLKID_MST_C_LRCLK]		= &axg_mst_c_lrclk.hw,
+		[AUD_CLKID_MST_D_LRCLK]		= &axg_mst_d_lrclk.hw,
+		[AUD_CLKID_MST_E_LRCLK]		= &axg_mst_e_lrclk.hw,
+		[AUD_CLKID_MST_F_LRCLK]		= &axg_mst_f_lrclk.hw,
+		[AUD_CLKID_TDMIN_A_SCLK_SEL]	= &axg_tdmin_a_sclk_sel.hw,
+		[AUD_CLKID_TDMIN_B_SCLK_SEL]	= &axg_tdmin_b_sclk_sel.hw,
+		[AUD_CLKID_TDMIN_C_SCLK_SEL]	= &axg_tdmin_c_sclk_sel.hw,
+		[AUD_CLKID_TDMIN_LB_SCLK_SEL]	= &axg_tdmin_lb_sclk_sel.hw,
+		[AUD_CLKID_TDMOUT_A_SCLK_SEL]	= &axg_tdmout_a_sclk_sel.hw,
+		[AUD_CLKID_TDMOUT_B_SCLK_SEL]	= &axg_tdmout_b_sclk_sel.hw,
+		[AUD_CLKID_TDMOUT_C_SCLK_SEL]	= &axg_tdmout_c_sclk_sel.hw,
+		[AUD_CLKID_TDMIN_A_SCLK_PRE_EN]	= &axg_tdmin_a_sclk_pre_en.hw,
+		[AUD_CLKID_TDMIN_B_SCLK_PRE_EN]	= &axg_tdmin_b_sclk_pre_en.hw,
+		[AUD_CLKID_TDMIN_C_SCLK_PRE_EN]	= &axg_tdmin_c_sclk_pre_en.hw,
+		[AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw,
+		[AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw,
+		[AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw,
+		[AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw,
+		[AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw,
+		[AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw,
+		[AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw,
+		[AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw,
+		[AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw,
+		[AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw,
+		[AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw,
+		[AUD_CLKID_TDMIN_A_SCLK]	= &axg_tdmin_a_sclk.hw,
+		[AUD_CLKID_TDMIN_B_SCLK]	= &axg_tdmin_b_sclk.hw,
+		[AUD_CLKID_TDMIN_C_SCLK]	= &axg_tdmin_c_sclk.hw,
+		[AUD_CLKID_TDMIN_LB_SCLK]	= &axg_tdmin_lb_sclk.hw,
+		[AUD_CLKID_TDMOUT_A_SCLK]	= &axg_tdmout_a_sclk.hw,
+		[AUD_CLKID_TDMOUT_B_SCLK]	= &axg_tdmout_b_sclk.hw,
+		[AUD_CLKID_TDMOUT_C_SCLK]	= &axg_tdmout_c_sclk.hw,
+		[AUD_CLKID_TDMIN_A_LRCLK]	= &axg_tdmin_a_lrclk.hw,
+		[AUD_CLKID_TDMIN_B_LRCLK]	= &axg_tdmin_b_lrclk.hw,
+		[AUD_CLKID_TDMIN_C_LRCLK]	= &axg_tdmin_c_lrclk.hw,
+		[AUD_CLKID_TDMIN_LB_LRCLK]	= &axg_tdmin_lb_lrclk.hw,
+		[AUD_CLKID_TDMOUT_A_LRCLK]	= &axg_tdmout_a_lrclk.hw,
+		[AUD_CLKID_TDMOUT_B_LRCLK]	= &axg_tdmout_b_lrclk.hw,
+		[AUD_CLKID_TDMOUT_C_LRCLK]	= &axg_tdmout_c_lrclk.hw,
+		[NR_CLKS] = NULL,
+	},
+	.num = NR_CLKS,
+};
+
+/* Convenience table to populate regmap in .probe() */
+static struct clk_regmap *const axg_audio_clk_regmaps[] = {
+	&axg_ddr_arb,
+	&axg_pdm,
+	&axg_tdmin_a,
+	&axg_tdmin_b,
+	&axg_tdmin_c,
+	&axg_tdmin_lb,
+	&axg_tdmout_a,
+	&axg_tdmout_b,
+	&axg_tdmout_c,
+	&axg_frddr_a,
+	&axg_frddr_b,
+	&axg_frddr_c,
+	&axg_toddr_a,
+	&axg_toddr_b,
+	&axg_toddr_c,
+	&axg_loopback,
+	&axg_spdifin,
+	&axg_spdifout,
+	&axg_resample,
+	&axg_power_detect,
+	&axg_mst_a_mclk_sel,
+	&axg_mst_b_mclk_sel,
+	&axg_mst_c_mclk_sel,
+	&axg_mst_d_mclk_sel,
+	&axg_mst_e_mclk_sel,
+	&axg_mst_f_mclk_sel,
+	&axg_mst_a_mclk_div,
+	&axg_mst_b_mclk_div,
+	&axg_mst_c_mclk_div,
+	&axg_mst_d_mclk_div,
+	&axg_mst_e_mclk_div,
+	&axg_mst_f_mclk_div,
+	&axg_mst_a_mclk,
+	&axg_mst_b_mclk,
+	&axg_mst_c_mclk,
+	&axg_mst_d_mclk,
+	&axg_mst_e_mclk,
+	&axg_mst_f_mclk,
+	&axg_spdifout_clk_sel,
+	&axg_spdifout_clk_div,
+	&axg_spdifout_clk,
+	&axg_spdifin_clk_sel,
+	&axg_spdifin_clk_div,
+	&axg_spdifin_clk,
+	&axg_pdm_dclk_sel,
+	&axg_pdm_dclk_div,
+	&axg_pdm_dclk,
+	&axg_pdm_sysclk_sel,
+	&axg_pdm_sysclk_div,
+	&axg_pdm_sysclk,
+	&axg_mst_a_sclk_pre_en,
+	&axg_mst_b_sclk_pre_en,
+	&axg_mst_c_sclk_pre_en,
+	&axg_mst_d_sclk_pre_en,
+	&axg_mst_e_sclk_pre_en,
+	&axg_mst_f_sclk_pre_en,
+	&axg_mst_a_sclk_div,
+	&axg_mst_b_sclk_div,
+	&axg_mst_c_sclk_div,
+	&axg_mst_d_sclk_div,
+	&axg_mst_e_sclk_div,
+	&axg_mst_f_sclk_div,
+	&axg_mst_a_sclk_post_en,
+	&axg_mst_b_sclk_post_en,
+	&axg_mst_c_sclk_post_en,
+	&axg_mst_d_sclk_post_en,
+	&axg_mst_e_sclk_post_en,
+	&axg_mst_f_sclk_post_en,
+	&axg_mst_a_sclk,
+	&axg_mst_b_sclk,
+	&axg_mst_c_sclk,
+	&axg_mst_d_sclk,
+	&axg_mst_e_sclk,
+	&axg_mst_f_sclk,
+	&axg_mst_a_lrclk_div,
+	&axg_mst_b_lrclk_div,
+	&axg_mst_c_lrclk_div,
+	&axg_mst_d_lrclk_div,
+	&axg_mst_e_lrclk_div,
+	&axg_mst_f_lrclk_div,
+	&axg_mst_a_lrclk,
+	&axg_mst_b_lrclk,
+	&axg_mst_c_lrclk,
+	&axg_mst_d_lrclk,
+	&axg_mst_e_lrclk,
+	&axg_mst_f_lrclk,
+	&axg_tdmin_a_sclk_sel,
+	&axg_tdmin_b_sclk_sel,
+	&axg_tdmin_c_sclk_sel,
+	&axg_tdmin_lb_sclk_sel,
+	&axg_tdmout_a_sclk_sel,
+	&axg_tdmout_b_sclk_sel,
+	&axg_tdmout_c_sclk_sel,
+	&axg_tdmin_a_sclk_pre_en,
+	&axg_tdmin_b_sclk_pre_en,
+	&axg_tdmin_c_sclk_pre_en,
+	&axg_tdmin_lb_sclk_pre_en,
+	&axg_tdmout_a_sclk_pre_en,
+	&axg_tdmout_b_sclk_pre_en,
+	&axg_tdmout_c_sclk_pre_en,
+	&axg_tdmin_a_sclk_post_en,
+	&axg_tdmin_b_sclk_post_en,
+	&axg_tdmin_c_sclk_post_en,
+	&axg_tdmin_lb_sclk_post_en,
+	&axg_tdmout_a_sclk_post_en,
+	&axg_tdmout_b_sclk_post_en,
+	&axg_tdmout_c_sclk_post_en,
+	&axg_tdmin_a_sclk,
+	&axg_tdmin_b_sclk,
+	&axg_tdmin_c_sclk,
+	&axg_tdmin_lb_sclk,
+	&axg_tdmout_a_sclk,
+	&axg_tdmout_b_sclk,
+	&axg_tdmout_c_sclk,
+	&axg_tdmin_a_lrclk,
+	&axg_tdmin_b_lrclk,
+	&axg_tdmin_c_lrclk,
+	&axg_tdmin_lb_lrclk,
+	&axg_tdmout_a_lrclk,
+	&axg_tdmout_b_lrclk,
+	&axg_tdmout_c_lrclk,
+};
+
+static struct clk *devm_clk_get_enable(struct device *dev, char *id)
+{
+	struct clk *clk;
+	int ret;
+
+	clk = devm_clk_get(dev, id);
+	if (IS_ERR(clk)) {
+		if (PTR_ERR(clk) != -EPROBE_DEFER)
+			dev_err(dev, "failed to get %s", id);
+		return clk;
+	}
+
+	ret = clk_prepare_enable(clk);
+	if (ret) {
+		dev_err(dev, "failed to enable %s", id);
+		return ERR_PTR(ret);
+	}
+
+	ret = devm_add_action_or_reset(dev,
+				       (void(*)(void *))clk_disable_unprepare,
+				       clk);
+	if (ret) {
+		dev_err(dev, "failed to add reset action on %s", id);
+		return ERR_PTR(ret);
+	}
+
+	return clk;
+}
+
+static const struct clk_ops axg_clk_no_ops = {};
+
+static struct clk_hw *axg_clk_hw_register_bypass(struct device *dev,
+						 const char *name,
+						 const char *parent_name)
+{
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	char *clk_name;
+	int ret;
+
+	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
+	if (!hw)
+		return ERR_PTR(-ENOMEM);
+
+	clk_name = kasprintf(GFP_KERNEL, "axg_%s", name);
+	if (!clk_name)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = clk_name;
+	init.ops = &axg_clk_no_ops;
+	init.flags = 0;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+	hw->init = &init;
+
+	ret = devm_clk_hw_register(dev, hw);
+	kfree(clk_name);
+
+	return ret ? ERR_PTR(ret) : hw;
+}
+
+static int axg_register_clk_hw_input(struct device *dev,
+				     const char *name,
+				     unsigned int clkid)
+{
+	struct clk *parent_clk = devm_clk_get(dev, name);
+	struct clk_hw *hw = NULL;
+
+	if (IS_ERR(parent_clk)) {
+		int err = PTR_ERR(parent_clk);
+
+		/* It is ok if an input clock is missing */
+		if (err == -ENOENT) {
+			dev_dbg(dev, "%s not provided", name);
+		} else {
+			if (err != -EPROBE_DEFER)
+				dev_err(dev, "failed to get %s clock", name);
+			return err;
+		}
+	} else {
+		hw = axg_clk_hw_register_bypass(dev, name,
+						__clk_get_name(parent_clk));
+	}
+
+	if (IS_ERR(hw)) {
+		dev_err(dev, "failed to register %s clock", name);
+		return PTR_ERR(hw);
+	}
+
+	axg_audio_hw_onecell_data.hws[clkid] = hw;
+	return 0;
+}
+
+static int axg_register_clk_hw_inputs(struct device *dev,
+				      const char *basename,
+				      unsigned int count,
+				      unsigned int clkid)
+{
+	char *name;
+	int i, ret;
+
+	for (i = 0; i < count; i++) {
+		name = kasprintf(GFP_KERNEL, "%s%d", basename, i);
+		if (!name)
+			return -ENOMEM;
+
+		ret = axg_register_clk_hw_input(dev, name, clkid + i);
+		kfree(name);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct regmap_config axg_audio_regmap_cfg = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= AUDIO_CLK_PDMIN_CTRL1,
+};
+
+static int axg_audio_clkc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct regmap *map;
+	struct resource *res;
+	void __iomem *regs;
+	struct clk *clk;
+	struct clk_hw *hw;
+	int ret, i;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	map = devm_regmap_init_mmio(dev, regs, &axg_audio_regmap_cfg);
+	if (IS_ERR(map)) {
+		dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(map));
+		return PTR_ERR(map);
+	}
+
+	/* Get the mandatory peripheral clock */
+	clk = devm_clk_get_enable(dev, "pclk");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	ret = device_reset(dev);
+	if (ret) {
+		dev_err(dev, "failed to reset device\n");
+		return ret;
+	}
+
+	/* Register the peripheral input clock */
+	hw = axg_clk_hw_register_bypass(dev, "audio_pclk",
+					__clk_get_name(clk));
+	if (IS_ERR(hw))
+		return PTR_ERR(hw);
+
+	axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw;
+
+	/* Register optional input master clocks */
+	ret = axg_register_clk_hw_inputs(dev, "mst_in",
+					 AXG_MST_IN_COUNT,
+					 AUD_CLKID_MST0);
+	if (ret)
+		return ret;
+
+	/* Register optional input slave sclks */
+	ret = axg_register_clk_hw_inputs(dev, "slv_sclk",
+					 AXG_SLV_SCLK_COUNT,
+					 AUD_CLKID_SLV_SCLK0);
+	if (ret)
+		return ret;
+
+	/* Register optional input slave lrclks */
+	ret = axg_register_clk_hw_inputs(dev, "slv_lrclk",
+					 AXG_SLV_LRCLK_COUNT,
+					 AUD_CLKID_SLV_LRCLK0);
+	if (ret)
+		return ret;
+
+	/* Populate regmap for the regmap backed clocks */
+	for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++)
+		axg_audio_clk_regmaps[i]->map = map;
+
+	/* Take care to skip the registered input clocks */
+	for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) {
+		hw = axg_audio_hw_onecell_data.hws[i];
+		/* array might be sparse */
+		if (!hw)
+			continue;
+
+		ret = devm_clk_hw_register(dev, hw);
+		if (ret) {
+			dev_err(dev, "failed to register clock %s\n",
+				hw->init->name);
+			return ret;
+		}
+	}
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+					   &axg_audio_hw_onecell_data);
+}
+
+static const struct of_device_id clkc_match_table[] = {
+	{ .compatible = "amlogic,axg-audio-clkc" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, clkc_match_table);
+
+static struct platform_driver axg_audio_driver = {
+	.probe		= axg_audio_clkc_probe,
+	.driver		= {
+		.name	= "axg-audio-clkc",
+		.of_match_table = clkc_match_table,
+	},
+};
+module_platform_driver(axg_audio_driver);
+
+MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h
new file mode 100644
index 000000000000..e7a0efd12429
--- /dev/null
+++ b/drivers/clk/meson/axg-audio.h
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __AXG_AUDIO_CLKC_H
+#define __AXG_AUDIO_CLKC_H
+
+/*
+ * Audio Clock  register offsets
+ *
+ * Register offsets from the datasheet must be multiplied by 4 before
+ * to get the right offset
+ */
+#define AUDIO_CLK_GATE_EN	0x000
+#define AUDIO_MCLK_A_CTRL	0x004
+#define AUDIO_MCLK_B_CTRL	0x008
+#define AUDIO_MCLK_C_CTRL	0x00C
+#define AUDIO_MCLK_D_CTRL	0x010
+#define AUDIO_MCLK_E_CTRL	0x014
+#define AUDIO_MCLK_F_CTRL	0x018
+#define AUDIO_MST_A_SCLK_CTRL0	0x040
+#define AUDIO_MST_A_SCLK_CTRL1	0x044
+#define AUDIO_MST_B_SCLK_CTRL0	0x048
+#define AUDIO_MST_B_SCLK_CTRL1	0x04C
+#define AUDIO_MST_C_SCLK_CTRL0	0x050
+#define AUDIO_MST_C_SCLK_CTRL1	0x054
+#define AUDIO_MST_D_SCLK_CTRL0	0x058
+#define AUDIO_MST_D_SCLK_CTRL1	0x05C
+#define AUDIO_MST_E_SCLK_CTRL0	0x060
+#define AUDIO_MST_E_SCLK_CTRL1	0x064
+#define AUDIO_MST_F_SCLK_CTRL0	0x068
+#define AUDIO_MST_F_SCLK_CTRL1	0x06C
+#define AUDIO_CLK_TDMIN_A_CTRL	0x080
+#define AUDIO_CLK_TDMIN_B_CTRL	0x084
+#define AUDIO_CLK_TDMIN_C_CTRL	0x088
+#define AUDIO_CLK_TDMIN_LB_CTRL 0x08C
+#define AUDIO_CLK_TDMOUT_A_CTRL 0x090
+#define AUDIO_CLK_TDMOUT_B_CTRL 0x094
+#define AUDIO_CLK_TDMOUT_C_CTRL 0x098
+#define AUDIO_CLK_SPDIFIN_CTRL	0x09C
+#define AUDIO_CLK_SPDIFOUT_CTRL 0x0A0
+#define AUDIO_CLK_RESAMPLE_CTRL 0x0A4
+#define AUDIO_CLK_LOCKER_CTRL	0x0A8
+#define AUDIO_CLK_PDMIN_CTRL0	0x0AC
+#define AUDIO_CLK_PDMIN_CTRL1	0x0B0
+
+/*
+ * CLKID index values
+ * These indices are entirely contrived and do not map onto the hardware.
+ */
+
+#define AUD_CLKID_PCLK			0
+#define AUD_CLKID_MST0			1
+#define AUD_CLKID_MST1			2
+#define AUD_CLKID_MST2			3
+#define AUD_CLKID_MST3			4
+#define AUD_CLKID_MST4			5
+#define AUD_CLKID_MST5			6
+#define AUD_CLKID_MST6			7
+#define AUD_CLKID_MST7			8
+#define AUD_CLKID_MST_A_MCLK_SEL	59
+#define AUD_CLKID_MST_B_MCLK_SEL	60
+#define AUD_CLKID_MST_C_MCLK_SEL	61
+#define AUD_CLKID_MST_D_MCLK_SEL	62
+#define AUD_CLKID_MST_E_MCLK_SEL	63
+#define AUD_CLKID_MST_F_MCLK_SEL	64
+#define AUD_CLKID_MST_A_MCLK_DIV	65
+#define AUD_CLKID_MST_B_MCLK_DIV	66
+#define AUD_CLKID_MST_C_MCLK_DIV	67
+#define AUD_CLKID_MST_D_MCLK_DIV	68
+#define AUD_CLKID_MST_E_MCLK_DIV	69
+#define AUD_CLKID_MST_F_MCLK_DIV	70
+#define AUD_CLKID_SPDIFOUT_CLK_SEL	71
+#define AUD_CLKID_SPDIFOUT_CLK_DIV	72
+#define AUD_CLKID_SPDIFIN_CLK_SEL	73
+#define AUD_CLKID_SPDIFIN_CLK_DIV	74
+#define AUD_CLKID_PDM_DCLK_SEL		75
+#define AUD_CLKID_PDM_DCLK_DIV		76
+#define AUD_CLKID_PDM_SYSCLK_SEL	77
+#define AUD_CLKID_PDM_SYSCLK_DIV	78
+#define AUD_CLKID_MST_A_SCLK_PRE_EN	92
+#define AUD_CLKID_MST_B_SCLK_PRE_EN	93
+#define AUD_CLKID_MST_C_SCLK_PRE_EN	94
+#define AUD_CLKID_MST_D_SCLK_PRE_EN	95
+#define AUD_CLKID_MST_E_SCLK_PRE_EN	96
+#define AUD_CLKID_MST_F_SCLK_PRE_EN	97
+#define AUD_CLKID_MST_A_SCLK_DIV	98
+#define AUD_CLKID_MST_B_SCLK_DIV	99
+#define AUD_CLKID_MST_C_SCLK_DIV	100
+#define AUD_CLKID_MST_D_SCLK_DIV	101
+#define AUD_CLKID_MST_E_SCLK_DIV	102
+#define AUD_CLKID_MST_F_SCLK_DIV	103
+#define AUD_CLKID_MST_A_SCLK_POST_EN	104
+#define AUD_CLKID_MST_B_SCLK_POST_EN	105
+#define AUD_CLKID_MST_C_SCLK_POST_EN	106
+#define AUD_CLKID_MST_D_SCLK_POST_EN	107
+#define AUD_CLKID_MST_E_SCLK_POST_EN	108
+#define AUD_CLKID_MST_F_SCLK_POST_EN	109
+#define AUD_CLKID_MST_A_LRCLK_DIV	110
+#define AUD_CLKID_MST_B_LRCLK_DIV	111
+#define AUD_CLKID_MST_C_LRCLK_DIV	112
+#define AUD_CLKID_MST_D_LRCLK_DIV	113
+#define AUD_CLKID_MST_E_LRCLK_DIV	114
+#define AUD_CLKID_MST_F_LRCLK_DIV	115
+#define AUD_CLKID_TDMIN_A_SCLK_PRE_EN	137
+#define AUD_CLKID_TDMIN_B_SCLK_PRE_EN	138
+#define AUD_CLKID_TDMIN_C_SCLK_PRE_EN	139
+#define AUD_CLKID_TDMIN_LB_SCLK_PRE_EN	140
+#define AUD_CLKID_TDMOUT_A_SCLK_PRE_EN	141
+#define AUD_CLKID_TDMOUT_B_SCLK_PRE_EN	142
+#define AUD_CLKID_TDMOUT_C_SCLK_PRE_EN	143
+#define AUD_CLKID_TDMIN_A_SCLK_POST_EN	144
+#define AUD_CLKID_TDMIN_B_SCLK_POST_EN	145
+#define AUD_CLKID_TDMIN_C_SCLK_POST_EN	146
+#define AUD_CLKID_TDMIN_LB_SCLK_POST_EN	147
+#define AUD_CLKID_TDMOUT_A_SCLK_POST_EN	148
+#define AUD_CLKID_TDMOUT_B_SCLK_POST_EN	149
+#define AUD_CLKID_TDMOUT_C_SCLK_POST_EN	150
+
+/* include the CLKIDs which are part of the DT bindings */
+#include <dt-bindings/clock/axg-audio-clkc.h>
+
+#define NR_CLKS	151
+
+#endif /*__AXG_AUDIO_CLKC_H */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH 1/7] clk: meson: clean-up meson clock configuration
  2018-04-25 16:32   ` Jerome Brunet
@ 2018-04-26  8:46     ` Neil Armstrong
  -1 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:46 UTC (permalink / raw)
  To: Jerome Brunet, Carlo Caione, Kevin Hilman
  Cc: Michael Turquette, Stephen Boyd, linux-amlogic, linux-clk,
	devicetree, linux-kernel

On 25/04/2018 18:32, Jerome Brunet wrote:
> Clean the dependencies in meson clock Kconfig.
> CLK_AMLOGIC should actually select CLK_REGMAP_MESON which it uses. Also,
> each platform should select CLK_AMLOGIC, so everything is properly turned
> on when the platform Kconfig enable each configuration flag
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Kconfig | 11 ++++-------
>  1 file changed, 4 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index d5cbec522aec..87d69573e172 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -1,7 +1,7 @@
>  config COMMON_CLK_AMLOGIC
>  	bool
> -	depends on OF
>  	depends on ARCH_MESON || COMPILE_TEST
> +	select COMMON_CLK_REGMAP_MESON
>  
>  config COMMON_CLK_REGMAP_MESON
>  	bool
> @@ -9,9 +9,8 @@ config COMMON_CLK_REGMAP_MESON
>  
>  config COMMON_CLK_MESON8B
>  	bool
> -	depends on COMMON_CLK_AMLOGIC
> +	select COMMON_CLK_AMLOGIC
>  	select RESET_CONTROLLER
> -	select COMMON_CLK_REGMAP_MESON
>  	help
>  	  Support for the clock controller on AmLogic S802 (Meson8),
>  	  S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
> @@ -19,9 +18,8 @@ config COMMON_CLK_MESON8B
>  
>  config COMMON_CLK_GXBB
>  	bool
> -	depends on COMMON_CLK_AMLOGIC
> +	select COMMON_CLK_AMLOGIC
>  	select RESET_CONTROLLER
> -	select COMMON_CLK_REGMAP_MESON
>  	select MFD_SYSCON
>  	help
>  	  Support for the clock controller on AmLogic S905 devices, aka gxbb.
> @@ -29,9 +27,8 @@ config COMMON_CLK_GXBB
>  
>  config COMMON_CLK_AXG
>  	bool
> -	depends on COMMON_CLK_AMLOGIC
> +	select COMMON_CLK_AMLOGIC
>  	select RESET_CONTROLLER
> -	select COMMON_CLK_REGMAP_MESON
>  	select MFD_SYSCON
>  	help
>  	  Support for the clock controller on AmLogic A113D devices, aka axg.
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 1/7] clk: meson: clean-up meson clock configuration
@ 2018-04-26  8:46     ` Neil Armstrong
  0 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:46 UTC (permalink / raw)
  To: linus-amlogic

On 25/04/2018 18:32, Jerome Brunet wrote:
> Clean the dependencies in meson clock Kconfig.
> CLK_AMLOGIC should actually select CLK_REGMAP_MESON which it uses. Also,
> each platform should select CLK_AMLOGIC, so everything is properly turned
> on when the platform Kconfig enable each configuration flag
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Kconfig | 11 ++++-------
>  1 file changed, 4 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index d5cbec522aec..87d69573e172 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -1,7 +1,7 @@
>  config COMMON_CLK_AMLOGIC
>  	bool
> -	depends on OF
>  	depends on ARCH_MESON || COMPILE_TEST
> +	select COMMON_CLK_REGMAP_MESON
>  
>  config COMMON_CLK_REGMAP_MESON
>  	bool
> @@ -9,9 +9,8 @@ config COMMON_CLK_REGMAP_MESON
>  
>  config COMMON_CLK_MESON8B
>  	bool
> -	depends on COMMON_CLK_AMLOGIC
> +	select COMMON_CLK_AMLOGIC
>  	select RESET_CONTROLLER
> -	select COMMON_CLK_REGMAP_MESON
>  	help
>  	  Support for the clock controller on AmLogic S802 (Meson8),
>  	  S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
> @@ -19,9 +18,8 @@ config COMMON_CLK_MESON8B
>  
>  config COMMON_CLK_GXBB
>  	bool
> -	depends on COMMON_CLK_AMLOGIC
> +	select COMMON_CLK_AMLOGIC
>  	select RESET_CONTROLLER
> -	select COMMON_CLK_REGMAP_MESON
>  	select MFD_SYSCON
>  	help
>  	  Support for the clock controller on AmLogic S905 devices, aka gxbb.
> @@ -29,9 +27,8 @@ config COMMON_CLK_GXBB
>  
>  config COMMON_CLK_AXG
>  	bool
> -	depends on COMMON_CLK_AMLOGIC
> +	select COMMON_CLK_AMLOGIC
>  	select RESET_CONTROLLER
> -	select COMMON_CLK_REGMAP_MESON
>  	select MFD_SYSCON
>  	help
>  	  Support for the clock controller on AmLogic A113D devices, aka axg.
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/7] clk: meson: add clk-phase clock driver
  2018-04-25 16:32   ` Jerome Brunet
@ 2018-04-26  8:46     ` Neil Armstrong
  -1 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:46 UTC (permalink / raw)
  To: Jerome Brunet, Carlo Caione, Kevin Hilman
  Cc: Michael Turquette, Stephen Boyd, linux-amlogic, linux-clk,
	devicetree, linux-kernel

On 25/04/2018 18:32, Jerome Brunet wrote:
> Add a driver based meson clk-regmap to control clock phase on
> amlogic SoCs
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Makefile    |  1 +
>  drivers/clk/meson/clk-phase.c | 63 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/meson/clkc.h      |  8 ++++++
>  3 files changed, 72 insertions(+)
>  create mode 100644 drivers/clk/meson/clk-phase.c
> 
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index ffee82e60b7a..352fb848c406 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -3,6 +3,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_MESON8B) += meson8b.o
>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
> diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c
> new file mode 100644
> index 000000000000..96e70497ef1b
> --- /dev/null
> +++ b/drivers/clk/meson/clk-phase.c
> @@ -0,0 +1,63 @@
> +// 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.h"
> +
> +#define phase_step(_width) (360 / (1 << (_width)))
> +
> +static inline struct meson_clk_phase_data *
> +meson_clk_phase_data(struct clk_regmap *clk)
> +{
> +	return (struct meson_clk_phase_data *)clk->data;
> +}
> +
> +int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
> +{
> +	return phase_step(width) * val;
> +}
> +EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val);
> +
> +unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
> +{
> +	unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width));
> +
> +	/*
> +	 * This last calculation is here for cases when degrees is rounded
> +	 * to 360, in which case val == (1 << width).
> +	 */
> +	return val % (1 << width);
> +}
> +EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val);
> +
> +static int meson_clk_phase_get_phase(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
> +	unsigned int val;
> +
> +	val = meson_parm_read(clk->map, &phase->ph);
> +
> +	return meson_clk_degrees_from_val(val, phase->ph.width);
> +}
> +
> +static int meson_clk_phase_set_phase(struct clk_hw *hw, int degrees)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
> +	unsigned int val;
> +
> +	val = meson_clk_degrees_to_val(degrees, phase->ph.width);
> +	meson_parm_write(clk->map, &phase->ph, val);
> +
> +	return 0;
> +}
> +
> +const struct clk_ops meson_clk_phase_ops = {
> +	.get_phase	= meson_clk_phase_get_phase,
> +	.set_phase	= meson_clk_phase_set_phase,
> +};
> +EXPORT_SYMBOL_GPL(meson_clk_phase_ops);
> diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
> index 8fe73c4edca8..9a17d6705e0a 100644
> --- a/drivers/clk/meson/clkc.h
> +++ b/drivers/clk/meson/clkc.h
> @@ -104,6 +104,13 @@ struct meson_clk_audio_div_data {
>  	u8 flags;
>  };
>  
> +struct meson_clk_phase_data {
> +	struct parm ph;
> +};
> +
> +int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
> +unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
> +
>  #define MESON_GATE(_name, _reg, _bit)					\
>  struct clk_regmap _name = {						\
>  	.data = &(struct clk_regmap_gate_data){				\
> @@ -127,5 +134,6 @@ extern const struct clk_ops meson_clk_mpll_ro_ops;
>  extern const struct clk_ops meson_clk_mpll_ops;
>  extern const struct clk_ops meson_clk_audio_divider_ro_ops;
>  extern const struct clk_ops meson_clk_audio_divider_ops;
> +extern const struct clk_ops meson_clk_phase_ops;
>  
>  #endif /* __CLKC_H */
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 2/7] clk: meson: add clk-phase clock driver
@ 2018-04-26  8:46     ` Neil Armstrong
  0 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:46 UTC (permalink / raw)
  To: linus-amlogic

On 25/04/2018 18:32, Jerome Brunet wrote:
> Add a driver based meson clk-regmap to control clock phase on
> amlogic SoCs
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Makefile    |  1 +
>  drivers/clk/meson/clk-phase.c | 63 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/meson/clkc.h      |  8 ++++++
>  3 files changed, 72 insertions(+)
>  create mode 100644 drivers/clk/meson/clk-phase.c
> 
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index ffee82e60b7a..352fb848c406 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -3,6 +3,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_MESON8B) += meson8b.o
>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
> diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c
> new file mode 100644
> index 000000000000..96e70497ef1b
> --- /dev/null
> +++ b/drivers/clk/meson/clk-phase.c
> @@ -0,0 +1,63 @@
> +// 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.h"
> +
> +#define phase_step(_width) (360 / (1 << (_width)))
> +
> +static inline struct meson_clk_phase_data *
> +meson_clk_phase_data(struct clk_regmap *clk)
> +{
> +	return (struct meson_clk_phase_data *)clk->data;
> +}
> +
> +int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
> +{
> +	return phase_step(width) * val;
> +}
> +EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val);
> +
> +unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
> +{
> +	unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width));
> +
> +	/*
> +	 * This last calculation is here for cases when degrees is rounded
> +	 * to 360, in which case val == (1 << width).
> +	 */
> +	return val % (1 << width);
> +}
> +EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val);
> +
> +static int meson_clk_phase_get_phase(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
> +	unsigned int val;
> +
> +	val = meson_parm_read(clk->map, &phase->ph);
> +
> +	return meson_clk_degrees_from_val(val, phase->ph.width);
> +}
> +
> +static int meson_clk_phase_set_phase(struct clk_hw *hw, int degrees)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_clk_phase_data *phase = meson_clk_phase_data(clk);
> +	unsigned int val;
> +
> +	val = meson_clk_degrees_to_val(degrees, phase->ph.width);
> +	meson_parm_write(clk->map, &phase->ph, val);
> +
> +	return 0;
> +}
> +
> +const struct clk_ops meson_clk_phase_ops = {
> +	.get_phase	= meson_clk_phase_get_phase,
> +	.set_phase	= meson_clk_phase_set_phase,
> +};
> +EXPORT_SYMBOL_GPL(meson_clk_phase_ops);
> diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
> index 8fe73c4edca8..9a17d6705e0a 100644
> --- a/drivers/clk/meson/clkc.h
> +++ b/drivers/clk/meson/clkc.h
> @@ -104,6 +104,13 @@ struct meson_clk_audio_div_data {
>  	u8 flags;
>  };
>  
> +struct meson_clk_phase_data {
> +	struct parm ph;
> +};
> +
> +int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
> +unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
> +
>  #define MESON_GATE(_name, _reg, _bit)					\
>  struct clk_regmap _name = {						\
>  	.data = &(struct clk_regmap_gate_data){				\
> @@ -127,5 +134,6 @@ extern const struct clk_ops meson_clk_mpll_ro_ops;
>  extern const struct clk_ops meson_clk_mpll_ops;
>  extern const struct clk_ops meson_clk_audio_divider_ro_ops;
>  extern const struct clk_ops meson_clk_audio_divider_ops;
> +extern const struct clk_ops meson_clk_phase_ops;
>  
>  #endif /* __CLKC_H */
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 3/7] clk: meson: add triple phase clock driver
  2018-04-25 16:33   ` Jerome Brunet
@ 2018-04-26  8:47     ` Neil Armstrong
  -1 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:47 UTC (permalink / raw)
  To: Jerome Brunet, Carlo Caione, Kevin Hilman
  Cc: Michael Turquette, Stephen Boyd, linux-amlogic, linux-clk,
	devicetree, linux-kernel

On 25/04/2018 18:33, Jerome Brunet wrote:
> 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.
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Kconfig        |  5 +++
>  drivers/clk/meson/Makefile       |  1 +
>  drivers/clk/meson/clk-triphase.c | 68 ++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/meson/clkc-audio.h   | 20 ++++++++++++
>  4 files changed, 94 insertions(+)
>  create mode 100644 drivers/clk/meson/clk-triphase.c
>  create mode 100644 drivers/clk/meson/clkc-audio.h
> 
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 87d69573e172..7f7fd6fb3809 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -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_REGMAP_MESON
>  	bool
>  	select REGMAP
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 352fb848c406..64bb917fe1f0 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -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_MESON8B) += meson8b.o
>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
> diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c
> new file mode 100644
> index 000000000000..9508c03c73c1
> --- /dev/null
> +++ b/drivers/clk/meson/clk-triphase.c
> @@ -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
> index 000000000000..286ff1201258
> --- /dev/null
> +++ b/drivers/clk/meson/clkc-audio.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0 */

// SPDX-License-Identifier: GPL-2.0

Checkpatch should have warned about this !

> +/*
> + * 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 */
> 

Apart that :

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 3/7] clk: meson: add triple phase clock driver
@ 2018-04-26  8:47     ` Neil Armstrong
  0 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:47 UTC (permalink / raw)
  To: linus-amlogic

On 25/04/2018 18:33, Jerome Brunet wrote:
> 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.
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Kconfig        |  5 +++
>  drivers/clk/meson/Makefile       |  1 +
>  drivers/clk/meson/clk-triphase.c | 68 ++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/meson/clkc-audio.h   | 20 ++++++++++++
>  4 files changed, 94 insertions(+)
>  create mode 100644 drivers/clk/meson/clk-triphase.c
>  create mode 100644 drivers/clk/meson/clkc-audio.h
> 
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 87d69573e172..7f7fd6fb3809 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -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_REGMAP_MESON
>  	bool
>  	select REGMAP
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 352fb848c406..64bb917fe1f0 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -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_MESON8B) += meson8b.o
>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
> diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c
> new file mode 100644
> index 000000000000..9508c03c73c1
> --- /dev/null
> +++ b/drivers/clk/meson/clk-triphase.c
> @@ -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
> index 000000000000..286ff1201258
> --- /dev/null
> +++ b/drivers/clk/meson/clkc-audio.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0 */

// SPDX-License-Identifier: GPL-2.0

Checkpatch should have warned about this !

> +/*
> + * 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 */
> 

Apart that :

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 4/7] clk: meson: add axg audio sclk divider driver
  2018-04-25 16:33   ` Jerome Brunet
@ 2018-04-26  8:47     ` Neil Armstrong
  -1 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:47 UTC (permalink / raw)
  To: Jerome Brunet, Carlo Caione, Kevin Hilman
  Cc: Michael Turquette, Stephen Boyd, linux-amlogic, linux-clk,
	devicetree, linux-kernel

On 25/04/2018 18:33, Jerome Brunet wrote:
> Add a driver to control the clock divider found in the sample clock
> generator of the axg audio clock controller.
> 
> The sclk divider accumulates specific features which make the generic
> divider unsuitable to control it:
> - zero based divider (div = val + 1), but zero value gates the clock,
>   so minimum divider value is 2.
> - lrclk variant may adjust the duty cycle depending the divider value
>   and the 'hi' value.
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Makefile     |   2 +-
>  drivers/clk/meson/clkc-audio.h |   8 ++
>  drivers/clk/meson/sclk-div.c   | 243 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 252 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/clk/meson/sclk-div.c
> 
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 64bb917fe1f0..f51b4754c31b 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -4,7 +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_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
>  obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
> diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h
> index 286ff1201258..0a7c157ebf81 100644
> --- a/drivers/clk/meson/clkc-audio.h
> +++ b/drivers/clk/meson/clkc-audio.h
> @@ -15,6 +15,14 @@ struct meson_clk_triphase_data {
>  	struct parm ph2;
>  };
>  
> +struct meson_sclk_div_data {
> +	struct parm div;
> +	struct parm hi;
> +	unsigned int cached_div;
> +	struct clk_duty cached_duty;
> +};
> +
>  extern const struct clk_ops meson_clk_triphase_ops;
> +extern const struct clk_ops meson_sclk_div_ops;
>  
>  #endif /* __MESON_CLKC_AUDIO_H */
> diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c
> new file mode 100644
> index 000000000000..8c0bc914a6d7
> --- /dev/null
> +++ b/drivers/clk/meson/sclk-div.c
> @@ -0,0 +1,243 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2018 BayLibre, SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + *
> + * Sample clock generator divider:
> + * This HW divider gates with value 0 but is otherwise a zero based divider:
> + *
> + * val >= 1
> + * divider = val + 1
> + *
> + * The duty cycle may also be set for the LR clock variant. The duty cycle
> + * ratio is:
> + *
> + * hi = [0 - val]
> + * duty_cycle = (1 + hi) / (1 + val)
> + */
> +
> +#include "clkc-audio.h"
> +
> +static inline struct meson_sclk_div_data *
> +meson_sclk_div_data(struct clk_regmap *clk)
> +{
> +	return (struct meson_sclk_div_data *)clk->data;
> +}
> +
> +static int sclk_div_maxval(struct meson_sclk_div_data *sclk)
> +{
> +	return (1 << sclk->div.width) - 1;
> +}
> +
> +static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk)
> +{
> +	return sclk_div_maxval(sclk) + 1;
> +}
> +
> +static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate,
> +			   unsigned long prate, int maxdiv)
> +{
> +	int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate);
> +
> +	return clamp(div, 2, maxdiv);
> +}
> +
> +static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long *prate,
> +			    struct meson_sclk_div_data *sclk)
> +{
> +	struct clk_hw *parent = clk_hw_get_parent(hw);
> +	int bestdiv = 0, i;
> +	unsigned long maxdiv, now, parent_now;
> +	unsigned long best = 0, best_parent = 0;
> +
> +	if (!rate)
> +		rate = 1;
> +
> +	maxdiv = sclk_div_maxdiv(sclk);
> +
> +	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
> +		return sclk_div_getdiv(hw, rate, *prate, maxdiv);
> +
> +	/*
> +	 * The maximum divider we can use without overflowing
> +	 * unsigned long in rate * i below
> +	 */
> +	maxdiv = min(ULONG_MAX / rate, maxdiv);
> +
> +	for (i = 2; i <= maxdiv; i++) {
> +		/*
> +		 * It's the most ideal case if the requested rate can be
> +		 * divided from parent clock without needing to change
> +		 * parent rate, so return the divider immediately.
> +		 */
> +		if (rate * i == *prate)
> +			return i;
> +
> +		parent_now = clk_hw_round_rate(parent, rate * i);
> +		now = DIV_ROUND_UP_ULL((u64)parent_now, i);
> +
> +		if (abs(rate - now) < abs(rate - best)) {
> +			bestdiv = i;
> +			best = now;
> +			best_parent = parent_now;
> +		}
> +	}
> +
> +	if (!bestdiv)
> +		bestdiv = sclk_div_maxdiv(sclk);
> +	else
> +		*prate = best_parent;
> +
> +	return bestdiv;
> +}
> +
> +static long sclk_div_round_rate(struct clk_hw *hw, unsigned long rate,
> +				unsigned long *prate)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +	int div;
> +
> +	div = sclk_div_bestdiv(hw, rate, prate, sclk);
> +
> +	return DIV_ROUND_UP_ULL((u64)*prate, div);
> +}
> +
> +static void sclk_apply_ratio(struct clk_regmap *clk,
> +			     struct meson_sclk_div_data *sclk)
> +{
> +	unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div *
> +					    sclk->cached_duty.num,
> +					    sclk->cached_duty.den);
> +
> +	if (hi)
> +		hi -= 1;
> +
> +	meson_parm_write(clk->map, &sclk->hi, hi);
> +}
> +
> +static int sclk_div_set_duty_cycle(struct clk_hw *hw,
> +				   struct clk_duty *duty)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	if (MESON_PARM_APPLICABLE(&sclk->hi)) {
> +		memcpy(&sclk->cached_duty, duty, sizeof(*duty));
> +		sclk_apply_ratio(clk, sclk);
> +	}
> +
> +	return 0;
> +}
> +
> +static int sclk_div_get_duty_cycle(struct clk_hw *hw,
> +				   struct clk_duty *duty)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +	int hi;
> +
> +	if (!MESON_PARM_APPLICABLE(&sclk->hi)) {
> +		duty->num = 1;
> +		duty->den = 2;
> +		return 0;
> +	}
> +
> +	hi = meson_parm_read(clk->map, &sclk->hi);
> +	duty->num = hi + 1;
> +	duty->den = sclk->cached_div;
> +	return 0;
> +}
> +
> +static void sclk_apply_divider(struct clk_regmap *clk,
> +			       struct meson_sclk_div_data *sclk)
> +{
> +	if (MESON_PARM_APPLICABLE(&sclk->hi))
> +		sclk_apply_ratio(clk, sclk);
> +
> +	meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1);
> +}
> +
> +static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
> +			     unsigned long prate)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +	unsigned long maxdiv = sclk_div_maxdiv(sclk);
> +
> +	sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv);
> +
> +	if (clk_hw_is_enabled(hw))
> +		sclk_apply_divider(clk, sclk);
> +
> +	return 0;
> +}
> +
> +static unsigned long sclk_div_recalc_rate(struct clk_hw *hw,
> +					  unsigned long prate)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	return DIV_ROUND_UP_ULL((u64)prate, sclk->cached_div);
> +}
> +
> +static int sclk_div_enable(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	sclk_apply_divider(clk, sclk);
> +
> +	return 0;
> +}
> +
> +static void sclk_div_disable(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	meson_parm_write(clk->map, &sclk->div, 0);
> +}
> +
> +static int sclk_div_is_enabled(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	if (meson_parm_read(clk->map, &sclk->div))
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static void sclk_div_init(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +	unsigned int val;
> +
> +	val = meson_parm_read(clk->map, &sclk->div);
> +
> +	/* if the divider is initially disabled, assume max */
> +	if (!val)
> +		sclk->cached_div = sclk_div_maxdiv(sclk);
> +	else
> +		sclk->cached_div = val + 1;
> +
> +	sclk_div_get_duty_cycle(hw, &sclk->cached_duty);
> +}
> +
> +const struct clk_ops meson_sclk_div_ops = {
> +	.recalc_rate	= sclk_div_recalc_rate,
> +	.round_rate	= sclk_div_round_rate,
> +	.set_rate	= sclk_div_set_rate,
> +	.enable		= sclk_div_enable,
> +	.disable	= sclk_div_disable,
> +	.is_enabled	= sclk_div_is_enabled,
> +	.get_duty_cycle	= sclk_div_get_duty_cycle,
> +	.set_duty_cycle = sclk_div_set_duty_cycle,
> +	.init		= sclk_div_init,
> +};
> +EXPORT_SYMBOL_GPL(meson_sclk_div_ops);
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 4/7] clk: meson: add axg audio sclk divider driver
@ 2018-04-26  8:47     ` Neil Armstrong
  0 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:47 UTC (permalink / raw)
  To: linus-amlogic

On 25/04/2018 18:33, Jerome Brunet wrote:
> Add a driver to control the clock divider found in the sample clock
> generator of the axg audio clock controller.
> 
> The sclk divider accumulates specific features which make the generic
> divider unsuitable to control it:
> - zero based divider (div = val + 1), but zero value gates the clock,
>   so minimum divider value is 2.
> - lrclk variant may adjust the duty cycle depending the divider value
>   and the 'hi' value.
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Makefile     |   2 +-
>  drivers/clk/meson/clkc-audio.h |   8 ++
>  drivers/clk/meson/sclk-div.c   | 243 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 252 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/clk/meson/sclk-div.c
> 
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 64bb917fe1f0..f51b4754c31b 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -4,7 +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_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
>  obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
> diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h
> index 286ff1201258..0a7c157ebf81 100644
> --- a/drivers/clk/meson/clkc-audio.h
> +++ b/drivers/clk/meson/clkc-audio.h
> @@ -15,6 +15,14 @@ struct meson_clk_triphase_data {
>  	struct parm ph2;
>  };
>  
> +struct meson_sclk_div_data {
> +	struct parm div;
> +	struct parm hi;
> +	unsigned int cached_div;
> +	struct clk_duty cached_duty;
> +};
> +
>  extern const struct clk_ops meson_clk_triphase_ops;
> +extern const struct clk_ops meson_sclk_div_ops;
>  
>  #endif /* __MESON_CLKC_AUDIO_H */
> diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c
> new file mode 100644
> index 000000000000..8c0bc914a6d7
> --- /dev/null
> +++ b/drivers/clk/meson/sclk-div.c
> @@ -0,0 +1,243 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2018 BayLibre, SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + *
> + * Sample clock generator divider:
> + * This HW divider gates with value 0 but is otherwise a zero based divider:
> + *
> + * val >= 1
> + * divider = val + 1
> + *
> + * The duty cycle may also be set for the LR clock variant. The duty cycle
> + * ratio is:
> + *
> + * hi = [0 - val]
> + * duty_cycle = (1 + hi) / (1 + val)
> + */
> +
> +#include "clkc-audio.h"
> +
> +static inline struct meson_sclk_div_data *
> +meson_sclk_div_data(struct clk_regmap *clk)
> +{
> +	return (struct meson_sclk_div_data *)clk->data;
> +}
> +
> +static int sclk_div_maxval(struct meson_sclk_div_data *sclk)
> +{
> +	return (1 << sclk->div.width) - 1;
> +}
> +
> +static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk)
> +{
> +	return sclk_div_maxval(sclk) + 1;
> +}
> +
> +static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate,
> +			   unsigned long prate, int maxdiv)
> +{
> +	int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate);
> +
> +	return clamp(div, 2, maxdiv);
> +}
> +
> +static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long *prate,
> +			    struct meson_sclk_div_data *sclk)
> +{
> +	struct clk_hw *parent = clk_hw_get_parent(hw);
> +	int bestdiv = 0, i;
> +	unsigned long maxdiv, now, parent_now;
> +	unsigned long best = 0, best_parent = 0;
> +
> +	if (!rate)
> +		rate = 1;
> +
> +	maxdiv = sclk_div_maxdiv(sclk);
> +
> +	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
> +		return sclk_div_getdiv(hw, rate, *prate, maxdiv);
> +
> +	/*
> +	 * The maximum divider we can use without overflowing
> +	 * unsigned long in rate * i below
> +	 */
> +	maxdiv = min(ULONG_MAX / rate, maxdiv);
> +
> +	for (i = 2; i <= maxdiv; i++) {
> +		/*
> +		 * It's the most ideal case if the requested rate can be
> +		 * divided from parent clock without needing to change
> +		 * parent rate, so return the divider immediately.
> +		 */
> +		if (rate * i == *prate)
> +			return i;
> +
> +		parent_now = clk_hw_round_rate(parent, rate * i);
> +		now = DIV_ROUND_UP_ULL((u64)parent_now, i);
> +
> +		if (abs(rate - now) < abs(rate - best)) {
> +			bestdiv = i;
> +			best = now;
> +			best_parent = parent_now;
> +		}
> +	}
> +
> +	if (!bestdiv)
> +		bestdiv = sclk_div_maxdiv(sclk);
> +	else
> +		*prate = best_parent;
> +
> +	return bestdiv;
> +}
> +
> +static long sclk_div_round_rate(struct clk_hw *hw, unsigned long rate,
> +				unsigned long *prate)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +	int div;
> +
> +	div = sclk_div_bestdiv(hw, rate, prate, sclk);
> +
> +	return DIV_ROUND_UP_ULL((u64)*prate, div);
> +}
> +
> +static void sclk_apply_ratio(struct clk_regmap *clk,
> +			     struct meson_sclk_div_data *sclk)
> +{
> +	unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div *
> +					    sclk->cached_duty.num,
> +					    sclk->cached_duty.den);
> +
> +	if (hi)
> +		hi -= 1;
> +
> +	meson_parm_write(clk->map, &sclk->hi, hi);
> +}
> +
> +static int sclk_div_set_duty_cycle(struct clk_hw *hw,
> +				   struct clk_duty *duty)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	if (MESON_PARM_APPLICABLE(&sclk->hi)) {
> +		memcpy(&sclk->cached_duty, duty, sizeof(*duty));
> +		sclk_apply_ratio(clk, sclk);
> +	}
> +
> +	return 0;
> +}
> +
> +static int sclk_div_get_duty_cycle(struct clk_hw *hw,
> +				   struct clk_duty *duty)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +	int hi;
> +
> +	if (!MESON_PARM_APPLICABLE(&sclk->hi)) {
> +		duty->num = 1;
> +		duty->den = 2;
> +		return 0;
> +	}
> +
> +	hi = meson_parm_read(clk->map, &sclk->hi);
> +	duty->num = hi + 1;
> +	duty->den = sclk->cached_div;
> +	return 0;
> +}
> +
> +static void sclk_apply_divider(struct clk_regmap *clk,
> +			       struct meson_sclk_div_data *sclk)
> +{
> +	if (MESON_PARM_APPLICABLE(&sclk->hi))
> +		sclk_apply_ratio(clk, sclk);
> +
> +	meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1);
> +}
> +
> +static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
> +			     unsigned long prate)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +	unsigned long maxdiv = sclk_div_maxdiv(sclk);
> +
> +	sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv);
> +
> +	if (clk_hw_is_enabled(hw))
> +		sclk_apply_divider(clk, sclk);
> +
> +	return 0;
> +}
> +
> +static unsigned long sclk_div_recalc_rate(struct clk_hw *hw,
> +					  unsigned long prate)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	return DIV_ROUND_UP_ULL((u64)prate, sclk->cached_div);
> +}
> +
> +static int sclk_div_enable(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	sclk_apply_divider(clk, sclk);
> +
> +	return 0;
> +}
> +
> +static void sclk_div_disable(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	meson_parm_write(clk->map, &sclk->div, 0);
> +}
> +
> +static int sclk_div_is_enabled(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +
> +	if (meson_parm_read(clk->map, &sclk->div))
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static void sclk_div_init(struct clk_hw *hw)
> +{
> +	struct clk_regmap *clk = to_clk_regmap(hw);
> +	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
> +	unsigned int val;
> +
> +	val = meson_parm_read(clk->map, &sclk->div);
> +
> +	/* if the divider is initially disabled, assume max */
> +	if (!val)
> +		sclk->cached_div = sclk_div_maxdiv(sclk);
> +	else
> +		sclk->cached_div = val + 1;
> +
> +	sclk_div_get_duty_cycle(hw, &sclk->cached_duty);
> +}
> +
> +const struct clk_ops meson_sclk_div_ops = {
> +	.recalc_rate	= sclk_div_recalc_rate,
> +	.round_rate	= sclk_div_round_rate,
> +	.set_rate	= sclk_div_set_rate,
> +	.enable		= sclk_div_enable,
> +	.disable	= sclk_div_disable,
> +	.is_enabled	= sclk_div_is_enabled,
> +	.get_duty_cycle	= sclk_div_get_duty_cycle,
> +	.set_duty_cycle = sclk_div_set_duty_cycle,
> +	.init		= sclk_div_init,
> +};
> +EXPORT_SYMBOL_GPL(meson_sclk_div_ops);
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 5/7] clk: meson: axg: export audio clock controller id bindings
  2018-04-25 16:33   ` Jerome Brunet
@ 2018-04-26  8:48     ` Neil Armstrong
  -1 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:48 UTC (permalink / raw)
  To: Jerome Brunet, Carlo Caione, Kevin Hilman
  Cc: Michael Turquette, Stephen Boyd, linux-amlogic, linux-clk,
	devicetree, linux-kernel

On 25/04/2018 18:33, Jerome Brunet wrote:
> export the clock ids dt-bindings usable by the consumers of the axg
> audio clock controller
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  include/dt-bindings/clock/axg-audio-clkc.h | 94 ++++++++++++++++++++++++++++++
>  1 file changed, 94 insertions(+)
>  create mode 100644 include/dt-bindings/clock/axg-audio-clkc.h
> 
> diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h
> new file mode 100644
> index 000000000000..4426ae655858
> --- /dev/null
> +++ b/include/dt-bindings/clock/axg-audio-clkc.h
> @@ -0,0 +1,94 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2018 Baylibre SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + */
> +
> +#ifndef __AXG_AUDIO_CLKC_BINDINGS_H
> +#define __AXG_AUDIO_CLKC_BINDINGS_H
> +
> +#define AUD_CLKID_SLV_SCLK0		9
> +#define AUD_CLKID_SLV_SCLK1		10
> +#define AUD_CLKID_SLV_SCLK2		11
> +#define AUD_CLKID_SLV_SCLK3		12
> +#define AUD_CLKID_SLV_SCLK4		13
> +#define AUD_CLKID_SLV_SCLK5		14
> +#define AUD_CLKID_SLV_SCLK6		15
> +#define AUD_CLKID_SLV_SCLK7		16
> +#define AUD_CLKID_SLV_SCLK8		17
> +#define AUD_CLKID_SLV_SCLK9		18
> +#define AUD_CLKID_SLV_LRCLK0		19
> +#define AUD_CLKID_SLV_LRCLK1		20
> +#define AUD_CLKID_SLV_LRCLK2		21
> +#define AUD_CLKID_SLV_LRCLK3		22
> +#define AUD_CLKID_SLV_LRCLK4		23
> +#define AUD_CLKID_SLV_LRCLK5		24
> +#define AUD_CLKID_SLV_LRCLK6		25
> +#define AUD_CLKID_SLV_LRCLK7		26
> +#define AUD_CLKID_SLV_LRCLK8		27
> +#define AUD_CLKID_SLV_LRCLK9		28
> +#define AUD_CLKID_DDR_ARB		29
> +#define AUD_CLKID_PDM			30
> +#define AUD_CLKID_TDMIN_A		31
> +#define AUD_CLKID_TDMIN_B		32
> +#define AUD_CLKID_TDMIN_C		33
> +#define AUD_CLKID_TDMIN_LB		34
> +#define AUD_CLKID_TDMOUT_A		35
> +#define AUD_CLKID_TDMOUT_B		36
> +#define AUD_CLKID_TDMOUT_C		37
> +#define AUD_CLKID_FRDDR_A		38
> +#define AUD_CLKID_FRDDR_B		39
> +#define AUD_CLKID_FRDDR_C		40
> +#define AUD_CLKID_TODDR_A		41
> +#define AUD_CLKID_TODDR_B		42
> +#define AUD_CLKID_TODDR_C		43
> +#define AUD_CLKID_LOOPBACK		44
> +#define AUD_CLKID_SPDIFIN		45
> +#define AUD_CLKID_SPDIFOUT		46
> +#define AUD_CLKID_RESAMPLE		47
> +#define AUD_CLKID_POWER_DETECT		48
> +#define AUD_CLKID_MST_A_MCLK		49
> +#define AUD_CLKID_MST_B_MCLK		50
> +#define AUD_CLKID_MST_C_MCLK		51
> +#define AUD_CLKID_MST_D_MCLK		52
> +#define AUD_CLKID_MST_E_MCLK		53
> +#define AUD_CLKID_MST_F_MCLK		54
> +#define AUD_CLKID_SPDIFOUT_CLK		55
> +#define AUD_CLKID_SPDIFIN_CLK		56
> +#define AUD_CLKID_PDM_DCLK		57
> +#define AUD_CLKID_PDM_SYSCLK		58
> +#define AUD_CLKID_MST_A_SCLK		79
> +#define AUD_CLKID_MST_B_SCLK		80
> +#define AUD_CLKID_MST_C_SCLK		81
> +#define AUD_CLKID_MST_D_SCLK		82
> +#define AUD_CLKID_MST_E_SCLK		83
> +#define AUD_CLKID_MST_F_SCLK		84
> +#define AUD_CLKID_MST_A_LRCLK		86
> +#define AUD_CLKID_MST_B_LRCLK		87
> +#define AUD_CLKID_MST_C_LRCLK		88
> +#define AUD_CLKID_MST_D_LRCLK		89
> +#define AUD_CLKID_MST_E_LRCLK		90
> +#define AUD_CLKID_MST_F_LRCLK		91
> +#define AUD_CLKID_TDMIN_A_SCLK_SEL	116
> +#define AUD_CLKID_TDMIN_B_SCLK_SEL	117
> +#define AUD_CLKID_TDMIN_C_SCLK_SEL	118
> +#define AUD_CLKID_TDMIN_LB_SCLK_SEL	119
> +#define AUD_CLKID_TDMOUT_A_SCLK_SEL	120
> +#define AUD_CLKID_TDMOUT_B_SCLK_SEL	121
> +#define AUD_CLKID_TDMOUT_C_SCLK_SEL	122
> +#define AUD_CLKID_TDMIN_A_SCLK		123
> +#define AUD_CLKID_TDMIN_B_SCLK		124
> +#define AUD_CLKID_TDMIN_C_SCLK		125
> +#define AUD_CLKID_TDMIN_LB_SCLK		126
> +#define AUD_CLKID_TDMOUT_A_SCLK		127
> +#define AUD_CLKID_TDMOUT_B_SCLK		128
> +#define AUD_CLKID_TDMOUT_C_SCLK		129
> +#define AUD_CLKID_TDMIN_A_LRCLK		130
> +#define AUD_CLKID_TDMIN_B_LRCLK		131
> +#define AUD_CLKID_TDMIN_C_LRCLK		132
> +#define AUD_CLKID_TDMIN_LB_LRCLK	133
> +#define AUD_CLKID_TDMOUT_A_LRCLK	134
> +#define AUD_CLKID_TDMOUT_B_LRCLK	135
> +#define AUD_CLKID_TDMOUT_C_LRCLK	136
> +
> +#endif /* __AXG_AUDIO_CLKC_BINDINGS_H */
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 5/7] clk: meson: axg: export audio clock controller id bindings
@ 2018-04-26  8:48     ` Neil Armstrong
  0 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:48 UTC (permalink / raw)
  To: linus-amlogic

On 25/04/2018 18:33, Jerome Brunet wrote:
> export the clock ids dt-bindings usable by the consumers of the axg
> audio clock controller
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  include/dt-bindings/clock/axg-audio-clkc.h | 94 ++++++++++++++++++++++++++++++
>  1 file changed, 94 insertions(+)
>  create mode 100644 include/dt-bindings/clock/axg-audio-clkc.h
> 
> diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h
> new file mode 100644
> index 000000000000..4426ae655858
> --- /dev/null
> +++ b/include/dt-bindings/clock/axg-audio-clkc.h
> @@ -0,0 +1,94 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2018 Baylibre SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + */
> +
> +#ifndef __AXG_AUDIO_CLKC_BINDINGS_H
> +#define __AXG_AUDIO_CLKC_BINDINGS_H
> +
> +#define AUD_CLKID_SLV_SCLK0		9
> +#define AUD_CLKID_SLV_SCLK1		10
> +#define AUD_CLKID_SLV_SCLK2		11
> +#define AUD_CLKID_SLV_SCLK3		12
> +#define AUD_CLKID_SLV_SCLK4		13
> +#define AUD_CLKID_SLV_SCLK5		14
> +#define AUD_CLKID_SLV_SCLK6		15
> +#define AUD_CLKID_SLV_SCLK7		16
> +#define AUD_CLKID_SLV_SCLK8		17
> +#define AUD_CLKID_SLV_SCLK9		18
> +#define AUD_CLKID_SLV_LRCLK0		19
> +#define AUD_CLKID_SLV_LRCLK1		20
> +#define AUD_CLKID_SLV_LRCLK2		21
> +#define AUD_CLKID_SLV_LRCLK3		22
> +#define AUD_CLKID_SLV_LRCLK4		23
> +#define AUD_CLKID_SLV_LRCLK5		24
> +#define AUD_CLKID_SLV_LRCLK6		25
> +#define AUD_CLKID_SLV_LRCLK7		26
> +#define AUD_CLKID_SLV_LRCLK8		27
> +#define AUD_CLKID_SLV_LRCLK9		28
> +#define AUD_CLKID_DDR_ARB		29
> +#define AUD_CLKID_PDM			30
> +#define AUD_CLKID_TDMIN_A		31
> +#define AUD_CLKID_TDMIN_B		32
> +#define AUD_CLKID_TDMIN_C		33
> +#define AUD_CLKID_TDMIN_LB		34
> +#define AUD_CLKID_TDMOUT_A		35
> +#define AUD_CLKID_TDMOUT_B		36
> +#define AUD_CLKID_TDMOUT_C		37
> +#define AUD_CLKID_FRDDR_A		38
> +#define AUD_CLKID_FRDDR_B		39
> +#define AUD_CLKID_FRDDR_C		40
> +#define AUD_CLKID_TODDR_A		41
> +#define AUD_CLKID_TODDR_B		42
> +#define AUD_CLKID_TODDR_C		43
> +#define AUD_CLKID_LOOPBACK		44
> +#define AUD_CLKID_SPDIFIN		45
> +#define AUD_CLKID_SPDIFOUT		46
> +#define AUD_CLKID_RESAMPLE		47
> +#define AUD_CLKID_POWER_DETECT		48
> +#define AUD_CLKID_MST_A_MCLK		49
> +#define AUD_CLKID_MST_B_MCLK		50
> +#define AUD_CLKID_MST_C_MCLK		51
> +#define AUD_CLKID_MST_D_MCLK		52
> +#define AUD_CLKID_MST_E_MCLK		53
> +#define AUD_CLKID_MST_F_MCLK		54
> +#define AUD_CLKID_SPDIFOUT_CLK		55
> +#define AUD_CLKID_SPDIFIN_CLK		56
> +#define AUD_CLKID_PDM_DCLK		57
> +#define AUD_CLKID_PDM_SYSCLK		58
> +#define AUD_CLKID_MST_A_SCLK		79
> +#define AUD_CLKID_MST_B_SCLK		80
> +#define AUD_CLKID_MST_C_SCLK		81
> +#define AUD_CLKID_MST_D_SCLK		82
> +#define AUD_CLKID_MST_E_SCLK		83
> +#define AUD_CLKID_MST_F_SCLK		84
> +#define AUD_CLKID_MST_A_LRCLK		86
> +#define AUD_CLKID_MST_B_LRCLK		87
> +#define AUD_CLKID_MST_C_LRCLK		88
> +#define AUD_CLKID_MST_D_LRCLK		89
> +#define AUD_CLKID_MST_E_LRCLK		90
> +#define AUD_CLKID_MST_F_LRCLK		91
> +#define AUD_CLKID_TDMIN_A_SCLK_SEL	116
> +#define AUD_CLKID_TDMIN_B_SCLK_SEL	117
> +#define AUD_CLKID_TDMIN_C_SCLK_SEL	118
> +#define AUD_CLKID_TDMIN_LB_SCLK_SEL	119
> +#define AUD_CLKID_TDMOUT_A_SCLK_SEL	120
> +#define AUD_CLKID_TDMOUT_B_SCLK_SEL	121
> +#define AUD_CLKID_TDMOUT_C_SCLK_SEL	122
> +#define AUD_CLKID_TDMIN_A_SCLK		123
> +#define AUD_CLKID_TDMIN_B_SCLK		124
> +#define AUD_CLKID_TDMIN_C_SCLK		125
> +#define AUD_CLKID_TDMIN_LB_SCLK		126
> +#define AUD_CLKID_TDMOUT_A_SCLK		127
> +#define AUD_CLKID_TDMOUT_B_SCLK		128
> +#define AUD_CLKID_TDMOUT_C_SCLK		129
> +#define AUD_CLKID_TDMIN_A_LRCLK		130
> +#define AUD_CLKID_TDMIN_B_LRCLK		131
> +#define AUD_CLKID_TDMIN_C_LRCLK		132
> +#define AUD_CLKID_TDMIN_LB_LRCLK	133
> +#define AUD_CLKID_TDMOUT_A_LRCLK	134
> +#define AUD_CLKID_TDMOUT_B_LRCLK	135
> +#define AUD_CLKID_TDMOUT_C_LRCLK	136
> +
> +#endif /* __AXG_AUDIO_CLKC_BINDINGS_H */
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
  2018-04-25 16:33   ` Jerome Brunet
@ 2018-04-26  8:49     ` Neil Armstrong
  -1 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:49 UTC (permalink / raw)
  To: Jerome Brunet, Carlo Caione, Kevin Hilman
  Cc: Michael Turquette, Stephen Boyd, linux-amlogic, linux-clk,
	devicetree, linux-kernel

On 25/04/2018 18:33, Jerome Brunet wrote:
> The axg audio clock controller is the clock generation unit for the
> amlogic audio subsystem of A113 based SoCs. It may be clocked by 8
> different plls provided by the primary clock controller and also by
> 10 slave bit clocks and 10 slave sample clocks which may be provided
> by external components, such as audio codecs, through the SoC pads.
> 
> It contains several muxes, dividers and gates which are fed into the
> the different devices of the audio subsystem.
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Kconfig     |   9 +
>  drivers/clk/meson/Makefile    |   1 +
>  drivers/clk/meson/axg-audio.c | 845 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/meson/axg-audio.h | 127 +++++++
>  4 files changed, 982 insertions(+)
>  create mode 100644 drivers/clk/meson/axg-audio.c
>  create mode 100644 drivers/clk/meson/axg-audio.h
> 
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 7f7fd6fb3809..006fa1204e5b 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -38,3 +38,12 @@ config COMMON_CLK_AXG
>  	help
>  	  Support for the clock controller on AmLogic A113D devices, aka axg.
>  	  Say Y if you want peripherals and CPU frequency scaling to work.
> +
> +config COMMON_CLK_AXG_AUDIO
> +	tristate "Meson AXG Audio Clock Controller Driver"
> +	depends on COMMON_CLK_AXG
> +	select COMMON_CLK_AMLOGIC_AUDIO
> +	select MFD_SYSCON
> +	help
> +	  Support for the audio clock controller on AmLogic A113D devices,
> +	  aka axg, Say Y if you want audio subsystem to work.
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index f51b4754c31b..1ab89b627586 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -8,4 +8,5 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
>  obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
> +obj-$(CONFIG_COMMON_CLK_AXG_AUDIO)	+= axg-audio.o
>  obj-$(CONFIG_COMMON_CLK_REGMAP_MESON)	+= clk-regmap.o
> diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
> new file mode 100644
> index 000000000000..830c13ccd819
> --- /dev/null
> +++ b/drivers/clk/meson/axg-audio.c
> @@ -0,0 +1,845 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2018 BayLibre, SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/init.h>
> +#include <linux/of_device.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +
> +#include "clkc-audio.h"
> +#include "axg-audio.h"
> +
> +#define AXG_MST_IN_COUNT	8
> +#define AXG_SLV_SCLK_COUNT	10
> +#define AXG_SLV_LRCLK_COUNT	10
> +
> +#define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags)		\
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct clk_regmap_gate_data){				\
> +		.offset = (_reg),					\
> +		.bit_idx = (_bit),					\
> +	},								\
> +	.hw.init = &(struct clk_init_data) {				\
> +		.name = "axg_"#_name,					\
> +		.ops = &clk_regmap_gate_ops,				\
> +		.parent_names = (const char *[]){ _pname },		\
> +		.num_parents = 1,					\
> +		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
> +	},								\
> +}
> +
> +#define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct clk_regmap_mux_data){				\
> +		.offset = (_reg),					\
> +		.mask = (_mask),					\
> +		.shift = (_shift),					\
> +		.flags = (_dflags),					\
> +	},								\
> +	.hw.init = &(struct clk_init_data){				\
> +		.name = "axg_"#_name,					\
> +		.ops = &clk_regmap_mux_ops,				\
> +		.parent_names = (_pnames),				\
> +		.num_parents = ARRAY_SIZE(_pnames),			\
> +		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
> +	},								\
> +}
> +
> +#define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct clk_regmap_div_data){				\
> +		.offset = (_reg),					\
> +		.shift = (_shift),					\
> +		.width = (_width),					\
> +		.flags = (_dflags),					\
> +	},								\
> +	.hw.init = &(struct clk_init_data){				\
> +		.name = "axg_"#_name,					\
> +		.ops = &clk_regmap_divider_ops,				\
> +		.parent_names = (const char *[]) { _pname },		\
> +		.num_parents = 1,					\
> +		.flags = (_iflags),					\
> +	},								\
> +}
> +
> +#define AXG_PCLK_GATE(_name, _bit)				\
> +	AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0)
> +
> +/* Audio peripheral clocks */
> +static AXG_PCLK_GATE(ddr_arb,	   0);
> +static AXG_PCLK_GATE(pdm,	   1);
> +static AXG_PCLK_GATE(tdmin_a,	   2);
> +static AXG_PCLK_GATE(tdmin_b,	   3);
> +static AXG_PCLK_GATE(tdmin_c,	   4);
> +static AXG_PCLK_GATE(tdmin_lb,	   5);
> +static AXG_PCLK_GATE(tdmout_a,	   6);
> +static AXG_PCLK_GATE(tdmout_b,	   7);
> +static AXG_PCLK_GATE(tdmout_c,	   8);
> +static AXG_PCLK_GATE(frddr_a,	   9);
> +static AXG_PCLK_GATE(frddr_b,	   10);
> +static AXG_PCLK_GATE(frddr_c,	   11);
> +static AXG_PCLK_GATE(toddr_a,	   12);
> +static AXG_PCLK_GATE(toddr_b,	   13);
> +static AXG_PCLK_GATE(toddr_c,	   14);
> +static AXG_PCLK_GATE(loopback,	   15);
> +static AXG_PCLK_GATE(spdifin,	   16);
> +static AXG_PCLK_GATE(spdifout,	   17);
> +static AXG_PCLK_GATE(resample,	   18);
> +static AXG_PCLK_GATE(power_detect, 19);
> +
> +/* Audio Master Clocks */
> +static const char * const mst_mux_parent_names[] = {
> +	"axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3",
> +	"axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7",
> +};
> +
> +#define AXG_MST_MCLK_MUX(_name, _reg)					\
> +	AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
> +		    mst_mux_parent_names, CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_MCLK_MUX(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
> +static AXG_MST_MCLK_MUX(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
> +static AXG_MST_MCLK_MUX(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
> +static AXG_MST_MCLK_MUX(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
> +static AXG_MST_MCLK_MUX(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
> +static AXG_MST_MCLK_MUX(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
> +static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
> +static AXG_MST_MCLK_MUX(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
> +static AXG_MST_MCLK_MUX(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
> +static AXG_MST_MCLK_MUX(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
> +
> +#define AXG_MST_MCLK_DIV(_name, _reg)					\
> +	AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
> +		    "axg_"#_name"_sel", CLK_SET_RATE_PARENT)		\
> +
> +static AXG_MST_MCLK_DIV(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
> +static AXG_MST_MCLK_DIV(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
> +static AXG_MST_MCLK_DIV(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
> +static AXG_MST_MCLK_DIV(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
> +static AXG_MST_MCLK_DIV(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
> +static AXG_MST_MCLK_DIV(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
> +static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
> +static AXG_MST_MCLK_DIV(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
> +static AXG_MST_MCLK_DIV(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
> +static AXG_MST_MCLK_DIV(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
> +
> +#define AXG_MST_MCLK_GATE(_name, _reg)					\
> +	AXG_AUD_GATE(_name, _reg, 31,  "axg_"#_name"_div",		\
> +		     CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_MCLK_GATE(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
> +static AXG_MST_MCLK_GATE(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
> +static AXG_MST_MCLK_GATE(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
> +static AXG_MST_MCLK_GATE(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
> +static AXG_MST_MCLK_GATE(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
> +static AXG_MST_MCLK_GATE(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
> +static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
> +static AXG_MST_MCLK_GATE(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
> +static AXG_MST_MCLK_GATE(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
> +static AXG_MST_MCLK_GATE(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
> +
> +/* Sample Clocks */
> +#define AXG_MST_SCLK_PRE_EN(_name, _reg)			\
> +	AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31,	\
> +		     "axg_mst_"#_name"_mclk", 0)
> +
> +static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0);
> +
> +#define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width,		\
> +			 _hi_shift, _hi_width, _pname, _iflags)		\
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct meson_sclk_div_data) {				\
> +		.div = {						\
> +			.reg_off = (_reg),				\
> +			.shift   = (_div_shift),			\
> +			.width   = (_div_width),			\
> +		},							\
> +		.hi = {							\
> +			.reg_off = (_reg),				\
> +			.shift   = (_hi_shift),				\
> +			.width   = (_hi_width),				\
> +		},							\
> +	},								\
> +	.hw.init = &(struct clk_init_data) {				\
> +		.name = "axg_"#_name,					\
> +		.ops = &meson_sclk_div_ops,				\
> +		.parent_names = (const char *[]) { _pname },		\
> +		.num_parents = 1,					\
> +		.flags = (_iflags),					\
> +	},								\
> +}
> +
> +#define AXG_MST_SCLK_DIV(_name, _reg)					\
> +	AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0,	\
> +			 "axg_mst_"#_name"_sclk_pre_en",		\
> +			 CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
> +
> +#define AXG_MST_SCLK_POST_EN(_name, _reg)				\
> +	AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30,		\
> +		     "axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0);
> +
> +#define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \
> +			 _pname, _iflags)				\
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct meson_clk_triphase_data) {			\
> +		.ph0 = {						\
> +			.reg_off = (_reg),				\
> +			.shift   = (_shift0),				\
> +			.width   = (_width),				\
> +		},							\
> +		.ph1 = {						\
> +			.reg_off = (_reg),				\
> +			.shift   = (_shift1),				\
> +			.width   = (_width),				\
> +		},							\
> +		.ph2 = {						\
> +			.reg_off = (_reg),				\
> +			.shift   = (_shift2),				\
> +			.width   = (_width),				\
> +		},							\
> +	},								\
> +	.hw.init = &(struct clk_init_data) {				\
> +		.name = "axg_"#_name,					\
> +		.ops = &meson_clk_triphase_ops,				\
> +		.parent_names = (const char *[]) { _pname },		\
> +		.num_parents = 1,					\
> +		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
> +	},								\
> +}
> +
> +#define AXG_MST_SCLK(_name, _reg)					\
> +	AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4,		\
> +			 "axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1);
> +static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1);
> +static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1);
> +static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1);
> +static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1);
> +static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1);
> +
> +#define AXG_MST_LRCLK_DIV(_name, _reg)					\
> +	AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10,	\
> +		    "axg_mst_"#_name"_sclk_post_en", 0)			\
> +
> +static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
> +
> +#define AXG_MST_LRCLK(_name, _reg)					\
> +	AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5,		\
> +			 "axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1);
> +static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1);
> +static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1);
> +static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1);
> +static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1);
> +static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1);
> +
> +static const char * const tdm_sclk_parent_names[] = {
> +	"axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk",
> +	"axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk",
> +	"axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2",
> +	"axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5",
> +	"axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8",
> +	"axg_slv_sclk9"
> +};
> +
> +#define AXG_TDM_SCLK_MUX(_name, _reg)				\
> +	AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24,	\
> +		    CLK_MUX_ROUND_CLOSEST,			\
> +		    tdm_sclk_parent_names, 0)
> +
> +static AXG_TDM_SCLK_MUX(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_SCLK_MUX(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_SCLK_MUX(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +#define AXG_TDM_SCLK_PRE_EN(_name, _reg)				\
> +	AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31,		\
> +		     "axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT)
> +
> +static AXG_TDM_SCLK_PRE_EN(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +#define AXG_TDM_SCLK_POST_EN(_name, _reg)				\
> +	AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30,		\
> +		     "axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT)
> +
> +static AXG_TDM_SCLK_POST_EN(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_SCLK_POST_EN(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_SCLK_POST_EN(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +#define AXG_TDM_SCLK(_name, _reg)					\
> +	struct clk_regmap axg_tdm##_name##_sclk = {			\
> +	.data = &(struct meson_clk_phase_data) {			\
> +		.ph = {							\
> +			.reg_off = (_reg),				\
> +			.shift   = 29,					\
> +			.width   = 1,					\
> +		},							\
> +	},								\
> +	.hw.init = &(struct clk_init_data) {				\
> +		.name = "axg_tdm"#_name"_sclk",				\
> +		.ops = &meson_clk_phase_ops,				\
> +		.parent_names = (const char *[])			\
> +		{ "axg_tdm"#_name"_sclk_post_en" },			\
> +		.num_parents = 1,					\
> +		.flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT,	\
> +	},								\
> +}
> +
> +static AXG_TDM_SCLK(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_SCLK(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_SCLK(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +static const char * const tdm_lrclk_parent_names[] = {
> +	"axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk",
> +	"axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk",
> +	"axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2",
> +	"axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5",
> +	"axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8",
> +	"axg_slv_lrclk9"
> +};
> +
> +#define AXG_TDM_LRLCK(_name, _reg)		       \
> +	AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \
> +		    CLK_MUX_ROUND_CLOSEST,	       \
> +		    tdm_lrclk_parent_names, 0)
> +
> +static AXG_TDM_LRLCK(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_LRLCK(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_LRLCK(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +/*
> + * Array of all clocks provided by this provider
> + * The input clocks of the controller will be populated at runtime
> + */
> +static struct clk_hw_onecell_data axg_audio_hw_onecell_data = {
> +	.hws = {
> +		[AUD_CLKID_DDR_ARB]		= &axg_ddr_arb.hw,
> +		[AUD_CLKID_PDM]			= &axg_pdm.hw,
> +		[AUD_CLKID_TDMIN_A]		= &axg_tdmin_a.hw,
> +		[AUD_CLKID_TDMIN_B]		= &axg_tdmin_b.hw,
> +		[AUD_CLKID_TDMIN_C]		= &axg_tdmin_c.hw,
> +		[AUD_CLKID_TDMIN_LB]		= &axg_tdmin_lb.hw,
> +		[AUD_CLKID_TDMOUT_A]		= &axg_tdmout_a.hw,
> +		[AUD_CLKID_TDMOUT_B]		= &axg_tdmout_b.hw,
> +		[AUD_CLKID_TDMOUT_C]		= &axg_tdmout_c.hw,
> +		[AUD_CLKID_FRDDR_A]		= &axg_frddr_a.hw,
> +		[AUD_CLKID_FRDDR_B]		= &axg_frddr_b.hw,
> +		[AUD_CLKID_FRDDR_C]		= &axg_frddr_c.hw,
> +		[AUD_CLKID_TODDR_A]		= &axg_toddr_a.hw,
> +		[AUD_CLKID_TODDR_B]		= &axg_toddr_b.hw,
> +		[AUD_CLKID_TODDR_C]		= &axg_toddr_c.hw,
> +		[AUD_CLKID_LOOPBACK]		= &axg_loopback.hw,
> +		[AUD_CLKID_SPDIFIN]		= &axg_spdifin.hw,
> +		[AUD_CLKID_SPDIFOUT]		= &axg_spdifout.hw,
> +		[AUD_CLKID_RESAMPLE]		= &axg_resample.hw,
> +		[AUD_CLKID_POWER_DETECT]	= &axg_power_detect.hw,
> +		[AUD_CLKID_MST_A_MCLK_SEL]	= &axg_mst_a_mclk_sel.hw,
> +		[AUD_CLKID_MST_B_MCLK_SEL]	= &axg_mst_b_mclk_sel.hw,
> +		[AUD_CLKID_MST_C_MCLK_SEL]	= &axg_mst_c_mclk_sel.hw,
> +		[AUD_CLKID_MST_D_MCLK_SEL]	= &axg_mst_d_mclk_sel.hw,
> +		[AUD_CLKID_MST_E_MCLK_SEL]	= &axg_mst_e_mclk_sel.hw,
> +		[AUD_CLKID_MST_F_MCLK_SEL]	= &axg_mst_f_mclk_sel.hw,
> +		[AUD_CLKID_MST_A_MCLK_DIV]	= &axg_mst_a_mclk_div.hw,
> +		[AUD_CLKID_MST_B_MCLK_DIV]	= &axg_mst_b_mclk_div.hw,
> +		[AUD_CLKID_MST_C_MCLK_DIV]	= &axg_mst_c_mclk_div.hw,
> +		[AUD_CLKID_MST_D_MCLK_DIV]	= &axg_mst_d_mclk_div.hw,
> +		[AUD_CLKID_MST_E_MCLK_DIV]	= &axg_mst_e_mclk_div.hw,
> +		[AUD_CLKID_MST_F_MCLK_DIV]	= &axg_mst_f_mclk_div.hw,
> +		[AUD_CLKID_MST_A_MCLK]		= &axg_mst_a_mclk.hw,
> +		[AUD_CLKID_MST_B_MCLK]		= &axg_mst_b_mclk.hw,
> +		[AUD_CLKID_MST_C_MCLK]		= &axg_mst_c_mclk.hw,
> +		[AUD_CLKID_MST_D_MCLK]		= &axg_mst_d_mclk.hw,
> +		[AUD_CLKID_MST_E_MCLK]		= &axg_mst_e_mclk.hw,
> +		[AUD_CLKID_MST_F_MCLK]		= &axg_mst_f_mclk.hw,
> +		[AUD_CLKID_SPDIFOUT_CLK_SEL]	= &axg_spdifout_clk_sel.hw,
> +		[AUD_CLKID_SPDIFOUT_CLK_DIV]	= &axg_spdifout_clk_div.hw,
> +		[AUD_CLKID_SPDIFOUT_CLK]	= &axg_spdifout_clk.hw,
> +		[AUD_CLKID_SPDIFIN_CLK_SEL]	= &axg_spdifin_clk_sel.hw,
> +		[AUD_CLKID_SPDIFIN_CLK_DIV]	= &axg_spdifin_clk_div.hw,
> +		[AUD_CLKID_SPDIFIN_CLK]		= &axg_spdifin_clk.hw,
> +		[AUD_CLKID_PDM_DCLK_SEL]	= &axg_pdm_dclk_sel.hw,
> +		[AUD_CLKID_PDM_DCLK_DIV]	= &axg_pdm_dclk_div.hw,
> +		[AUD_CLKID_PDM_DCLK]		= &axg_pdm_dclk.hw,
> +		[AUD_CLKID_PDM_SYSCLK_SEL]	= &axg_pdm_sysclk_sel.hw,
> +		[AUD_CLKID_PDM_SYSCLK_DIV]	= &axg_pdm_sysclk_div.hw,
> +		[AUD_CLKID_PDM_SYSCLK]		= &axg_pdm_sysclk.hw,
> +		[AUD_CLKID_MST_A_SCLK_PRE_EN]	= &axg_mst_a_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_B_SCLK_PRE_EN]	= &axg_mst_b_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_C_SCLK_PRE_EN]	= &axg_mst_c_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_D_SCLK_PRE_EN]	= &axg_mst_d_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_E_SCLK_PRE_EN]	= &axg_mst_e_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_F_SCLK_PRE_EN]	= &axg_mst_f_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_A_SCLK_DIV]	= &axg_mst_a_sclk_div.hw,
> +		[AUD_CLKID_MST_B_SCLK_DIV]	= &axg_mst_b_sclk_div.hw,
> +		[AUD_CLKID_MST_C_SCLK_DIV]	= &axg_mst_c_sclk_div.hw,
> +		[AUD_CLKID_MST_D_SCLK_DIV]	= &axg_mst_d_sclk_div.hw,
> +		[AUD_CLKID_MST_E_SCLK_DIV]	= &axg_mst_e_sclk_div.hw,
> +		[AUD_CLKID_MST_F_SCLK_DIV]	= &axg_mst_f_sclk_div.hw,
> +		[AUD_CLKID_MST_A_SCLK_POST_EN]	= &axg_mst_a_sclk_post_en.hw,
> +		[AUD_CLKID_MST_B_SCLK_POST_EN]	= &axg_mst_b_sclk_post_en.hw,
> +		[AUD_CLKID_MST_C_SCLK_POST_EN]	= &axg_mst_c_sclk_post_en.hw,
> +		[AUD_CLKID_MST_D_SCLK_POST_EN]	= &axg_mst_d_sclk_post_en.hw,
> +		[AUD_CLKID_MST_E_SCLK_POST_EN]	= &axg_mst_e_sclk_post_en.hw,
> +		[AUD_CLKID_MST_F_SCLK_POST_EN]	= &axg_mst_f_sclk_post_en.hw,
> +		[AUD_CLKID_MST_A_SCLK]		= &axg_mst_a_sclk.hw,
> +		[AUD_CLKID_MST_B_SCLK]		= &axg_mst_b_sclk.hw,
> +		[AUD_CLKID_MST_C_SCLK]		= &axg_mst_c_sclk.hw,
> +		[AUD_CLKID_MST_D_SCLK]		= &axg_mst_d_sclk.hw,
> +		[AUD_CLKID_MST_E_SCLK]		= &axg_mst_e_sclk.hw,
> +		[AUD_CLKID_MST_F_SCLK]		= &axg_mst_f_sclk.hw,
> +		[AUD_CLKID_MST_A_LRCLK_DIV]	= &axg_mst_a_lrclk_div.hw,
> +		[AUD_CLKID_MST_B_LRCLK_DIV]	= &axg_mst_b_lrclk_div.hw,
> +		[AUD_CLKID_MST_C_LRCLK_DIV]	= &axg_mst_c_lrclk_div.hw,
> +		[AUD_CLKID_MST_D_LRCLK_DIV]	= &axg_mst_d_lrclk_div.hw,
> +		[AUD_CLKID_MST_E_LRCLK_DIV]	= &axg_mst_e_lrclk_div.hw,
> +		[AUD_CLKID_MST_F_LRCLK_DIV]	= &axg_mst_f_lrclk_div.hw,
> +		[AUD_CLKID_MST_A_LRCLK]		= &axg_mst_a_lrclk.hw,
> +		[AUD_CLKID_MST_B_LRCLK]		= &axg_mst_b_lrclk.hw,
> +		[AUD_CLKID_MST_C_LRCLK]		= &axg_mst_c_lrclk.hw,
> +		[AUD_CLKID_MST_D_LRCLK]		= &axg_mst_d_lrclk.hw,
> +		[AUD_CLKID_MST_E_LRCLK]		= &axg_mst_e_lrclk.hw,
> +		[AUD_CLKID_MST_F_LRCLK]		= &axg_mst_f_lrclk.hw,
> +		[AUD_CLKID_TDMIN_A_SCLK_SEL]	= &axg_tdmin_a_sclk_sel.hw,
> +		[AUD_CLKID_TDMIN_B_SCLK_SEL]	= &axg_tdmin_b_sclk_sel.hw,
> +		[AUD_CLKID_TDMIN_C_SCLK_SEL]	= &axg_tdmin_c_sclk_sel.hw,
> +		[AUD_CLKID_TDMIN_LB_SCLK_SEL]	= &axg_tdmin_lb_sclk_sel.hw,
> +		[AUD_CLKID_TDMOUT_A_SCLK_SEL]	= &axg_tdmout_a_sclk_sel.hw,
> +		[AUD_CLKID_TDMOUT_B_SCLK_SEL]	= &axg_tdmout_b_sclk_sel.hw,
> +		[AUD_CLKID_TDMOUT_C_SCLK_SEL]	= &axg_tdmout_c_sclk_sel.hw,
> +		[AUD_CLKID_TDMIN_A_SCLK_PRE_EN]	= &axg_tdmin_a_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMIN_B_SCLK_PRE_EN]	= &axg_tdmin_b_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMIN_C_SCLK_PRE_EN]	= &axg_tdmin_c_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw,
> +		[AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw,
> +		[AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw,
> +		[AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw,
> +		[AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw,
> +		[AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw,
> +		[AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw,
> +		[AUD_CLKID_TDMIN_A_SCLK]	= &axg_tdmin_a_sclk.hw,
> +		[AUD_CLKID_TDMIN_B_SCLK]	= &axg_tdmin_b_sclk.hw,
> +		[AUD_CLKID_TDMIN_C_SCLK]	= &axg_tdmin_c_sclk.hw,
> +		[AUD_CLKID_TDMIN_LB_SCLK]	= &axg_tdmin_lb_sclk.hw,
> +		[AUD_CLKID_TDMOUT_A_SCLK]	= &axg_tdmout_a_sclk.hw,
> +		[AUD_CLKID_TDMOUT_B_SCLK]	= &axg_tdmout_b_sclk.hw,
> +		[AUD_CLKID_TDMOUT_C_SCLK]	= &axg_tdmout_c_sclk.hw,
> +		[AUD_CLKID_TDMIN_A_LRCLK]	= &axg_tdmin_a_lrclk.hw,
> +		[AUD_CLKID_TDMIN_B_LRCLK]	= &axg_tdmin_b_lrclk.hw,
> +		[AUD_CLKID_TDMIN_C_LRCLK]	= &axg_tdmin_c_lrclk.hw,
> +		[AUD_CLKID_TDMIN_LB_LRCLK]	= &axg_tdmin_lb_lrclk.hw,
> +		[AUD_CLKID_TDMOUT_A_LRCLK]	= &axg_tdmout_a_lrclk.hw,
> +		[AUD_CLKID_TDMOUT_B_LRCLK]	= &axg_tdmout_b_lrclk.hw,
> +		[AUD_CLKID_TDMOUT_C_LRCLK]	= &axg_tdmout_c_lrclk.hw,
> +		[NR_CLKS] = NULL,
> +	},
> +	.num = NR_CLKS,
> +};
> +
> +/* Convenience table to populate regmap in .probe() */
> +static struct clk_regmap *const axg_audio_clk_regmaps[] = {
> +	&axg_ddr_arb,
> +	&axg_pdm,
> +	&axg_tdmin_a,
> +	&axg_tdmin_b,
> +	&axg_tdmin_c,
> +	&axg_tdmin_lb,
> +	&axg_tdmout_a,
> +	&axg_tdmout_b,
> +	&axg_tdmout_c,
> +	&axg_frddr_a,
> +	&axg_frddr_b,
> +	&axg_frddr_c,
> +	&axg_toddr_a,
> +	&axg_toddr_b,
> +	&axg_toddr_c,
> +	&axg_loopback,
> +	&axg_spdifin,
> +	&axg_spdifout,
> +	&axg_resample,
> +	&axg_power_detect,
> +	&axg_mst_a_mclk_sel,
> +	&axg_mst_b_mclk_sel,
> +	&axg_mst_c_mclk_sel,
> +	&axg_mst_d_mclk_sel,
> +	&axg_mst_e_mclk_sel,
> +	&axg_mst_f_mclk_sel,
> +	&axg_mst_a_mclk_div,
> +	&axg_mst_b_mclk_div,
> +	&axg_mst_c_mclk_div,
> +	&axg_mst_d_mclk_div,
> +	&axg_mst_e_mclk_div,
> +	&axg_mst_f_mclk_div,
> +	&axg_mst_a_mclk,
> +	&axg_mst_b_mclk,
> +	&axg_mst_c_mclk,
> +	&axg_mst_d_mclk,
> +	&axg_mst_e_mclk,
> +	&axg_mst_f_mclk,
> +	&axg_spdifout_clk_sel,
> +	&axg_spdifout_clk_div,
> +	&axg_spdifout_clk,
> +	&axg_spdifin_clk_sel,
> +	&axg_spdifin_clk_div,
> +	&axg_spdifin_clk,
> +	&axg_pdm_dclk_sel,
> +	&axg_pdm_dclk_div,
> +	&axg_pdm_dclk,
> +	&axg_pdm_sysclk_sel,
> +	&axg_pdm_sysclk_div,
> +	&axg_pdm_sysclk,
> +	&axg_mst_a_sclk_pre_en,
> +	&axg_mst_b_sclk_pre_en,
> +	&axg_mst_c_sclk_pre_en,
> +	&axg_mst_d_sclk_pre_en,
> +	&axg_mst_e_sclk_pre_en,
> +	&axg_mst_f_sclk_pre_en,
> +	&axg_mst_a_sclk_div,
> +	&axg_mst_b_sclk_div,
> +	&axg_mst_c_sclk_div,
> +	&axg_mst_d_sclk_div,
> +	&axg_mst_e_sclk_div,
> +	&axg_mst_f_sclk_div,
> +	&axg_mst_a_sclk_post_en,
> +	&axg_mst_b_sclk_post_en,
> +	&axg_mst_c_sclk_post_en,
> +	&axg_mst_d_sclk_post_en,
> +	&axg_mst_e_sclk_post_en,
> +	&axg_mst_f_sclk_post_en,
> +	&axg_mst_a_sclk,
> +	&axg_mst_b_sclk,
> +	&axg_mst_c_sclk,
> +	&axg_mst_d_sclk,
> +	&axg_mst_e_sclk,
> +	&axg_mst_f_sclk,
> +	&axg_mst_a_lrclk_div,
> +	&axg_mst_b_lrclk_div,
> +	&axg_mst_c_lrclk_div,
> +	&axg_mst_d_lrclk_div,
> +	&axg_mst_e_lrclk_div,
> +	&axg_mst_f_lrclk_div,
> +	&axg_mst_a_lrclk,
> +	&axg_mst_b_lrclk,
> +	&axg_mst_c_lrclk,
> +	&axg_mst_d_lrclk,
> +	&axg_mst_e_lrclk,
> +	&axg_mst_f_lrclk,
> +	&axg_tdmin_a_sclk_sel,
> +	&axg_tdmin_b_sclk_sel,
> +	&axg_tdmin_c_sclk_sel,
> +	&axg_tdmin_lb_sclk_sel,
> +	&axg_tdmout_a_sclk_sel,
> +	&axg_tdmout_b_sclk_sel,
> +	&axg_tdmout_c_sclk_sel,
> +	&axg_tdmin_a_sclk_pre_en,
> +	&axg_tdmin_b_sclk_pre_en,
> +	&axg_tdmin_c_sclk_pre_en,
> +	&axg_tdmin_lb_sclk_pre_en,
> +	&axg_tdmout_a_sclk_pre_en,
> +	&axg_tdmout_b_sclk_pre_en,
> +	&axg_tdmout_c_sclk_pre_en,
> +	&axg_tdmin_a_sclk_post_en,
> +	&axg_tdmin_b_sclk_post_en,
> +	&axg_tdmin_c_sclk_post_en,
> +	&axg_tdmin_lb_sclk_post_en,
> +	&axg_tdmout_a_sclk_post_en,
> +	&axg_tdmout_b_sclk_post_en,
> +	&axg_tdmout_c_sclk_post_en,
> +	&axg_tdmin_a_sclk,
> +	&axg_tdmin_b_sclk,
> +	&axg_tdmin_c_sclk,
> +	&axg_tdmin_lb_sclk,
> +	&axg_tdmout_a_sclk,
> +	&axg_tdmout_b_sclk,
> +	&axg_tdmout_c_sclk,
> +	&axg_tdmin_a_lrclk,
> +	&axg_tdmin_b_lrclk,
> +	&axg_tdmin_c_lrclk,
> +	&axg_tdmin_lb_lrclk,
> +	&axg_tdmout_a_lrclk,
> +	&axg_tdmout_b_lrclk,
> +	&axg_tdmout_c_lrclk,
> +};
> +
> +static struct clk *devm_clk_get_enable(struct device *dev, char *id)
> +{
> +	struct clk *clk;
> +	int ret;
> +
> +	clk = devm_clk_get(dev, id);
> +	if (IS_ERR(clk)) {
> +		if (PTR_ERR(clk) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get %s", id);
> +		return clk;
> +	}
> +
> +	ret = clk_prepare_enable(clk);
> +	if (ret) {
> +		dev_err(dev, "failed to enable %s", id);
> +		return ERR_PTR(ret);
> +	}
> +
> +	ret = devm_add_action_or_reset(dev,
> +				       (void(*)(void *))clk_disable_unprepare,
> +				       clk);
> +	if (ret) {
> +		dev_err(dev, "failed to add reset action on %s", id);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return clk;
> +}
> +
> +static const struct clk_ops axg_clk_no_ops = {};
> +
> +static struct clk_hw *axg_clk_hw_register_bypass(struct device *dev,
> +						 const char *name,
> +						 const char *parent_name)
> +{
> +	struct clk_hw *hw;
> +	struct clk_init_data init;
> +	char *clk_name;
> +	int ret;
> +
> +	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
> +	if (!hw)
> +		return ERR_PTR(-ENOMEM);
> +
> +	clk_name = kasprintf(GFP_KERNEL, "axg_%s", name);
> +	if (!clk_name)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = clk_name;
> +	init.ops = &axg_clk_no_ops;
> +	init.flags = 0;
> +	init.parent_names = parent_name ? &parent_name : NULL;
> +	init.num_parents = parent_name ? 1 : 0;
> +	hw->init = &init;
> +
> +	ret = devm_clk_hw_register(dev, hw);
> +	kfree(clk_name);
> +
> +	return ret ? ERR_PTR(ret) : hw;
> +}
> +
> +static int axg_register_clk_hw_input(struct device *dev,
> +				     const char *name,
> +				     unsigned int clkid)
> +{
> +	struct clk *parent_clk = devm_clk_get(dev, name);
> +	struct clk_hw *hw = NULL;
> +
> +	if (IS_ERR(parent_clk)) {
> +		int err = PTR_ERR(parent_clk);
> +
> +		/* It is ok if an input clock is missing */
> +		if (err == -ENOENT) {
> +			dev_dbg(dev, "%s not provided", name);
> +		} else {
> +			if (err != -EPROBE_DEFER)
> +				dev_err(dev, "failed to get %s clock", name);
> +			return err;
> +		}
> +	} else {
> +		hw = axg_clk_hw_register_bypass(dev, name,
> +						__clk_get_name(parent_clk));
> +	}
> +
> +	if (IS_ERR(hw)) {
> +		dev_err(dev, "failed to register %s clock", name);
> +		return PTR_ERR(hw);
> +	}
> +
> +	axg_audio_hw_onecell_data.hws[clkid] = hw;
> +	return 0;
> +}
> +
> +static int axg_register_clk_hw_inputs(struct device *dev,
> +				      const char *basename,
> +				      unsigned int count,
> +				      unsigned int clkid)
> +{
> +	char *name;
> +	int i, ret;
> +
> +	for (i = 0; i < count; i++) {
> +		name = kasprintf(GFP_KERNEL, "%s%d", basename, i);
> +		if (!name)
> +			return -ENOMEM;
> +
> +		ret = axg_register_clk_hw_input(dev, name, clkid + i);
> +		kfree(name);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct regmap_config axg_audio_regmap_cfg = {
> +	.reg_bits	= 32,
> +	.val_bits	= 32,
> +	.reg_stride	= 4,
> +	.max_register	= AUDIO_CLK_PDMIN_CTRL1,
> +};
> +
> +static int axg_audio_clkc_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct regmap *map;
> +	struct resource *res;
> +	void __iomem *regs;
> +	struct clk *clk;
> +	struct clk_hw *hw;
> +	int ret, i;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	regs = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(regs))
> +		return PTR_ERR(regs);
> +
> +	map = devm_regmap_init_mmio(dev, regs, &axg_audio_regmap_cfg);
> +	if (IS_ERR(map)) {
> +		dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(map));
> +		return PTR_ERR(map);
> +	}
> +
> +	/* Get the mandatory peripheral clock */
> +	clk = devm_clk_get_enable(dev, "pclk");
> +	if (IS_ERR(clk))
> +		return PTR_ERR(clk);
> +
> +	ret = device_reset(dev);
> +	if (ret) {
> +		dev_err(dev, "failed to reset device\n");
> +		return ret;
> +	}
> +
> +	/* Register the peripheral input clock */
> +	hw = axg_clk_hw_register_bypass(dev, "audio_pclk",
> +					__clk_get_name(clk));
> +	if (IS_ERR(hw))
> +		return PTR_ERR(hw);
> +
> +	axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw;
> +
> +	/* Register optional input master clocks */
> +	ret = axg_register_clk_hw_inputs(dev, "mst_in",
> +					 AXG_MST_IN_COUNT,
> +					 AUD_CLKID_MST0);
> +	if (ret)
> +		return ret;
> +
> +	/* Register optional input slave sclks */
> +	ret = axg_register_clk_hw_inputs(dev, "slv_sclk",
> +					 AXG_SLV_SCLK_COUNT,
> +					 AUD_CLKID_SLV_SCLK0);
> +	if (ret)
> +		return ret;
> +
> +	/* Register optional input slave lrclks */
> +	ret = axg_register_clk_hw_inputs(dev, "slv_lrclk",
> +					 AXG_SLV_LRCLK_COUNT,
> +					 AUD_CLKID_SLV_LRCLK0);
> +	if (ret)
> +		return ret;
> +
> +	/* Populate regmap for the regmap backed clocks */
> +	for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++)
> +		axg_audio_clk_regmaps[i]->map = map;
> +
> +	/* Take care to skip the registered input clocks */
> +	for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) {
> +		hw = axg_audio_hw_onecell_data.hws[i];
> +		/* array might be sparse */
> +		if (!hw)
> +			continue;
> +
> +		ret = devm_clk_hw_register(dev, hw);
> +		if (ret) {
> +			dev_err(dev, "failed to register clock %s\n",
> +				hw->init->name);
> +			return ret;
> +		}
> +	}
> +
> +	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> +					   &axg_audio_hw_onecell_data);
> +}
> +
> +static const struct of_device_id clkc_match_table[] = {
> +	{ .compatible = "amlogic,axg-audio-clkc" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, clkc_match_table);
> +
> +static struct platform_driver axg_audio_driver = {
> +	.probe		= axg_audio_clkc_probe,
> +	.driver		= {
> +		.name	= "axg-audio-clkc",
> +		.of_match_table = clkc_match_table,
> +	},
> +};
> +module_platform_driver(axg_audio_driver);
> +
> +MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver");
> +MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h
> new file mode 100644
> index 000000000000..e7a0efd12429
> --- /dev/null
> +++ b/drivers/clk/meson/axg-audio.h
> @@ -0,0 +1,127 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2018 BayLibre, SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + */
> +
> +#ifndef __AXG_AUDIO_CLKC_H
> +#define __AXG_AUDIO_CLKC_H
> +
> +/*
> + * Audio Clock  register offsets
> + *
> + * Register offsets from the datasheet must be multiplied by 4 before
> + * to get the right offset
> + */
> +#define AUDIO_CLK_GATE_EN	0x000
> +#define AUDIO_MCLK_A_CTRL	0x004
> +#define AUDIO_MCLK_B_CTRL	0x008
> +#define AUDIO_MCLK_C_CTRL	0x00C
> +#define AUDIO_MCLK_D_CTRL	0x010
> +#define AUDIO_MCLK_E_CTRL	0x014
> +#define AUDIO_MCLK_F_CTRL	0x018
> +#define AUDIO_MST_A_SCLK_CTRL0	0x040
> +#define AUDIO_MST_A_SCLK_CTRL1	0x044
> +#define AUDIO_MST_B_SCLK_CTRL0	0x048
> +#define AUDIO_MST_B_SCLK_CTRL1	0x04C
> +#define AUDIO_MST_C_SCLK_CTRL0	0x050
> +#define AUDIO_MST_C_SCLK_CTRL1	0x054
> +#define AUDIO_MST_D_SCLK_CTRL0	0x058
> +#define AUDIO_MST_D_SCLK_CTRL1	0x05C
> +#define AUDIO_MST_E_SCLK_CTRL0	0x060
> +#define AUDIO_MST_E_SCLK_CTRL1	0x064
> +#define AUDIO_MST_F_SCLK_CTRL0	0x068
> +#define AUDIO_MST_F_SCLK_CTRL1	0x06C
> +#define AUDIO_CLK_TDMIN_A_CTRL	0x080
> +#define AUDIO_CLK_TDMIN_B_CTRL	0x084
> +#define AUDIO_CLK_TDMIN_C_CTRL	0x088
> +#define AUDIO_CLK_TDMIN_LB_CTRL 0x08C
> +#define AUDIO_CLK_TDMOUT_A_CTRL 0x090
> +#define AUDIO_CLK_TDMOUT_B_CTRL 0x094
> +#define AUDIO_CLK_TDMOUT_C_CTRL 0x098
> +#define AUDIO_CLK_SPDIFIN_CTRL	0x09C
> +#define AUDIO_CLK_SPDIFOUT_CTRL 0x0A0
> +#define AUDIO_CLK_RESAMPLE_CTRL 0x0A4
> +#define AUDIO_CLK_LOCKER_CTRL	0x0A8
> +#define AUDIO_CLK_PDMIN_CTRL0	0x0AC
> +#define AUDIO_CLK_PDMIN_CTRL1	0x0B0
> +
> +/*
> + * CLKID index values
> + * These indices are entirely contrived and do not map onto the hardware.
> + */
> +
> +#define AUD_CLKID_PCLK			0
> +#define AUD_CLKID_MST0			1
> +#define AUD_CLKID_MST1			2
> +#define AUD_CLKID_MST2			3
> +#define AUD_CLKID_MST3			4
> +#define AUD_CLKID_MST4			5
> +#define AUD_CLKID_MST5			6
> +#define AUD_CLKID_MST6			7
> +#define AUD_CLKID_MST7			8
> +#define AUD_CLKID_MST_A_MCLK_SEL	59
> +#define AUD_CLKID_MST_B_MCLK_SEL	60
> +#define AUD_CLKID_MST_C_MCLK_SEL	61
> +#define AUD_CLKID_MST_D_MCLK_SEL	62
> +#define AUD_CLKID_MST_E_MCLK_SEL	63
> +#define AUD_CLKID_MST_F_MCLK_SEL	64
> +#define AUD_CLKID_MST_A_MCLK_DIV	65
> +#define AUD_CLKID_MST_B_MCLK_DIV	66
> +#define AUD_CLKID_MST_C_MCLK_DIV	67
> +#define AUD_CLKID_MST_D_MCLK_DIV	68
> +#define AUD_CLKID_MST_E_MCLK_DIV	69
> +#define AUD_CLKID_MST_F_MCLK_DIV	70
> +#define AUD_CLKID_SPDIFOUT_CLK_SEL	71
> +#define AUD_CLKID_SPDIFOUT_CLK_DIV	72
> +#define AUD_CLKID_SPDIFIN_CLK_SEL	73
> +#define AUD_CLKID_SPDIFIN_CLK_DIV	74
> +#define AUD_CLKID_PDM_DCLK_SEL		75
> +#define AUD_CLKID_PDM_DCLK_DIV		76
> +#define AUD_CLKID_PDM_SYSCLK_SEL	77
> +#define AUD_CLKID_PDM_SYSCLK_DIV	78
> +#define AUD_CLKID_MST_A_SCLK_PRE_EN	92
> +#define AUD_CLKID_MST_B_SCLK_PRE_EN	93
> +#define AUD_CLKID_MST_C_SCLK_PRE_EN	94
> +#define AUD_CLKID_MST_D_SCLK_PRE_EN	95
> +#define AUD_CLKID_MST_E_SCLK_PRE_EN	96
> +#define AUD_CLKID_MST_F_SCLK_PRE_EN	97
> +#define AUD_CLKID_MST_A_SCLK_DIV	98
> +#define AUD_CLKID_MST_B_SCLK_DIV	99
> +#define AUD_CLKID_MST_C_SCLK_DIV	100
> +#define AUD_CLKID_MST_D_SCLK_DIV	101
> +#define AUD_CLKID_MST_E_SCLK_DIV	102
> +#define AUD_CLKID_MST_F_SCLK_DIV	103
> +#define AUD_CLKID_MST_A_SCLK_POST_EN	104
> +#define AUD_CLKID_MST_B_SCLK_POST_EN	105
> +#define AUD_CLKID_MST_C_SCLK_POST_EN	106
> +#define AUD_CLKID_MST_D_SCLK_POST_EN	107
> +#define AUD_CLKID_MST_E_SCLK_POST_EN	108
> +#define AUD_CLKID_MST_F_SCLK_POST_EN	109
> +#define AUD_CLKID_MST_A_LRCLK_DIV	110
> +#define AUD_CLKID_MST_B_LRCLK_DIV	111
> +#define AUD_CLKID_MST_C_LRCLK_DIV	112
> +#define AUD_CLKID_MST_D_LRCLK_DIV	113
> +#define AUD_CLKID_MST_E_LRCLK_DIV	114
> +#define AUD_CLKID_MST_F_LRCLK_DIV	115
> +#define AUD_CLKID_TDMIN_A_SCLK_PRE_EN	137
> +#define AUD_CLKID_TDMIN_B_SCLK_PRE_EN	138
> +#define AUD_CLKID_TDMIN_C_SCLK_PRE_EN	139
> +#define AUD_CLKID_TDMIN_LB_SCLK_PRE_EN	140
> +#define AUD_CLKID_TDMOUT_A_SCLK_PRE_EN	141
> +#define AUD_CLKID_TDMOUT_B_SCLK_PRE_EN	142
> +#define AUD_CLKID_TDMOUT_C_SCLK_PRE_EN	143
> +#define AUD_CLKID_TDMIN_A_SCLK_POST_EN	144
> +#define AUD_CLKID_TDMIN_B_SCLK_POST_EN	145
> +#define AUD_CLKID_TDMIN_C_SCLK_POST_EN	146
> +#define AUD_CLKID_TDMIN_LB_SCLK_POST_EN	147
> +#define AUD_CLKID_TDMOUT_A_SCLK_POST_EN	148
> +#define AUD_CLKID_TDMOUT_B_SCLK_POST_EN	149
> +#define AUD_CLKID_TDMOUT_C_SCLK_POST_EN	150
> +
> +/* include the CLKIDs which are part of the DT bindings */
> +#include <dt-bindings/clock/axg-audio-clkc.h>
> +
> +#define NR_CLKS	151
> +
> +#endif /*__AXG_AUDIO_CLKC_H */
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
@ 2018-04-26  8:49     ` Neil Armstrong
  0 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:49 UTC (permalink / raw)
  To: linus-amlogic

On 25/04/2018 18:33, Jerome Brunet wrote:
> The axg audio clock controller is the clock generation unit for the
> amlogic audio subsystem of A113 based SoCs. It may be clocked by 8
> different plls provided by the primary clock controller and also by
> 10 slave bit clocks and 10 slave sample clocks which may be provided
> by external components, such as audio codecs, through the SoC pads.
> 
> It contains several muxes, dividers and gates which are fed into the
> the different devices of the audio subsystem.
> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  drivers/clk/meson/Kconfig     |   9 +
>  drivers/clk/meson/Makefile    |   1 +
>  drivers/clk/meson/axg-audio.c | 845 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/meson/axg-audio.h | 127 +++++++
>  4 files changed, 982 insertions(+)
>  create mode 100644 drivers/clk/meson/axg-audio.c
>  create mode 100644 drivers/clk/meson/axg-audio.h
> 
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 7f7fd6fb3809..006fa1204e5b 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -38,3 +38,12 @@ config COMMON_CLK_AXG
>  	help
>  	  Support for the clock controller on AmLogic A113D devices, aka axg.
>  	  Say Y if you want peripherals and CPU frequency scaling to work.
> +
> +config COMMON_CLK_AXG_AUDIO
> +	tristate "Meson AXG Audio Clock Controller Driver"
> +	depends on COMMON_CLK_AXG
> +	select COMMON_CLK_AMLOGIC_AUDIO
> +	select MFD_SYSCON
> +	help
> +	  Support for the audio clock controller on AmLogic A113D devices,
> +	  aka axg, Say Y if you want audio subsystem to work.
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index f51b4754c31b..1ab89b627586 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -8,4 +8,5 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO)	+= clk-triphase.o sclk-div.o
>  obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
> +obj-$(CONFIG_COMMON_CLK_AXG_AUDIO)	+= axg-audio.o
>  obj-$(CONFIG_COMMON_CLK_REGMAP_MESON)	+= clk-regmap.o
> diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
> new file mode 100644
> index 000000000000..830c13ccd819
> --- /dev/null
> +++ b/drivers/clk/meson/axg-audio.c
> @@ -0,0 +1,845 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2018 BayLibre, SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/init.h>
> +#include <linux/of_device.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +
> +#include "clkc-audio.h"
> +#include "axg-audio.h"
> +
> +#define AXG_MST_IN_COUNT	8
> +#define AXG_SLV_SCLK_COUNT	10
> +#define AXG_SLV_LRCLK_COUNT	10
> +
> +#define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags)		\
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct clk_regmap_gate_data){				\
> +		.offset = (_reg),					\
> +		.bit_idx = (_bit),					\
> +	},								\
> +	.hw.init = &(struct clk_init_data) {				\
> +		.name = "axg_"#_name,					\
> +		.ops = &clk_regmap_gate_ops,				\
> +		.parent_names = (const char *[]){ _pname },		\
> +		.num_parents = 1,					\
> +		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
> +	},								\
> +}
> +
> +#define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct clk_regmap_mux_data){				\
> +		.offset = (_reg),					\
> +		.mask = (_mask),					\
> +		.shift = (_shift),					\
> +		.flags = (_dflags),					\
> +	},								\
> +	.hw.init = &(struct clk_init_data){				\
> +		.name = "axg_"#_name,					\
> +		.ops = &clk_regmap_mux_ops,				\
> +		.parent_names = (_pnames),				\
> +		.num_parents = ARRAY_SIZE(_pnames),			\
> +		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
> +	},								\
> +}
> +
> +#define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct clk_regmap_div_data){				\
> +		.offset = (_reg),					\
> +		.shift = (_shift),					\
> +		.width = (_width),					\
> +		.flags = (_dflags),					\
> +	},								\
> +	.hw.init = &(struct clk_init_data){				\
> +		.name = "axg_"#_name,					\
> +		.ops = &clk_regmap_divider_ops,				\
> +		.parent_names = (const char *[]) { _pname },		\
> +		.num_parents = 1,					\
> +		.flags = (_iflags),					\
> +	},								\
> +}
> +
> +#define AXG_PCLK_GATE(_name, _bit)				\
> +	AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0)
> +
> +/* Audio peripheral clocks */
> +static AXG_PCLK_GATE(ddr_arb,	   0);
> +static AXG_PCLK_GATE(pdm,	   1);
> +static AXG_PCLK_GATE(tdmin_a,	   2);
> +static AXG_PCLK_GATE(tdmin_b,	   3);
> +static AXG_PCLK_GATE(tdmin_c,	   4);
> +static AXG_PCLK_GATE(tdmin_lb,	   5);
> +static AXG_PCLK_GATE(tdmout_a,	   6);
> +static AXG_PCLK_GATE(tdmout_b,	   7);
> +static AXG_PCLK_GATE(tdmout_c,	   8);
> +static AXG_PCLK_GATE(frddr_a,	   9);
> +static AXG_PCLK_GATE(frddr_b,	   10);
> +static AXG_PCLK_GATE(frddr_c,	   11);
> +static AXG_PCLK_GATE(toddr_a,	   12);
> +static AXG_PCLK_GATE(toddr_b,	   13);
> +static AXG_PCLK_GATE(toddr_c,	   14);
> +static AXG_PCLK_GATE(loopback,	   15);
> +static AXG_PCLK_GATE(spdifin,	   16);
> +static AXG_PCLK_GATE(spdifout,	   17);
> +static AXG_PCLK_GATE(resample,	   18);
> +static AXG_PCLK_GATE(power_detect, 19);
> +
> +/* Audio Master Clocks */
> +static const char * const mst_mux_parent_names[] = {
> +	"axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3",
> +	"axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7",
> +};
> +
> +#define AXG_MST_MCLK_MUX(_name, _reg)					\
> +	AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
> +		    mst_mux_parent_names, CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_MCLK_MUX(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
> +static AXG_MST_MCLK_MUX(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
> +static AXG_MST_MCLK_MUX(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
> +static AXG_MST_MCLK_MUX(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
> +static AXG_MST_MCLK_MUX(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
> +static AXG_MST_MCLK_MUX(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
> +static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
> +static AXG_MST_MCLK_MUX(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
> +static AXG_MST_MCLK_MUX(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
> +static AXG_MST_MCLK_MUX(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
> +
> +#define AXG_MST_MCLK_DIV(_name, _reg)					\
> +	AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
> +		    "axg_"#_name"_sel", CLK_SET_RATE_PARENT)		\
> +
> +static AXG_MST_MCLK_DIV(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
> +static AXG_MST_MCLK_DIV(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
> +static AXG_MST_MCLK_DIV(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
> +static AXG_MST_MCLK_DIV(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
> +static AXG_MST_MCLK_DIV(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
> +static AXG_MST_MCLK_DIV(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
> +static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
> +static AXG_MST_MCLK_DIV(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
> +static AXG_MST_MCLK_DIV(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
> +static AXG_MST_MCLK_DIV(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
> +
> +#define AXG_MST_MCLK_GATE(_name, _reg)					\
> +	AXG_AUD_GATE(_name, _reg, 31,  "axg_"#_name"_div",		\
> +		     CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_MCLK_GATE(mst_a_mclk,   AUDIO_MCLK_A_CTRL);
> +static AXG_MST_MCLK_GATE(mst_b_mclk,   AUDIO_MCLK_B_CTRL);
> +static AXG_MST_MCLK_GATE(mst_c_mclk,   AUDIO_MCLK_C_CTRL);
> +static AXG_MST_MCLK_GATE(mst_d_mclk,   AUDIO_MCLK_D_CTRL);
> +static AXG_MST_MCLK_GATE(mst_e_mclk,   AUDIO_MCLK_E_CTRL);
> +static AXG_MST_MCLK_GATE(mst_f_mclk,   AUDIO_MCLK_F_CTRL);
> +static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
> +static AXG_MST_MCLK_GATE(spdifin_clk,  AUDIO_CLK_SPDIFIN_CTRL);
> +static AXG_MST_MCLK_GATE(pdm_dclk,     AUDIO_CLK_PDMIN_CTRL0);
> +static AXG_MST_MCLK_GATE(pdm_sysclk,   AUDIO_CLK_PDMIN_CTRL1);
> +
> +/* Sample Clocks */
> +#define AXG_MST_SCLK_PRE_EN(_name, _reg)			\
> +	AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31,	\
> +		     "axg_mst_"#_name"_mclk", 0)
> +
> +static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0);
> +static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0);
> +
> +#define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width,		\
> +			 _hi_shift, _hi_width, _pname, _iflags)		\
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct meson_sclk_div_data) {				\
> +		.div = {						\
> +			.reg_off = (_reg),				\
> +			.shift   = (_div_shift),			\
> +			.width   = (_div_width),			\
> +		},							\
> +		.hi = {							\
> +			.reg_off = (_reg),				\
> +			.shift   = (_hi_shift),				\
> +			.width   = (_hi_width),				\
> +		},							\
> +	},								\
> +	.hw.init = &(struct clk_init_data) {				\
> +		.name = "axg_"#_name,					\
> +		.ops = &meson_sclk_div_ops,				\
> +		.parent_names = (const char *[]) { _pname },		\
> +		.num_parents = 1,					\
> +		.flags = (_iflags),					\
> +	},								\
> +}
> +
> +#define AXG_MST_SCLK_DIV(_name, _reg)					\
> +	AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0,	\
> +			 "axg_mst_"#_name"_sclk_pre_en",		\
> +			 CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
> +static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
> +
> +#define AXG_MST_SCLK_POST_EN(_name, _reg)				\
> +	AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30,		\
> +		     "axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0);
> +static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0);
> +
> +#define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \
> +			 _pname, _iflags)				\
> +struct clk_regmap axg_##_name = {					\
> +	.data = &(struct meson_clk_triphase_data) {			\
> +		.ph0 = {						\
> +			.reg_off = (_reg),				\
> +			.shift   = (_shift0),				\
> +			.width   = (_width),				\
> +		},							\
> +		.ph1 = {						\
> +			.reg_off = (_reg),				\
> +			.shift   = (_shift1),				\
> +			.width   = (_width),				\
> +		},							\
> +		.ph2 = {						\
> +			.reg_off = (_reg),				\
> +			.shift   = (_shift2),				\
> +			.width   = (_width),				\
> +		},							\
> +	},								\
> +	.hw.init = &(struct clk_init_data) {				\
> +		.name = "axg_"#_name,					\
> +		.ops = &meson_clk_triphase_ops,				\
> +		.parent_names = (const char *[]) { _pname },		\
> +		.num_parents = 1,					\
> +		.flags = CLK_DUTY_CYCLE_PARENT | (_iflags),		\
> +	},								\
> +}
> +
> +#define AXG_MST_SCLK(_name, _reg)					\
> +	AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4,		\
> +			 "axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1);
> +static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1);
> +static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1);
> +static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1);
> +static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1);
> +static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1);
> +
> +#define AXG_MST_LRCLK_DIV(_name, _reg)					\
> +	AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10,	\
> +		    "axg_mst_"#_name"_sclk_post_en", 0)			\
> +
> +static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
> +static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0);
> +
> +#define AXG_MST_LRCLK(_name, _reg)					\
> +	AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5,		\
> +			 "axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT)
> +
> +static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1);
> +static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1);
> +static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1);
> +static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1);
> +static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1);
> +static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1);
> +
> +static const char * const tdm_sclk_parent_names[] = {
> +	"axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk",
> +	"axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk",
> +	"axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2",
> +	"axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5",
> +	"axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8",
> +	"axg_slv_sclk9"
> +};
> +
> +#define AXG_TDM_SCLK_MUX(_name, _reg)				\
> +	AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24,	\
> +		    CLK_MUX_ROUND_CLOSEST,			\
> +		    tdm_sclk_parent_names, 0)
> +
> +static AXG_TDM_SCLK_MUX(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_SCLK_MUX(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_SCLK_MUX(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +#define AXG_TDM_SCLK_PRE_EN(_name, _reg)				\
> +	AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31,		\
> +		     "axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT)
> +
> +static AXG_TDM_SCLK_PRE_EN(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +#define AXG_TDM_SCLK_POST_EN(_name, _reg)				\
> +	AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30,		\
> +		     "axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT)
> +
> +static AXG_TDM_SCLK_POST_EN(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_SCLK_POST_EN(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_SCLK_POST_EN(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +#define AXG_TDM_SCLK(_name, _reg)					\
> +	struct clk_regmap axg_tdm##_name##_sclk = {			\
> +	.data = &(struct meson_clk_phase_data) {			\
> +		.ph = {							\
> +			.reg_off = (_reg),				\
> +			.shift   = 29,					\
> +			.width   = 1,					\
> +		},							\
> +	},								\
> +	.hw.init = &(struct clk_init_data) {				\
> +		.name = "axg_tdm"#_name"_sclk",				\
> +		.ops = &meson_clk_phase_ops,				\
> +		.parent_names = (const char *[])			\
> +		{ "axg_tdm"#_name"_sclk_post_en" },			\
> +		.num_parents = 1,					\
> +		.flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT,	\
> +	},								\
> +}
> +
> +static AXG_TDM_SCLK(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_SCLK(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_SCLK(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +static const char * const tdm_lrclk_parent_names[] = {
> +	"axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk",
> +	"axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk",
> +	"axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2",
> +	"axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5",
> +	"axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8",
> +	"axg_slv_lrclk9"
> +};
> +
> +#define AXG_TDM_LRLCK(_name, _reg)		       \
> +	AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \
> +		    CLK_MUX_ROUND_CLOSEST,	       \
> +		    tdm_lrclk_parent_names, 0)
> +
> +static AXG_TDM_LRLCK(in_a,  AUDIO_CLK_TDMIN_A_CTRL);
> +static AXG_TDM_LRLCK(in_b,  AUDIO_CLK_TDMIN_B_CTRL);
> +static AXG_TDM_LRLCK(in_c,  AUDIO_CLK_TDMIN_C_CTRL);
> +static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
> +static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
> +static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
> +static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
> +
> +/*
> + * Array of all clocks provided by this provider
> + * The input clocks of the controller will be populated at runtime
> + */
> +static struct clk_hw_onecell_data axg_audio_hw_onecell_data = {
> +	.hws = {
> +		[AUD_CLKID_DDR_ARB]		= &axg_ddr_arb.hw,
> +		[AUD_CLKID_PDM]			= &axg_pdm.hw,
> +		[AUD_CLKID_TDMIN_A]		= &axg_tdmin_a.hw,
> +		[AUD_CLKID_TDMIN_B]		= &axg_tdmin_b.hw,
> +		[AUD_CLKID_TDMIN_C]		= &axg_tdmin_c.hw,
> +		[AUD_CLKID_TDMIN_LB]		= &axg_tdmin_lb.hw,
> +		[AUD_CLKID_TDMOUT_A]		= &axg_tdmout_a.hw,
> +		[AUD_CLKID_TDMOUT_B]		= &axg_tdmout_b.hw,
> +		[AUD_CLKID_TDMOUT_C]		= &axg_tdmout_c.hw,
> +		[AUD_CLKID_FRDDR_A]		= &axg_frddr_a.hw,
> +		[AUD_CLKID_FRDDR_B]		= &axg_frddr_b.hw,
> +		[AUD_CLKID_FRDDR_C]		= &axg_frddr_c.hw,
> +		[AUD_CLKID_TODDR_A]		= &axg_toddr_a.hw,
> +		[AUD_CLKID_TODDR_B]		= &axg_toddr_b.hw,
> +		[AUD_CLKID_TODDR_C]		= &axg_toddr_c.hw,
> +		[AUD_CLKID_LOOPBACK]		= &axg_loopback.hw,
> +		[AUD_CLKID_SPDIFIN]		= &axg_spdifin.hw,
> +		[AUD_CLKID_SPDIFOUT]		= &axg_spdifout.hw,
> +		[AUD_CLKID_RESAMPLE]		= &axg_resample.hw,
> +		[AUD_CLKID_POWER_DETECT]	= &axg_power_detect.hw,
> +		[AUD_CLKID_MST_A_MCLK_SEL]	= &axg_mst_a_mclk_sel.hw,
> +		[AUD_CLKID_MST_B_MCLK_SEL]	= &axg_mst_b_mclk_sel.hw,
> +		[AUD_CLKID_MST_C_MCLK_SEL]	= &axg_mst_c_mclk_sel.hw,
> +		[AUD_CLKID_MST_D_MCLK_SEL]	= &axg_mst_d_mclk_sel.hw,
> +		[AUD_CLKID_MST_E_MCLK_SEL]	= &axg_mst_e_mclk_sel.hw,
> +		[AUD_CLKID_MST_F_MCLK_SEL]	= &axg_mst_f_mclk_sel.hw,
> +		[AUD_CLKID_MST_A_MCLK_DIV]	= &axg_mst_a_mclk_div.hw,
> +		[AUD_CLKID_MST_B_MCLK_DIV]	= &axg_mst_b_mclk_div.hw,
> +		[AUD_CLKID_MST_C_MCLK_DIV]	= &axg_mst_c_mclk_div.hw,
> +		[AUD_CLKID_MST_D_MCLK_DIV]	= &axg_mst_d_mclk_div.hw,
> +		[AUD_CLKID_MST_E_MCLK_DIV]	= &axg_mst_e_mclk_div.hw,
> +		[AUD_CLKID_MST_F_MCLK_DIV]	= &axg_mst_f_mclk_div.hw,
> +		[AUD_CLKID_MST_A_MCLK]		= &axg_mst_a_mclk.hw,
> +		[AUD_CLKID_MST_B_MCLK]		= &axg_mst_b_mclk.hw,
> +		[AUD_CLKID_MST_C_MCLK]		= &axg_mst_c_mclk.hw,
> +		[AUD_CLKID_MST_D_MCLK]		= &axg_mst_d_mclk.hw,
> +		[AUD_CLKID_MST_E_MCLK]		= &axg_mst_e_mclk.hw,
> +		[AUD_CLKID_MST_F_MCLK]		= &axg_mst_f_mclk.hw,
> +		[AUD_CLKID_SPDIFOUT_CLK_SEL]	= &axg_spdifout_clk_sel.hw,
> +		[AUD_CLKID_SPDIFOUT_CLK_DIV]	= &axg_spdifout_clk_div.hw,
> +		[AUD_CLKID_SPDIFOUT_CLK]	= &axg_spdifout_clk.hw,
> +		[AUD_CLKID_SPDIFIN_CLK_SEL]	= &axg_spdifin_clk_sel.hw,
> +		[AUD_CLKID_SPDIFIN_CLK_DIV]	= &axg_spdifin_clk_div.hw,
> +		[AUD_CLKID_SPDIFIN_CLK]		= &axg_spdifin_clk.hw,
> +		[AUD_CLKID_PDM_DCLK_SEL]	= &axg_pdm_dclk_sel.hw,
> +		[AUD_CLKID_PDM_DCLK_DIV]	= &axg_pdm_dclk_div.hw,
> +		[AUD_CLKID_PDM_DCLK]		= &axg_pdm_dclk.hw,
> +		[AUD_CLKID_PDM_SYSCLK_SEL]	= &axg_pdm_sysclk_sel.hw,
> +		[AUD_CLKID_PDM_SYSCLK_DIV]	= &axg_pdm_sysclk_div.hw,
> +		[AUD_CLKID_PDM_SYSCLK]		= &axg_pdm_sysclk.hw,
> +		[AUD_CLKID_MST_A_SCLK_PRE_EN]	= &axg_mst_a_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_B_SCLK_PRE_EN]	= &axg_mst_b_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_C_SCLK_PRE_EN]	= &axg_mst_c_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_D_SCLK_PRE_EN]	= &axg_mst_d_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_E_SCLK_PRE_EN]	= &axg_mst_e_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_F_SCLK_PRE_EN]	= &axg_mst_f_sclk_pre_en.hw,
> +		[AUD_CLKID_MST_A_SCLK_DIV]	= &axg_mst_a_sclk_div.hw,
> +		[AUD_CLKID_MST_B_SCLK_DIV]	= &axg_mst_b_sclk_div.hw,
> +		[AUD_CLKID_MST_C_SCLK_DIV]	= &axg_mst_c_sclk_div.hw,
> +		[AUD_CLKID_MST_D_SCLK_DIV]	= &axg_mst_d_sclk_div.hw,
> +		[AUD_CLKID_MST_E_SCLK_DIV]	= &axg_mst_e_sclk_div.hw,
> +		[AUD_CLKID_MST_F_SCLK_DIV]	= &axg_mst_f_sclk_div.hw,
> +		[AUD_CLKID_MST_A_SCLK_POST_EN]	= &axg_mst_a_sclk_post_en.hw,
> +		[AUD_CLKID_MST_B_SCLK_POST_EN]	= &axg_mst_b_sclk_post_en.hw,
> +		[AUD_CLKID_MST_C_SCLK_POST_EN]	= &axg_mst_c_sclk_post_en.hw,
> +		[AUD_CLKID_MST_D_SCLK_POST_EN]	= &axg_mst_d_sclk_post_en.hw,
> +		[AUD_CLKID_MST_E_SCLK_POST_EN]	= &axg_mst_e_sclk_post_en.hw,
> +		[AUD_CLKID_MST_F_SCLK_POST_EN]	= &axg_mst_f_sclk_post_en.hw,
> +		[AUD_CLKID_MST_A_SCLK]		= &axg_mst_a_sclk.hw,
> +		[AUD_CLKID_MST_B_SCLK]		= &axg_mst_b_sclk.hw,
> +		[AUD_CLKID_MST_C_SCLK]		= &axg_mst_c_sclk.hw,
> +		[AUD_CLKID_MST_D_SCLK]		= &axg_mst_d_sclk.hw,
> +		[AUD_CLKID_MST_E_SCLK]		= &axg_mst_e_sclk.hw,
> +		[AUD_CLKID_MST_F_SCLK]		= &axg_mst_f_sclk.hw,
> +		[AUD_CLKID_MST_A_LRCLK_DIV]	= &axg_mst_a_lrclk_div.hw,
> +		[AUD_CLKID_MST_B_LRCLK_DIV]	= &axg_mst_b_lrclk_div.hw,
> +		[AUD_CLKID_MST_C_LRCLK_DIV]	= &axg_mst_c_lrclk_div.hw,
> +		[AUD_CLKID_MST_D_LRCLK_DIV]	= &axg_mst_d_lrclk_div.hw,
> +		[AUD_CLKID_MST_E_LRCLK_DIV]	= &axg_mst_e_lrclk_div.hw,
> +		[AUD_CLKID_MST_F_LRCLK_DIV]	= &axg_mst_f_lrclk_div.hw,
> +		[AUD_CLKID_MST_A_LRCLK]		= &axg_mst_a_lrclk.hw,
> +		[AUD_CLKID_MST_B_LRCLK]		= &axg_mst_b_lrclk.hw,
> +		[AUD_CLKID_MST_C_LRCLK]		= &axg_mst_c_lrclk.hw,
> +		[AUD_CLKID_MST_D_LRCLK]		= &axg_mst_d_lrclk.hw,
> +		[AUD_CLKID_MST_E_LRCLK]		= &axg_mst_e_lrclk.hw,
> +		[AUD_CLKID_MST_F_LRCLK]		= &axg_mst_f_lrclk.hw,
> +		[AUD_CLKID_TDMIN_A_SCLK_SEL]	= &axg_tdmin_a_sclk_sel.hw,
> +		[AUD_CLKID_TDMIN_B_SCLK_SEL]	= &axg_tdmin_b_sclk_sel.hw,
> +		[AUD_CLKID_TDMIN_C_SCLK_SEL]	= &axg_tdmin_c_sclk_sel.hw,
> +		[AUD_CLKID_TDMIN_LB_SCLK_SEL]	= &axg_tdmin_lb_sclk_sel.hw,
> +		[AUD_CLKID_TDMOUT_A_SCLK_SEL]	= &axg_tdmout_a_sclk_sel.hw,
> +		[AUD_CLKID_TDMOUT_B_SCLK_SEL]	= &axg_tdmout_b_sclk_sel.hw,
> +		[AUD_CLKID_TDMOUT_C_SCLK_SEL]	= &axg_tdmout_c_sclk_sel.hw,
> +		[AUD_CLKID_TDMIN_A_SCLK_PRE_EN]	= &axg_tdmin_a_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMIN_B_SCLK_PRE_EN]	= &axg_tdmin_b_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMIN_C_SCLK_PRE_EN]	= &axg_tdmin_c_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw,
> +		[AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw,
> +		[AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw,
> +		[AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw,
> +		[AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw,
> +		[AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw,
> +		[AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw,
> +		[AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw,
> +		[AUD_CLKID_TDMIN_A_SCLK]	= &axg_tdmin_a_sclk.hw,
> +		[AUD_CLKID_TDMIN_B_SCLK]	= &axg_tdmin_b_sclk.hw,
> +		[AUD_CLKID_TDMIN_C_SCLK]	= &axg_tdmin_c_sclk.hw,
> +		[AUD_CLKID_TDMIN_LB_SCLK]	= &axg_tdmin_lb_sclk.hw,
> +		[AUD_CLKID_TDMOUT_A_SCLK]	= &axg_tdmout_a_sclk.hw,
> +		[AUD_CLKID_TDMOUT_B_SCLK]	= &axg_tdmout_b_sclk.hw,
> +		[AUD_CLKID_TDMOUT_C_SCLK]	= &axg_tdmout_c_sclk.hw,
> +		[AUD_CLKID_TDMIN_A_LRCLK]	= &axg_tdmin_a_lrclk.hw,
> +		[AUD_CLKID_TDMIN_B_LRCLK]	= &axg_tdmin_b_lrclk.hw,
> +		[AUD_CLKID_TDMIN_C_LRCLK]	= &axg_tdmin_c_lrclk.hw,
> +		[AUD_CLKID_TDMIN_LB_LRCLK]	= &axg_tdmin_lb_lrclk.hw,
> +		[AUD_CLKID_TDMOUT_A_LRCLK]	= &axg_tdmout_a_lrclk.hw,
> +		[AUD_CLKID_TDMOUT_B_LRCLK]	= &axg_tdmout_b_lrclk.hw,
> +		[AUD_CLKID_TDMOUT_C_LRCLK]	= &axg_tdmout_c_lrclk.hw,
> +		[NR_CLKS] = NULL,
> +	},
> +	.num = NR_CLKS,
> +};
> +
> +/* Convenience table to populate regmap in .probe() */
> +static struct clk_regmap *const axg_audio_clk_regmaps[] = {
> +	&axg_ddr_arb,
> +	&axg_pdm,
> +	&axg_tdmin_a,
> +	&axg_tdmin_b,
> +	&axg_tdmin_c,
> +	&axg_tdmin_lb,
> +	&axg_tdmout_a,
> +	&axg_tdmout_b,
> +	&axg_tdmout_c,
> +	&axg_frddr_a,
> +	&axg_frddr_b,
> +	&axg_frddr_c,
> +	&axg_toddr_a,
> +	&axg_toddr_b,
> +	&axg_toddr_c,
> +	&axg_loopback,
> +	&axg_spdifin,
> +	&axg_spdifout,
> +	&axg_resample,
> +	&axg_power_detect,
> +	&axg_mst_a_mclk_sel,
> +	&axg_mst_b_mclk_sel,
> +	&axg_mst_c_mclk_sel,
> +	&axg_mst_d_mclk_sel,
> +	&axg_mst_e_mclk_sel,
> +	&axg_mst_f_mclk_sel,
> +	&axg_mst_a_mclk_div,
> +	&axg_mst_b_mclk_div,
> +	&axg_mst_c_mclk_div,
> +	&axg_mst_d_mclk_div,
> +	&axg_mst_e_mclk_div,
> +	&axg_mst_f_mclk_div,
> +	&axg_mst_a_mclk,
> +	&axg_mst_b_mclk,
> +	&axg_mst_c_mclk,
> +	&axg_mst_d_mclk,
> +	&axg_mst_e_mclk,
> +	&axg_mst_f_mclk,
> +	&axg_spdifout_clk_sel,
> +	&axg_spdifout_clk_div,
> +	&axg_spdifout_clk,
> +	&axg_spdifin_clk_sel,
> +	&axg_spdifin_clk_div,
> +	&axg_spdifin_clk,
> +	&axg_pdm_dclk_sel,
> +	&axg_pdm_dclk_div,
> +	&axg_pdm_dclk,
> +	&axg_pdm_sysclk_sel,
> +	&axg_pdm_sysclk_div,
> +	&axg_pdm_sysclk,
> +	&axg_mst_a_sclk_pre_en,
> +	&axg_mst_b_sclk_pre_en,
> +	&axg_mst_c_sclk_pre_en,
> +	&axg_mst_d_sclk_pre_en,
> +	&axg_mst_e_sclk_pre_en,
> +	&axg_mst_f_sclk_pre_en,
> +	&axg_mst_a_sclk_div,
> +	&axg_mst_b_sclk_div,
> +	&axg_mst_c_sclk_div,
> +	&axg_mst_d_sclk_div,
> +	&axg_mst_e_sclk_div,
> +	&axg_mst_f_sclk_div,
> +	&axg_mst_a_sclk_post_en,
> +	&axg_mst_b_sclk_post_en,
> +	&axg_mst_c_sclk_post_en,
> +	&axg_mst_d_sclk_post_en,
> +	&axg_mst_e_sclk_post_en,
> +	&axg_mst_f_sclk_post_en,
> +	&axg_mst_a_sclk,
> +	&axg_mst_b_sclk,
> +	&axg_mst_c_sclk,
> +	&axg_mst_d_sclk,
> +	&axg_mst_e_sclk,
> +	&axg_mst_f_sclk,
> +	&axg_mst_a_lrclk_div,
> +	&axg_mst_b_lrclk_div,
> +	&axg_mst_c_lrclk_div,
> +	&axg_mst_d_lrclk_div,
> +	&axg_mst_e_lrclk_div,
> +	&axg_mst_f_lrclk_div,
> +	&axg_mst_a_lrclk,
> +	&axg_mst_b_lrclk,
> +	&axg_mst_c_lrclk,
> +	&axg_mst_d_lrclk,
> +	&axg_mst_e_lrclk,
> +	&axg_mst_f_lrclk,
> +	&axg_tdmin_a_sclk_sel,
> +	&axg_tdmin_b_sclk_sel,
> +	&axg_tdmin_c_sclk_sel,
> +	&axg_tdmin_lb_sclk_sel,
> +	&axg_tdmout_a_sclk_sel,
> +	&axg_tdmout_b_sclk_sel,
> +	&axg_tdmout_c_sclk_sel,
> +	&axg_tdmin_a_sclk_pre_en,
> +	&axg_tdmin_b_sclk_pre_en,
> +	&axg_tdmin_c_sclk_pre_en,
> +	&axg_tdmin_lb_sclk_pre_en,
> +	&axg_tdmout_a_sclk_pre_en,
> +	&axg_tdmout_b_sclk_pre_en,
> +	&axg_tdmout_c_sclk_pre_en,
> +	&axg_tdmin_a_sclk_post_en,
> +	&axg_tdmin_b_sclk_post_en,
> +	&axg_tdmin_c_sclk_post_en,
> +	&axg_tdmin_lb_sclk_post_en,
> +	&axg_tdmout_a_sclk_post_en,
> +	&axg_tdmout_b_sclk_post_en,
> +	&axg_tdmout_c_sclk_post_en,
> +	&axg_tdmin_a_sclk,
> +	&axg_tdmin_b_sclk,
> +	&axg_tdmin_c_sclk,
> +	&axg_tdmin_lb_sclk,
> +	&axg_tdmout_a_sclk,
> +	&axg_tdmout_b_sclk,
> +	&axg_tdmout_c_sclk,
> +	&axg_tdmin_a_lrclk,
> +	&axg_tdmin_b_lrclk,
> +	&axg_tdmin_c_lrclk,
> +	&axg_tdmin_lb_lrclk,
> +	&axg_tdmout_a_lrclk,
> +	&axg_tdmout_b_lrclk,
> +	&axg_tdmout_c_lrclk,
> +};
> +
> +static struct clk *devm_clk_get_enable(struct device *dev, char *id)
> +{
> +	struct clk *clk;
> +	int ret;
> +
> +	clk = devm_clk_get(dev, id);
> +	if (IS_ERR(clk)) {
> +		if (PTR_ERR(clk) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to get %s", id);
> +		return clk;
> +	}
> +
> +	ret = clk_prepare_enable(clk);
> +	if (ret) {
> +		dev_err(dev, "failed to enable %s", id);
> +		return ERR_PTR(ret);
> +	}
> +
> +	ret = devm_add_action_or_reset(dev,
> +				       (void(*)(void *))clk_disable_unprepare,
> +				       clk);
> +	if (ret) {
> +		dev_err(dev, "failed to add reset action on %s", id);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return clk;
> +}
> +
> +static const struct clk_ops axg_clk_no_ops = {};
> +
> +static struct clk_hw *axg_clk_hw_register_bypass(struct device *dev,
> +						 const char *name,
> +						 const char *parent_name)
> +{
> +	struct clk_hw *hw;
> +	struct clk_init_data init;
> +	char *clk_name;
> +	int ret;
> +
> +	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
> +	if (!hw)
> +		return ERR_PTR(-ENOMEM);
> +
> +	clk_name = kasprintf(GFP_KERNEL, "axg_%s", name);
> +	if (!clk_name)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = clk_name;
> +	init.ops = &axg_clk_no_ops;
> +	init.flags = 0;
> +	init.parent_names = parent_name ? &parent_name : NULL;
> +	init.num_parents = parent_name ? 1 : 0;
> +	hw->init = &init;
> +
> +	ret = devm_clk_hw_register(dev, hw);
> +	kfree(clk_name);
> +
> +	return ret ? ERR_PTR(ret) : hw;
> +}
> +
> +static int axg_register_clk_hw_input(struct device *dev,
> +				     const char *name,
> +				     unsigned int clkid)
> +{
> +	struct clk *parent_clk = devm_clk_get(dev, name);
> +	struct clk_hw *hw = NULL;
> +
> +	if (IS_ERR(parent_clk)) {
> +		int err = PTR_ERR(parent_clk);
> +
> +		/* It is ok if an input clock is missing */
> +		if (err == -ENOENT) {
> +			dev_dbg(dev, "%s not provided", name);
> +		} else {
> +			if (err != -EPROBE_DEFER)
> +				dev_err(dev, "failed to get %s clock", name);
> +			return err;
> +		}
> +	} else {
> +		hw = axg_clk_hw_register_bypass(dev, name,
> +						__clk_get_name(parent_clk));
> +	}
> +
> +	if (IS_ERR(hw)) {
> +		dev_err(dev, "failed to register %s clock", name);
> +		return PTR_ERR(hw);
> +	}
> +
> +	axg_audio_hw_onecell_data.hws[clkid] = hw;
> +	return 0;
> +}
> +
> +static int axg_register_clk_hw_inputs(struct device *dev,
> +				      const char *basename,
> +				      unsigned int count,
> +				      unsigned int clkid)
> +{
> +	char *name;
> +	int i, ret;
> +
> +	for (i = 0; i < count; i++) {
> +		name = kasprintf(GFP_KERNEL, "%s%d", basename, i);
> +		if (!name)
> +			return -ENOMEM;
> +
> +		ret = axg_register_clk_hw_input(dev, name, clkid + i);
> +		kfree(name);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct regmap_config axg_audio_regmap_cfg = {
> +	.reg_bits	= 32,
> +	.val_bits	= 32,
> +	.reg_stride	= 4,
> +	.max_register	= AUDIO_CLK_PDMIN_CTRL1,
> +};
> +
> +static int axg_audio_clkc_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct regmap *map;
> +	struct resource *res;
> +	void __iomem *regs;
> +	struct clk *clk;
> +	struct clk_hw *hw;
> +	int ret, i;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	regs = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(regs))
> +		return PTR_ERR(regs);
> +
> +	map = devm_regmap_init_mmio(dev, regs, &axg_audio_regmap_cfg);
> +	if (IS_ERR(map)) {
> +		dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(map));
> +		return PTR_ERR(map);
> +	}
> +
> +	/* Get the mandatory peripheral clock */
> +	clk = devm_clk_get_enable(dev, "pclk");
> +	if (IS_ERR(clk))
> +		return PTR_ERR(clk);
> +
> +	ret = device_reset(dev);
> +	if (ret) {
> +		dev_err(dev, "failed to reset device\n");
> +		return ret;
> +	}
> +
> +	/* Register the peripheral input clock */
> +	hw = axg_clk_hw_register_bypass(dev, "audio_pclk",
> +					__clk_get_name(clk));
> +	if (IS_ERR(hw))
> +		return PTR_ERR(hw);
> +
> +	axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw;
> +
> +	/* Register optional input master clocks */
> +	ret = axg_register_clk_hw_inputs(dev, "mst_in",
> +					 AXG_MST_IN_COUNT,
> +					 AUD_CLKID_MST0);
> +	if (ret)
> +		return ret;
> +
> +	/* Register optional input slave sclks */
> +	ret = axg_register_clk_hw_inputs(dev, "slv_sclk",
> +					 AXG_SLV_SCLK_COUNT,
> +					 AUD_CLKID_SLV_SCLK0);
> +	if (ret)
> +		return ret;
> +
> +	/* Register optional input slave lrclks */
> +	ret = axg_register_clk_hw_inputs(dev, "slv_lrclk",
> +					 AXG_SLV_LRCLK_COUNT,
> +					 AUD_CLKID_SLV_LRCLK0);
> +	if (ret)
> +		return ret;
> +
> +	/* Populate regmap for the regmap backed clocks */
> +	for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++)
> +		axg_audio_clk_regmaps[i]->map = map;
> +
> +	/* Take care to skip the registered input clocks */
> +	for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) {
> +		hw = axg_audio_hw_onecell_data.hws[i];
> +		/* array might be sparse */
> +		if (!hw)
> +			continue;
> +
> +		ret = devm_clk_hw_register(dev, hw);
> +		if (ret) {
> +			dev_err(dev, "failed to register clock %s\n",
> +				hw->init->name);
> +			return ret;
> +		}
> +	}
> +
> +	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> +					   &axg_audio_hw_onecell_data);
> +}
> +
> +static const struct of_device_id clkc_match_table[] = {
> +	{ .compatible = "amlogic,axg-audio-clkc" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, clkc_match_table);
> +
> +static struct platform_driver axg_audio_driver = {
> +	.probe		= axg_audio_clkc_probe,
> +	.driver		= {
> +		.name	= "axg-audio-clkc",
> +		.of_match_table = clkc_match_table,
> +	},
> +};
> +module_platform_driver(axg_audio_driver);
> +
> +MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver");
> +MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h
> new file mode 100644
> index 000000000000..e7a0efd12429
> --- /dev/null
> +++ b/drivers/clk/meson/axg-audio.h
> @@ -0,0 +1,127 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2018 BayLibre, SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + */
> +
> +#ifndef __AXG_AUDIO_CLKC_H
> +#define __AXG_AUDIO_CLKC_H
> +
> +/*
> + * Audio Clock  register offsets
> + *
> + * Register offsets from the datasheet must be multiplied by 4 before
> + * to get the right offset
> + */
> +#define AUDIO_CLK_GATE_EN	0x000
> +#define AUDIO_MCLK_A_CTRL	0x004
> +#define AUDIO_MCLK_B_CTRL	0x008
> +#define AUDIO_MCLK_C_CTRL	0x00C
> +#define AUDIO_MCLK_D_CTRL	0x010
> +#define AUDIO_MCLK_E_CTRL	0x014
> +#define AUDIO_MCLK_F_CTRL	0x018
> +#define AUDIO_MST_A_SCLK_CTRL0	0x040
> +#define AUDIO_MST_A_SCLK_CTRL1	0x044
> +#define AUDIO_MST_B_SCLK_CTRL0	0x048
> +#define AUDIO_MST_B_SCLK_CTRL1	0x04C
> +#define AUDIO_MST_C_SCLK_CTRL0	0x050
> +#define AUDIO_MST_C_SCLK_CTRL1	0x054
> +#define AUDIO_MST_D_SCLK_CTRL0	0x058
> +#define AUDIO_MST_D_SCLK_CTRL1	0x05C
> +#define AUDIO_MST_E_SCLK_CTRL0	0x060
> +#define AUDIO_MST_E_SCLK_CTRL1	0x064
> +#define AUDIO_MST_F_SCLK_CTRL0	0x068
> +#define AUDIO_MST_F_SCLK_CTRL1	0x06C
> +#define AUDIO_CLK_TDMIN_A_CTRL	0x080
> +#define AUDIO_CLK_TDMIN_B_CTRL	0x084
> +#define AUDIO_CLK_TDMIN_C_CTRL	0x088
> +#define AUDIO_CLK_TDMIN_LB_CTRL 0x08C
> +#define AUDIO_CLK_TDMOUT_A_CTRL 0x090
> +#define AUDIO_CLK_TDMOUT_B_CTRL 0x094
> +#define AUDIO_CLK_TDMOUT_C_CTRL 0x098
> +#define AUDIO_CLK_SPDIFIN_CTRL	0x09C
> +#define AUDIO_CLK_SPDIFOUT_CTRL 0x0A0
> +#define AUDIO_CLK_RESAMPLE_CTRL 0x0A4
> +#define AUDIO_CLK_LOCKER_CTRL	0x0A8
> +#define AUDIO_CLK_PDMIN_CTRL0	0x0AC
> +#define AUDIO_CLK_PDMIN_CTRL1	0x0B0
> +
> +/*
> + * CLKID index values
> + * These indices are entirely contrived and do not map onto the hardware.
> + */
> +
> +#define AUD_CLKID_PCLK			0
> +#define AUD_CLKID_MST0			1
> +#define AUD_CLKID_MST1			2
> +#define AUD_CLKID_MST2			3
> +#define AUD_CLKID_MST3			4
> +#define AUD_CLKID_MST4			5
> +#define AUD_CLKID_MST5			6
> +#define AUD_CLKID_MST6			7
> +#define AUD_CLKID_MST7			8
> +#define AUD_CLKID_MST_A_MCLK_SEL	59
> +#define AUD_CLKID_MST_B_MCLK_SEL	60
> +#define AUD_CLKID_MST_C_MCLK_SEL	61
> +#define AUD_CLKID_MST_D_MCLK_SEL	62
> +#define AUD_CLKID_MST_E_MCLK_SEL	63
> +#define AUD_CLKID_MST_F_MCLK_SEL	64
> +#define AUD_CLKID_MST_A_MCLK_DIV	65
> +#define AUD_CLKID_MST_B_MCLK_DIV	66
> +#define AUD_CLKID_MST_C_MCLK_DIV	67
> +#define AUD_CLKID_MST_D_MCLK_DIV	68
> +#define AUD_CLKID_MST_E_MCLK_DIV	69
> +#define AUD_CLKID_MST_F_MCLK_DIV	70
> +#define AUD_CLKID_SPDIFOUT_CLK_SEL	71
> +#define AUD_CLKID_SPDIFOUT_CLK_DIV	72
> +#define AUD_CLKID_SPDIFIN_CLK_SEL	73
> +#define AUD_CLKID_SPDIFIN_CLK_DIV	74
> +#define AUD_CLKID_PDM_DCLK_SEL		75
> +#define AUD_CLKID_PDM_DCLK_DIV		76
> +#define AUD_CLKID_PDM_SYSCLK_SEL	77
> +#define AUD_CLKID_PDM_SYSCLK_DIV	78
> +#define AUD_CLKID_MST_A_SCLK_PRE_EN	92
> +#define AUD_CLKID_MST_B_SCLK_PRE_EN	93
> +#define AUD_CLKID_MST_C_SCLK_PRE_EN	94
> +#define AUD_CLKID_MST_D_SCLK_PRE_EN	95
> +#define AUD_CLKID_MST_E_SCLK_PRE_EN	96
> +#define AUD_CLKID_MST_F_SCLK_PRE_EN	97
> +#define AUD_CLKID_MST_A_SCLK_DIV	98
> +#define AUD_CLKID_MST_B_SCLK_DIV	99
> +#define AUD_CLKID_MST_C_SCLK_DIV	100
> +#define AUD_CLKID_MST_D_SCLK_DIV	101
> +#define AUD_CLKID_MST_E_SCLK_DIV	102
> +#define AUD_CLKID_MST_F_SCLK_DIV	103
> +#define AUD_CLKID_MST_A_SCLK_POST_EN	104
> +#define AUD_CLKID_MST_B_SCLK_POST_EN	105
> +#define AUD_CLKID_MST_C_SCLK_POST_EN	106
> +#define AUD_CLKID_MST_D_SCLK_POST_EN	107
> +#define AUD_CLKID_MST_E_SCLK_POST_EN	108
> +#define AUD_CLKID_MST_F_SCLK_POST_EN	109
> +#define AUD_CLKID_MST_A_LRCLK_DIV	110
> +#define AUD_CLKID_MST_B_LRCLK_DIV	111
> +#define AUD_CLKID_MST_C_LRCLK_DIV	112
> +#define AUD_CLKID_MST_D_LRCLK_DIV	113
> +#define AUD_CLKID_MST_E_LRCLK_DIV	114
> +#define AUD_CLKID_MST_F_LRCLK_DIV	115
> +#define AUD_CLKID_TDMIN_A_SCLK_PRE_EN	137
> +#define AUD_CLKID_TDMIN_B_SCLK_PRE_EN	138
> +#define AUD_CLKID_TDMIN_C_SCLK_PRE_EN	139
> +#define AUD_CLKID_TDMIN_LB_SCLK_PRE_EN	140
> +#define AUD_CLKID_TDMOUT_A_SCLK_PRE_EN	141
> +#define AUD_CLKID_TDMOUT_B_SCLK_PRE_EN	142
> +#define AUD_CLKID_TDMOUT_C_SCLK_PRE_EN	143
> +#define AUD_CLKID_TDMIN_A_SCLK_POST_EN	144
> +#define AUD_CLKID_TDMIN_B_SCLK_POST_EN	145
> +#define AUD_CLKID_TDMIN_C_SCLK_POST_EN	146
> +#define AUD_CLKID_TDMIN_LB_SCLK_POST_EN	147
> +#define AUD_CLKID_TDMOUT_A_SCLK_POST_EN	148
> +#define AUD_CLKID_TDMOUT_B_SCLK_POST_EN	149
> +#define AUD_CLKID_TDMOUT_C_SCLK_POST_EN	150
> +
> +/* include the CLKIDs which are part of the DT bindings */
> +#include <dt-bindings/clock/axg-audio-clkc.h>
> +
> +#define NR_CLKS	151
> +
> +#endif /*__AXG_AUDIO_CLKC_H */
> 

Acked-by: Neil Armstrong <narmstrong@baylibre.com>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 3/7] clk: meson: add triple phase clock driver
  2018-04-26  8:47     ` Neil Armstrong
@ 2018-04-26  8:50       ` Neil Armstrong
  -1 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:50 UTC (permalink / raw)
  To: Jerome Brunet, Carlo Caione, Kevin Hilman
  Cc: Michael Turquette, Stephen Boyd, linux-amlogic, linux-clk,
	devicetree, linux-kernel

On 26/04/2018 10:47, Neil Armstrong wrote:
> On 25/04/2018 18:33, Jerome Brunet wrote:
>> 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.
>>
>> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
>> ---
>>  drivers/clk/meson/Kconfig        |  5 +++
>>  drivers/clk/meson/Makefile       |  1 +
>>  drivers/clk/meson/clk-triphase.c | 68 ++++++++++++++++++++++++++++++++++++++++
>>  drivers/clk/meson/clkc-audio.h   | 20 ++++++++++++
>>  4 files changed, 94 insertions(+)
>>  create mode 100644 drivers/clk/meson/clk-triphase.c
>>  create mode 100644 drivers/clk/meson/clkc-audio.h
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index 87d69573e172..7f7fd6fb3809 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -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_REGMAP_MESON
>>  	bool
>>  	select REGMAP
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index 352fb848c406..64bb917fe1f0 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -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_MESON8B) += meson8b.o
>>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
>> diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c
>> new file mode 100644
>> index 000000000000..9508c03c73c1
>> --- /dev/null
>> +++ b/drivers/clk/meson/clk-triphase.c
>> @@ -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
>> index 000000000000..286ff1201258
>> --- /dev/null
>> +++ b/drivers/clk/meson/clkc-audio.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
> 
> // SPDX-License-Identifier: GPL-2.0
> 
> Checkpatch should have warned about this !

My bad, I wasn't totally aware there is an exception in headers...

> 
>> +/*
>> + * 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 */
>>
> 
> Apart that :
> 
> Acked-by: Neil Armstrong <narmstrong@baylibre.com>
> 

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 3/7] clk: meson: add triple phase clock driver
@ 2018-04-26  8:50       ` Neil Armstrong
  0 siblings, 0 replies; 43+ messages in thread
From: Neil Armstrong @ 2018-04-26  8:50 UTC (permalink / raw)
  To: linus-amlogic

On 26/04/2018 10:47, Neil Armstrong wrote:
> On 25/04/2018 18:33, Jerome Brunet wrote:
>> 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.
>>
>> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
>> ---
>>  drivers/clk/meson/Kconfig        |  5 +++
>>  drivers/clk/meson/Makefile       |  1 +
>>  drivers/clk/meson/clk-triphase.c | 68 ++++++++++++++++++++++++++++++++++++++++
>>  drivers/clk/meson/clkc-audio.h   | 20 ++++++++++++
>>  4 files changed, 94 insertions(+)
>>  create mode 100644 drivers/clk/meson/clk-triphase.c
>>  create mode 100644 drivers/clk/meson/clkc-audio.h
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index 87d69573e172..7f7fd6fb3809 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -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_REGMAP_MESON
>>  	bool
>>  	select REGMAP
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index 352fb848c406..64bb917fe1f0 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -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_MESON8B) += meson8b.o
>>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
>>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o
>> diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c
>> new file mode 100644
>> index 000000000000..9508c03c73c1
>> --- /dev/null
>> +++ b/drivers/clk/meson/clk-triphase.c
>> @@ -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
>> index 000000000000..286ff1201258
>> --- /dev/null
>> +++ b/drivers/clk/meson/clkc-audio.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
> 
> // SPDX-License-Identifier: GPL-2.0
> 
> Checkpatch should have warned about this !

My bad, I wasn't totally aware there is an exception in headers...

> 
>> +/*
>> + * 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 */
>>
> 
> Apart that :
> 
> Acked-by: Neil Armstrong <narmstrong@baylibre.com>
> 

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
  2018-04-25 16:33   ` Jerome Brunet
  (?)
@ 2018-04-27  1:13     ` kbuild test robot
  -1 siblings, 0 replies; 43+ messages in thread
From: kbuild test robot @ 2018-04-27  1:13 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: kbuild-all, Neil Armstrong, Carlo Caione, Kevin Hilman,
	Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4337 bytes --]

Hi Jerome,

I love your patch! Yet something to improve:

[auto build test ERROR on clk/clk-next]
[also build test ERROR on v4.17-rc2 next-20180426]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Jerome-Brunet/clk-meson-axg-add-audio-clock-controller-support/20180427-035149
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All error/warnings (new ones prefixed by >>):

   In file included from drivers/clk/meson/clk-triphase.c:8:0:
>> drivers/clk/meson/clkc-audio.h:22:18: error: field 'cached_duty' has incomplete type
     struct clk_duty cached_duty;
                     ^~~~~~~~~~~
--
   In file included from drivers/clk/meson/sclk-div.c:19:0:
>> drivers/clk/meson/clkc-audio.h:22:18: error: field 'cached_duty' has incomplete type
     struct clk_duty cached_duty;
                     ^~~~~~~~~~~
   drivers/clk/meson/sclk-div.c: In function 'sclk_div_set_duty_cycle':
>> drivers/clk/meson/sclk-div.c:127:43: error: dereferencing pointer to incomplete type 'struct clk_duty'
      memcpy(&sclk->cached_duty, duty, sizeof(*duty));
                                              ^~~~~
   drivers/clk/meson/sclk-div.c: At top level:
>> drivers/clk/meson/sclk-div.c:239:3: error: 'const struct clk_ops' has no member named 'get_duty_cycle'
     .get_duty_cycle = sclk_div_get_duty_cycle,
      ^~~~~~~~~~~~~~
>> drivers/clk/meson/sclk-div.c:239:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .get_duty_cycle = sclk_div_get_duty_cycle,
                       ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/clk/meson/sclk-div.c:239:20: note: (near initialization for 'meson_sclk_div_ops.disable_unused')
>> drivers/clk/meson/sclk-div.c:240:3: error: 'const struct clk_ops' has no member named 'set_duty_cycle'
     .set_duty_cycle = sclk_div_set_duty_cycle,
      ^~~~~~~~~~~~~~
   drivers/clk/meson/sclk-div.c:240:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .set_duty_cycle = sclk_div_set_duty_cycle,
                       ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/clk/meson/sclk-div.c:240:20: note: (near initialization for 'meson_sclk_div_ops.recalc_rate')
   cc1: some warnings being treated as errors
--
   In file included from drivers/clk/meson/axg-audio.c:17:0:
>> drivers/clk/meson/clkc-audio.h:22:18: error: field 'cached_duty' has incomplete type
     struct clk_duty cached_duty;
                     ^~~~~~~~~~~
>> drivers/clk/meson/axg-audio.c:35:12: error: 'CLK_DUTY_CYCLE_PARENT' undeclared here (not in a function); did you mean 'CLK_SET_RATE_PARENT'?
      .flags = CLK_DUTY_CYCLE_PARENT | (_iflags),  \
               ^
>> drivers/clk/meson/axg-audio.c:74:2: note: in expansion of macro 'AXG_AUD_GATE'
     AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0)
     ^~~~~~~~~~~~
>> drivers/clk/meson/axg-audio.c:77:8: note: in expansion of macro 'AXG_PCLK_GATE'
    static AXG_PCLK_GATE(ddr_arb,    0);
           ^~~~~~~~~~~~~

vim +/cached_duty +22 drivers/clk/meson/clkc-audio.h

6f493fa86 Jerome Brunet 2018-04-25  17  
e8e28d3aa Jerome Brunet 2018-04-25  18  struct meson_sclk_div_data {
e8e28d3aa Jerome Brunet 2018-04-25  19  	struct parm div;
e8e28d3aa Jerome Brunet 2018-04-25  20  	struct parm hi;
e8e28d3aa Jerome Brunet 2018-04-25  21  	unsigned int cached_div;
e8e28d3aa Jerome Brunet 2018-04-25 @22  	struct clk_duty cached_duty;
e8e28d3aa Jerome Brunet 2018-04-25  23  };
e8e28d3aa Jerome Brunet 2018-04-25  24  

:::::: The code at line 22 was first introduced by commit
:::::: e8e28d3aaf526ae3af0d0fd0e8b4c8c8ad2041d8 clk: meson: add axg audio sclk divider driver

:::::: TO: Jerome Brunet <jbrunet@baylibre.com>
:::::: CC: 0day robot <fengguang.wu@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 59068 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
@ 2018-04-27  1:13     ` kbuild test robot
  0 siblings, 0 replies; 43+ messages in thread
From: kbuild test robot @ 2018-04-27  1:13 UTC (permalink / raw)
  Cc: kbuild-all, Neil Armstrong, Carlo Caione, Kevin Hilman,
	Jerome Brunet, Michael Turquette, Stephen Boyd, linux-amlogic,
	linux-clk, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4337 bytes --]

Hi Jerome,

I love your patch! Yet something to improve:

[auto build test ERROR on clk/clk-next]
[also build test ERROR on v4.17-rc2 next-20180426]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Jerome-Brunet/clk-meson-axg-add-audio-clock-controller-support/20180427-035149
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All error/warnings (new ones prefixed by >>):

   In file included from drivers/clk/meson/clk-triphase.c:8:0:
>> drivers/clk/meson/clkc-audio.h:22:18: error: field 'cached_duty' has incomplete type
     struct clk_duty cached_duty;
                     ^~~~~~~~~~~
--
   In file included from drivers/clk/meson/sclk-div.c:19:0:
>> drivers/clk/meson/clkc-audio.h:22:18: error: field 'cached_duty' has incomplete type
     struct clk_duty cached_duty;
                     ^~~~~~~~~~~
   drivers/clk/meson/sclk-div.c: In function 'sclk_div_set_duty_cycle':
>> drivers/clk/meson/sclk-div.c:127:43: error: dereferencing pointer to incomplete type 'struct clk_duty'
      memcpy(&sclk->cached_duty, duty, sizeof(*duty));
                                              ^~~~~
   drivers/clk/meson/sclk-div.c: At top level:
>> drivers/clk/meson/sclk-div.c:239:3: error: 'const struct clk_ops' has no member named 'get_duty_cycle'
     .get_duty_cycle = sclk_div_get_duty_cycle,
      ^~~~~~~~~~~~~~
>> drivers/clk/meson/sclk-div.c:239:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .get_duty_cycle = sclk_div_get_duty_cycle,
                       ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/clk/meson/sclk-div.c:239:20: note: (near initialization for 'meson_sclk_div_ops.disable_unused')
>> drivers/clk/meson/sclk-div.c:240:3: error: 'const struct clk_ops' has no member named 'set_duty_cycle'
     .set_duty_cycle = sclk_div_set_duty_cycle,
      ^~~~~~~~~~~~~~
   drivers/clk/meson/sclk-div.c:240:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .set_duty_cycle = sclk_div_set_duty_cycle,
                       ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/clk/meson/sclk-div.c:240:20: note: (near initialization for 'meson_sclk_div_ops.recalc_rate')
   cc1: some warnings being treated as errors
--
   In file included from drivers/clk/meson/axg-audio.c:17:0:
>> drivers/clk/meson/clkc-audio.h:22:18: error: field 'cached_duty' has incomplete type
     struct clk_duty cached_duty;
                     ^~~~~~~~~~~
>> drivers/clk/meson/axg-audio.c:35:12: error: 'CLK_DUTY_CYCLE_PARENT' undeclared here (not in a function); did you mean 'CLK_SET_RATE_PARENT'?
      .flags = CLK_DUTY_CYCLE_PARENT | (_iflags),  \
               ^
>> drivers/clk/meson/axg-audio.c:74:2: note: in expansion of macro 'AXG_AUD_GATE'
     AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0)
     ^~~~~~~~~~~~
>> drivers/clk/meson/axg-audio.c:77:8: note: in expansion of macro 'AXG_PCLK_GATE'
    static AXG_PCLK_GATE(ddr_arb,    0);
           ^~~~~~~~~~~~~

vim +/cached_duty +22 drivers/clk/meson/clkc-audio.h

6f493fa86 Jerome Brunet 2018-04-25  17  
e8e28d3aa Jerome Brunet 2018-04-25  18  struct meson_sclk_div_data {
e8e28d3aa Jerome Brunet 2018-04-25  19  	struct parm div;
e8e28d3aa Jerome Brunet 2018-04-25  20  	struct parm hi;
e8e28d3aa Jerome Brunet 2018-04-25  21  	unsigned int cached_div;
e8e28d3aa Jerome Brunet 2018-04-25 @22  	struct clk_duty cached_duty;
e8e28d3aa Jerome Brunet 2018-04-25  23  };
e8e28d3aa Jerome Brunet 2018-04-25  24  

:::::: The code at line 22 was first introduced by commit
:::::: e8e28d3aaf526ae3af0d0fd0e8b4c8c8ad2041d8 clk: meson: add axg audio sclk divider driver

:::::: TO: Jerome Brunet <jbrunet@baylibre.com>
:::::: CC: 0day robot <fengguang.wu@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 59068 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
@ 2018-04-27  1:13     ` kbuild test robot
  0 siblings, 0 replies; 43+ messages in thread
From: kbuild test robot @ 2018-04-27  1:13 UTC (permalink / raw)
  To: linus-amlogic

Hi Jerome,

I love your patch! Yet something to improve:

[auto build test ERROR on clk/clk-next]
[also build test ERROR on v4.17-rc2 next-20180426]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Jerome-Brunet/clk-meson-axg-add-audio-clock-controller-support/20180427-035149
base:   https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All error/warnings (new ones prefixed by >>):

   In file included from drivers/clk/meson/clk-triphase.c:8:0:
>> drivers/clk/meson/clkc-audio.h:22:18: error: field 'cached_duty' has incomplete type
     struct clk_duty cached_duty;
                     ^~~~~~~~~~~
--
   In file included from drivers/clk/meson/sclk-div.c:19:0:
>> drivers/clk/meson/clkc-audio.h:22:18: error: field 'cached_duty' has incomplete type
     struct clk_duty cached_duty;
                     ^~~~~~~~~~~
   drivers/clk/meson/sclk-div.c: In function 'sclk_div_set_duty_cycle':
>> drivers/clk/meson/sclk-div.c:127:43: error: dereferencing pointer to incomplete type 'struct clk_duty'
      memcpy(&sclk->cached_duty, duty, sizeof(*duty));
                                              ^~~~~
   drivers/clk/meson/sclk-div.c: At top level:
>> drivers/clk/meson/sclk-div.c:239:3: error: 'const struct clk_ops' has no member named 'get_duty_cycle'
     .get_duty_cycle = sclk_div_get_duty_cycle,
      ^~~~~~~~~~~~~~
>> drivers/clk/meson/sclk-div.c:239:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .get_duty_cycle = sclk_div_get_duty_cycle,
                       ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/clk/meson/sclk-div.c:239:20: note: (near initialization for 'meson_sclk_div_ops.disable_unused')
>> drivers/clk/meson/sclk-div.c:240:3: error: 'const struct clk_ops' has no member named 'set_duty_cycle'
     .set_duty_cycle = sclk_div_set_duty_cycle,
      ^~~~~~~~~~~~~~
   drivers/clk/meson/sclk-div.c:240:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     .set_duty_cycle = sclk_div_set_duty_cycle,
                       ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/clk/meson/sclk-div.c:240:20: note: (near initialization for 'meson_sclk_div_ops.recalc_rate')
   cc1: some warnings being treated as errors
--
   In file included from drivers/clk/meson/axg-audio.c:17:0:
>> drivers/clk/meson/clkc-audio.h:22:18: error: field 'cached_duty' has incomplete type
     struct clk_duty cached_duty;
                     ^~~~~~~~~~~
>> drivers/clk/meson/axg-audio.c:35:12: error: 'CLK_DUTY_CYCLE_PARENT' undeclared here (not in a function); did you mean 'CLK_SET_RATE_PARENT'?
      .flags = CLK_DUTY_CYCLE_PARENT | (_iflags),  \
               ^
>> drivers/clk/meson/axg-audio.c:74:2: note: in expansion of macro 'AXG_AUD_GATE'
     AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0)
     ^~~~~~~~~~~~
>> drivers/clk/meson/axg-audio.c:77:8: note: in expansion of macro 'AXG_PCLK_GATE'
    static AXG_PCLK_GATE(ddr_arb,    0);
           ^~~~~~~~~~~~~

vim +/cached_duty +22 drivers/clk/meson/clkc-audio.h

6f493fa86 Jerome Brunet 2018-04-25  17  
e8e28d3aa Jerome Brunet 2018-04-25  18  struct meson_sclk_div_data {
e8e28d3aa Jerome Brunet 2018-04-25  19  	struct parm div;
e8e28d3aa Jerome Brunet 2018-04-25  20  	struct parm hi;
e8e28d3aa Jerome Brunet 2018-04-25  21  	unsigned int cached_div;
e8e28d3aa Jerome Brunet 2018-04-25 @22  	struct clk_duty cached_duty;
e8e28d3aa Jerome Brunet 2018-04-25  23  };
e8e28d3aa Jerome Brunet 2018-04-25  24  

:::::: The code at line 22 was first introduced by commit
:::::: e8e28d3aaf526ae3af0d0fd0e8b4c8c8ad2041d8 clk: meson: add axg audio sclk divider driver

:::::: TO: Jerome Brunet <jbrunet@baylibre.com>
:::::: CC: 0day robot <fengguang.wu@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 59068 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-amlogic/attachments/20180427/e65e0f59/attachment.gz>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 5/7] clk: meson: axg: export audio clock controller id bindings
  2018-04-25 16:33   ` Jerome Brunet
@ 2018-05-01 14:31     ` Rob Herring
  -1 siblings, 0 replies; 43+ messages in thread
From: Rob Herring @ 2018-05-01 14:31 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: Neil Armstrong, Carlo Caione, Kevin Hilman, Michael Turquette,
	Stephen Boyd, linux-amlogic, linux-clk, devicetree, linux-kernel

On Wed, Apr 25, 2018 at 06:33:02PM +0200, Jerome Brunet wrote:
> export the clock ids dt-bindings usable by the consumers of the axg
> audio clock controller

Capitalization and punctuation would be nice.

> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  include/dt-bindings/clock/axg-audio-clkc.h | 94 ++++++++++++++++++++++++++++++
>  1 file changed, 94 insertions(+)
>  create mode 100644 include/dt-bindings/clock/axg-audio-clkc.h

This can be combined with the next patch. Otherwise,

Reviewed-by: Rob Herring <robh@kernel.org>

> 
> diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h
> new file mode 100644
> index 000000000000..4426ae655858
> --- /dev/null
> +++ b/include/dt-bindings/clock/axg-audio-clkc.h
> @@ -0,0 +1,94 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2018 Baylibre SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + */
> +
> +#ifndef __AXG_AUDIO_CLKC_BINDINGS_H
> +#define __AXG_AUDIO_CLKC_BINDINGS_H
> +
> +#define AUD_CLKID_SLV_SCLK0		9
> +#define AUD_CLKID_SLV_SCLK1		10
> +#define AUD_CLKID_SLV_SCLK2		11
> +#define AUD_CLKID_SLV_SCLK3		12
> +#define AUD_CLKID_SLV_SCLK4		13
> +#define AUD_CLKID_SLV_SCLK5		14
> +#define AUD_CLKID_SLV_SCLK6		15
> +#define AUD_CLKID_SLV_SCLK7		16
> +#define AUD_CLKID_SLV_SCLK8		17
> +#define AUD_CLKID_SLV_SCLK9		18
> +#define AUD_CLKID_SLV_LRCLK0		19
> +#define AUD_CLKID_SLV_LRCLK1		20
> +#define AUD_CLKID_SLV_LRCLK2		21
> +#define AUD_CLKID_SLV_LRCLK3		22
> +#define AUD_CLKID_SLV_LRCLK4		23
> +#define AUD_CLKID_SLV_LRCLK5		24
> +#define AUD_CLKID_SLV_LRCLK6		25
> +#define AUD_CLKID_SLV_LRCLK7		26
> +#define AUD_CLKID_SLV_LRCLK8		27
> +#define AUD_CLKID_SLV_LRCLK9		28
> +#define AUD_CLKID_DDR_ARB		29
> +#define AUD_CLKID_PDM			30
> +#define AUD_CLKID_TDMIN_A		31
> +#define AUD_CLKID_TDMIN_B		32
> +#define AUD_CLKID_TDMIN_C		33
> +#define AUD_CLKID_TDMIN_LB		34
> +#define AUD_CLKID_TDMOUT_A		35
> +#define AUD_CLKID_TDMOUT_B		36
> +#define AUD_CLKID_TDMOUT_C		37
> +#define AUD_CLKID_FRDDR_A		38
> +#define AUD_CLKID_FRDDR_B		39
> +#define AUD_CLKID_FRDDR_C		40
> +#define AUD_CLKID_TODDR_A		41
> +#define AUD_CLKID_TODDR_B		42
> +#define AUD_CLKID_TODDR_C		43
> +#define AUD_CLKID_LOOPBACK		44
> +#define AUD_CLKID_SPDIFIN		45
> +#define AUD_CLKID_SPDIFOUT		46
> +#define AUD_CLKID_RESAMPLE		47
> +#define AUD_CLKID_POWER_DETECT		48
> +#define AUD_CLKID_MST_A_MCLK		49
> +#define AUD_CLKID_MST_B_MCLK		50
> +#define AUD_CLKID_MST_C_MCLK		51
> +#define AUD_CLKID_MST_D_MCLK		52
> +#define AUD_CLKID_MST_E_MCLK		53
> +#define AUD_CLKID_MST_F_MCLK		54
> +#define AUD_CLKID_SPDIFOUT_CLK		55
> +#define AUD_CLKID_SPDIFIN_CLK		56
> +#define AUD_CLKID_PDM_DCLK		57
> +#define AUD_CLKID_PDM_SYSCLK		58
> +#define AUD_CLKID_MST_A_SCLK		79
> +#define AUD_CLKID_MST_B_SCLK		80
> +#define AUD_CLKID_MST_C_SCLK		81
> +#define AUD_CLKID_MST_D_SCLK		82
> +#define AUD_CLKID_MST_E_SCLK		83
> +#define AUD_CLKID_MST_F_SCLK		84
> +#define AUD_CLKID_MST_A_LRCLK		86
> +#define AUD_CLKID_MST_B_LRCLK		87
> +#define AUD_CLKID_MST_C_LRCLK		88
> +#define AUD_CLKID_MST_D_LRCLK		89
> +#define AUD_CLKID_MST_E_LRCLK		90
> +#define AUD_CLKID_MST_F_LRCLK		91
> +#define AUD_CLKID_TDMIN_A_SCLK_SEL	116
> +#define AUD_CLKID_TDMIN_B_SCLK_SEL	117
> +#define AUD_CLKID_TDMIN_C_SCLK_SEL	118
> +#define AUD_CLKID_TDMIN_LB_SCLK_SEL	119
> +#define AUD_CLKID_TDMOUT_A_SCLK_SEL	120
> +#define AUD_CLKID_TDMOUT_B_SCLK_SEL	121
> +#define AUD_CLKID_TDMOUT_C_SCLK_SEL	122
> +#define AUD_CLKID_TDMIN_A_SCLK		123
> +#define AUD_CLKID_TDMIN_B_SCLK		124
> +#define AUD_CLKID_TDMIN_C_SCLK		125
> +#define AUD_CLKID_TDMIN_LB_SCLK		126
> +#define AUD_CLKID_TDMOUT_A_SCLK		127
> +#define AUD_CLKID_TDMOUT_B_SCLK		128
> +#define AUD_CLKID_TDMOUT_C_SCLK		129
> +#define AUD_CLKID_TDMIN_A_LRCLK		130
> +#define AUD_CLKID_TDMIN_B_LRCLK		131
> +#define AUD_CLKID_TDMIN_C_LRCLK		132
> +#define AUD_CLKID_TDMIN_LB_LRCLK	133
> +#define AUD_CLKID_TDMOUT_A_LRCLK	134
> +#define AUD_CLKID_TDMOUT_B_LRCLK	135
> +#define AUD_CLKID_TDMOUT_C_LRCLK	136
> +
> +#endif /* __AXG_AUDIO_CLKC_BINDINGS_H */
> -- 
> 2.14.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 5/7] clk: meson: axg: export audio clock controller id bindings
@ 2018-05-01 14:31     ` Rob Herring
  0 siblings, 0 replies; 43+ messages in thread
From: Rob Herring @ 2018-05-01 14:31 UTC (permalink / raw)
  To: linus-amlogic

On Wed, Apr 25, 2018 at 06:33:02PM +0200, Jerome Brunet wrote:
> export the clock ids dt-bindings usable by the consumers of the axg
> audio clock controller

Capitalization and punctuation would be nice.

> 
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  include/dt-bindings/clock/axg-audio-clkc.h | 94 ++++++++++++++++++++++++++++++
>  1 file changed, 94 insertions(+)
>  create mode 100644 include/dt-bindings/clock/axg-audio-clkc.h

This can be combined with the next patch. Otherwise,

Reviewed-by: Rob Herring <robh@kernel.org>

> 
> diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h
> new file mode 100644
> index 000000000000..4426ae655858
> --- /dev/null
> +++ b/include/dt-bindings/clock/axg-audio-clkc.h
> @@ -0,0 +1,94 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2018 Baylibre SAS.
> + * Author: Jerome Brunet <jbrunet@baylibre.com>
> + */
> +
> +#ifndef __AXG_AUDIO_CLKC_BINDINGS_H
> +#define __AXG_AUDIO_CLKC_BINDINGS_H
> +
> +#define AUD_CLKID_SLV_SCLK0		9
> +#define AUD_CLKID_SLV_SCLK1		10
> +#define AUD_CLKID_SLV_SCLK2		11
> +#define AUD_CLKID_SLV_SCLK3		12
> +#define AUD_CLKID_SLV_SCLK4		13
> +#define AUD_CLKID_SLV_SCLK5		14
> +#define AUD_CLKID_SLV_SCLK6		15
> +#define AUD_CLKID_SLV_SCLK7		16
> +#define AUD_CLKID_SLV_SCLK8		17
> +#define AUD_CLKID_SLV_SCLK9		18
> +#define AUD_CLKID_SLV_LRCLK0		19
> +#define AUD_CLKID_SLV_LRCLK1		20
> +#define AUD_CLKID_SLV_LRCLK2		21
> +#define AUD_CLKID_SLV_LRCLK3		22
> +#define AUD_CLKID_SLV_LRCLK4		23
> +#define AUD_CLKID_SLV_LRCLK5		24
> +#define AUD_CLKID_SLV_LRCLK6		25
> +#define AUD_CLKID_SLV_LRCLK7		26
> +#define AUD_CLKID_SLV_LRCLK8		27
> +#define AUD_CLKID_SLV_LRCLK9		28
> +#define AUD_CLKID_DDR_ARB		29
> +#define AUD_CLKID_PDM			30
> +#define AUD_CLKID_TDMIN_A		31
> +#define AUD_CLKID_TDMIN_B		32
> +#define AUD_CLKID_TDMIN_C		33
> +#define AUD_CLKID_TDMIN_LB		34
> +#define AUD_CLKID_TDMOUT_A		35
> +#define AUD_CLKID_TDMOUT_B		36
> +#define AUD_CLKID_TDMOUT_C		37
> +#define AUD_CLKID_FRDDR_A		38
> +#define AUD_CLKID_FRDDR_B		39
> +#define AUD_CLKID_FRDDR_C		40
> +#define AUD_CLKID_TODDR_A		41
> +#define AUD_CLKID_TODDR_B		42
> +#define AUD_CLKID_TODDR_C		43
> +#define AUD_CLKID_LOOPBACK		44
> +#define AUD_CLKID_SPDIFIN		45
> +#define AUD_CLKID_SPDIFOUT		46
> +#define AUD_CLKID_RESAMPLE		47
> +#define AUD_CLKID_POWER_DETECT		48
> +#define AUD_CLKID_MST_A_MCLK		49
> +#define AUD_CLKID_MST_B_MCLK		50
> +#define AUD_CLKID_MST_C_MCLK		51
> +#define AUD_CLKID_MST_D_MCLK		52
> +#define AUD_CLKID_MST_E_MCLK		53
> +#define AUD_CLKID_MST_F_MCLK		54
> +#define AUD_CLKID_SPDIFOUT_CLK		55
> +#define AUD_CLKID_SPDIFIN_CLK		56
> +#define AUD_CLKID_PDM_DCLK		57
> +#define AUD_CLKID_PDM_SYSCLK		58
> +#define AUD_CLKID_MST_A_SCLK		79
> +#define AUD_CLKID_MST_B_SCLK		80
> +#define AUD_CLKID_MST_C_SCLK		81
> +#define AUD_CLKID_MST_D_SCLK		82
> +#define AUD_CLKID_MST_E_SCLK		83
> +#define AUD_CLKID_MST_F_SCLK		84
> +#define AUD_CLKID_MST_A_LRCLK		86
> +#define AUD_CLKID_MST_B_LRCLK		87
> +#define AUD_CLKID_MST_C_LRCLK		88
> +#define AUD_CLKID_MST_D_LRCLK		89
> +#define AUD_CLKID_MST_E_LRCLK		90
> +#define AUD_CLKID_MST_F_LRCLK		91
> +#define AUD_CLKID_TDMIN_A_SCLK_SEL	116
> +#define AUD_CLKID_TDMIN_B_SCLK_SEL	117
> +#define AUD_CLKID_TDMIN_C_SCLK_SEL	118
> +#define AUD_CLKID_TDMIN_LB_SCLK_SEL	119
> +#define AUD_CLKID_TDMOUT_A_SCLK_SEL	120
> +#define AUD_CLKID_TDMOUT_B_SCLK_SEL	121
> +#define AUD_CLKID_TDMOUT_C_SCLK_SEL	122
> +#define AUD_CLKID_TDMIN_A_SCLK		123
> +#define AUD_CLKID_TDMIN_B_SCLK		124
> +#define AUD_CLKID_TDMIN_C_SCLK		125
> +#define AUD_CLKID_TDMIN_LB_SCLK		126
> +#define AUD_CLKID_TDMOUT_A_SCLK		127
> +#define AUD_CLKID_TDMOUT_B_SCLK		128
> +#define AUD_CLKID_TDMOUT_C_SCLK		129
> +#define AUD_CLKID_TDMIN_A_LRCLK		130
> +#define AUD_CLKID_TDMIN_B_LRCLK		131
> +#define AUD_CLKID_TDMIN_C_LRCLK		132
> +#define AUD_CLKID_TDMIN_LB_LRCLK	133
> +#define AUD_CLKID_TDMOUT_A_LRCLK	134
> +#define AUD_CLKID_TDMOUT_B_LRCLK	135
> +#define AUD_CLKID_TDMOUT_C_LRCLK	136
> +
> +#endif /* __AXG_AUDIO_CLKC_BINDINGS_H */
> -- 
> 2.14.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 6/7] clk: meson: axg: document bindings for the audio clock controller
  2018-04-25 16:33   ` Jerome Brunet
@ 2018-05-01 14:37     ` Rob Herring
  -1 siblings, 0 replies; 43+ messages in thread
From: Rob Herring @ 2018-05-01 14:37 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: Neil Armstrong, Carlo Caione, Kevin Hilman, Michael Turquette,
	Stephen Boyd, linux-amlogic, linux-clk, devicetree, linux-kernel

On Wed, Apr 25, 2018 at 06:33:03PM +0200, Jerome Brunet wrote:
> Add documentation for the device tree bindings of the audio clock
> controller of the A113 based SoCs
> 

The preferred subject prefix for bindings is 'dt/bindings: clock: ...'

> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  .../bindings/clock/amlogic,axg-audio-clkc.txt      | 56 ++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> 
> diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> new file mode 100644
> index 000000000000..1b989ceda567
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> @@ -0,0 +1,56 @@
> +* Amlogic AXG Audio Clock Controllers
> +
> +The Amlogic AXG audio clock controller generates and supplies clock to the
> +other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
> +devices.
> +
> +Required Properties:
> +
> +- compatible	: should be "amlogic,axg-audio-clkc" for the A113X and A113D
> +- reg		: physical base address of the clock controller and length of
> +		  memory mapped region.
> +- clocks	: a list of phandle + clock-specifier pairs for the clocks listed
> +		  in clock-names.
> +- clock-names	: must contain the following:
> +		  * "pclk" - Main peripheral bus clock
> +		  may contain the following:
> +		  * "mst_in[0-7]" - 8 input plls to generate clock signals

Unless the sources don't exist, then you should always have the clocks. 
It should not be based on whether you are using them or not.

> +		  * "slv_sclk[0-9]" - 10 slave bit clocks provided by external
> +				      components.
> +		  * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external
> +				       components.

I'm guessing these may come from pins that aren't connected, so being 
optional is fine.

> +- reset		: phandle of the internal reset line

resets

> +- #clock-cells	: should be 1.
> +
> +Each clock is assigned an identifier and client nodes can use this identifier
> +to specify the clock which they consume. All available clocks are defined as
> +preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
> +used in device tree sources.
> +
> +Example:
> +
> +clkc_audio: clock-controller {

Needs a unit address.

> +	compatible = "amlogic,axg-audio-clkc";
> +	reg = <0x0 0x0 0x0 0xb4>;
> +	#clock-cells = <1>;
> +
> +	clocks = <&clkc CLKID_AUDIO>,
> +		 <&clkc CLKID_MPLL0>,
> +		 <&clkc CLKID_MPLL1>,
> +		 <&clkc CLKID_MPLL2>,
> +		 <&clkc CLKID_MPLL3>,
> +		 <&clkc CLKID_HIFI_PLL>,
> +		 <&clkc CLKID_FCLK_DIV3>,
> +		 <&clkc CLKID_FCLK_DIV4>,
> +		 <&clkc CLKID_GP0_PLL>;
> +	clock-names = "pclk",
> +		      "mst_in0",
> +		      "mst_in1",
> +		      "mst_in2",
> +		      "mst_in3",
> +		      "mst_in4",
> +		      "mst_in5",
> +		      "mst_in6",
> +		      "mst_in7";
> +	resets = <&reset RESET_AUDIO>;
> +};
> -- 
> 2.14.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 6/7] clk: meson: axg: document bindings for the audio clock controller
@ 2018-05-01 14:37     ` Rob Herring
  0 siblings, 0 replies; 43+ messages in thread
From: Rob Herring @ 2018-05-01 14:37 UTC (permalink / raw)
  To: linus-amlogic

On Wed, Apr 25, 2018 at 06:33:03PM +0200, Jerome Brunet wrote:
> Add documentation for the device tree bindings of the audio clock
> controller of the A113 based SoCs
> 

The preferred subject prefix for bindings is 'dt/bindings: clock: ...'

> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> ---
>  .../bindings/clock/amlogic,axg-audio-clkc.txt      | 56 ++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> 
> diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> new file mode 100644
> index 000000000000..1b989ceda567
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> @@ -0,0 +1,56 @@
> +* Amlogic AXG Audio Clock Controllers
> +
> +The Amlogic AXG audio clock controller generates and supplies clock to the
> +other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
> +devices.
> +
> +Required Properties:
> +
> +- compatible	: should be "amlogic,axg-audio-clkc" for the A113X and A113D
> +- reg		: physical base address of the clock controller and length of
> +		  memory mapped region.
> +- clocks	: a list of phandle + clock-specifier pairs for the clocks listed
> +		  in clock-names.
> +- clock-names	: must contain the following:
> +		  * "pclk" - Main peripheral bus clock
> +		  may contain the following:
> +		  * "mst_in[0-7]" - 8 input plls to generate clock signals

Unless the sources don't exist, then you should always have the clocks. 
It should not be based on whether you are using them or not.

> +		  * "slv_sclk[0-9]" - 10 slave bit clocks provided by external
> +				      components.
> +		  * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external
> +				       components.

I'm guessing these may come from pins that aren't connected, so being 
optional is fine.

> +- reset		: phandle of the internal reset line

resets

> +- #clock-cells	: should be 1.
> +
> +Each clock is assigned an identifier and client nodes can use this identifier
> +to specify the clock which they consume. All available clocks are defined as
> +preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
> +used in device tree sources.
> +
> +Example:
> +
> +clkc_audio: clock-controller {

Needs a unit address.

> +	compatible = "amlogic,axg-audio-clkc";
> +	reg = <0x0 0x0 0x0 0xb4>;
> +	#clock-cells = <1>;
> +
> +	clocks = <&clkc CLKID_AUDIO>,
> +		 <&clkc CLKID_MPLL0>,
> +		 <&clkc CLKID_MPLL1>,
> +		 <&clkc CLKID_MPLL2>,
> +		 <&clkc CLKID_MPLL3>,
> +		 <&clkc CLKID_HIFI_PLL>,
> +		 <&clkc CLKID_FCLK_DIV3>,
> +		 <&clkc CLKID_FCLK_DIV4>,
> +		 <&clkc CLKID_GP0_PLL>;
> +	clock-names = "pclk",
> +		      "mst_in0",
> +		      "mst_in1",
> +		      "mst_in2",
> +		      "mst_in3",
> +		      "mst_in4",
> +		      "mst_in5",
> +		      "mst_in6",
> +		      "mst_in7";
> +	resets = <&reset RESET_AUDIO>;
> +};
> -- 
> 2.14.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 6/7] clk: meson: axg: document bindings for the audio clock controller
  2018-05-01 14:37     ` Rob Herring
  (?)
@ 2018-05-14 14:16       ` Jerome Brunet
  -1 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-05-14 14:16 UTC (permalink / raw)
  To: Rob Herring
  Cc: Neil Armstrong, Carlo Caione, Kevin Hilman, Michael Turquette,
	Stephen Boyd, linux-amlogic, linux-clk, devicetree, linux-kernel

On Tue, 2018-05-01 at 09:37 -0500, Rob Herring wrote:
> On Wed, Apr 25, 2018 at 06:33:03PM +0200, Jerome Brunet wrote:
> > Add documentation for the device tree bindings of the audio clock
> > controller of the A113 based SoCs
> > 
> 
> The preferred subject prefix for bindings is 'dt/bindings: clock: ...'

Noted, I suppose meant 'dt-bindings: clocks: ..." which seems to used half of
the times
The rest use 'clk: {platform}: ...'

> 
> > Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> > ---
> >  .../bindings/clock/amlogic,axg-audio-clkc.txt      | 56 ++++++++++++++++++++++
> >  1 file changed, 56 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> > new file mode 100644
> > index 000000000000..1b989ceda567
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> > @@ -0,0 +1,56 @@
> > +* Amlogic AXG Audio Clock Controllers
> > +
> > +The Amlogic AXG audio clock controller generates and supplies clock to the
> > +other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
> > +devices.
> > +
> > +Required Properties:
> > +
> > +- compatible	: should be "amlogic,axg-audio-clkc" for the A113X and A113D
> > +- reg		: physical base address of the clock controller and length of
> > +		  memory mapped region.
> > +- clocks	: a list of phandle + clock-specifier pairs for the clocks listed
> > +		  in clock-names.
> > +- clock-names	: must contain the following:
> > +		  * "pclk" - Main peripheral bus clock
> > +		  may contain the following:
> > +		  * "mst_in[0-7]" - 8 input plls to generate clock signals
> 
> Unless the sources don't exist, then you should always have the clocks. 
> It should not be based on whether you are using them or not.

This is not really the point. The parent controller may or may not provide some
of the PLL. This was the case during the development of the controller when the
HIFI pll was not available simply because there was no driver for it.

Whatever the reason for an input clock to be missing, this clock controller may
continue to serve its purpose even if some input plls are not provided/available
which is why these are not "mandatory"

> 
> > +		  * "slv_sclk[0-9]" - 10 slave bit clocks provided by external
> > +				      components.
> > +		  * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external
> > +				       components.
> 
> I'm guessing these may come from pins that aren't connected, so being 
> optional is fine.
> 
> > +- reset		: phandle of the internal reset line
> 
> resets
> 
> > +- #clock-cells	: should be 1.
> > +
> > +Each clock is assigned an identifier and client nodes can use this identifier
> > +to specify the clock which they consume. All available clocks are defined as
> > +preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
> > +used in device tree sources.
> > +
> > +Example:
> > +
> > +clkc_audio: clock-controller {
> 
> Needs a unit address.
> 
> > +	compatible = "amlogic,axg-audio-clkc";
> > +	reg = <0x0 0x0 0x0 0xb4>;
> > +	#clock-cells = <1>;
> > +
> > +	clocks = <&clkc CLKID_AUDIO>,
> > +		 <&clkc CLKID_MPLL0>,
> > +		 <&clkc CLKID_MPLL1>,
> > +		 <&clkc CLKID_MPLL2>,
> > +		 <&clkc CLKID_MPLL3>,
> > +		 <&clkc CLKID_HIFI_PLL>,
> > +		 <&clkc CLKID_FCLK_DIV3>,
> > +		 <&clkc CLKID_FCLK_DIV4>,
> > +		 <&clkc CLKID_GP0_PLL>;
> > +	clock-names = "pclk",
> > +		      "mst_in0",
> > +		      "mst_in1",
> > +		      "mst_in2",
> > +		      "mst_in3",
> > +		      "mst_in4",
> > +		      "mst_in5",
> > +		      "mst_in6",
> > +		      "mst_in7";
> > +	resets = <&reset RESET_AUDIO>;
> > +};
> > -- 
> > 2.14.3
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe devicetree" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 6/7] clk: meson: axg: document bindings for the audio clock controller
@ 2018-05-14 14:16       ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-05-14 14:16 UTC (permalink / raw)
  To: Rob Herring
  Cc: Neil Armstrong, Carlo Caione, Kevin Hilman, Michael Turquette,
	Stephen Boyd, linux-amlogic, linux-clk, devicetree, linux-kernel

On Tue, 2018-05-01 at 09:37 -0500, Rob Herring wrote:
> On Wed, Apr 25, 2018 at 06:33:03PM +0200, Jerome Brunet wrote:
> > Add documentation for the device tree bindings of the audio clock
> > controller of the A113 based SoCs
> > 
> 
> The preferred subject prefix for bindings is 'dt/bindings: clock: ...'

Noted, I suppose meant 'dt-bindings: clocks: ..." which seems to used half of
the times
The rest use 'clk: {platform}: ...'

> 
> > Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> > ---
> >  .../bindings/clock/amlogic,axg-audio-clkc.txt      | 56 ++++++++++++++++++++++
> >  1 file changed, 56 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> > new file mode 100644
> > index 000000000000..1b989ceda567
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> > @@ -0,0 +1,56 @@
> > +* Amlogic AXG Audio Clock Controllers
> > +
> > +The Amlogic AXG audio clock controller generates and supplies clock to the
> > +other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
> > +devices.
> > +
> > +Required Properties:
> > +
> > +- compatible	: should be "amlogic,axg-audio-clkc" for the A113X and A113D
> > +- reg		: physical base address of the clock controller and length of
> > +		  memory mapped region.
> > +- clocks	: a list of phandle + clock-specifier pairs for the clocks listed
> > +		  in clock-names.
> > +- clock-names	: must contain the following:
> > +		  * "pclk" - Main peripheral bus clock
> > +		  may contain the following:
> > +		  * "mst_in[0-7]" - 8 input plls to generate clock signals
> 
> Unless the sources don't exist, then you should always have the clocks. 
> It should not be based on whether you are using them or not.

This is not really the point. The parent controller may or may not provide some
of the PLL. This was the case during the development of the controller when the
HIFI pll was not available simply because there was no driver for it.

Whatever the reason for an input clock to be missing, this clock controller may
continue to serve its purpose even if some input plls are not provided/available
which is why these are not "mandatory"

> 
> > +		  * "slv_sclk[0-9]" - 10 slave bit clocks provided by external
> > +				      components.
> > +		  * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external
> > +				       components.
> 
> I'm guessing these may come from pins that aren't connected, so being 
> optional is fine.
> 
> > +- reset		: phandle of the internal reset line
> 
> resets
> 
> > +- #clock-cells	: should be 1.
> > +
> > +Each clock is assigned an identifier and client nodes can use this identifier
> > +to specify the clock which they consume. All available clocks are defined as
> > +preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
> > +used in device tree sources.
> > +
> > +Example:
> > +
> > +clkc_audio: clock-controller {
> 
> Needs a unit address.
> 
> > +	compatible = "amlogic,axg-audio-clkc";
> > +	reg = <0x0 0x0 0x0 0xb4>;
> > +	#clock-cells = <1>;
> > +
> > +	clocks = <&clkc CLKID_AUDIO>,
> > +		 <&clkc CLKID_MPLL0>,
> > +		 <&clkc CLKID_MPLL1>,
> > +		 <&clkc CLKID_MPLL2>,
> > +		 <&clkc CLKID_MPLL3>,
> > +		 <&clkc CLKID_HIFI_PLL>,
> > +		 <&clkc CLKID_FCLK_DIV3>,
> > +		 <&clkc CLKID_FCLK_DIV4>,
> > +		 <&clkc CLKID_GP0_PLL>;
> > +	clock-names = "pclk",
> > +		      "mst_in0",
> > +		      "mst_in1",
> > +		      "mst_in2",
> > +		      "mst_in3",
> > +		      "mst_in4",
> > +		      "mst_in5",
> > +		      "mst_in6",
> > +		      "mst_in7";
> > +	resets = <&reset RESET_AUDIO>;
> > +};
> > -- 
> > 2.14.3
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe devicetree" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 6/7] clk: meson: axg: document bindings for the audio clock controller
@ 2018-05-14 14:16       ` Jerome Brunet
  0 siblings, 0 replies; 43+ messages in thread
From: Jerome Brunet @ 2018-05-14 14:16 UTC (permalink / raw)
  To: linus-amlogic

On Tue, 2018-05-01 at 09:37 -0500, Rob Herring wrote:
> On Wed, Apr 25, 2018 at 06:33:03PM +0200, Jerome Brunet wrote:
> > Add documentation for the device tree bindings of the audio clock
> > controller of the A113 based SoCs
> > 
> 
> The preferred subject prefix for bindings is 'dt/bindings: clock: ...'

Noted, I suppose meant 'dt-bindings: clocks: ..." which seems to used half of
the times
The rest use 'clk: {platform}: ...'

> 
> > Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> > ---
> >  .../bindings/clock/amlogic,axg-audio-clkc.txt      | 56 ++++++++++++++++++++++
> >  1 file changed, 56 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> > new file mode 100644
> > index 000000000000..1b989ceda567
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> > @@ -0,0 +1,56 @@
> > +* Amlogic AXG Audio Clock Controllers
> > +
> > +The Amlogic AXG audio clock controller generates and supplies clock to the
> > +other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
> > +devices.
> > +
> > +Required Properties:
> > +
> > +- compatible	: should be "amlogic,axg-audio-clkc" for the A113X and A113D
> > +- reg		: physical base address of the clock controller and length of
> > +		  memory mapped region.
> > +- clocks	: a list of phandle + clock-specifier pairs for the clocks listed
> > +		  in clock-names.
> > +- clock-names	: must contain the following:
> > +		  * "pclk" - Main peripheral bus clock
> > +		  may contain the following:
> > +		  * "mst_in[0-7]" - 8 input plls to generate clock signals
> 
> Unless the sources don't exist, then you should always have the clocks. 
> It should not be based on whether you are using them or not.

This is not really the point. The parent controller may or may not provide some
of the PLL. This was the case during the development of the controller when the
HIFI pll was not available simply because there was no driver for it.

Whatever the reason for an input clock to be missing, this clock controller may
continue to serve its purpose even if some input plls are not provided/available
which is why these are not "mandatory"

> 
> > +		  * "slv_sclk[0-9]" - 10 slave bit clocks provided by external
> > +				      components.
> > +		  * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external
> > +				       components.
> 
> I'm guessing these may come from pins that aren't connected, so being 
> optional is fine.
> 
> > +- reset		: phandle of the internal reset line
> 
> resets
> 
> > +- #clock-cells	: should be 1.
> > +
> > +Each clock is assigned an identifier and client nodes can use this identifier
> > +to specify the clock which they consume. All available clocks are defined as
> > +preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
> > +used in device tree sources.
> > +
> > +Example:
> > +
> > +clkc_audio: clock-controller {
> 
> Needs a unit address.
> 
> > +	compatible = "amlogic,axg-audio-clkc";
> > +	reg = <0x0 0x0 0x0 0xb4>;
> > +	#clock-cells = <1>;
> > +
> > +	clocks = <&clkc CLKID_AUDIO>,
> > +		 <&clkc CLKID_MPLL0>,
> > +		 <&clkc CLKID_MPLL1>,
> > +		 <&clkc CLKID_MPLL2>,
> > +		 <&clkc CLKID_MPLL3>,
> > +		 <&clkc CLKID_HIFI_PLL>,
> > +		 <&clkc CLKID_FCLK_DIV3>,
> > +		 <&clkc CLKID_FCLK_DIV4>,
> > +		 <&clkc CLKID_GP0_PLL>;
> > +	clock-names = "pclk",
> > +		      "mst_in0",
> > +		      "mst_in1",
> > +		      "mst_in2",
> > +		      "mst_in3",
> > +		      "mst_in4",
> > +		      "mst_in5",
> > +		      "mst_in6",
> > +		      "mst_in7";
> > +	resets = <&reset RESET_AUDIO>;
> > +};
> > -- 
> > 2.14.3
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe devicetree" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
  2018-04-26  8:49     ` Neil Armstrong
  (?)
@ 2018-05-15 23:41       ` Stephen Boyd
  -1 siblings, 0 replies; 43+ messages in thread
From: Stephen Boyd @ 2018-05-15 23:41 UTC (permalink / raw)
  To: Carlo Caione, Jerome Brunet, Kevin Hilman, Neil Armstrong
  Cc: Michael Turquette, linux-amlogic, linux-clk, devicetree, linux-kernel

Quoting Neil Armstrong (2018-04-26 01:49:29)
> On 25/04/2018 18:33, Jerome Brunet wrote:
> > +#endif /*__AXG_AUDIO_CLKC_H */
> > 
> 
> Acked-by: Neil Armstrong <narmstrong@baylibre.com>

Please trim replies.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
@ 2018-05-15 23:41       ` Stephen Boyd
  0 siblings, 0 replies; 43+ messages in thread
From: Stephen Boyd @ 2018-05-15 23:41 UTC (permalink / raw)
  To: Carlo Caione, Jerome Brunet, Kevin Hilman, Neil Armstrong
  Cc: Michael Turquette, linux-amlogic, linux-clk, devicetree, linux-kernel

Quoting Neil Armstrong (2018-04-26 01:49:29)
> On 25/04/2018 18:33, Jerome Brunet wrote:
> > +#endif /*__AXG_AUDIO_CLKC_H */
> > =

> =

> Acked-by: Neil Armstrong <narmstrong@baylibre.com>

Please trim replies.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 7/7] clk: meson: axg: add the audio clock controller driver
@ 2018-05-15 23:41       ` Stephen Boyd
  0 siblings, 0 replies; 43+ messages in thread
From: Stephen Boyd @ 2018-05-15 23:41 UTC (permalink / raw)
  To: linus-amlogic

Quoting Neil Armstrong (2018-04-26 01:49:29)
> On 25/04/2018 18:33, Jerome Brunet wrote:
> > +#endif /*__AXG_AUDIO_CLKC_H */
> > 
> 
> Acked-by: Neil Armstrong <narmstrong@baylibre.com>

Please trim replies.

^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2018-05-15 23:41 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-25 16:32 [PATCH 0/7] clk: meson: axg: add audio clock controller support Jerome Brunet
2018-04-25 16:32 ` Jerome Brunet
2018-04-25 16:32 ` [PATCH 1/7] clk: meson: clean-up meson clock configuration Jerome Brunet
2018-04-25 16:32   ` Jerome Brunet
2018-04-26  8:46   ` Neil Armstrong
2018-04-26  8:46     ` Neil Armstrong
2018-04-25 16:32 ` [PATCH 2/7] clk: meson: add clk-phase clock driver Jerome Brunet
2018-04-25 16:32   ` Jerome Brunet
2018-04-26  8:46   ` Neil Armstrong
2018-04-26  8:46     ` Neil Armstrong
2018-04-25 16:33 ` [PATCH 3/7] clk: meson: add triple phase " Jerome Brunet
2018-04-25 16:33   ` Jerome Brunet
2018-04-26  8:47   ` Neil Armstrong
2018-04-26  8:47     ` Neil Armstrong
2018-04-26  8:50     ` Neil Armstrong
2018-04-26  8:50       ` Neil Armstrong
2018-04-25 16:33 ` [PATCH 4/7] clk: meson: add axg audio sclk divider driver Jerome Brunet
2018-04-25 16:33   ` Jerome Brunet
2018-04-26  8:47   ` Neil Armstrong
2018-04-26  8:47     ` Neil Armstrong
2018-04-25 16:33 ` [PATCH 5/7] clk: meson: axg: export audio clock controller id bindings Jerome Brunet
2018-04-25 16:33   ` Jerome Brunet
2018-04-26  8:48   ` Neil Armstrong
2018-04-26  8:48     ` Neil Armstrong
2018-05-01 14:31   ` Rob Herring
2018-05-01 14:31     ` Rob Herring
2018-04-25 16:33 ` [PATCH 6/7] clk: meson: axg: document bindings for the audio clock controller Jerome Brunet
2018-04-25 16:33   ` Jerome Brunet
2018-05-01 14:37   ` Rob Herring
2018-05-01 14:37     ` Rob Herring
2018-05-14 14:16     ` Jerome Brunet
2018-05-14 14:16       ` Jerome Brunet
2018-05-14 14:16       ` Jerome Brunet
2018-04-25 16:33 ` [PATCH 7/7] clk: meson: axg: add the audio clock controller driver Jerome Brunet
2018-04-25 16:33   ` Jerome Brunet
2018-04-26  8:49   ` Neil Armstrong
2018-04-26  8:49     ` Neil Armstrong
2018-05-15 23:41     ` Stephen Boyd
2018-05-15 23:41       ` Stephen Boyd
2018-05-15 23:41       ` Stephen Boyd
2018-04-27  1:13   ` kbuild test robot
2018-04-27  1:13     ` kbuild test robot
2018-04-27  1:13     ` kbuild test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.