2024-04-19 13:01:32

by Jan Dakinevich

[permalink] [raw]
Subject: [RFC PATCH v3 0/6] Add A1 Soc audio clock controller driver

This series adds support for audio clock and reset controllers on A1 SoC family.

Changes v2 -> v3
- reset:
* added auxiliary device
- yaml:
* added declaration of optional clocks
* fixed names in example and another cosmetics
- clocks:
* reworked naming
* stop using of "core" clock name
* fixed wrong parenting

Changes v1 -> v2:
- Detached from v1's series (patch 2, 3, 4, 25).
- Reuse some of defines from axg-audio;
- Split the controller into two memory regions.

Links:
[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://lore.kernel.org/lkml/[email protected]/

Jan Dakinevich (6):
reset: reset-meson-audio: introduce separate driver
clk: meson: axg: share the set of audio helper macro
clk: meson: axg: introduce AUD_MUX_TABLE() helper macro
dt-bindings: clock: meson: document A1 SoC audio clock controller
driver
clk: meson: a1: add the audio clock controller driver
arm64: dts: meson: a1: add the audio clock controller

.../bindings/clock/amlogic,a1-audio-clkc.yaml | 124 ++++
arch/arm64/boot/dts/amlogic/meson-a1.dtsi | 46 ++
drivers/clk/meson/Kconfig | 16 +
drivers/clk/meson/Makefile | 1 +
drivers/clk/meson/a1-audio.c | 651 ++++++++++++++++++
drivers/clk/meson/axg-audio.c | 244 +------
drivers/clk/meson/meson-audio.h | 149 ++++
drivers/reset/Kconfig | 7 +
drivers/reset/Makefile | 1 +
drivers/reset/reset-meson-audio.c | 207 ++++++
.../dt-bindings/clock/amlogic,a1-audio-clkc.h | 122 ++++
.../reset/amlogic,meson-a1-audio-reset.h | 29 +
include/soc/amlogic/meson-audio-reset.h | 10 +
13 files changed, 1371 insertions(+), 236 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml
create mode 100644 drivers/clk/meson/a1-audio.c
create mode 100644 drivers/clk/meson/meson-audio.h
create mode 100644 drivers/reset/reset-meson-audio.c
create mode 100644 include/dt-bindings/clock/amlogic,a1-audio-clkc.h
create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h
create mode 100644 include/soc/amlogic/meson-audio-reset.h

--
2.34.1



2024-04-19 13:01:42

by Jan Dakinevich

[permalink] [raw]
Subject: [RFC PATCH v3 2/6] clk: meson: axg: share the set of audio helper macro

These macro will be used in upcoming audio clock controller
for Meson A1 SoC.

Signed-off-by: Jan Dakinevich <[email protected]>
---
drivers/clk/meson/axg-audio.c | 138 +-----------------------------
drivers/clk/meson/meson-audio.h | 143 ++++++++++++++++++++++++++++++++
2 files changed, 144 insertions(+), 137 deletions(-)
create mode 100644 drivers/clk/meson/meson-audio.h

diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
index 9cd6b5c3aa7e..ee0698bf4383 100644
--- a/drivers/clk/meson/axg-audio.c
+++ b/drivers/clk/meson/axg-audio.c
@@ -17,6 +17,7 @@
#include <soc/amlogic/meson-audio-reset.h>

#include "meson-clkc-utils.h"
+#include "meson-audio.h"
#include "axg-audio.h"
#include "clk-regmap.h"
#include "clk-phase.h"
@@ -24,52 +25,6 @@

#include <dt-bindings/clock/axg-audio-clkc.h>

-#define AUD_GATE(_name, _reg, _bit, _pname, _iflags) { \
- .data = &(struct clk_regmap_gate_data){ \
- .offset = (_reg), \
- .bit_idx = (_bit), \
- }, \
- .hw.init = &(struct clk_init_data) { \
- .name = "aud_"#_name, \
- .ops = &clk_regmap_gate_ops, \
- .parent_names = (const char *[]){ #_pname }, \
- .num_parents = 1, \
- .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \
- }, \
-}
-
-#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pdata, _iflags) { \
- .data = &(struct clk_regmap_mux_data){ \
- .offset = (_reg), \
- .mask = (_mask), \
- .shift = (_shift), \
- .flags = (_dflags), \
- }, \
- .hw.init = &(struct clk_init_data){ \
- .name = "aud_"#_name, \
- .ops = &clk_regmap_mux_ops, \
- .parent_data = _pdata, \
- .num_parents = ARRAY_SIZE(_pdata), \
- .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \
- }, \
-}
-
-#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) { \
- .data = &(struct clk_regmap_div_data){ \
- .offset = (_reg), \
- .shift = (_shift), \
- .width = (_width), \
- .flags = (_dflags), \
- }, \
- .hw.init = &(struct clk_init_data){ \
- .name = "aud_"#_name, \
- .ops = &clk_regmap_divider_ops, \
- .parent_names = (const char *[]){ #_pname }, \
- .num_parents = 1, \
- .flags = (_iflags), \
- }, \
-}
-
#define AUD_PCLK_GATE(_name, _reg, _bit) { \
.data = &(struct clk_regmap_gate_data){ \
.offset = (_reg), \
@@ -83,97 +38,6 @@
}, \
}

-#define AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \
- _hi_shift, _hi_width, _pname, _iflags) { \
- .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 = "aud_"#_name, \
- .ops = &meson_sclk_div_ops, \
- .parent_names = (const char *[]){ #_pname }, \
- .num_parents = 1, \
- .flags = (_iflags), \
- }, \
-}
-
-#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \
- _pname, _iflags) { \
- .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 = "aud_"#_name, \
- .ops = &meson_clk_triphase_ops, \
- .parent_names = (const char *[]){ #_pname }, \
- .num_parents = 1, \
- .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \
- }, \
-}
-
-#define AUD_PHASE(_name, _reg, _width, _shift, _pname, _iflags) { \
- .data = &(struct meson_clk_phase_data) { \
- .ph = { \
- .reg_off = (_reg), \
- .shift = (_shift), \
- .width = (_width), \
- }, \
- }, \
- .hw.init = &(struct clk_init_data) { \
- .name = "aud_"#_name, \
- .ops = &meson_clk_phase_ops, \
- .parent_names = (const char *[]){ #_pname }, \
- .num_parents = 1, \
- .flags = (_iflags), \
- }, \
-}
-
-#define AUD_SCLK_WS(_name, _reg, _width, _shift_ph, _shift_ws, _pname, \
- _iflags) { \
- .data = &(struct meson_sclk_ws_inv_data) { \
- .ph = { \
- .reg_off = (_reg), \
- .shift = (_shift_ph), \
- .width = (_width), \
- }, \
- .ws = { \
- .reg_off = (_reg), \
- .shift = (_shift_ws), \
- .width = (_width), \
- }, \
- }, \
- .hw.init = &(struct clk_init_data) { \
- .name = "aud_"#_name, \
- .ops = &meson_clk_phase_ops, \
- .parent_names = (const char *[]){ #_pname }, \
- .num_parents = 1, \
- .flags = (_iflags), \
- }, \
-}
-
/* Audio Master Clocks */
static const struct clk_parent_data mst_mux_parent_data[] = {
{ .fw_name = "mst_in0", },
diff --git a/drivers/clk/meson/meson-audio.h b/drivers/clk/meson/meson-audio.h
new file mode 100644
index 000000000000..cbcdbd487d4a
--- /dev/null
+++ b/drivers/clk/meson/meson-audio.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+
+#ifndef __MESON_AUDIO_H__
+#define __MESON_AUDIO_H__
+
+#define AUD_GATE(_name, _reg, _bit, _pname, _iflags) { \
+ .data = &(struct clk_regmap_gate_data){ \
+ .offset = (_reg), \
+ .bit_idx = (_bit), \
+ }, \
+ .hw.init = &(struct clk_init_data) { \
+ .name = "aud_"#_name, \
+ .ops = &clk_regmap_gate_ops, \
+ .parent_names = (const char *[]){ #_pname }, \
+ .num_parents = 1, \
+ .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \
+ }, \
+}
+
+#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pdata, _iflags) { \
+ .data = &(struct clk_regmap_mux_data){ \
+ .offset = (_reg), \
+ .mask = (_mask), \
+ .shift = (_shift), \
+ .flags = (_dflags), \
+ }, \
+ .hw.init = &(struct clk_init_data){ \
+ .name = "aud_"#_name, \
+ .ops = &clk_regmap_mux_ops, \
+ .parent_data = _pdata, \
+ .num_parents = ARRAY_SIZE(_pdata), \
+ .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \
+ }, \
+}
+
+#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) { \
+ .data = &(struct clk_regmap_div_data){ \
+ .offset = (_reg), \
+ .shift = (_shift), \
+ .width = (_width), \
+ .flags = (_dflags), \
+ }, \
+ .hw.init = &(struct clk_init_data){ \
+ .name = "aud_"#_name, \
+ .ops = &clk_regmap_divider_ops, \
+ .parent_names = (const char *[]){ #_pname }, \
+ .num_parents = 1, \
+ .flags = (_iflags), \
+ }, \
+}
+
+#define AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \
+ _hi_shift, _hi_width, _pname, _iflags) { \
+ .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 = "aud_"#_name, \
+ .ops = &meson_sclk_div_ops, \
+ .parent_names = (const char *[]){ #_pname }, \
+ .num_parents = 1, \
+ .flags = (_iflags), \
+ }, \
+}
+
+#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \
+ _pname, _iflags) { \
+ .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 = "aud_"#_name, \
+ .ops = &meson_clk_triphase_ops, \
+ .parent_names = (const char *[]){ #_pname }, \
+ .num_parents = 1, \
+ .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \
+ }, \
+}
+
+#define AUD_PHASE(_name, _reg, _width, _shift, _pname, _iflags) { \
+ .data = &(struct meson_clk_phase_data) { \
+ .ph = { \
+ .reg_off = (_reg), \
+ .shift = (_shift), \
+ .width = (_width), \
+ }, \
+ }, \
+ .hw.init = &(struct clk_init_data) { \
+ .name = "aud_"#_name, \
+ .ops = &meson_clk_phase_ops, \
+ .parent_names = (const char *[]){ #_pname }, \
+ .num_parents = 1, \
+ .flags = (_iflags), \
+ }, \
+}
+
+#define AUD_SCLK_WS(_name, _reg, _width, _shift_ph, _shift_ws, _pname, \
+ _iflags) { \
+ .data = &(struct meson_sclk_ws_inv_data) { \
+ .ph = { \
+ .reg_off = (_reg), \
+ .shift = (_shift_ph), \
+ .width = (_width), \
+ }, \
+ .ws = { \
+ .reg_off = (_reg), \
+ .shift = (_shift_ws), \
+ .width = (_width), \
+ }, \
+ }, \
+ .hw.init = &(struct clk_init_data) { \
+ .name = "aud_"#_name, \
+ .ops = &meson_clk_phase_ops, \
+ .parent_names = (const char *[]){ #_pname }, \
+ .num_parents = 1, \
+ .flags = (_iflags), \
+ }, \
+}
+
+#endif /* __MESON_AUDIO_H__ */
--
2.34.1


2024-04-19 13:01:50

by Jan Dakinevich

[permalink] [raw]
Subject: [RFC PATCH v3 6/6] arm64: dts: meson: a1: add the audio clock controller

Add the bus and audio clock controllers' device tree nodes.

Signed-off-by: Jan Dakinevich <[email protected]>
---
arch/arm64/boot/dts/amlogic/meson-a1.dtsi | 46 +++++++++++++++++++++++
1 file changed, 46 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
index c03e207ea6c5..b45407aa95da 100644
--- a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
@@ -5,6 +5,7 @@

#include <dt-bindings/clock/amlogic,a1-pll-clkc.h>
#include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
+#include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
#include <dt-bindings/gpio/meson-a1-gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
@@ -435,6 +436,51 @@ sd_emmc: sd@10000 {
power-domains = <&pwrc PWRC_SD_EMMC_ID>;
status = "disabled";
};
+
+ audio: bus@50000 {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x0 0x0 0x0 0x50000 0 0x4980>;
+ power-domains = <&pwrc PWRC_AUDIO_ID>;
+
+ clkc_audio: clock-controller@0 {
+ compatible = "amlogic,a1-audio-clkc";
+ reg = <0x0 0x0 0x0 0xb0>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ clocks = <&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>,
+ <&clkc_periphs CLKID_DDS_IN>,
+ <&clkc_pll CLKID_FCLK_DIV2>,
+ <&clkc_pll CLKID_FCLK_DIV3>,
+ <&clkc_pll CLKID_HIFI_PLL>,
+ <&xtal>;
+ clock-names = "pclk",
+ "dds_in",
+ "fclk_div2",
+ "fclk_div3",
+ "hifi_pll",
+ "xtal";
+ };
+
+ clkc_audio_vad: clock-controller@4800 {
+ compatible = "amlogic,a1-audio-vad-clkc";
+ reg = <0x0 0x4800 0x0 0x20>;
+ #clock-cells = <1>;
+ clocks = <&clkc_periphs CLKID_AUDIO>,
+ <&clkc_periphs CLKID_DDS_IN>,
+ <&clkc_pll CLKID_FCLK_DIV2>,
+ <&clkc_pll CLKID_FCLK_DIV3>,
+ <&clkc_pll CLKID_HIFI_PLL>,
+ <&xtal>;
+ clock-names = "pclk",
+ "dds_in",
+ "fclk_div2",
+ "fclk_div3",
+ "hifi_pll",
+ "xtal";
+ };
+ };
};

usb: usb@fe004400 {
--
2.34.1


2024-04-19 13:02:27

by Jan Dakinevich

[permalink] [raw]
Subject: [RFC PATCH v3 5/6] clk: meson: a1: add the audio clock controller driver

This controller provides clocks and reset functionality for audio
peripherals on Amlogic A1 SoC family.

The driver is almost identical to 'axg-audio', however it would be better
to keep it separate due to following reasons:

- significant amount of bits has another definition. I will bring there
a mess of new defines with A1_ suffixes.

- registers of this controller are located in two separate regions. It
will give a lot of complications for 'axg-audio' to support this.

Signed-off-by: Jan Dakinevich <[email protected]>
---
drivers/clk/meson/Kconfig | 14 +
drivers/clk/meson/Makefile | 1 +
drivers/clk/meson/a1-audio.c | 651 ++++++++++++++++++++++++++++++
drivers/reset/reset-meson-audio.c | 10 +
4 files changed, 676 insertions(+)
create mode 100644 drivers/clk/meson/a1-audio.c

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 33614f8b8cf7..8aa2b38914fc 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -130,6 +130,20 @@ config COMMON_CLK_A1_PERIPHERALS
device, A1 SoC Family. Say Y if you want A1 Peripherals clock
controller to work.

+config COMMON_CLK_A1_AUDIO
+ tristate "Amlogic A1 SoC Audio clock controller support"
+ depends on ARM64
+ select COMMON_CLK_MESON_REGMAP
+ select COMMON_CLK_MESON_CLKC_UTILS
+ select COMMON_CLK_MESON_PHASE
+ select COMMON_CLK_MESON_SCLK_DIV
+ select RESET_CONTROLLER
+ select RESET_MESON_AUDIO
+ help
+ Support for the Audio clock controller on Amlogic A113L based
+ device, A1 SoC Family. Say Y if you want A1 Audio clock controller
+ to work.
+
config COMMON_CLK_G12A
tristate "G12 and SM1 SoC clock controllers support"
depends on ARM64
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 9ee4b954c896..5e0260cef111 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
+obj-$(CONFIG_COMMON_CLK_A1_AUDIO) += a1-audio.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
diff --git a/drivers/clk/meson/a1-audio.c b/drivers/clk/meson/a1-audio.c
new file mode 100644
index 000000000000..bf08e354f32d
--- /dev/null
+++ b/drivers/clk/meson/a1-audio.c
@@ -0,0 +1,651 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ *
+ * Author: Jan Dakinevich <[email protected]>
+ */
+
+#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/reset-controller.h>
+#include <linux/slab.h>
+
+#include <soc/amlogic/meson-audio-reset.h>
+#include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
+
+#include "meson-clkc-utils.h"
+#include "meson-audio.h"
+#include "clk-regmap.h"
+#include "clk-phase.h"
+#include "sclk-div.h"
+
+#define AUDIO_CLK_GATE_EN0 0x000
+#define AUDIO_MCLK_A_CTRL 0x008
+#define AUDIO_MCLK_B_CTRL 0x00c
+#define AUDIO_MCLK_C_CTRL 0x010
+#define AUDIO_MCLK_D_CTRL 0x014
+#define AUDIO_SW_RESET0 0x028
+#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_CLK_TDMIN_A_CTRL 0x080
+#define AUDIO_CLK_TDMIN_B_CTRL 0x084
+#define AUDIO_CLK_TDMIN_LB_CTRL 0x08c
+#define AUDIO_CLK_TDMOUT_A_CTRL 0x090
+#define AUDIO_CLK_TDMOUT_B_CTRL 0x094
+#define AUDIO_CLK_SPDIFIN_CTRL 0x09c
+#define AUDIO_CLK_RESAMPLEA_CTRL 0x0a4
+#define AUDIO_CLK_LOCKER_CTRL 0x0a8
+#define AUDIO_CLK_EQDRC_CTRL 0x0c0
+
+#define AUDIO2_CLK_GATE_EN0 0x00c
+#define AUDIO2_MCLK_VAD_CTRL 0x040
+#define AUDIO2_CLK_VAD_CTRL 0x044
+#define AUDIO2_CLK_PDMIN_CTRL0 0x058
+#define AUDIO2_CLK_PDMIN_CTRL1 0x05c
+
+static const struct clk_parent_data a1_pclk_pdata[] = {
+ { .fw_name = "pclk" },
+};
+
+#define AUD_PCLK_GATE(_name, _reg, _bit) { \
+ .data = &(struct clk_regmap_gate_data){ \
+ .offset = (_reg), \
+ .bit_idx = (_bit), \
+ }, \
+ .hw.init = &(struct clk_init_data) { \
+ .name = "aud_"#_name, \
+ .ops = &clk_regmap_gate_ops, \
+ .parent_data = a1_pclk_pdata, \
+ .num_parents = 1, \
+ }, \
+}
+
+struct clk_regmap aud_ddr_arb =
+ AUD_PCLK_GATE(ddr_arb, AUDIO_CLK_GATE_EN0, 0);
+struct clk_regmap aud_tdmin_a =
+ AUD_PCLK_GATE(tdmin_a, AUDIO_CLK_GATE_EN0, 1);
+struct clk_regmap aud_tdmin_b =
+ AUD_PCLK_GATE(tdmin_b, AUDIO_CLK_GATE_EN0, 2);
+struct clk_regmap aud_tdmin_lb =
+ AUD_PCLK_GATE(tdmin_lb, AUDIO_CLK_GATE_EN0, 3);
+struct clk_regmap aud_loopback =
+ AUD_PCLK_GATE(loopback, AUDIO_CLK_GATE_EN0, 4);
+struct clk_regmap aud_tdmout_a =
+ AUD_PCLK_GATE(tdmout_a, AUDIO_CLK_GATE_EN0, 5);
+struct clk_regmap aud_tdmout_b =
+ AUD_PCLK_GATE(tdmout_b, AUDIO_CLK_GATE_EN0, 6);
+struct clk_regmap aud_frddr_a =
+ AUD_PCLK_GATE(frddr_a, AUDIO_CLK_GATE_EN0, 7);
+struct clk_regmap aud_frddr_b =
+ AUD_PCLK_GATE(frddr_b, AUDIO_CLK_GATE_EN0, 8);
+struct clk_regmap aud_toddr_a =
+ AUD_PCLK_GATE(toddr_a, AUDIO_CLK_GATE_EN0, 9);
+struct clk_regmap aud_toddr_b =
+ AUD_PCLK_GATE(toddr_b, AUDIO_CLK_GATE_EN0, 10);
+struct clk_regmap aud_spdifin =
+ AUD_PCLK_GATE(spdifin, AUDIO_CLK_GATE_EN0, 11);
+struct clk_regmap aud_resample =
+ AUD_PCLK_GATE(resample, AUDIO_CLK_GATE_EN0, 12);
+struct clk_regmap aud_eqdrc =
+ AUD_PCLK_GATE(eqdrc, AUDIO_CLK_GATE_EN0, 13);
+struct clk_regmap aud_audiolocker =
+ AUD_PCLK_GATE(audiolocker, AUDIO_CLK_GATE_EN0, 14);
+
+struct clk_regmap aud_vad_ddr_arb =
+ AUD_PCLK_GATE(vad_ddr_arb, AUDIO2_CLK_GATE_EN0, 0);
+struct clk_regmap aud_vad_pdm =
+ AUD_PCLK_GATE(vad_pdm, AUDIO2_CLK_GATE_EN0, 1);
+struct clk_regmap aud_vad_tdmin_vad =
+ AUD_PCLK_GATE(vad_tdmin_vad, AUDIO2_CLK_GATE_EN0, 2);
+struct clk_regmap aud_vad_toddr_vad =
+ AUD_PCLK_GATE(vad_toddr_vad, AUDIO2_CLK_GATE_EN0, 3);
+struct clk_regmap aud_vad =
+ AUD_PCLK_GATE(vad, AUDIO2_CLK_GATE_EN0, 4);
+struct clk_regmap aud_vad_audiotop =
+ AUD_PCLK_GATE(vad_audiotop, AUDIO2_CLK_GATE_EN0, 7);
+
+static const struct clk_parent_data a1_mst_pdata[] = {
+ { .fw_name = "dds_in" },
+ { .fw_name = "fclk_div2" },
+ { .fw_name = "fclk_div3" },
+ { .fw_name = "hifi_pll" },
+ { .fw_name = "xtal" },
+};
+
+#define AUD_MST_MCLK_MUX(_name, _reg) \
+ AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
+ a1_mst_pdata, 0)
+#define AUD_MST_MCLK_DIV(_name, _reg) \
+ AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
+ aud_##_name##_sel, CLK_SET_RATE_PARENT)
+#define AUD_MST_MCLK_GATE(_name, _reg) \
+ AUD_GATE(_name, _reg, 31, aud_##_name##_div, \
+ CLK_SET_RATE_PARENT)
+
+struct clk_regmap aud_mst_a_mclk_sel =
+ AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL);
+struct clk_regmap aud_mst_a_mclk_div =
+ AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL);
+struct clk_regmap aud_mst_a_mclk =
+ AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL);
+
+struct clk_regmap aud_mst_b_mclk_sel =
+ AUD_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL);
+struct clk_regmap aud_mst_b_mclk_div =
+ AUD_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL);
+struct clk_regmap aud_mst_b_mclk =
+ AUD_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL);
+
+struct clk_regmap aud_mst_c_mclk_sel =
+ AUD_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL);
+struct clk_regmap aud_mst_c_mclk_div =
+ AUD_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL);
+struct clk_regmap aud_mst_c_mclk =
+ AUD_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL);
+
+struct clk_regmap aud_mst_d_mclk_sel =
+ AUD_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL);
+struct clk_regmap aud_mst_d_mclk_div =
+ AUD_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL);
+struct clk_regmap aud_mst_d_mclk =
+ AUD_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL);
+
+struct clk_regmap aud_spdifin_clk_sel =
+ AUD_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
+struct clk_regmap aud_spdifin_clk_div =
+ AUD_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
+struct clk_regmap aud_spdifin_clk =
+ AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
+
+struct clk_regmap aud_eqdrc_clk_sel =
+ AUD_MST_MCLK_MUX(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
+struct clk_regmap aud_eqdrc_clk_div =
+ AUD_MST_MCLK_DIV(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
+struct clk_regmap aud_eqdrc_clk =
+ AUD_MST_MCLK_GATE(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
+
+struct clk_regmap aud_resample_clk_sel =
+ AUD_MUX(resample_clk_sel, AUDIO_CLK_RESAMPLEA_CTRL, 0xf, 24,
+ CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, 0);
+struct clk_regmap aud_resample_clk_div =
+ AUD_DIV(resample_clk_div, AUDIO_CLK_RESAMPLEA_CTRL, 0, 8,
+ CLK_DIVIDER_ROUND_CLOSEST, aud_resample_clk_sel,
+ CLK_SET_RATE_PARENT);
+struct clk_regmap aud_resample_clk =
+ AUD_GATE(resample_clk, AUDIO_CLK_RESAMPLEA_CTRL, 31,
+ aud_resample_clk_div, CLK_SET_RATE_PARENT);
+
+struct clk_regmap aud_locker_in_clk_sel =
+ AUD_MUX(locker_in_clk_sel, AUDIO_CLK_LOCKER_CTRL, 0xf, 8,
+ CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, 0);
+struct clk_regmap aud_locker_in_clk_div =
+ AUD_DIV(locker_in_clk_div, AUDIO_CLK_LOCKER_CTRL, 0, 8,
+ CLK_DIVIDER_ROUND_CLOSEST, aud_locker_in_clk_sel,
+ CLK_SET_RATE_PARENT);
+struct clk_regmap aud_locker_in_clk =
+ AUD_GATE(locker_in_clk, AUDIO_CLK_LOCKER_CTRL, 15,
+ aud_locker_in_clk_div, CLK_SET_RATE_PARENT);
+
+struct clk_regmap aud_locker_out_clk_sel =
+ AUD_MUX(locker_out_clk_sel, AUDIO_CLK_LOCKER_CTRL, 0xf, 24,
+ CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, 0);
+struct clk_regmap aud_locker_out_clk_div =
+ AUD_DIV(locker_out_clk_div, AUDIO_CLK_LOCKER_CTRL, 16, 8,
+ CLK_DIVIDER_ROUND_CLOSEST, aud_locker_out_clk_sel,
+ CLK_SET_RATE_PARENT);
+struct clk_regmap aud_locker_out_clk =
+ AUD_GATE(locker_out_clk, AUDIO_CLK_LOCKER_CTRL, 31,
+ aud_locker_out_clk_div, CLK_SET_RATE_PARENT);
+
+struct clk_regmap aud_vad_mclk_sel =
+ AUD_MST_MCLK_MUX(vad_mclk, AUDIO2_MCLK_VAD_CTRL);
+struct clk_regmap aud_vad_mclk_div =
+ AUD_MST_MCLK_DIV(vad_mclk, AUDIO2_MCLK_VAD_CTRL);
+struct clk_regmap aud_vad_mclk =
+ AUD_MST_MCLK_GATE(vad_mclk, AUDIO2_MCLK_VAD_CTRL);
+
+struct clk_regmap aud_vad_clk_sel =
+ AUD_MST_MCLK_MUX(vad_clk, AUDIO2_CLK_VAD_CTRL);
+struct clk_regmap aud_vad_clk_div =
+ AUD_MST_MCLK_DIV(vad_clk, AUDIO2_CLK_VAD_CTRL);
+struct clk_regmap aud_vad_clk =
+ AUD_MST_MCLK_GATE(vad_clk, AUDIO2_CLK_VAD_CTRL);
+
+struct clk_regmap aud_vad_pdm_dclk_sel =
+ AUD_MST_MCLK_MUX(vad_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
+struct clk_regmap aud_vad_pdm_dclk_div =
+ AUD_MST_MCLK_DIV(vad_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
+struct clk_regmap aud_vad_pdm_dclk =
+ AUD_MST_MCLK_GATE(vad_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
+
+struct clk_regmap aud_vad_pdm_sysclk_sel =
+ AUD_MST_MCLK_MUX(vad_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
+struct clk_regmap aud_vad_pdm_sysclk_div =
+ AUD_MST_MCLK_DIV(vad_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
+struct clk_regmap aud_vad_pdm_sysclk =
+ AUD_MST_MCLK_GATE(vad_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
+
+#define AUD_MST_SCLK_PRE_EN(_name, _reg, _pname) \
+ AUD_GATE(_name##_pre_en, _reg, 31, \
+ aud_##_pname, 0)
+#define AUD_MST_SCLK_DIV(_name, _reg) \
+ AUD_SCLK_DIV(_name##_div, _reg, 20, 10, 0, 0, \
+ aud_##_name##_pre_en, CLK_SET_RATE_PARENT)
+#define AUD_MST_SCLK_POST_EN(_name, _reg) \
+ AUD_GATE(_name##_post_en, _reg, 30, \
+ aud_##_name##_div, CLK_SET_RATE_PARENT)
+#define AUD_MST_SCLK(_name, _reg) \
+ AUD_TRIPHASE(_name, _reg, 1, 0, 2, 4, \
+ aud_##_name##_post_en, CLK_SET_RATE_PARENT)
+
+struct clk_regmap aud_mst_a_sclk_pre_en =
+ AUD_MST_SCLK_PRE_EN(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0, mst_a_mclk);
+struct clk_regmap aud_mst_a_sclk_div =
+ AUD_MST_SCLK_DIV(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0);
+struct clk_regmap aud_mst_a_sclk_post_en =
+ AUD_MST_SCLK_POST_EN(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0);
+struct clk_regmap aud_mst_a_sclk =
+ AUD_MST_SCLK(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL1);
+
+struct clk_regmap aud_mst_b_sclk_pre_en =
+ AUD_MST_SCLK_PRE_EN(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0, mst_b_mclk);
+struct clk_regmap aud_mst_b_sclk_div =
+ AUD_MST_SCLK_DIV(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0);
+struct clk_regmap aud_mst_b_sclk_post_en =
+ AUD_MST_SCLK_POST_EN(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0);
+struct clk_regmap aud_mst_b_sclk =
+ AUD_MST_SCLK(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL1);
+
+struct clk_regmap aud_mst_c_sclk_pre_en =
+ AUD_MST_SCLK_PRE_EN(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0, mst_c_mclk);
+struct clk_regmap aud_mst_c_sclk_div =
+ AUD_MST_SCLK_DIV(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0);
+struct clk_regmap aud_mst_c_sclk_post_en =
+ AUD_MST_SCLK_POST_EN(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0);
+struct clk_regmap aud_mst_c_sclk =
+ AUD_MST_SCLK(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL1);
+
+struct clk_regmap aud_mst_d_sclk_pre_en =
+ AUD_MST_SCLK_PRE_EN(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0, mst_d_mclk);
+struct clk_regmap aud_mst_d_sclk_div =
+ AUD_MST_SCLK_DIV(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0);
+struct clk_regmap aud_mst_d_sclk_post_en =
+ AUD_MST_SCLK_POST_EN(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0);
+struct clk_regmap aud_mst_d_sclk =
+ AUD_MST_SCLK(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL1);
+
+#define AUD_MST_LRCLK_DIV(_name, _reg, _pname) \
+ AUD_SCLK_DIV(_name##_div, _reg, 0, 10, 10, 10, \
+ aud_##_pname, 0)
+#define AUD_MST_LRCLK(_name, _reg) \
+ AUD_TRIPHASE(_name, _reg, 1, 1, 3, 5, \
+ aud_##_name##_div, CLK_SET_RATE_PARENT)
+
+struct clk_regmap aud_mst_a_lrclk_div =
+ AUD_MST_LRCLK_DIV(mst_a_lrclk, AUDIO_MST_A_SCLK_CTRL0,
+ mst_a_sclk_post_en);
+struct clk_regmap aud_mst_a_lrclk =
+ AUD_MST_LRCLK(mst_a_lrclk, AUDIO_MST_A_SCLK_CTRL1);
+
+struct clk_regmap aud_mst_b_lrclk_div =
+ AUD_MST_LRCLK_DIV(mst_b_lrclk, AUDIO_MST_B_SCLK_CTRL0,
+ mst_b_sclk_post_en);
+struct clk_regmap aud_mst_b_lrclk =
+ AUD_MST_LRCLK(mst_b_lrclk, AUDIO_MST_B_SCLK_CTRL1);
+
+struct clk_regmap aud_mst_c_lrclk_div =
+ AUD_MST_LRCLK_DIV(mst_c_lrclk, AUDIO_MST_C_SCLK_CTRL0,
+ mst_c_sclk_post_en);
+struct clk_regmap aud_mst_c_lrclk =
+ AUD_MST_LRCLK(mst_c_lrclk, AUDIO_MST_C_SCLK_CTRL1);
+
+struct clk_regmap aud_mst_d_lrclk_div =
+ AUD_MST_LRCLK_DIV(mst_d_lrclk, AUDIO_MST_D_SCLK_CTRL0,
+ mst_d_sclk_post_en);
+struct clk_regmap aud_mst_d_lrclk =
+ AUD_MST_LRCLK(mst_d_lrclk, AUDIO_MST_D_SCLK_CTRL1);
+
+static const struct clk_parent_data a1_mst_sclk_pdata[] = {
+ { .hw = &aud_mst_a_sclk.hw, .index = -1 },
+ { .hw = &aud_mst_b_sclk.hw, .index = -1 },
+ { .hw = &aud_mst_c_sclk.hw, .index = -1 },
+ { .hw = &aud_mst_d_sclk.hw, .index = -1 },
+ { .fw_name = "slv_sclk0" },
+ { .fw_name = "slv_sclk1" },
+ { .fw_name = "slv_sclk2" },
+ { .fw_name = "slv_sclk3" },
+ { .fw_name = "slv_sclk4" },
+ { .fw_name = "slv_sclk5" },
+ { .fw_name = "slv_sclk6" },
+ { .fw_name = "slv_sclk7" },
+ { .fw_name = "slv_sclk8" },
+ { .fw_name = "slv_sclk9" },
+};
+
+static u32 a1_mst_sclk_table[] = {
+ 0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const struct clk_parent_data a1_mst_lrclk_pdata[] = {
+ { .hw = &aud_mst_a_lrclk.hw, .index = -1 },
+ { .hw = &aud_mst_b_lrclk.hw, .index = -1 },
+ { .hw = &aud_mst_c_lrclk.hw, .index = -1 },
+ { .hw = &aud_mst_d_lrclk.hw, .index = -1 },
+ { .fw_name = "slv_lrclk0" },
+ { .fw_name = "slv_lrclk1" },
+ { .fw_name = "slv_lrclk2" },
+ { .fw_name = "slv_lrclk3" },
+ { .fw_name = "slv_lrclk4" },
+ { .fw_name = "slv_lrclk5" },
+ { .fw_name = "slv_lrclk6" },
+ { .fw_name = "slv_lrclk7" },
+ { .fw_name = "slv_lrclk8" },
+ { .fw_name = "slv_lrclk9" },
+};
+
+static u32 a1_mst_lrclk_table[] = {
+ 0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+#define AUD_TDM_SCLK_MUX(_name, _reg) \
+ AUD_MUX_TABLE(_name##_sel, _reg, a1_mst_sclk_table, 0xf, 24, \
+ CLK_MUX_ROUND_CLOSEST, a1_mst_sclk_pdata, 0)
+#define AUD_TDM_SCLK_PRE_EN(_name, _reg) \
+ AUD_GATE(_name##_pre_en, _reg, 31, \
+ aud_##_name##_sel, CLK_SET_RATE_PARENT)
+#define AUD_TDM_SCLK_POST_EN(_name, _reg) \
+ AUD_GATE(_name##_post_en, _reg, 30, \
+ aud_##_name##_pre_en, CLK_SET_RATE_PARENT)
+#define AUD_TDM_SCLK_WS(_name, _reg) \
+ AUD_SCLK_WS(_name, _reg, 1, 29, 28, \
+ aud_##_name##_post_en, \
+ CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)
+
+#define AUD_TDM_LRLCK(_name, _reg) \
+ AUD_MUX_TABLE(_name, _reg, a1_mst_lrclk_table, 0xf, 20, \
+ CLK_MUX_ROUND_CLOSEST, a1_mst_lrclk_pdata, \
+ CLK_SET_RATE_PARENT)
+
+struct clk_regmap aud_tdmin_a_sclk_sel =
+ AUD_TDM_SCLK_MUX(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
+struct clk_regmap aud_tdmin_a_sclk_pre_en =
+ AUD_TDM_SCLK_PRE_EN(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
+struct clk_regmap aud_tdmin_a_sclk_post_en =
+ AUD_TDM_SCLK_POST_EN(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
+struct clk_regmap aud_tdmin_a_sclk =
+ AUD_TDM_SCLK_WS(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
+struct clk_regmap aud_tdmin_a_lrclk =
+ AUD_TDM_LRLCK(tdmin_a_lrclk, AUDIO_CLK_TDMIN_A_CTRL);
+
+struct clk_regmap aud_tdmin_b_sclk_sel =
+ AUD_TDM_SCLK_MUX(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
+struct clk_regmap aud_tdmin_b_sclk_pre_en =
+ AUD_TDM_SCLK_PRE_EN(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
+struct clk_regmap aud_tdmin_b_sclk_post_en =
+ AUD_TDM_SCLK_POST_EN(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
+struct clk_regmap aud_tdmin_b_sclk =
+ AUD_TDM_SCLK_WS(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
+struct clk_regmap aud_tdmin_b_lrclk =
+ AUD_TDM_LRLCK(tdmin_b_lrclk, AUDIO_CLK_TDMIN_B_CTRL);
+
+struct clk_regmap aud_tdmin_lb_sclk_sel =
+ AUD_TDM_SCLK_MUX(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
+struct clk_regmap aud_tdmin_lb_sclk_pre_en =
+ AUD_TDM_SCLK_PRE_EN(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
+struct clk_regmap aud_tdmin_lb_sclk_post_en =
+ AUD_TDM_SCLK_POST_EN(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
+struct clk_regmap aud_tdmin_lb_sclk =
+ AUD_TDM_SCLK_WS(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
+struct clk_regmap aud_tdmin_lb_lrclk =
+ AUD_TDM_LRLCK(tdmin_lb_lrclk, AUDIO_CLK_TDMIN_LB_CTRL);
+
+struct clk_regmap aud_tdmout_a_sclk_sel =
+ AUD_TDM_SCLK_MUX(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
+struct clk_regmap aud_tdmout_a_sclk_pre_en =
+ AUD_TDM_SCLK_PRE_EN(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
+struct clk_regmap aud_tdmout_a_sclk_post_en =
+ AUD_TDM_SCLK_POST_EN(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
+struct clk_regmap aud_tdmout_a_sclk =
+ AUD_TDM_SCLK_WS(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
+struct clk_regmap aud_tdmout_a_lrclk =
+ AUD_TDM_LRLCK(tdmout_a_lrclk, AUDIO_CLK_TDMOUT_A_CTRL);
+
+struct clk_regmap aud_tdmout_b_sclk_sel =
+ AUD_TDM_SCLK_MUX(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
+struct clk_regmap aud_tdmout_b_sclk_pre_en =
+ AUD_TDM_SCLK_PRE_EN(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
+struct clk_regmap aud_tdmout_b_sclk_post_en =
+ AUD_TDM_SCLK_POST_EN(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
+struct clk_regmap aud_tdmout_b_sclk =
+ AUD_TDM_SCLK_WS(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
+struct clk_regmap aud_tdmout_b_lrclk =
+ AUD_TDM_LRLCK(tdmout_b_lrclk, AUDIO_CLK_TDMOUT_B_CTRL);
+
+static struct clk_hw *a1_audio_hw_clks[] = {
+ [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw,
+ [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw,
+ [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw,
+ [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw,
+ [AUD_CLKID_LOOPBACK] = &aud_loopback.hw,
+ [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw,
+ [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw,
+ [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw,
+ [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw,
+ [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw,
+ [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw,
+ [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw,
+ [AUD_CLKID_RESAMPLE] = &aud_resample.hw,
+ [AUD_CLKID_EQDRC] = &aud_eqdrc.hw,
+ [AUD_CLKID_LOCKER] = &aud_audiolocker.hw,
+ [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_sel.hw,
+ [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw,
+ [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw,
+ [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_sel.hw,
+ [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw,
+ [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw,
+ [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_sel.hw,
+ [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw,
+ [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw,
+ [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_sel.hw,
+ [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw,
+ [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw,
+ [AUD_CLKID_RESAMPLE_CLK_SEL] = &aud_resample_clk_sel.hw,
+ [AUD_CLKID_RESAMPLE_CLK_DIV] = &aud_resample_clk_div.hw,
+ [AUD_CLKID_RESAMPLE_CLK] = &aud_resample_clk.hw,
+ [AUD_CLKID_LOCKER_IN_CLK_SEL] = &aud_locker_in_clk_sel.hw,
+ [AUD_CLKID_LOCKER_IN_CLK_DIV] = &aud_locker_in_clk_div.hw,
+ [AUD_CLKID_LOCKER_IN_CLK] = &aud_locker_in_clk.hw,
+ [AUD_CLKID_LOCKER_OUT_CLK_SEL] = &aud_locker_out_clk_sel.hw,
+ [AUD_CLKID_LOCKER_OUT_CLK_DIV] = &aud_locker_out_clk_div.hw,
+ [AUD_CLKID_LOCKER_OUT_CLK] = &aud_locker_out_clk.hw,
+ [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_sel.hw,
+ [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw,
+ [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw,
+ [AUD_CLKID_EQDRC_CLK_SEL] = &aud_eqdrc_clk_sel.hw,
+ [AUD_CLKID_EQDRC_CLK_DIV] = &aud_eqdrc_clk_div.hw,
+ [AUD_CLKID_EQDRC_CLK] = &aud_eqdrc_clk.hw,
+ [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw,
+ [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw,
+ [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw,
+ [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw,
+ [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw,
+ [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw,
+ [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw,
+ [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw,
+ [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw,
+ [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw,
+ [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw,
+ [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw,
+ [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw,
+ [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw,
+ [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw,
+ [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw,
+ [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw,
+ [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw,
+ [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw,
+ [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw,
+ [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw,
+ [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw,
+ [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw,
+ [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw,
+ [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_sel.hw,
+ [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw,
+ [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw,
+ [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw,
+ [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw,
+ [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_sel.hw,
+ [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw,
+ [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw,
+ [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw,
+ [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw,
+ [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_sel.hw,
+ [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw,
+ [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw,
+ [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw,
+ [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw,
+ [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_sel.hw,
+ [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw,
+ [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw,
+ [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw,
+ [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw,
+ [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_sel.hw,
+ [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw,
+ [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw,
+ [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw,
+ [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw,
+};
+
+static struct clk_hw *a1_audio_vad_hw_clks[] = {
+ [AUD_CLKID_VAD_DDR_ARB] = &aud_vad_ddr_arb.hw,
+ [AUD_CLKID_VAD_PDM] = &aud_vad_pdm.hw,
+ [AUD_CLKID_VAD_TDMIN] = &aud_vad_tdmin_vad.hw,
+ [AUD_CLKID_VAD_TODDR] = &aud_vad_toddr_vad.hw,
+ [AUD_CLKID_VAD] = &aud_vad.hw,
+ [AUD_CLKID_VAD_AUDIOTOP] = &aud_vad_audiotop.hw,
+ [AUD_CLKID_VAD_MCLK_SEL] = &aud_vad_mclk_sel.hw,
+ [AUD_CLKID_VAD_MCLK_DIV] = &aud_vad_mclk_div.hw,
+ [AUD_CLKID_VAD_MCLK] = &aud_vad_mclk.hw,
+ [AUD_CLKID_VAD_CLK_SEL] = &aud_vad_clk_sel.hw,
+ [AUD_CLKID_VAD_CLK_DIV] = &aud_vad_clk_div.hw,
+ [AUD_CLKID_VAD_CLK] = &aud_vad_clk.hw,
+ [AUD_CLKID_VAD_PDM_DCLK_SEL] = &aud_vad_pdm_dclk_sel.hw,
+ [AUD_CLKID_VAD_PDM_DCLK_DIV] = &aud_vad_pdm_dclk_div.hw,
+ [AUD_CLKID_VAD_PDM_DCLK] = &aud_vad_pdm_dclk.hw,
+ [AUD_CLKID_VAD_PDM_SYSCLK_SEL] = &aud_vad_pdm_sysclk_sel.hw,
+ [AUD_CLKID_VAD_PDM_SYSCLK_DIV] = &aud_vad_pdm_sysclk_div.hw,
+ [AUD_CLKID_VAD_PDM_SYSCLK] = &aud_vad_pdm_sysclk.hw,
+};
+
+struct a1_audio_data {
+ struct meson_clk_hw_data hw_clks;
+ const char *reset_name;
+};
+
+static const struct regmap_config a1_audio_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int a1_audio_clkc_probe(struct platform_device *pdev)
+{
+ const struct a1_audio_data *data;
+ struct regmap *map;
+ void __iomem *base;
+ struct clk *clk;
+ unsigned int i;
+ int ret;
+
+ data = of_device_get_match_data(&pdev->dev);
+ if (!data)
+ return -EINVAL;
+
+ clk = devm_clk_get_enabled(&pdev->dev, "pclk");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ map = devm_regmap_init_mmio(&pdev->dev, base, &a1_audio_regmap_cfg);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ for (i = 0; i < data->hw_clks.num; i++) {
+ struct clk_hw *hw = data->hw_clks.hws[i];
+ struct clk_regmap *clk_regmap = to_clk_regmap(hw);
+
+ if (!hw)
+ continue;
+
+ clk_regmap->map = map;
+
+ ret = devm_clk_hw_register(&pdev->dev, hw);
+ if (ret)
+ return ret;
+ }
+
+ ret = devm_of_clk_add_hw_provider(&pdev->dev, meson_clk_hw_get,
+ (void *)&data->hw_clks);
+ if (ret)
+ return ret;
+
+ if (!data->reset_name)
+ return 0;
+
+ return meson_audio_reset_register(&pdev->dev, data->reset_name);
+}
+
+struct a1_audio_data a1_audio_data = {
+ .hw_clks = {
+ .hws = a1_audio_hw_clks,
+ .num = ARRAY_SIZE(a1_audio_hw_clks),
+ },
+ .reset_name = "a1",
+};
+
+struct a1_audio_data a1_audio_vad_data = {
+ .hw_clks = {
+ .hws = a1_audio_vad_hw_clks,
+ .num = ARRAY_SIZE(a1_audio_vad_hw_clks),
+ },
+};
+
+static const struct of_device_id a1_audio_clkc_match_table[] = {
+ {
+ .compatible = "amlogic,a1-audio-clkc",
+ .data = &a1_audio_data,
+ },
+ {
+ .compatible = "amlogic,a1-audio-vad-clkc",
+ .data = &a1_audio_vad_data,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, a1_audio_clkc_match_table);
+
+static struct platform_driver a1_audio_clkc_driver = {
+ .probe = a1_audio_clkc_probe,
+ .driver = {
+ .name = "a1-audio-clkc",
+ .of_match_table = a1_audio_clkc_match_table,
+ },
+};
+module_platform_driver(a1_audio_clkc_driver);
+
+MODULE_DESCRIPTION("Amlogic A1 Audio Clock driver");
+MODULE_AUTHOR("Jan Dakinevich <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/reset/reset-meson-audio.c b/drivers/reset/reset-meson-audio.c
index aaea9931cfe2..faf098012721 100644
--- a/drivers/reset/reset-meson-audio.c
+++ b/drivers/reset/reset-meson-audio.c
@@ -145,6 +145,12 @@ static const struct meson_audio_reset_info meson_audio_reset_info_sm1 = {
.reset_offset = 0x028,
.reset_num = 39,
};
+
+static const struct meson_audio_reset_info meson_audio_reset_info_a1 = {
+ .reset_offset = 0x028,
+ .reset_num = 32,
+};
+
static const struct auxiliary_device_id meson_audio_reset_id[] = {
{
.name = "reset_meson_audio.g12a",
@@ -154,6 +160,10 @@ static const struct auxiliary_device_id meson_audio_reset_id[] = {
.name = "reset_meson_audio.sm1",
.driver_data = (kernel_ulong_t)&meson_audio_reset_info_sm1,
},
+ {
+ .name = "reset_meson_audio.a1",
+ .driver_data = (kernel_ulong_t)&meson_audio_reset_info_a1,
+ },
{},
};
MODULE_DEVICE_TABLE(auxiliary, meson_audio_reset_id);
--
2.34.1


2024-04-19 13:02:55

by Jan Dakinevich

[permalink] [raw]
Subject: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver

Add device tree bindings for A1 SoC audio clock and reset controllers.

Signed-off-by: Jan Dakinevich <[email protected]>
---

This controller has 6 mandatory and up to 20 optional clocks. To describe
this, I use 'additionalItems'. It produces correct processed-schema.json:

"clock-names": {
"maxItems": 26,
"items": [
{
"const": "pclk"
},
{
"const": "dds_in"
},
{
"const": "fclk_div2"
},
{
"const": "fclk_div3"
},
{
"const": "hifi_pll"
},
{
"const": "xtal"
}
],
"additionalItems": {
"oneOf": [
{
"pattern": "^slv_sclk[0-9]$"
},
{
"pattern": "^slv_lrclk[0-9]$"
}
]
},
"type": "array",
"minItems": 6
},

and it behaves as expected. However, the checking is followed by
complaints like this:

Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'

And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
do it right?
---
.../bindings/clock/amlogic,a1-audio-clkc.yaml | 124 ++++++++++++++++++
.../dt-bindings/clock/amlogic,a1-audio-clkc.h | 122 +++++++++++++++++
.../reset/amlogic,meson-a1-audio-reset.h | 29 ++++
3 files changed, 275 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml
create mode 100644 include/dt-bindings/clock/amlogic,a1-audio-clkc.h
create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h

diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml
new file mode 100644
index 000000000000..40a0af3635f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,a1-audio-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic A1 Audio Clock Control Unit and Reset Controller
+
+maintainers:
+ - Neil Armstrong <[email protected]>
+ - Jerome Brunet <[email protected]>
+ - Jan Dakinevich <[email protected]>
+
+properties:
+ compatible:
+ enum:
+ - amlogic,a1-audio-clkc
+ - amlogic,a1-audio-vad-clkc
+
+ '#clock-cells':
+ const: 1
+
+ '#reset-cells':
+ const: 1
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 26
+ items:
+ - description: input main peripheral bus clock
+ - description: input dds_in
+ - description: input fixed pll div2
+ - description: input fixed pll div3
+ - description: input hifi_pll
+ - description: input oscillator (usually at 24MHz)
+ additionalItems:
+ oneOf:
+ - description: slv_sclk[0-9] - slave bit clocks provided by external components
+ - description: slv_lrclk[0-9]- slave sample clocks provided by external components
+
+ clock-names:
+ maxItems: 26
+ items:
+ - const: pclk
+ - const: dds_in
+ - const: fclk_div2
+ - const: fclk_div3
+ - const: hifi_pll
+ - const: xtal
+ additionalItems:
+ oneOf:
+ - pattern: "^slv_sclk[0-9]$"
+ - pattern: "^slv_lrclk[0-9]$"
+
+required:
+ - compatible
+ - '#clock-cells'
+ - reg
+ - clocks
+ - clock-names
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: amlogic,a1-audio-clkc
+ then:
+ required:
+ - '#reset-cells'
+ else:
+ properties:
+ '#reset-cells': false
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/amlogic,a1-pll-clkc.h>
+ #include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
+ #include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
+ audio {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ clkc_audio: clock-controller@fe050000 {
+ compatible = "amlogic,a1-audio-clkc";
+ reg = <0x0 0xfe050000 0x0 0xb0>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ clocks = <&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>,
+ <&clkc_periphs CLKID_DDS_IN>,
+ <&clkc_pll CLKID_FCLK_DIV2>,
+ <&clkc_pll CLKID_FCLK_DIV3>,
+ <&clkc_pll CLKID_HIFI_PLL>,
+ <&xtal>;
+ clock-names = "pclk",
+ "dds_in",
+ "fclk_div2",
+ "fclk_div3",
+ "hifi_pll",
+ "xtal";
+ };
+
+ clkc_audio_vad: clock-controller@fe054800 {
+ compatible = "amlogic,a1-audio2-clkc";
+ reg = <0x0 0xfe054800 0x0 0x20>;
+ #clock-cells = <1>;
+ clocks = <&clkc_periphs CLKID_AUDIO>,
+ <&clkc_periphs CLKID_DDS_IN>,
+ <&clkc_pll CLKID_FCLK_DIV2>,
+ <&clkc_pll CLKID_FCLK_DIV3>,
+ <&clkc_pll CLKID_HIFI_PLL>,
+ <&xtal>;
+ clock-names = "pclk",
+ "dds_in",
+ "fclk_div2",
+ "fclk_div3",
+ "hifi_pll",
+ "xtal";
+ };
+ };
diff --git a/include/dt-bindings/clock/amlogic,a1-audio-clkc.h b/include/dt-bindings/clock/amlogic,a1-audio-clkc.h
new file mode 100644
index 000000000000..6534d1878816
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,a1-audio-clkc.h
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ *
+ * Author: Jan Dakinevich <[email protected]>
+ */
+
+#ifndef __A1_AUDIO_CLKC_BINDINGS_H
+#define __A1_AUDIO_CLKC_BINDINGS_H
+
+#define AUD_CLKID_DDR_ARB 1
+#define AUD_CLKID_TDMIN_A 2
+#define AUD_CLKID_TDMIN_B 3
+#define AUD_CLKID_TDMIN_LB 4
+#define AUD_CLKID_LOOPBACK 5
+#define AUD_CLKID_TDMOUT_A 6
+#define AUD_CLKID_TDMOUT_B 7
+#define AUD_CLKID_FRDDR_A 8
+#define AUD_CLKID_FRDDR_B 9
+#define AUD_CLKID_TODDR_A 10
+#define AUD_CLKID_TODDR_B 11
+#define AUD_CLKID_SPDIFIN 12
+#define AUD_CLKID_RESAMPLE 13
+#define AUD_CLKID_EQDRC 14
+#define AUD_CLKID_LOCKER 15
+#define AUD_CLKID_MST_A_MCLK_SEL 16
+#define AUD_CLKID_MST_A_MCLK_DIV 17
+#define AUD_CLKID_MST_A_MCLK 18
+#define AUD_CLKID_MST_B_MCLK_SEL 19
+#define AUD_CLKID_MST_B_MCLK_DIV 20
+#define AUD_CLKID_MST_B_MCLK 21
+#define AUD_CLKID_MST_C_MCLK_SEL 22
+#define AUD_CLKID_MST_C_MCLK_DIV 23
+#define AUD_CLKID_MST_C_MCLK 24
+#define AUD_CLKID_MST_D_MCLK_SEL 25
+#define AUD_CLKID_MST_D_MCLK_DIV 26
+#define AUD_CLKID_MST_D_MCLK 27
+#define AUD_CLKID_SPDIFIN_CLK_SEL 28
+#define AUD_CLKID_SPDIFIN_CLK_DIV 29
+#define AUD_CLKID_SPDIFIN_CLK 30
+#define AUD_CLKID_RESAMPLE_CLK_SEL 31
+#define AUD_CLKID_RESAMPLE_CLK_DIV 32
+#define AUD_CLKID_RESAMPLE_CLK 33
+#define AUD_CLKID_LOCKER_IN_CLK_SEL 34
+#define AUD_CLKID_LOCKER_IN_CLK_DIV 35
+#define AUD_CLKID_LOCKER_IN_CLK 36
+#define AUD_CLKID_LOCKER_OUT_CLK_SEL 37
+#define AUD_CLKID_LOCKER_OUT_CLK_DIV 38
+#define AUD_CLKID_LOCKER_OUT_CLK 39
+#define AUD_CLKID_EQDRC_CLK_SEL 40
+#define AUD_CLKID_EQDRC_CLK_DIV 41
+#define AUD_CLKID_EQDRC_CLK 42
+#define AUD_CLKID_MST_A_SCLK_PRE_EN 43
+#define AUD_CLKID_MST_A_SCLK_DIV 44
+#define AUD_CLKID_MST_A_SCLK_POST_EN 45
+#define AUD_CLKID_MST_A_SCLK 46
+#define AUD_CLKID_MST_B_SCLK_PRE_EN 47
+#define AUD_CLKID_MST_B_SCLK_DIV 48
+#define AUD_CLKID_MST_B_SCLK_POST_EN 49
+#define AUD_CLKID_MST_B_SCLK 50
+#define AUD_CLKID_MST_C_SCLK_PRE_EN 51
+#define AUD_CLKID_MST_C_SCLK_DIV 52
+#define AUD_CLKID_MST_C_SCLK_POST_EN 53
+#define AUD_CLKID_MST_C_SCLK 54
+#define AUD_CLKID_MST_D_SCLK_PRE_EN 55
+#define AUD_CLKID_MST_D_SCLK_DIV 56
+#define AUD_CLKID_MST_D_SCLK_POST_EN 57
+#define AUD_CLKID_MST_D_SCLK 58
+#define AUD_CLKID_MST_A_LRCLK_DIV 59
+#define AUD_CLKID_MST_A_LRCLK 60
+#define AUD_CLKID_MST_B_LRCLK_DIV 61
+#define AUD_CLKID_MST_B_LRCLK 62
+#define AUD_CLKID_MST_C_LRCLK_DIV 63
+#define AUD_CLKID_MST_C_LRCLK 64
+#define AUD_CLKID_MST_D_LRCLK_DIV 65
+#define AUD_CLKID_MST_D_LRCLK 66
+#define AUD_CLKID_TDMIN_A_SCLK_SEL 67
+#define AUD_CLKID_TDMIN_A_SCLK_PRE_EN 68
+#define AUD_CLKID_TDMIN_A_SCLK_POST_EN 69
+#define AUD_CLKID_TDMIN_A_SCLK 70
+#define AUD_CLKID_TDMIN_A_LRCLK 71
+#define AUD_CLKID_TDMIN_B_SCLK_SEL 72
+#define AUD_CLKID_TDMIN_B_SCLK_PRE_EN 73
+#define AUD_CLKID_TDMIN_B_SCLK_POST_EN 74
+#define AUD_CLKID_TDMIN_B_SCLK 75
+#define AUD_CLKID_TDMIN_B_LRCLK 76
+#define AUD_CLKID_TDMIN_LB_SCLK_SEL 77
+#define AUD_CLKID_TDMIN_LB_SCLK_PRE_EN 78
+#define AUD_CLKID_TDMIN_LB_SCLK_POST_EN 79
+#define AUD_CLKID_TDMIN_LB_SCLK 80
+#define AUD_CLKID_TDMIN_LB_LRCLK 81
+#define AUD_CLKID_TDMOUT_A_SCLK_SEL 82
+#define AUD_CLKID_TDMOUT_A_SCLK_PRE_EN 83
+#define AUD_CLKID_TDMOUT_A_SCLK_POST_EN 84
+#define AUD_CLKID_TDMOUT_A_SCLK 85
+#define AUD_CLKID_TDMOUT_A_LRCLK 86
+#define AUD_CLKID_TDMOUT_B_SCLK_SEL 87
+#define AUD_CLKID_TDMOUT_B_SCLK_PRE_EN 88
+#define AUD_CLKID_TDMOUT_B_SCLK_POST_EN 89
+#define AUD_CLKID_TDMOUT_B_SCLK 90
+#define AUD_CLKID_TDMOUT_B_LRCLK 91
+
+#define AUD_CLKID_VAD_DDR_ARB 1
+#define AUD_CLKID_VAD_PDM 2
+#define AUD_CLKID_VAD_TDMIN 3
+#define AUD_CLKID_VAD_TODDR 4
+#define AUD_CLKID_VAD 5
+#define AUD_CLKID_VAD_AUDIOTOP 6
+#define AUD_CLKID_VAD_MCLK_SEL 7
+#define AUD_CLKID_VAD_MCLK_DIV 8
+#define AUD_CLKID_VAD_MCLK 9
+#define AUD_CLKID_VAD_CLK_SEL 10
+#define AUD_CLKID_VAD_CLK_DIV 11
+#define AUD_CLKID_VAD_CLK 12
+#define AUD_CLKID_VAD_PDM_DCLK_SEL 13
+#define AUD_CLKID_VAD_PDM_DCLK_DIV 14
+#define AUD_CLKID_VAD_PDM_DCLK 15
+#define AUD_CLKID_VAD_PDM_SYSCLK_SEL 16
+#define AUD_CLKID_VAD_PDM_SYSCLK_DIV 17
+#define AUD_CLKID_VAD_PDM_SYSCLK 18
+
+#endif /* __A1_AUDIO_CLKC_BINDINGS_H */
diff --git a/include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h b/include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h
new file mode 100644
index 000000000000..653fddba1d8f
--- /dev/null
+++ b/include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
+ *
+ * Author: Jan Dakinevich <[email protected]>
+ */
+
+#ifndef _DT_BINDINGS_AMLOGIC_MESON_A1_AUDIO_RESET_H
+#define _DT_BINDINGS_AMLOGIC_MESON_A1_AUDIO_RESET_H
+
+#define AUD_RESET_DDRARB 0
+#define AUD_RESET_TDMIN_A 1
+#define AUD_RESET_TDMIN_B 2
+#define AUD_RESET_TDMIN_LB 3
+#define AUD_RESET_LOOPBACK 4
+#define AUD_RESET_TDMOUT_A 5
+#define AUD_RESET_TDMOUT_B 6
+#define AUD_RESET_FRDDR_A 7
+#define AUD_RESET_FRDDR_B 8
+#define AUD_RESET_TODDR_A 9
+#define AUD_RESET_TODDR_B 10
+#define AUD_RESET_SPDIFIN 11
+#define AUD_RESET_RESAMPLE 12
+#define AUD_RESET_EQDRC 13
+#define AUD_RESET_LOCKER 14
+#define AUD_RESET_TOACODEC 30
+#define AUD_RESET_CLKTREE 31
+
+#endif /* _DT_BINDINGS_AMLOGIC_MESON_A1_AUDIO_RESET_H */
--
2.34.1


2024-04-19 13:05:40

by Jan Dakinevich

[permalink] [raw]
Subject: [RFC PATCH v3 1/6] reset: reset-meson-audio: introduce separate driver

Typically, Amlogic Meson SoCs have a couple a reset registers lost in
middle of audio clock controller. Reset controller on top of them was
implemented inside audio clock controller driver. This patch moves reset
functionality of this controller to auxiliary driver. There are at least
two reasons for this:

- architecturally it is more convenient;

- reusing the code of reset controller for new SoCs becomes easier.

Signed-off-by: Jan Dakinevich <[email protected]>
---
drivers/clk/meson/Kconfig | 2 +
drivers/clk/meson/axg-audio.c | 106 +------------
drivers/reset/Kconfig | 7 +
drivers/reset/Makefile | 1 +
drivers/reset/reset-meson-audio.c | 197 ++++++++++++++++++++++++
include/soc/amlogic/meson-audio-reset.h | 10 ++
6 files changed, 224 insertions(+), 99 deletions(-)
create mode 100644 drivers/reset/reset-meson-audio.c
create mode 100644 include/soc/amlogic/meson-audio-reset.h

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 29ffd14d267b..33614f8b8cf7 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -101,6 +101,8 @@ config COMMON_CLK_AXG_AUDIO
select COMMON_CLK_MESON_PHASE
select COMMON_CLK_MESON_SCLK_DIV
select COMMON_CLK_MESON_CLKC_UTILS
+ select RESET_CONTROLLER
+ select RESET_MESON_AUDIO
select REGMAP_MMIO
help
Support for the audio clock controller on AmLogic A113D devices,
diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
index ac3482960903..9cd6b5c3aa7e 100644
--- a/drivers/clk/meson/axg-audio.c
+++ b/drivers/clk/meson/axg-audio.c
@@ -12,9 +12,10 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
-#include <linux/reset-controller.h>
#include <linux/slab.h>

+#include <soc/amlogic/meson-audio-reset.h>
+
#include "meson-clkc-utils.h"
#include "axg-audio.h"
#include "clk-regmap.h"
@@ -1648,84 +1649,6 @@ static struct clk_regmap *const sm1_clk_regmaps[] = {
&sm1_sysclk_b_en,
};

-struct axg_audio_reset_data {
- struct reset_controller_dev rstc;
- struct regmap *map;
- unsigned int offset;
-};
-
-static void axg_audio_reset_reg_and_bit(struct axg_audio_reset_data *rst,
- unsigned long id,
- unsigned int *reg,
- unsigned int *bit)
-{
- unsigned int stride = regmap_get_reg_stride(rst->map);
-
- *reg = (id / (stride * BITS_PER_BYTE)) * stride;
- *reg += rst->offset;
- *bit = id % (stride * BITS_PER_BYTE);
-}
-
-static int axg_audio_reset_update(struct reset_controller_dev *rcdev,
- unsigned long id, bool assert)
-{
- struct axg_audio_reset_data *rst =
- container_of(rcdev, struct axg_audio_reset_data, rstc);
- unsigned int offset, bit;
-
- axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
-
- regmap_update_bits(rst->map, offset, BIT(bit),
- assert ? BIT(bit) : 0);
-
- return 0;
-}
-
-static int axg_audio_reset_status(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct axg_audio_reset_data *rst =
- container_of(rcdev, struct axg_audio_reset_data, rstc);
- unsigned int val, offset, bit;
-
- axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
-
- regmap_read(rst->map, offset, &val);
-
- return !!(val & BIT(bit));
-}
-
-static int axg_audio_reset_assert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- return axg_audio_reset_update(rcdev, id, true);
-}
-
-static int axg_audio_reset_deassert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- return axg_audio_reset_update(rcdev, id, false);
-}
-
-static int axg_audio_reset_toggle(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- int ret;
-
- ret = axg_audio_reset_assert(rcdev, id);
- if (ret)
- return ret;
-
- return axg_audio_reset_deassert(rcdev, id);
-}
-
-static const struct reset_control_ops axg_audio_rstc_ops = {
- .assert = axg_audio_reset_assert,
- .deassert = axg_audio_reset_deassert,
- .reset = axg_audio_reset_toggle,
- .status = axg_audio_reset_status,
-};
-
static const struct regmap_config axg_audio_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
@@ -1737,15 +1660,13 @@ struct audioclk_data {
struct clk_regmap *const *regmap_clks;
unsigned int regmap_clk_num;
struct meson_clk_hw_data hw_clks;
- unsigned int reset_offset;
- unsigned int reset_num;
+ const char *reset_name;
};

static int axg_audio_clkc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct audioclk_data *data;
- struct axg_audio_reset_data *rst;
struct regmap *map;
void __iomem *regs;
struct clk_hw *hw;
@@ -1804,21 +1725,10 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
return ret;

/* Stop here if there is no reset */
- if (!data->reset_num)
+ if (!data->reset_name)
return 0;

- rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL);
- if (!rst)
- return -ENOMEM;
-
- rst->map = map;
- rst->offset = data->reset_offset;
- rst->rstc.nr_resets = data->reset_num;
- rst->rstc.ops = &axg_audio_rstc_ops;
- rst->rstc.of_node = dev->of_node;
- rst->rstc.owner = THIS_MODULE;
-
- return devm_reset_controller_register(dev, &rst->rstc);
+ return meson_audio_reset_register(dev, data->reset_name);
}

static const struct audioclk_data axg_audioclk_data = {
@@ -1837,8 +1747,7 @@ static const struct audioclk_data g12a_audioclk_data = {
.hws = g12a_audio_hw_clks,
.num = ARRAY_SIZE(g12a_audio_hw_clks),
},
- .reset_offset = AUDIO_SW_RESET,
- .reset_num = 26,
+ .reset_name = "g12a",
};

static const struct audioclk_data sm1_audioclk_data = {
@@ -1848,8 +1757,7 @@ static const struct audioclk_data sm1_audioclk_data = {
.hws = sm1_audio_hw_clks,
.num = ARRAY_SIZE(sm1_audio_hw_clks),
},
- .reset_offset = AUDIO_SM1_SW_RESET0,
- .reset_num = 39,
+ .reset_name = "sm1",
};

static const struct of_device_id clkc_match_table[] = {
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 7112f5932609..98106694566f 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -138,6 +138,13 @@ config RESET_MESON
help
This enables the reset driver for Amlogic Meson SoCs.

+config RESET_MESON_AUDIO
+ tristate "Meson Audio Reset Driver"
+ depends on ARCH_MESON || COMPILE_TEST
+ select AUXILIARY_BUS
+ help
+ This enables the audio reset driver for Amlogic Meson SoCs.
+
config RESET_MESON_AUDIO_ARB
tristate "Meson Audio Memory Arbiter Reset Driver"
depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index fd8b49fa46fc..8ee7a57ccf03 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
+obj-$(CONFIG_RESET_MESON_AUDIO) += reset-meson-audio.o
obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
obj-$(CONFIG_RESET_NPCM) += reset-npcm.o
obj-$(CONFIG_RESET_NUVOTON_MA35D1) += reset-ma35d1.o
diff --git a/drivers/reset/reset-meson-audio.c b/drivers/reset/reset-meson-audio.c
new file mode 100644
index 000000000000..aaea9931cfe2
--- /dev/null
+++ b/drivers/reset/reset-meson-audio.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <[email protected]>
+ */
+
+#include <linux/regmap.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/reset-controller.h>
+
+#include <soc/amlogic/meson-audio-reset.h>
+
+struct meson_audio_reset_data {
+ struct reset_controller_dev rstc;
+ struct regmap *map;
+ unsigned int offset;
+};
+
+struct meson_audio_reset_info {
+ unsigned int reset_offset;
+ unsigned int reset_num;
+};
+
+static void meson_audio_reset_reg_and_bit(struct meson_audio_reset_data *rst,
+ unsigned long id,
+ unsigned int *reg,
+ unsigned int *bit)
+{
+ unsigned int stride = regmap_get_reg_stride(rst->map);
+
+ *reg = (id / (stride * BITS_PER_BYTE)) * stride;
+ *reg += rst->offset;
+ *bit = id % (stride * BITS_PER_BYTE);
+}
+
+static int meson_audio_reset_update(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct meson_audio_reset_data *rst =
+ container_of(rcdev, struct meson_audio_reset_data, rstc);
+ unsigned int offset, bit;
+
+ meson_audio_reset_reg_and_bit(rst, id, &offset, &bit);
+
+ regmap_update_bits(rst->map, offset, BIT(bit),
+ assert ? BIT(bit) : 0);
+
+ return 0;
+}
+
+static int meson_audio_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct meson_audio_reset_data *rst =
+ container_of(rcdev, struct meson_audio_reset_data, rstc);
+ unsigned int val, offset, bit;
+
+ meson_audio_reset_reg_and_bit(rst, id, &offset, &bit);
+
+ regmap_read(rst->map, offset, &val);
+
+ return !!(val & BIT(bit));
+}
+
+static int meson_audio_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return meson_audio_reset_update(rcdev, id, true);
+}
+
+static int meson_audio_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return meson_audio_reset_update(rcdev, id, false);
+}
+
+static int meson_audio_reset_toggle(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ int ret;
+
+ ret = meson_audio_reset_assert(rcdev, id);
+ if (ret)
+ return ret;
+
+ return meson_audio_reset_deassert(rcdev, id);
+}
+
+static const struct reset_control_ops meson_audio_reset_ops = {
+ .assert = meson_audio_reset_assert,
+ .deassert = meson_audio_reset_deassert,
+ .reset = meson_audio_reset_toggle,
+ .status = meson_audio_reset_status,
+};
+
+static int meson_audio_reset_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct device *dev = &adev->dev;
+ struct meson_audio_reset_info *info =
+ (struct meson_audio_reset_info *)id->driver_data;
+ struct meson_audio_reset_data *rst;
+
+ dev_info(dev, "%s, reset_offset = %#x, reset_num = %u", __func__,
+ info->reset_offset, info->reset_num);
+
+ rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL);
+ if (!rst)
+ return -ENOMEM;
+
+ rst->map = dev_get_regmap(dev->parent, NULL);
+ if (!rst->map)
+ return -ENODEV;
+
+ rst->offset = info->reset_offset;
+ rst->rstc.ops = &meson_audio_reset_ops;
+ rst->rstc.of_node = dev->parent->of_node;
+ rst->rstc.nr_resets = info->reset_num;
+ rst->rstc.owner = THIS_MODULE;
+
+ return devm_reset_controller_register(dev, &rst->rstc);
+}
+
+static void meson_audio_reset_adev_release(struct device *dev)
+{
+ struct auxiliary_device *adev = to_auxiliary_dev(dev);
+
+ kfree(adev);
+}
+
+static void meson_audio_reset_adev_unregister(void *_adev)
+{
+ struct auxiliary_device *adev = _adev;
+
+ auxiliary_device_delete(adev);
+ auxiliary_device_uninit(adev);
+}
+
+static const struct meson_audio_reset_info meson_audio_reset_info_g12a = {
+ .reset_offset = 0x024,
+ .reset_num = 26,
+};
+
+static const struct meson_audio_reset_info meson_audio_reset_info_sm1 = {
+ .reset_offset = 0x028,
+ .reset_num = 39,
+};
+static const struct auxiliary_device_id meson_audio_reset_id[] = {
+ {
+ .name = "reset_meson_audio.g12a",
+ .driver_data = (kernel_ulong_t)&meson_audio_reset_info_g12a,
+ },
+ {
+ .name = "reset_meson_audio.sm1",
+ .driver_data = (kernel_ulong_t)&meson_audio_reset_info_sm1,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(auxiliary, meson_audio_reset_id);
+
+static struct auxiliary_driver meson_audio_reset_driver = {
+ .probe = meson_audio_reset_probe,
+ .id_table = meson_audio_reset_id,
+};
+
+module_auxiliary_driver(meson_audio_reset_driver);
+
+int meson_audio_reset_register(struct device *dev, const char *name)
+{
+ struct auxiliary_device *adev;
+ int ret;
+
+ adev = kzalloc(sizeof(*adev), GFP_KERNEL);
+ if (!adev)
+ return -ENOMEM;
+
+ adev->name = name;
+ adev->dev.parent = dev;
+ adev->dev.release = meson_audio_reset_adev_release;
+ adev->id = 0;
+
+ ret = auxiliary_device_init(adev);
+ if (ret)
+ return ret;
+
+ ret = auxiliary_device_add(adev);
+ if (ret) {
+ auxiliary_device_uninit(adev);
+ return ret;
+ }
+
+ return devm_add_action_or_reset(dev, meson_audio_reset_adev_unregister,
+ adev);
+}
+EXPORT_SYMBOL_GPL(meson_audio_reset_register);
+
+MODULE_LICENSE("GPL v2");
diff --git a/include/soc/amlogic/meson-audio-reset.h b/include/soc/amlogic/meson-audio-reset.h
new file mode 100644
index 000000000000..279c6a2197ec
--- /dev/null
+++ b/include/soc/amlogic/meson-audio-reset.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+
+#ifndef __MESON_AUDIO_RESET_H
+#define __MESON_AUDIO_RESET_H
+
+#include <linux/device.h>
+
+int meson_audio_reset_register(struct device *dev, const char *name);
+
+#endif /* __MESON_AUDIO_RESET_H */
--
2.34.1


2024-04-19 14:20:37

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver

On 19/04/2024 14:58, Jan Dakinevich wrote:
> Add device tree bindings for A1 SoC audio clock and reset controllers.
>
> Signed-off-by: Jan Dakinevich <[email protected]>

This is still RFC, so not ready.

Limited, incomplete review follows. Full review will be provided when
the work is ready.

Drop "driver" references, e.g. from subject. Bindings are about hardware.


...

> +
> + clocks:
> + maxItems: 26
> + items:
> + - description: input main peripheral bus clock
> + - description: input dds_in
> + - description: input fixed pll div2
> + - description: input fixed pll div3
> + - description: input hifi_pll
> + - description: input oscillator (usually at 24MHz)
> + additionalItems:
> + oneOf:
> + - description: slv_sclk[0-9] - slave bit clocks provided by external components
> + - description: slv_lrclk[0-9]- slave sample clocks provided by external components

What does it mean the clocks are optional? Pins could be not routed?
It's really rare case that clocks within the SoC are optional, so every
such case is questionable.


> +
> + clock-names:
> + maxItems: 26
> + items:
> + - const: pclk
> + - const: dds_in
> + - const: fclk_div2
> + - const: fclk_div3
> + - const: hifi_pll
> + - const: xtal
> + additionalItems:
> + oneOf:
> + - pattern: "^slv_sclk[0-9]$"
> + - pattern: "^slv_lrclk[0-9]$"
> +
> +required:
> + - compatible
> + - '#clock-cells'
> + - reg
> + - clocks
> + - clock-names
> +
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: amlogic,a1-audio-clkc
> + then:
> + required:
> + - '#reset-cells'
> + else:
> + properties:
> + '#reset-cells': false
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/amlogic,a1-pll-clkc.h>
> + #include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
> + #include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
> + audio {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + clkc_audio: clock-controller@fe050000 {
> + compatible = "amlogic,a1-audio-clkc";
> + reg = <0x0 0xfe050000 0x0 0xb0>;
> + #clock-cells = <1>;
> + #reset-cells = <1>;
> + clocks = <&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>,
> + <&clkc_periphs CLKID_DDS_IN>,
> + <&clkc_pll CLKID_FCLK_DIV2>,
> + <&clkc_pll CLKID_FCLK_DIV3>,
> + <&clkc_pll CLKID_HIFI_PLL>,
> + <&xtal>;
> + clock-names = "pclk",
> + "dds_in",
> + "fclk_div2",
> + "fclk_div3",
> + "hifi_pll",
> + "xtal";

Make it complete - list all clocks.

> + };
> +
> + clkc_audio_vad: clock-controller@fe054800 {

Just keep one example. It's basically almost the same.



Best regards,
Krzysztof


2024-04-19 16:44:10

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver


On Fri, 19 Apr 2024 15:58:10 +0300, Jan Dakinevich wrote:
> Add device tree bindings for A1 SoC audio clock and reset controllers.
>
> Signed-off-by: Jan Dakinevich <[email protected]>
> ---
>
> This controller has 6 mandatory and up to 20 optional clocks. To describe
> this, I use 'additionalItems'. It produces correct processed-schema.json:
>
> "clock-names": {
> "maxItems": 26,
> "items": [
> {
> "const": "pclk"
> },
> {
> "const": "dds_in"
> },
> {
> "const": "fclk_div2"
> },
> {
> "const": "fclk_div3"
> },
> {
> "const": "hifi_pll"
> },
> {
> "const": "xtal"
> }
> ],
> "additionalItems": {
> "oneOf": [
> {
> "pattern": "^slv_sclk[0-9]$"
> },
> {
> "pattern": "^slv_lrclk[0-9]$"
> }
> ]
> },
> "type": "array",
> "minItems": 6
> },
>
> and it behaves as expected. However, the checking is followed by
> complaints like this:
>
> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>
> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
> do it right?
> ---
> .../bindings/clock/amlogic,a1-audio-clkc.yaml | 124 ++++++++++++++++++
> .../dt-bindings/clock/amlogic,a1-audio-clkc.h | 122 +++++++++++++++++
> .../reset/amlogic,meson-a1-audio-reset.h | 29 ++++
> 3 files changed, 275 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml
> create mode 100644 include/dt-bindings/clock/amlogic,a1-audio-clkc.h
> create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h
>

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
from schema $id: http://devicetree.org/meta-schemas/keywords.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clocks:additionalItems: {'oneOf': [{'description': 'slv_sclk[0-9] - slave bit clocks provided by external components'}, {'description': 'slv_lrclk[0-9]- slave sample clocks provided by external components'}]} is not of type 'boolean'
from schema $id: http://devicetree.org/meta-schemas/keywords.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
from schema $id: http://devicetree.org/meta-schemas/string-array.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clocks: 'oneOf' conditional failed, one must be fixed:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clocks: 'anyOf' conditional failed, one must be fixed:
'items' is not one of ['maxItems', 'description', 'deprecated']
hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
'additionalItems' is not one of ['maxItems', 'description', 'deprecated']
hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
'maxItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
'items' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
'additionalItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref', 'oneOf']
{'oneOf': [{'description': 'slv_sclk[0-9] - slave bit clocks provided by external components'}, {'description': 'slv_lrclk[0-9]- slave sample clocks provided by external components'}]} is not of type 'boolean'
hint: Arrays must be described with a combination of minItems/maxItems/items
True was expected
hint: Arrays must be described with a combination of minItems/maxItems/items
1 was expected
hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
hint: cell array properties must define how many entries and what the entries are when there is more than one entry.
from schema $id: http://devicetree.org/meta-schemas/clocks.yaml#
'maxItems' is not one of ['type', 'description', 'dependencies', 'dependentRequired', 'dependentSchemas', 'properties', 'patternProperties', 'additionalProperties', 'unevaluatedProperties', 'deprecated', 'required', 'not', 'allOf', 'anyOf', 'oneOf', '$ref']
'items' is not one of ['type', 'description', 'dependencies', 'dependentRequired', 'dependentSchemas', 'properties', 'patternProperties', 'additionalProperties', 'unevaluatedProperties', 'deprecated', 'required', 'not', 'allOf', 'anyOf', 'oneOf', '$ref']
'additionalItems' is not one of ['type', 'description', 'dependencies', 'dependentRequired', 'dependentSchemas', 'properties', 'patternProperties', 'additionalProperties', 'unevaluatedProperties', 'deprecated', 'required', 'not', 'allOf', 'anyOf', 'oneOf', '$ref']
'type' is a required property
hint: DT nodes ("object" type in schemas) can only use a subset of json-schema keywords
from schema $id: http://devicetree.org/meta-schemas/clocks.yaml#
Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.example.dtb: /example-0/audio/clock-controller@fe054800: failed to match any schema with compatible: ['amlogic,a1-audio2-clkc']

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


2024-04-19 21:09:59

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver

On Fri, Apr 19, 2024 at 03:58:10PM +0300, Jan Dakinevich wrote:
> Add device tree bindings for A1 SoC audio clock and reset controllers.
>
> Signed-off-by: Jan Dakinevich <[email protected]>
> ---
>
> This controller has 6 mandatory and up to 20 optional clocks. To describe
> this, I use 'additionalItems'. It produces correct processed-schema.json:
>
> "clock-names": {
> "maxItems": 26,
> "items": [
> {
> "const": "pclk"
> },
> {
> "const": "dds_in"
> },
> {
> "const": "fclk_div2"
> },
> {
> "const": "fclk_div3"
> },
> {
> "const": "hifi_pll"
> },
> {
> "const": "xtal"
> }
> ],
> "additionalItems": {
> "oneOf": [
> {
> "pattern": "^slv_sclk[0-9]$"
> },
> {
> "pattern": "^slv_lrclk[0-9]$"
> }
> ]
> },
> "type": "array",
> "minItems": 6
> },
>
> and it behaves as expected. However, the checking is followed by
> complaints like this:
>
> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>
> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
> do it right?

The meta-schemas are written both to prevent nonsense that json-schema
allows by default (e.g additionalitems (wrong case)) and constraints to
follow the patterns we expect. I'm happy to loosen the latter case if
there's really a need.

Generally, most bindings shouldn't be using 'additionalItems' at all as
all entries should be defined, but there's a few exceptions. Here, the
only reasoning I see is 26 entries is a lot to write out, but that
wouldn't really justify it. As Krzysztof pointed out, you either have
the clocks in the h/w or you don't, so saying they are variable is
suspect.

Rob

2024-04-20 14:51:09

by Jan Dakinevich

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver



On 4/19/24 17:06, Krzysztof Kozlowski wrote:
> On 19/04/2024 14:58, Jan Dakinevich wrote:
>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>
>> Signed-off-by: Jan Dakinevich <[email protected]>
>
> This is still RFC, so not ready.
>
> Limited, incomplete review follows. Full review will be provided when
> the work is ready.
>
> Drop "driver" references, e.g. from subject. Bindings are about hardware.
>
>
> ....
>
>> +
>> + clocks:
>> + maxItems: 26
>> + items:
>> + - description: input main peripheral bus clock
>> + - description: input dds_in
>> + - description: input fixed pll div2
>> + - description: input fixed pll div3
>> + - description: input hifi_pll
>> + - description: input oscillator (usually at 24MHz)
>> + additionalItems:
>> + oneOf:
>> + - description: slv_sclk[0-9] - slave bit clocks provided by external components
>> + - description: slv_lrclk[0-9]- slave sample clocks provided by external components
>
> What does it mean the clocks are optional? Pins could be not routed?

Yes exactly. Pins could be routed in any combination or could be not
routed at all. It is determined by schematics and that how external
codecs are configured.

> It's really rare case that clocks within the SoC are optional, so every
> such case is questionable.
>
>
>> +
>> + clock-names:
>> + maxItems: 26
>> + items:
>> + - const: pclk
>> + - const: dds_in
>> + - const: fclk_div2
>> + - const: fclk_div3
>> + - const: hifi_pll
>> + - const: xtal
>> + additionalItems:
>> + oneOf:
>> + - pattern: "^slv_sclk[0-9]$"
>> + - pattern: "^slv_lrclk[0-9]$"
>> +
>> +required:
>> + - compatible
>> + - '#clock-cells'
>> + - reg
>> + - clocks
>> + - clock-names
>> +
>> +allOf:
>> + - if:
>> + properties:
>> + compatible:
>> + contains:
>> + const: amlogic,a1-audio-clkc
>> + then:
>> + required:
>> + - '#reset-cells'
>> + else:
>> + properties:
>> + '#reset-cells': false
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/clock/amlogic,a1-pll-clkc.h>
>> + #include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
>> + #include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
>> + audio {
>> + #address-cells = <2>;
>> + #size-cells = <2>;
>> +
>> + clkc_audio: clock-controller@fe050000 {
>> + compatible = "amlogic,a1-audio-clkc";
>> + reg = <0x0 0xfe050000 0x0 0xb0>;
>> + #clock-cells = <1>;
>> + #reset-cells = <1>;
>> + clocks = <&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>,
>> + <&clkc_periphs CLKID_DDS_IN>,
>> + <&clkc_pll CLKID_FCLK_DIV2>,
>> + <&clkc_pll CLKID_FCLK_DIV3>,
>> + <&clkc_pll CLKID_HIFI_PLL>,
>> + <&xtal>;
>> + clock-names = "pclk",
>> + "dds_in",
>> + "fclk_div2",
>> + "fclk_div3",
>> + "hifi_pll",
>> + "xtal";
>
> Make it complete - list all clocks.
>

You mean, all optional clocks should be mentioned here. Right?

>> + };
>> +
>> + clkc_audio_vad: clock-controller@fe054800 {
>
> Just keep one example. It's basically almost the same.
>

The worth of this duplication is to show how a clock from second
controller (<&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>) is used by first
one. May be it would be better to keep it... What do you think?

>
>
> Best regards,
> Krzysztof
>

--
Best regards
Jan Dakinevich

2024-04-20 16:17:48

by Jan Dakinevich

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver



On 4/20/24 00:09, Rob Herring wrote:
> On Fri, Apr 19, 2024 at 03:58:10PM +0300, Jan Dakinevich wrote:
>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>
>> Signed-off-by: Jan Dakinevich <[email protected]>
>> ---
>>
>> This controller has 6 mandatory and up to 20 optional clocks. To describe
>> this, I use 'additionalItems'. It produces correct processed-schema.json:
>>
>> "clock-names": {
>> "maxItems": 26,
>> "items": [
>> {
>> "const": "pclk"
>> },
>> {
>> "const": "dds_in"
>> },
>> {
>> "const": "fclk_div2"
>> },
>> {
>> "const": "fclk_div3"
>> },
>> {
>> "const": "hifi_pll"
>> },
>> {
>> "const": "xtal"
>> }
>> ],
>> "additionalItems": {
>> "oneOf": [
>> {
>> "pattern": "^slv_sclk[0-9]$"
>> },
>> {
>> "pattern": "^slv_lrclk[0-9]$"
>> }
>> ]
>> },
>> "type": "array",
>> "minItems": 6
>> },
>>
>> and it behaves as expected. However, the checking is followed by
>> complaints like this:
>>
>> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>>
>> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
>> do it right?
>
> The meta-schemas are written both to prevent nonsense that json-schema
> allows by default (e.g additionalitems (wrong case)) and constraints to
> follow the patterns we expect. I'm happy to loosen the latter case if
> there's really a need.
>
> Generally, most bindings shouldn't be using 'additionalItems' at all as
> all entries should be defined, but there's a few exceptions. Here, the
> only reasoning I see is 26 entries is a lot to write out, but that
> wouldn't really justify it.

Writing a lot of entries don't scary me too much, but the reason is that
the existence of optional clock sources depends on schematics. Also, we
unable to declare dt-nodes for 'clocks' array in any generic way,
because their declaration would depends on that what is actually
connected to the SoC (dt-node could be "fixed-clock" with specific rate
or something else).

By the way, I don't know any example (neither for A1 SoC nor for other
Amlogic's SoCs) where these optional clocks are used, but they are
allowed by hw.

This is my understanding of this controller. I hope, Jerome Brunet will
clarify how it actually works.

> As Krzysztof pointed out, you either have
> the clocks in the h/w or you don't, so saying they are variable is
> suspect.
>
> Rob

--
Best regards
Jan Dakinevich

2024-04-21 14:02:37

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver

On 20/04/2024 16:48, Jan Dakinevich wrote:
>>> + clock-names = "pclk",
>>> + "dds_in",
>>> + "fclk_div2",
>>> + "fclk_div3",
>>> + "hifi_pll",
>>> + "xtal";
>>
>> Make it complete - list all clocks.
>>
>
> You mean, all optional clocks should be mentioned here. Right?

Yes.

>
>>> + };
>>> +
>>> + clkc_audio_vad: clock-controller@fe054800 {
>>
>> Just keep one example. It's basically almost the same.
>>
>
> The worth of this duplication is to show how a clock from second
> controller (<&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>) is used by first
> one. May be it would be better to keep it... What do you think?

I don't understand what is worth here. Using clocks is kind of obvious?
What's special?

Best regards,
Krzysztof


2024-04-21 15:38:01

by Jan Dakinevich

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver



On 4/21/24 17:02, Krzysztof Kozlowski wrote:
> On 20/04/2024 16:48, Jan Dakinevich wrote:
>>>> + clock-names = "pclk",
>>>> + "dds_in",
>>>> + "fclk_div2",
>>>> + "fclk_div3",
>>>> + "hifi_pll",
>>>> + "xtal";
>>>
>>> Make it complete - list all clocks.
>>>
>>
>> You mean, all optional clocks should be mentioned here. Right?
>
> Yes.
> >>
>>>> + };
>>>> +
>>>> + clkc_audio_vad: clock-controller@fe054800 {
>>>
>>> Just keep one example. It's basically almost the same.
>>>
>>
>> The worth of this duplication is to show how a clock from second
>> controller (<&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>) is used by first
>> one. May be it would be better to keep it... What do you think?
>
> I don't understand what is worth here. Using clocks is kind of obvious?
> What's special?
>

The special is that the clock "pclk" for "clkc_audio" must be
<&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>. This thing is not obvious. I
can keep only "clkc_audio" node here, but reference to "clkc_audio_vad"
will be undefined in example. Is it okay?

> Best regards,
> Krzysztof
>

--
Best regards
Jan Dakinevich

2024-04-21 18:14:47

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver

On 20/04/2024 18:15, Jan Dakinevich wrote:
>
>
> On 4/20/24 00:09, Rob Herring wrote:
>> On Fri, Apr 19, 2024 at 03:58:10PM +0300, Jan Dakinevich wrote:
>>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>>
>>> Signed-off-by: Jan Dakinevich <[email protected]>
>>> ---
>>>
>>> This controller has 6 mandatory and up to 20 optional clocks. To describe
>>> this, I use 'additionalItems'. It produces correct processed-schema.json:
>>>
>>> "clock-names": {
>>> "maxItems": 26,
>>> "items": [
>>> {
>>> "const": "pclk"
>>> },
>>> {
>>> "const": "dds_in"
>>> },
>>> {
>>> "const": "fclk_div2"
>>> },
>>> {
>>> "const": "fclk_div3"
>>> },
>>> {
>>> "const": "hifi_pll"
>>> },
>>> {
>>> "const": "xtal"
>>> }
>>> ],
>>> "additionalItems": {
>>> "oneOf": [
>>> {
>>> "pattern": "^slv_sclk[0-9]$"
>>> },
>>> {
>>> "pattern": "^slv_lrclk[0-9]$"
>>> }
>>> ]
>>> },
>>> "type": "array",
>>> "minItems": 6
>>> },
>>>
>>> and it behaves as expected. However, the checking is followed by
>>> complaints like this:
>>>
>>> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>>>
>>> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
>>> do it right?
>>
>> The meta-schemas are written both to prevent nonsense that json-schema
>> allows by default (e.g additionalitems (wrong case)) and constraints to
>> follow the patterns we expect. I'm happy to loosen the latter case if
>> there's really a need.
>>
>> Generally, most bindings shouldn't be using 'additionalItems' at all as
>> all entries should be defined, but there's a few exceptions. Here, the
>> only reasoning I see is 26 entries is a lot to write out, but that
>> wouldn't really justify it.
>
> Writing a lot of entries don't scary me too much, but the reason is that
> the existence of optional clock sources depends on schematics. Also, we

Aren't you documenting SoC component, not a board? So how exactly it
depends on schematics? SoC is done or not done...

> unable to declare dt-nodes for 'clocks' array in any generic way,
> because their declaration would depends on that what is actually
> connected to the SoC (dt-node could be "fixed-clock" with specific rate
> or something else).

So these are clock inputs to the SoC?

>
> By the way, I don't know any example (neither for A1 SoC nor for other
> Amlogic's SoCs) where these optional clocks are used, but they are
> allowed by hw.
>
> This is my understanding of this controller. I hope, Jerome Brunet will
> clarify how it actually works.

Best regards,
Krzysztof


2024-04-21 18:17:36

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver

On 21/04/2024 17:35, Jan Dakinevich wrote:
>>>>
>>>>> + };
>>>>> +
>>>>> + clkc_audio_vad: clock-controller@fe054800 {
>>>>
>>>> Just keep one example. It's basically almost the same.
>>>>
>>>
>>> The worth of this duplication is to show how a clock from second
>>> controller (<&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>) is used by first
>>> one. May be it would be better to keep it... What do you think?
>>
>> I don't understand what is worth here. Using clocks is kind of obvious?
>> What's special?
>>
>
> The special is that the clock "pclk" for "clkc_audio" must be
> <&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>. This thing is not obvious. I

So you want to document non-obvious SoC architecture via example, not
via actual documentation. Plus you want to document it for purpose of
..? Isn't this SoC component, so once you write DTSI it is done?

I fail to see any logic in this, but maybe the binding is kind of
special, misrepresented or hardware is different? But the subject
clearly states it is part of SoC, so dunno...

> can keep only "clkc_audio" node here, but reference to "clkc_audio_vad"
> will be undefined in example. Is it okay?

Just like all phandles.

Best regards,
Krzysztof


2024-04-21 21:06:01

by Jan Dakinevich

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver



On 4/21/24 21:14, Krzysztof Kozlowski wrote:
> On 20/04/2024 18:15, Jan Dakinevich wrote:
>>
>>
>> On 4/20/24 00:09, Rob Herring wrote:
>>> On Fri, Apr 19, 2024 at 03:58:10PM +0300, Jan Dakinevich wrote:
>>>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>>>
>>>> Signed-off-by: Jan Dakinevich <[email protected]>
>>>> ---
>>>>
>>>> This controller has 6 mandatory and up to 20 optional clocks. To describe
>>>> this, I use 'additionalItems'. It produces correct processed-schema.json:
>>>>
>>>> "clock-names": {
>>>> "maxItems": 26,
>>>> "items": [
>>>> {
>>>> "const": "pclk"
>>>> },
>>>> {
>>>> "const": "dds_in"
>>>> },
>>>> {
>>>> "const": "fclk_div2"
>>>> },
>>>> {
>>>> "const": "fclk_div3"
>>>> },
>>>> {
>>>> "const": "hifi_pll"
>>>> },
>>>> {
>>>> "const": "xtal"
>>>> }
>>>> ],
>>>> "additionalItems": {
>>>> "oneOf": [
>>>> {
>>>> "pattern": "^slv_sclk[0-9]$"
>>>> },
>>>> {
>>>> "pattern": "^slv_lrclk[0-9]$"
>>>> }
>>>> ]
>>>> },
>>>> "type": "array",
>>>> "minItems": 6
>>>> },
>>>>
>>>> and it behaves as expected. However, the checking is followed by
>>>> complaints like this:
>>>>
>>>> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>>>>
>>>> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
>>>> do it right?
>>>
>>> The meta-schemas are written both to prevent nonsense that json-schema
>>> allows by default (e.g additionalitems (wrong case)) and constraints to
>>> follow the patterns we expect. I'm happy to loosen the latter case if
>>> there's really a need.
>>>
>>> Generally, most bindings shouldn't be using 'additionalItems' at all as
>>> all entries should be defined, but there's a few exceptions. Here, the
>>> only reasoning I see is 26 entries is a lot to write out, but that
>>> wouldn't really justify it.
>>
>> Writing a lot of entries don't scary me too much, but the reason is that
>> the existence of optional clock sources depends on schematics. Also, we
>
> Aren't you documenting SoC component, not a board?

Yes, I'm documenting SoC component. And the feature of this component is
that its external clock inputs are not mandatory.

> So how exactly it
> depends on schematics? SoC is done or not done...
>

Schematics determines which external clock sources exist.

>> unable to declare dt-nodes for 'clocks' array in any generic way,
>> because their declaration would depends on that what is actually
>> connected to the SoC (dt-node could be "fixed-clock" with specific rate
>> or something else).
>
> So these are clock inputs to the SoC?
>

Yes, these are clock inputs to the SoC, and external hardware could be
connected to them.

>>
>> By the way, I don't know any example (neither for A1 SoC nor for other
>> Amlogic's SoCs) where these optional clocks are used, but they are
>> allowed by hw.
>>
>> This is my understanding of this controller. I hope, Jerome Brunet will
>> clarify how it actually works.
>
> Best regards,
> Krzysztof
>

--
Best regards
Jan Dakinevich

2024-04-22 07:40:46

by Jerome Brunet

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver


On Sun 21 Apr 2024 at 20:14, Krzysztof Kozlowski <[email protected]> wrote:

> On 20/04/2024 18:15, Jan Dakinevich wrote:
>>
>>
>> On 4/20/24 00:09, Rob Herring wrote:
>>> On Fri, Apr 19, 2024 at 03:58:10PM +0300, Jan Dakinevich wrote:
>>>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>>>
>>>> Signed-off-by: Jan Dakinevich <[email protected]>
>>>> ---
>>>>
>>>> This controller has 6 mandatory and up to 20 optional clocks. To describe
>>>> this, I use 'additionalItems'. It produces correct processed-schema.json:
>>>>
>>>> "clock-names": {
>>>> "maxItems": 26,
>>>> "items": [
>>>> {
>>>> "const": "pclk"
>>>> },
>>>> {
>>>> "const": "dds_in"
>>>> },
>>>> {
>>>> "const": "fclk_div2"
>>>> },
>>>> {
>>>> "const": "fclk_div3"
>>>> },
>>>> {
>>>> "const": "hifi_pll"
>>>> },
>>>> {
>>>> "const": "xtal"
>>>> }
>>>> ],
>>>> "additionalItems": {
>>>> "oneOf": [
>>>> {
>>>> "pattern": "^slv_sclk[0-9]$"
>>>> },
>>>> {
>>>> "pattern": "^slv_lrclk[0-9]$"
>>>> }
>>>> ]
>>>> },
>>>> "type": "array",
>>>> "minItems": 6
>>>> },
>>>>
>>>> and it behaves as expected. However, the checking is followed by
>>>> complaints like this:
>>>>
>>>> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>>>>
>>>> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
>>>> do it right?
>>>
>>> The meta-schemas are written both to prevent nonsense that json-schema
>>> allows by default (e.g additionalitems (wrong case)) and constraints to
>>> follow the patterns we expect. I'm happy to loosen the latter case if
>>> there's really a need.
>>>
>>> Generally, most bindings shouldn't be using 'additionalItems' at all as
>>> all entries should be defined, but there's a few exceptions. Here, the
>>> only reasoning I see is 26 entries is a lot to write out, but that
>>> wouldn't really justify it.
>>
>> Writing a lot of entries don't scary me too much, but the reason is that
>> the existence of optional clock sources depends on schematics. Also, we
>
> Aren't you documenting SoC component, not a board? So how exactly it
> depends on schematics? SoC is done or not done...
>
>> unable to declare dt-nodes for 'clocks' array in any generic way,
>> because their declaration would depends on that what is actually
>> connected to the SoC (dt-node could be "fixed-clock" with specific rate
>> or something else).
>
> So these are clock inputs to the SoC?
>

Yes, possibly.
Like an external crystal or a set clocks provided by an external codec
where the codec is the clock master of the link.

This is same case as the AXG that was discussed here:
https://lore.kernel.org/linux-devicetree/[email protected]/

IMO, like the AXG, only the pclk is a required clock.
All the others - master and slave clocks - are optional.
The controller is designed to operate with grounded inputs

>>
>> By the way, I don't know any example (neither for A1 SoC nor for other
>> Amlogic's SoCs) where these optional clocks are used, but they are
>> allowed by hw.

Those scenario exists and have been tested. There is just no dts using
that upstream because they are all mostly copy of the AML ref design.

>>
>> This is my understanding of this controller. I hope, Jerome Brunet will
>> clarify how it actually works.
>

I think the simpliest way to deal with this to just list all the clocks
with 'minItems = 1'. It is going be hard to read with a lot of '<0>,' in
the DTS when do need those slave clocks but at least the binding doc
will be simple.

> Best regards,
> Krzysztof

If you are going ahead with this, please name the file
amlogic,axg-audio-clkc.yaml because this is really the first controller
of the type and is meant to be documented in the same file.

You are free to handle the conversion of the AXG at the same time if
you'd like. It would be much appreciated if you do.

--
Jerome

2024-04-22 07:43:20

by Jerome Brunet

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver


On Fri 19 Apr 2024 at 15:58, Jan Dakinevich <[email protected]> wrote:

> Add device tree bindings for A1 SoC audio clock and reset controllers.
>
> Signed-off-by: Jan Dakinevich <[email protected]>
> ---
>
> This controller has 6 mandatory and up to 20 optional clocks. To describe
> this, I use 'additionalItems'. It produces correct processed-schema.json:
>
> "clock-names": {
> "maxItems": 26,
> "items": [
> {
> "const": "pclk"
> },
> {
> "const": "dds_in"
> },
> {
> "const": "fclk_div2"
> },
> {
> "const": "fclk_div3"
> },
> {
> "const": "hifi_pll"
> },
> {
> "const": "xtal"
> }
> ],
> "additionalItems": {
> "oneOf": [
> {
> "pattern": "^slv_sclk[0-9]$"
> },
> {
> "pattern": "^slv_lrclk[0-9]$"
> }
> ]
> },
> "type": "array",
> "minItems": 6
> },
>
> and it behaves as expected. However, the checking is followed by
> complaints like this:
>
> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>
> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
> do it right?
> ---
> .../bindings/clock/amlogic,a1-audio-clkc.yaml | 124 ++++++++++++++++++
> .../dt-bindings/clock/amlogic,a1-audio-clkc.h | 122 +++++++++++++++++
> .../reset/amlogic,meson-a1-audio-reset.h | 29 ++++
> 3 files changed, 275 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml
> create mode 100644 include/dt-bindings/clock/amlogic,a1-audio-clkc.h
> create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h
>
> diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml
> new file mode 100644
> index 000000000000..40a0af3635f4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml
> @@ -0,0 +1,124 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/amlogic,a1-audio-clkc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Amlogic A1 Audio Clock Control Unit and Reset Controller
> +
> +maintainers:
> + - Neil Armstrong <[email protected]>
> + - Jerome Brunet <[email protected]>
> + - Jan Dakinevich <[email protected]>
> +
> +properties:
> + compatible:
> + enum:
> + - amlogic,a1-audio-clkc
> + - amlogic,a1-audio-vad-clkc
> +
> + '#clock-cells':
> + const: 1
> +
> + '#reset-cells':
> + const: 1
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + maxItems: 26
> + items:
> + - description: input main peripheral bus clock
> + - description: input dds_in
> + - description: input fixed pll div2
> + - description: input fixed pll div3
> + - description: input hifi_pll
> + - description: input oscillator (usually at 24MHz)
> + additionalItems:
> + oneOf:
> + - description: slv_sclk[0-9] - slave bit clocks provided by external components
> + - description: slv_lrclk[0-9]- slave sample clocks provided by external components
> +
> + clock-names:
> + maxItems: 26
> + items:
> + - const: pclk
> + - const: dds_in
> + - const: fclk_div2
> + - const: fclk_div3
> + - const: hifi_pll
> + - const: xtal
> + additionalItems:
> + oneOf:
> + - pattern: "^slv_sclk[0-9]$"
> + - pattern: "^slv_lrclk[0-9]$"
> +
> +required:
> + - compatible
> + - '#clock-cells'
> + - reg
> + - clocks
> + - clock-names
> +
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: amlogic,a1-audio-clkc
> + then:
> + required:
> + - '#reset-cells'
> + else:
> + properties:
> + '#reset-cells': false
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/amlogic,a1-pll-clkc.h>
> + #include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
> + #include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
> + audio {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + clkc_audio: clock-controller@fe050000 {
> + compatible = "amlogic,a1-audio-clkc";
> + reg = <0x0 0xfe050000 0x0 0xb0>;
> + #clock-cells = <1>;
> + #reset-cells = <1>;
> + clocks = <&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>,
> + <&clkc_periphs CLKID_DDS_IN>,
> + <&clkc_pll CLKID_FCLK_DIV2>,
> + <&clkc_pll CLKID_FCLK_DIV3>,
> + <&clkc_pll CLKID_HIFI_PLL>,
> + <&xtal>;
> + clock-names = "pclk",
> + "dds_in",
> + "fclk_div2",
> + "fclk_div3",
> + "hifi_pll",
> + "xtal";
> + };
> +
> + clkc_audio_vad: clock-controller@fe054800 {
> + compatible = "amlogic,a1-audio2-clkc";
> + reg = <0x0 0xfe054800 0x0 0x20>;
> + #clock-cells = <1>;
> + clocks = <&clkc_periphs CLKID_AUDIO>,
> + <&clkc_periphs CLKID_DDS_IN>,
> + <&clkc_pll CLKID_FCLK_DIV2>,
> + <&clkc_pll CLKID_FCLK_DIV3>,
> + <&clkc_pll CLKID_HIFI_PLL>,
> + <&xtal>;
> + clock-names = "pclk",
> + "dds_in",
> + "fclk_div2",
> + "fclk_div3",
> + "hifi_pll",
> + "xtal";
> + };
> + };
> diff --git a/include/dt-bindings/clock/amlogic,a1-audio-clkc.h b/include/dt-bindings/clock/amlogic,a1-audio-clkc.h
> new file mode 100644
> index 000000000000..6534d1878816
> --- /dev/null
> +++ b/include/dt-bindings/clock/amlogic,a1-audio-clkc.h
> @@ -0,0 +1,122 @@
> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
> +/*
> + * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
> + *
> + * Author: Jan Dakinevich <[email protected]>
> + */
> +
> +#ifndef __A1_AUDIO_CLKC_BINDINGS_H
> +#define __A1_AUDIO_CLKC_BINDINGS_H
> +
> +#define AUD_CLKID_DDR_ARB 1
> +#define AUD_CLKID_TDMIN_A 2
> +#define AUD_CLKID_TDMIN_B 3
> +#define AUD_CLKID_TDMIN_LB 4
> +#define AUD_CLKID_LOOPBACK 5
> +#define AUD_CLKID_TDMOUT_A 6
> +#define AUD_CLKID_TDMOUT_B 7
> +#define AUD_CLKID_FRDDR_A 8
> +#define AUD_CLKID_FRDDR_B 9
> +#define AUD_CLKID_TODDR_A 10
> +#define AUD_CLKID_TODDR_B 11
> +#define AUD_CLKID_SPDIFIN 12
> +#define AUD_CLKID_RESAMPLE 13
> +#define AUD_CLKID_EQDRC 14
> +#define AUD_CLKID_LOCKER 15
> +#define AUD_CLKID_MST_A_MCLK_SEL 16
> +#define AUD_CLKID_MST_A_MCLK_DIV 17
> +#define AUD_CLKID_MST_A_MCLK 18
> +#define AUD_CLKID_MST_B_MCLK_SEL 19
> +#define AUD_CLKID_MST_B_MCLK_DIV 20
> +#define AUD_CLKID_MST_B_MCLK 21
> +#define AUD_CLKID_MST_C_MCLK_SEL 22
> +#define AUD_CLKID_MST_C_MCLK_DIV 23
> +#define AUD_CLKID_MST_C_MCLK 24
> +#define AUD_CLKID_MST_D_MCLK_SEL 25
> +#define AUD_CLKID_MST_D_MCLK_DIV 26
> +#define AUD_CLKID_MST_D_MCLK 27
> +#define AUD_CLKID_SPDIFIN_CLK_SEL 28
> +#define AUD_CLKID_SPDIFIN_CLK_DIV 29
> +#define AUD_CLKID_SPDIFIN_CLK 30
> +#define AUD_CLKID_RESAMPLE_CLK_SEL 31
> +#define AUD_CLKID_RESAMPLE_CLK_DIV 32
> +#define AUD_CLKID_RESAMPLE_CLK 33
> +#define AUD_CLKID_LOCKER_IN_CLK_SEL 34
> +#define AUD_CLKID_LOCKER_IN_CLK_DIV 35
> +#define AUD_CLKID_LOCKER_IN_CLK 36
> +#define AUD_CLKID_LOCKER_OUT_CLK_SEL 37
> +#define AUD_CLKID_LOCKER_OUT_CLK_DIV 38
> +#define AUD_CLKID_LOCKER_OUT_CLK 39
> +#define AUD_CLKID_EQDRC_CLK_SEL 40
> +#define AUD_CLKID_EQDRC_CLK_DIV 41
> +#define AUD_CLKID_EQDRC_CLK 42
> +#define AUD_CLKID_MST_A_SCLK_PRE_EN 43
> +#define AUD_CLKID_MST_A_SCLK_DIV 44
> +#define AUD_CLKID_MST_A_SCLK_POST_EN 45
> +#define AUD_CLKID_MST_A_SCLK 46
> +#define AUD_CLKID_MST_B_SCLK_PRE_EN 47
> +#define AUD_CLKID_MST_B_SCLK_DIV 48
> +#define AUD_CLKID_MST_B_SCLK_POST_EN 49
> +#define AUD_CLKID_MST_B_SCLK 50
> +#define AUD_CLKID_MST_C_SCLK_PRE_EN 51
> +#define AUD_CLKID_MST_C_SCLK_DIV 52
> +#define AUD_CLKID_MST_C_SCLK_POST_EN 53
> +#define AUD_CLKID_MST_C_SCLK 54
> +#define AUD_CLKID_MST_D_SCLK_PRE_EN 55
> +#define AUD_CLKID_MST_D_SCLK_DIV 56
> +#define AUD_CLKID_MST_D_SCLK_POST_EN 57
> +#define AUD_CLKID_MST_D_SCLK 58
> +#define AUD_CLKID_MST_A_LRCLK_DIV 59
> +#define AUD_CLKID_MST_A_LRCLK 60
> +#define AUD_CLKID_MST_B_LRCLK_DIV 61
> +#define AUD_CLKID_MST_B_LRCLK 62
> +#define AUD_CLKID_MST_C_LRCLK_DIV 63
> +#define AUD_CLKID_MST_C_LRCLK 64
> +#define AUD_CLKID_MST_D_LRCLK_DIV 65
> +#define AUD_CLKID_MST_D_LRCLK 66
> +#define AUD_CLKID_TDMIN_A_SCLK_SEL 67
> +#define AUD_CLKID_TDMIN_A_SCLK_PRE_EN 68
> +#define AUD_CLKID_TDMIN_A_SCLK_POST_EN 69
> +#define AUD_CLKID_TDMIN_A_SCLK 70
> +#define AUD_CLKID_TDMIN_A_LRCLK 71
> +#define AUD_CLKID_TDMIN_B_SCLK_SEL 72
> +#define AUD_CLKID_TDMIN_B_SCLK_PRE_EN 73
> +#define AUD_CLKID_TDMIN_B_SCLK_POST_EN 74
> +#define AUD_CLKID_TDMIN_B_SCLK 75
> +#define AUD_CLKID_TDMIN_B_LRCLK 76
> +#define AUD_CLKID_TDMIN_LB_SCLK_SEL 77
> +#define AUD_CLKID_TDMIN_LB_SCLK_PRE_EN 78
> +#define AUD_CLKID_TDMIN_LB_SCLK_POST_EN 79
> +#define AUD_CLKID_TDMIN_LB_SCLK 80
> +#define AUD_CLKID_TDMIN_LB_LRCLK 81
> +#define AUD_CLKID_TDMOUT_A_SCLK_SEL 82
> +#define AUD_CLKID_TDMOUT_A_SCLK_PRE_EN 83
> +#define AUD_CLKID_TDMOUT_A_SCLK_POST_EN 84
> +#define AUD_CLKID_TDMOUT_A_SCLK 85
> +#define AUD_CLKID_TDMOUT_A_LRCLK 86
> +#define AUD_CLKID_TDMOUT_B_SCLK_SEL 87
> +#define AUD_CLKID_TDMOUT_B_SCLK_PRE_EN 88
> +#define AUD_CLKID_TDMOUT_B_SCLK_POST_EN 89
> +#define AUD_CLKID_TDMOUT_B_SCLK 90
> +#define AUD_CLKID_TDMOUT_B_LRCLK 91
> +
> +#define AUD_CLKID_VAD_DDR_ARB 1
> +#define AUD_CLKID_VAD_PDM 2
> +#define AUD_CLKID_VAD_TDMIN 3
> +#define AUD_CLKID_VAD_TODDR 4
> +#define AUD_CLKID_VAD 5
> +#define AUD_CLKID_VAD_AUDIOTOP 6
> +#define AUD_CLKID_VAD_MCLK_SEL 7
> +#define AUD_CLKID_VAD_MCLK_DIV 8
> +#define AUD_CLKID_VAD_MCLK 9
> +#define AUD_CLKID_VAD_CLK_SEL 10
> +#define AUD_CLKID_VAD_CLK_DIV 11
> +#define AUD_CLKID_VAD_CLK 12
> +#define AUD_CLKID_VAD_PDM_DCLK_SEL 13
> +#define AUD_CLKID_VAD_PDM_DCLK_DIV 14
> +#define AUD_CLKID_VAD_PDM_DCLK 15
> +#define AUD_CLKID_VAD_PDM_SYSCLK_SEL 16
> +#define AUD_CLKID_VAD_PDM_SYSCLK_DIV 17
> +#define AUD_CLKID_VAD_PDM_SYSCLK 18
> +

Again, please split the a1 and a1-vad controller.
They are independent and there is no reason to use a single file for them

> +#endif /* __A1_AUDIO_CLKC_BINDINGS_H */
> diff --git a/include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h b/include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h
> new file mode 100644
> index 000000000000..653fddba1d8f
> --- /dev/null
> +++ b/include/dt-bindings/reset/amlogic,meson-a1-audio-reset.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
> +/*
> + * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
> + *
> + * Author: Jan Dakinevich <[email protected]>
> + */
> +
> +#ifndef _DT_BINDINGS_AMLOGIC_MESON_A1_AUDIO_RESET_H
> +#define _DT_BINDINGS_AMLOGIC_MESON_A1_AUDIO_RESET_H
> +
> +#define AUD_RESET_DDRARB 0
> +#define AUD_RESET_TDMIN_A 1
> +#define AUD_RESET_TDMIN_B 2
> +#define AUD_RESET_TDMIN_LB 3
> +#define AUD_RESET_LOOPBACK 4
> +#define AUD_RESET_TDMOUT_A 5
> +#define AUD_RESET_TDMOUT_B 6
> +#define AUD_RESET_FRDDR_A 7
> +#define AUD_RESET_FRDDR_B 8
> +#define AUD_RESET_TODDR_A 9
> +#define AUD_RESET_TODDR_B 10
> +#define AUD_RESET_SPDIFIN 11
> +#define AUD_RESET_RESAMPLE 12
> +#define AUD_RESET_EQDRC 13
> +#define AUD_RESET_LOCKER 14
> +#define AUD_RESET_TOACODEC 30
> +#define AUD_RESET_CLKTREE 31
> +
> +#endif /* _DT_BINDINGS_AMLOGIC_MESON_A1_AUDIO_RESET_H */


--
Jerome

2024-04-22 07:45:15

by Jerome Brunet

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver


On Sat 20 Apr 2024 at 17:48, Jan Dakinevich <[email protected]> wrote:

> On 4/19/24 17:06, Krzysztof Kozlowski wrote:
>> On 19/04/2024 14:58, Jan Dakinevich wrote:
>>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>>
>>> Signed-off-by: Jan Dakinevich <[email protected]>
>>
>> This is still RFC, so not ready.
>>
>> Limited, incomplete review follows. Full review will be provided when
>> the work is ready.
>>
>> Drop "driver" references, e.g. from subject. Bindings are about hardware.
>>
>>
>> ....
>>
>>> +
>>> + clocks:
>>> + maxItems: 26
>>> + items:
>>> + - description: input main peripheral bus clock
>>> + - description: input dds_in
>>> + - description: input fixed pll div2
>>> + - description: input fixed pll div3
>>> + - description: input hifi_pll
>>> + - description: input oscillator (usually at 24MHz)
>>> + additionalItems:
>>> + oneOf:
>>> + - description: slv_sclk[0-9] - slave bit clocks provided by external components
>>> + - description: slv_lrclk[0-9]- slave sample clocks provided by external components
>>
>> What does it mean the clocks are optional? Pins could be not routed?
>
> Yes exactly. Pins could be routed in any combination or could be not
> routed at all. It is determined by schematics and that how external
> codecs are configured.
>
>> It's really rare case that clocks within the SoC are optional, so every
>> such case is questionable.
>>
>>
>>> +
>>> + clock-names:
>>> + maxItems: 26
>>> + items:
>>> + - const: pclk
>>> + - const: dds_in
>>> + - const: fclk_div2
>>> + - const: fclk_div3
>>> + - const: hifi_pll
>>> + - const: xtal
>>> + additionalItems:
>>> + oneOf:
>>> + - pattern: "^slv_sclk[0-9]$"
>>> + - pattern: "^slv_lrclk[0-9]$"
>>> +
>>> +required:
>>> + - compatible
>>> + - '#clock-cells'
>>> + - reg
>>> + - clocks
>>> + - clock-names
>>> +
>>> +allOf:
>>> + - if:
>>> + properties:
>>> + compatible:
>>> + contains:
>>> + const: amlogic,a1-audio-clkc
>>> + then:
>>> + required:
>>> + - '#reset-cells'
>>> + else:
>>> + properties:
>>> + '#reset-cells': false
>>> +
>>> +additionalProperties: false
>>> +
>>> +examples:
>>> + - |
>>> + #include <dt-bindings/clock/amlogic,a1-pll-clkc.h>
>>> + #include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
>>> + #include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
>>> + audio {
>>> + #address-cells = <2>;
>>> + #size-cells = <2>;
>>> +
>>> + clkc_audio: clock-controller@fe050000 {
>>> + compatible = "amlogic,a1-audio-clkc";
>>> + reg = <0x0 0xfe050000 0x0 0xb0>;
>>> + #clock-cells = <1>;
>>> + #reset-cells = <1>;
>>> + clocks = <&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>,
>>> + <&clkc_periphs CLKID_DDS_IN>,
>>> + <&clkc_pll CLKID_FCLK_DIV2>,
>>> + <&clkc_pll CLKID_FCLK_DIV3>,
>>> + <&clkc_pll CLKID_HIFI_PLL>,
>>> + <&xtal>;
>>> + clock-names = "pclk",
>>> + "dds_in",
>>> + "fclk_div2",
>>> + "fclk_div3",
>>> + "hifi_pll",
>>> + "xtal";
>>
>> Make it complete - list all clocks.
>>
>
> You mean, all optional clocks should be mentioned here. Right?
>
>>> + };
>>> +
>>> + clkc_audio_vad: clock-controller@fe054800 {
>>
>> Just keep one example. It's basically almost the same.
>>
>
> The worth of this duplication is to show how a clock from second
> controller (<&clkc_audio_vad AUD_CLKID_VAD_AUDIOTOP>) is used by first
> one. May be it would be better to keep it... What do you think?

If you think that is worth mentioning, make it part of the
documentation, not the example.

>
>>
>>
>> Best regards,
>> Krzysztof
>>


--
Jerome

2024-04-22 07:54:45

by Jerome Brunet

[permalink] [raw]
Subject: Re: [RFC PATCH v3 1/6] reset: reset-meson-audio: introduce separate driver


On Fri 19 Apr 2024 at 15:58, Jan Dakinevich <[email protected]> wrote:

> Typically, Amlogic Meson SoCs have a couple a reset registers lost in
> middle of audio clock controller. Reset controller on top of them was
> implemented inside audio clock controller driver. This patch moves reset
> functionality of this controller to auxiliary driver. There are at least
> two reasons for this:
>
> - architecturally it is more convenient;
>
> - reusing the code of reset controller for new SoCs becomes easier.
>
> Signed-off-by: Jan Dakinevich <[email protected]>
> ---
> drivers/clk/meson/Kconfig | 2 +
> drivers/clk/meson/axg-audio.c | 106 +------------
> drivers/reset/Kconfig | 7 +
> drivers/reset/Makefile | 1 +
> drivers/reset/reset-meson-audio.c | 197 ++++++++++++++++++++++++
> include/soc/amlogic/meson-audio-reset.h | 10 ++

You must an effort to touch a single subsystem per series.
Making a series about a single subsystem makes like a lot easier for
maintainers. clk, reset and dt and different subsystems

That constraints relaxed for RFCs but mixing subsystems within a single
patch is a red flag, unless you really have a good reason ... and you
don't have one here.

Nothing blocks introducting support in reset, then use it in clocks.

You could also have allowed a bit more time before reposting since I
said I would look at the reset issue.

I doubt introducing a separate driver for this is required since since
the current amlogic reset driver is fairly close.

> 6 files changed, 224 insertions(+), 99 deletions(-)
> create mode 100644 drivers/reset/reset-meson-audio.c
> create mode 100644 include/soc/amlogic/meson-audio-reset.h
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 29ffd14d267b..33614f8b8cf7 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -101,6 +101,8 @@ config COMMON_CLK_AXG_AUDIO
> select COMMON_CLK_MESON_PHASE
> select COMMON_CLK_MESON_SCLK_DIV
> select COMMON_CLK_MESON_CLKC_UTILS
> + select RESET_CONTROLLER
> + select RESET_MESON_AUDIO
> select REGMAP_MMIO
> help
> Support for the audio clock controller on AmLogic A113D devices,
> diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
> index ac3482960903..9cd6b5c3aa7e 100644
> --- a/drivers/clk/meson/axg-audio.c
> +++ b/drivers/clk/meson/axg-audio.c
> @@ -12,9 +12,10 @@
> #include <linux/platform_device.h>
> #include <linux/regmap.h>
> #include <linux/reset.h>
> -#include <linux/reset-controller.h>
> #include <linux/slab.h>
>
> +#include <soc/amlogic/meson-audio-reset.h>
> +
> #include "meson-clkc-utils.h"
> #include "axg-audio.h"
> #include "clk-regmap.h"
> @@ -1648,84 +1649,6 @@ static struct clk_regmap *const sm1_clk_regmaps[] = {
> &sm1_sysclk_b_en,
> };
>
> -struct axg_audio_reset_data {
> - struct reset_controller_dev rstc;
> - struct regmap *map;
> - unsigned int offset;
> -};
> -
> -static void axg_audio_reset_reg_and_bit(struct axg_audio_reset_data *rst,
> - unsigned long id,
> - unsigned int *reg,
> - unsigned int *bit)
> -{
> - unsigned int stride = regmap_get_reg_stride(rst->map);
> -
> - *reg = (id / (stride * BITS_PER_BYTE)) * stride;
> - *reg += rst->offset;
> - *bit = id % (stride * BITS_PER_BYTE);
> -}
> -
> -static int axg_audio_reset_update(struct reset_controller_dev *rcdev,
> - unsigned long id, bool assert)
> -{
> - struct axg_audio_reset_data *rst =
> - container_of(rcdev, struct axg_audio_reset_data, rstc);
> - unsigned int offset, bit;
> -
> - axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
> -
> - regmap_update_bits(rst->map, offset, BIT(bit),
> - assert ? BIT(bit) : 0);
> -
> - return 0;
> -}
> -
> -static int axg_audio_reset_status(struct reset_controller_dev *rcdev,
> - unsigned long id)
> -{
> - struct axg_audio_reset_data *rst =
> - container_of(rcdev, struct axg_audio_reset_data, rstc);
> - unsigned int val, offset, bit;
> -
> - axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
> -
> - regmap_read(rst->map, offset, &val);
> -
> - return !!(val & BIT(bit));
> -}
> -
> -static int axg_audio_reset_assert(struct reset_controller_dev *rcdev,
> - unsigned long id)
> -{
> - return axg_audio_reset_update(rcdev, id, true);
> -}
> -
> -static int axg_audio_reset_deassert(struct reset_controller_dev *rcdev,
> - unsigned long id)
> -{
> - return axg_audio_reset_update(rcdev, id, false);
> -}
> -
> -static int axg_audio_reset_toggle(struct reset_controller_dev *rcdev,
> - unsigned long id)
> -{
> - int ret;
> -
> - ret = axg_audio_reset_assert(rcdev, id);
> - if (ret)
> - return ret;
> -
> - return axg_audio_reset_deassert(rcdev, id);
> -}
> -
> -static const struct reset_control_ops axg_audio_rstc_ops = {
> - .assert = axg_audio_reset_assert,
> - .deassert = axg_audio_reset_deassert,
> - .reset = axg_audio_reset_toggle,
> - .status = axg_audio_reset_status,
> -};
> -
> static const struct regmap_config axg_audio_regmap_cfg = {
> .reg_bits = 32,
> .val_bits = 32,
> @@ -1737,15 +1660,13 @@ struct audioclk_data {
> struct clk_regmap *const *regmap_clks;
> unsigned int regmap_clk_num;
> struct meson_clk_hw_data hw_clks;
> - unsigned int reset_offset;
> - unsigned int reset_num;
> + const char *reset_name;
> };
>
> static int axg_audio_clkc_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> const struct audioclk_data *data;
> - struct axg_audio_reset_data *rst;
> struct regmap *map;
> void __iomem *regs;
> struct clk_hw *hw;
> @@ -1804,21 +1725,10 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
> return ret;
>
> /* Stop here if there is no reset */
> - if (!data->reset_num)
> + if (!data->reset_name)
> return 0;
>
> - rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL);
> - if (!rst)
> - return -ENOMEM;
> -
> - rst->map = map;
> - rst->offset = data->reset_offset;
> - rst->rstc.nr_resets = data->reset_num;
> - rst->rstc.ops = &axg_audio_rstc_ops;
> - rst->rstc.of_node = dev->of_node;
> - rst->rstc.owner = THIS_MODULE;
> -
> - return devm_reset_controller_register(dev, &rst->rstc);
> + return meson_audio_reset_register(dev, data->reset_name);
> }
>
> static const struct audioclk_data axg_audioclk_data = {
> @@ -1837,8 +1747,7 @@ static const struct audioclk_data g12a_audioclk_data = {
> .hws = g12a_audio_hw_clks,
> .num = ARRAY_SIZE(g12a_audio_hw_clks),
> },
> - .reset_offset = AUDIO_SW_RESET,
> - .reset_num = 26,
> + .reset_name = "g12a",
> };
>
> static const struct audioclk_data sm1_audioclk_data = {
> @@ -1848,8 +1757,7 @@ static const struct audioclk_data sm1_audioclk_data = {
> .hws = sm1_audio_hw_clks,
> .num = ARRAY_SIZE(sm1_audio_hw_clks),
> },
> - .reset_offset = AUDIO_SM1_SW_RESET0,
> - .reset_num = 39,
> + .reset_name = "sm1",
> };
>
> static const struct of_device_id clkc_match_table[] = {
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index 7112f5932609..98106694566f 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -138,6 +138,13 @@ config RESET_MESON
> help
> This enables the reset driver for Amlogic Meson SoCs.
>
> +config RESET_MESON_AUDIO
> + tristate "Meson Audio Reset Driver"
> + depends on ARCH_MESON || COMPILE_TEST
> + select AUXILIARY_BUS
> + help
> + This enables the audio reset driver for Amlogic Meson SoCs.
> +
> config RESET_MESON_AUDIO_ARB
> tristate "Meson Audio Memory Arbiter Reset Driver"
> depends on ARCH_MESON || COMPILE_TEST
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index fd8b49fa46fc..8ee7a57ccf03 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
> obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
> obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o
> obj-$(CONFIG_RESET_MESON) += reset-meson.o
> +obj-$(CONFIG_RESET_MESON_AUDIO) += reset-meson-audio.o
> obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
> obj-$(CONFIG_RESET_NPCM) += reset-npcm.o
> obj-$(CONFIG_RESET_NUVOTON_MA35D1) += reset-ma35d1.o
> diff --git a/drivers/reset/reset-meson-audio.c b/drivers/reset/reset-meson-audio.c
> new file mode 100644
> index 000000000000..aaea9931cfe2
> --- /dev/null
> +++ b/drivers/reset/reset-meson-audio.c
> @@ -0,0 +1,197 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Copyright (c) 2018 BayLibre, SAS.
> + * Author: Jerome Brunet <[email protected]>
> + */
> +
> +#include <linux/regmap.h>
> +#include <linux/auxiliary_bus.h>
> +#include <linux/reset-controller.h>
> +
> +#include <soc/amlogic/meson-audio-reset.h>
> +
> +struct meson_audio_reset_data {
> + struct reset_controller_dev rstc;
> + struct regmap *map;
> + unsigned int offset;
> +};
> +
> +struct meson_audio_reset_info {
> + unsigned int reset_offset;
> + unsigned int reset_num;
> +};
> +
> +static void meson_audio_reset_reg_and_bit(struct meson_audio_reset_data *rst,
> + unsigned long id,
> + unsigned int *reg,
> + unsigned int *bit)
> +{
> + unsigned int stride = regmap_get_reg_stride(rst->map);
> +
> + *reg = (id / (stride * BITS_PER_BYTE)) * stride;
> + *reg += rst->offset;
> + *bit = id % (stride * BITS_PER_BYTE);
> +}
> +
> +static int meson_audio_reset_update(struct reset_controller_dev *rcdev,
> + unsigned long id, bool assert)
> +{
> + struct meson_audio_reset_data *rst =
> + container_of(rcdev, struct meson_audio_reset_data, rstc);
> + unsigned int offset, bit;
> +
> + meson_audio_reset_reg_and_bit(rst, id, &offset, &bit);
> +
> + regmap_update_bits(rst->map, offset, BIT(bit),
> + assert ? BIT(bit) : 0);
> +
> + return 0;
> +}
> +
> +static int meson_audio_reset_status(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct meson_audio_reset_data *rst =
> + container_of(rcdev, struct meson_audio_reset_data, rstc);
> + unsigned int val, offset, bit;
> +
> + meson_audio_reset_reg_and_bit(rst, id, &offset, &bit);
> +
> + regmap_read(rst->map, offset, &val);
> +
> + return !!(val & BIT(bit));
> +}
> +
> +static int meson_audio_reset_assert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + return meson_audio_reset_update(rcdev, id, true);
> +}
> +
> +static int meson_audio_reset_deassert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + return meson_audio_reset_update(rcdev, id, false);
> +}
> +
> +static int meson_audio_reset_toggle(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + int ret;
> +
> + ret = meson_audio_reset_assert(rcdev, id);
> + if (ret)
> + return ret;
> +
> + return meson_audio_reset_deassert(rcdev, id);
> +}
> +
> +static const struct reset_control_ops meson_audio_reset_ops = {
> + .assert = meson_audio_reset_assert,
> + .deassert = meson_audio_reset_deassert,
> + .reset = meson_audio_reset_toggle,
> + .status = meson_audio_reset_status,
> +};
> +
> +static int meson_audio_reset_probe(struct auxiliary_device *adev,
> + const struct auxiliary_device_id *id)
> +{
> + struct device *dev = &adev->dev;
> + struct meson_audio_reset_info *info =
> + (struct meson_audio_reset_info *)id->driver_data;
> + struct meson_audio_reset_data *rst;
> +
> + dev_info(dev, "%s, reset_offset = %#x, reset_num = %u", __func__,
> + info->reset_offset, info->reset_num);
> +
> + rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL);
> + if (!rst)
> + return -ENOMEM;
> +
> + rst->map = dev_get_regmap(dev->parent, NULL);
> + if (!rst->map)
> + return -ENODEV;
> +
> + rst->offset = info->reset_offset;
> + rst->rstc.ops = &meson_audio_reset_ops;
> + rst->rstc.of_node = dev->parent->of_node;
> + rst->rstc.nr_resets = info->reset_num;
> + rst->rstc.owner = THIS_MODULE;
> +
> + return devm_reset_controller_register(dev, &rst->rstc);
> +}
> +
> +static void meson_audio_reset_adev_release(struct device *dev)
> +{
> + struct auxiliary_device *adev = to_auxiliary_dev(dev);
> +
> + kfree(adev);
> +}
> +
> +static void meson_audio_reset_adev_unregister(void *_adev)
> +{
> + struct auxiliary_device *adev = _adev;
> +
> + auxiliary_device_delete(adev);
> + auxiliary_device_uninit(adev);
> +}
> +
> +static const struct meson_audio_reset_info meson_audio_reset_info_g12a = {
> + .reset_offset = 0x024,
> + .reset_num = 26,
> +};
> +
> +static const struct meson_audio_reset_info meson_audio_reset_info_sm1 = {
> + .reset_offset = 0x028,
> + .reset_num = 39,
> +};
> +static const struct auxiliary_device_id meson_audio_reset_id[] = {
> + {
> + .name = "reset_meson_audio.g12a",
> + .driver_data = (kernel_ulong_t)&meson_audio_reset_info_g12a,
> + },
> + {
> + .name = "reset_meson_audio.sm1",
> + .driver_data = (kernel_ulong_t)&meson_audio_reset_info_sm1,
> + },
> + {},
> +};
> +MODULE_DEVICE_TABLE(auxiliary, meson_audio_reset_id);
> +
> +static struct auxiliary_driver meson_audio_reset_driver = {
> + .probe = meson_audio_reset_probe,
> + .id_table = meson_audio_reset_id,
> +};
> +
> +module_auxiliary_driver(meson_audio_reset_driver);
> +
> +int meson_audio_reset_register(struct device *dev, const char *name)
> +{
> + struct auxiliary_device *adev;
> + int ret;
> +
> + adev = kzalloc(sizeof(*adev), GFP_KERNEL);
> + if (!adev)
> + return -ENOMEM;
> +
> + adev->name = name;
> + adev->dev.parent = dev;
> + adev->dev.release = meson_audio_reset_adev_release;
> + adev->id = 0;
> +
> + ret = auxiliary_device_init(adev);
> + if (ret)
> + return ret;
> +
> + ret = auxiliary_device_add(adev);
> + if (ret) {
> + auxiliary_device_uninit(adev);
> + return ret;
> + }
> +
> + return devm_add_action_or_reset(dev, meson_audio_reset_adev_unregister,
> + adev);
> +}
> +EXPORT_SYMBOL_GPL(meson_audio_reset_register);
> +
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/soc/amlogic/meson-audio-reset.h b/include/soc/amlogic/meson-audio-reset.h
> new file mode 100644
> index 000000000000..279c6a2197ec
> --- /dev/null
> +++ b/include/soc/amlogic/meson-audio-reset.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
> +
> +#ifndef __MESON_AUDIO_RESET_H
> +#define __MESON_AUDIO_RESET_H
> +
> +#include <linux/device.h>
> +
> +int meson_audio_reset_register(struct device *dev, const char *name);
> +
> +#endif /* __MESON_AUDIO_RESET_H */


--
Jerome

2024-04-22 07:58:24

by Jerome Brunet

[permalink] [raw]
Subject: Re: [RFC PATCH v3 5/6] clk: meson: a1: add the audio clock controller driver


On Fri 19 Apr 2024 at 15:58, Jan Dakinevich <[email protected]> wrote:

> This controller provides clocks and reset functionality for audio
> peripherals on Amlogic A1 SoC family.
>
> The driver is almost identical to 'axg-audio', however it would be better
> to keep it separate due to following reasons:
>
> - significant amount of bits has another definition. I will bring there
> a mess of new defines with A1_ suffixes.
>
> - registers of this controller are located in two separate regions. It
> will give a lot of complications for 'axg-audio' to support this.
>
> Signed-off-by: Jan Dakinevich <[email protected]>
> ---
> drivers/clk/meson/Kconfig | 14 +
> drivers/clk/meson/Makefile | 1 +
> drivers/clk/meson/a1-audio.c | 651 ++++++++++++++++++++++++++++++
> drivers/reset/reset-meson-audio.c | 10 +
> 4 files changed, 676 insertions(+)
> create mode 100644 drivers/clk/meson/a1-audio.c
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 33614f8b8cf7..8aa2b38914fc 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -130,6 +130,20 @@ config COMMON_CLK_A1_PERIPHERALS
> device, A1 SoC Family. Say Y if you want A1 Peripherals clock
> controller to work.
>
> +config COMMON_CLK_A1_AUDIO
> + tristate "Amlogic A1 SoC Audio clock controller support"
> + depends on ARM64
> + select COMMON_CLK_MESON_REGMAP
> + select COMMON_CLK_MESON_CLKC_UTILS
> + select COMMON_CLK_MESON_PHASE
> + select COMMON_CLK_MESON_SCLK_DIV
> + select RESET_CONTROLLER
> + select RESET_MESON_AUDIO
> + help
> + Support for the Audio clock controller on Amlogic A113L based
> + device, A1 SoC Family. Say Y if you want A1 Audio clock controller
> + to work.
> +
> config COMMON_CLK_G12A
> tristate "G12 and SM1 SoC clock controllers support"
> depends on ARM64
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 9ee4b954c896..5e0260cef111 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -19,6 +19,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
> obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
> +obj-$(CONFIG_COMMON_CLK_A1_AUDIO) += a1-audio.o
> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
> obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
> obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
> diff --git a/drivers/clk/meson/a1-audio.c b/drivers/clk/meson/a1-audio.c
> new file mode 100644
> index 000000000000..bf08e354f32d
> --- /dev/null
> +++ b/drivers/clk/meson/a1-audio.c
> @@ -0,0 +1,651 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
> + *
> + * Author: Jan Dakinevich <[email protected]>
> + */
> +
> +#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/reset-controller.h>
> +#include <linux/slab.h>
> +
> +#include <soc/amlogic/meson-audio-reset.h>
> +#include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
> +
> +#include "meson-clkc-utils.h"
> +#include "meson-audio.h"
> +#include "clk-regmap.h"
> +#include "clk-phase.h"
> +#include "sclk-div.h"
> +
> +#define AUDIO_CLK_GATE_EN0 0x000
> +#define AUDIO_MCLK_A_CTRL 0x008
> +#define AUDIO_MCLK_B_CTRL 0x00c
> +#define AUDIO_MCLK_C_CTRL 0x010
> +#define AUDIO_MCLK_D_CTRL 0x014
> +#define AUDIO_SW_RESET0 0x028
> +#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_CLK_TDMIN_A_CTRL 0x080
> +#define AUDIO_CLK_TDMIN_B_CTRL 0x084
> +#define AUDIO_CLK_TDMIN_LB_CTRL 0x08c
> +#define AUDIO_CLK_TDMOUT_A_CTRL 0x090
> +#define AUDIO_CLK_TDMOUT_B_CTRL 0x094
> +#define AUDIO_CLK_SPDIFIN_CTRL 0x09c
> +#define AUDIO_CLK_RESAMPLEA_CTRL 0x0a4
> +#define AUDIO_CLK_LOCKER_CTRL 0x0a8
> +#define AUDIO_CLK_EQDRC_CTRL 0x0c0
> +
> +#define AUDIO2_CLK_GATE_EN0 0x00c
> +#define AUDIO2_MCLK_VAD_CTRL 0x040
> +#define AUDIO2_CLK_VAD_CTRL 0x044
> +#define AUDIO2_CLK_PDMIN_CTRL0 0x058
> +#define AUDIO2_CLK_PDMIN_CTRL1 0x05c
> +
> +static const struct clk_parent_data a1_pclk_pdata[] = {
> + { .fw_name = "pclk" },
> +};
> +
> +#define AUD_PCLK_GATE(_name, _reg, _bit) { \
> + .data = &(struct clk_regmap_gate_data){ \
> + .offset = (_reg), \
> + .bit_idx = (_bit), \
> + }, \
> + .hw.init = &(struct clk_init_data) { \
> + .name = "aud_"#_name, \
> + .ops = &clk_regmap_gate_ops, \
> + .parent_data = a1_pclk_pdata, \
> + .num_parents = 1, \
> + }, \
> +}
> +
> +struct clk_regmap aud_ddr_arb =
> + AUD_PCLK_GATE(ddr_arb, AUDIO_CLK_GATE_EN0, 0);
> +struct clk_regmap aud_tdmin_a =
> + AUD_PCLK_GATE(tdmin_a, AUDIO_CLK_GATE_EN0, 1);
> +struct clk_regmap aud_tdmin_b =
> + AUD_PCLK_GATE(tdmin_b, AUDIO_CLK_GATE_EN0, 2);
> +struct clk_regmap aud_tdmin_lb =
> + AUD_PCLK_GATE(tdmin_lb, AUDIO_CLK_GATE_EN0, 3);
> +struct clk_regmap aud_loopback =
> + AUD_PCLK_GATE(loopback, AUDIO_CLK_GATE_EN0, 4);
> +struct clk_regmap aud_tdmout_a =
> + AUD_PCLK_GATE(tdmout_a, AUDIO_CLK_GATE_EN0, 5);
> +struct clk_regmap aud_tdmout_b =
> + AUD_PCLK_GATE(tdmout_b, AUDIO_CLK_GATE_EN0, 6);
> +struct clk_regmap aud_frddr_a =
> + AUD_PCLK_GATE(frddr_a, AUDIO_CLK_GATE_EN0, 7);
> +struct clk_regmap aud_frddr_b =
> + AUD_PCLK_GATE(frddr_b, AUDIO_CLK_GATE_EN0, 8);
> +struct clk_regmap aud_toddr_a =
> + AUD_PCLK_GATE(toddr_a, AUDIO_CLK_GATE_EN0, 9);
> +struct clk_regmap aud_toddr_b =
> + AUD_PCLK_GATE(toddr_b, AUDIO_CLK_GATE_EN0, 10);
> +struct clk_regmap aud_spdifin =
> + AUD_PCLK_GATE(spdifin, AUDIO_CLK_GATE_EN0, 11);
> +struct clk_regmap aud_resample =
> + AUD_PCLK_GATE(resample, AUDIO_CLK_GATE_EN0, 12);
> +struct clk_regmap aud_eqdrc =
> + AUD_PCLK_GATE(eqdrc, AUDIO_CLK_GATE_EN0, 13);
> +struct clk_regmap aud_audiolocker =
> + AUD_PCLK_GATE(audiolocker, AUDIO_CLK_GATE_EN0, 14);
> +
> +struct clk_regmap aud_vad_ddr_arb =
> + AUD_PCLK_GATE(vad_ddr_arb, AUDIO2_CLK_GATE_EN0, 0);
> +struct clk_regmap aud_vad_pdm =
> + AUD_PCLK_GATE(vad_pdm, AUDIO2_CLK_GATE_EN0, 1);
> +struct clk_regmap aud_vad_tdmin_vad =
> + AUD_PCLK_GATE(vad_tdmin_vad, AUDIO2_CLK_GATE_EN0, 2);
> +struct clk_regmap aud_vad_toddr_vad =
> + AUD_PCLK_GATE(vad_toddr_vad, AUDIO2_CLK_GATE_EN0, 3);
> +struct clk_regmap aud_vad =
> + AUD_PCLK_GATE(vad, AUDIO2_CLK_GATE_EN0, 4);
> +struct clk_regmap aud_vad_audiotop =
> + AUD_PCLK_GATE(vad_audiotop, AUDIO2_CLK_GATE_EN0, 7);
> +
> +static const struct clk_parent_data a1_mst_pdata[] = {
> + { .fw_name = "dds_in" },
> + { .fw_name = "fclk_div2" },
> + { .fw_name = "fclk_div3" },
> + { .fw_name = "hifi_pll" },
> + { .fw_name = "xtal" },
> +};
> +
> +#define AUD_MST_MCLK_MUX(_name, _reg) \
> + AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
> + a1_mst_pdata, 0)
> +#define AUD_MST_MCLK_DIV(_name, _reg) \
> + AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
> + aud_##_name##_sel, CLK_SET_RATE_PARENT)
> +#define AUD_MST_MCLK_GATE(_name, _reg) \
> + AUD_GATE(_name, _reg, 31, aud_##_name##_div, \
> + CLK_SET_RATE_PARENT)
> +
> +struct clk_regmap aud_mst_a_mclk_sel =
> + AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL);
> +struct clk_regmap aud_mst_a_mclk_div =
> + AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL);
> +struct clk_regmap aud_mst_a_mclk =
> + AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL);
> +
> +struct clk_regmap aud_mst_b_mclk_sel =
> + AUD_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL);
> +struct clk_regmap aud_mst_b_mclk_div =
> + AUD_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL);
> +struct clk_regmap aud_mst_b_mclk =
> + AUD_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL);
> +
> +struct clk_regmap aud_mst_c_mclk_sel =
> + AUD_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL);
> +struct clk_regmap aud_mst_c_mclk_div =
> + AUD_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL);
> +struct clk_regmap aud_mst_c_mclk =
> + AUD_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL);
> +
> +struct clk_regmap aud_mst_d_mclk_sel =
> + AUD_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL);
> +struct clk_regmap aud_mst_d_mclk_div =
> + AUD_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL);
> +struct clk_regmap aud_mst_d_mclk =
> + AUD_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL);
> +
> +struct clk_regmap aud_spdifin_clk_sel =
> + AUD_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
> +struct clk_regmap aud_spdifin_clk_div =
> + AUD_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
> +struct clk_regmap aud_spdifin_clk =
> + AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
> +
> +struct clk_regmap aud_eqdrc_clk_sel =
> + AUD_MST_MCLK_MUX(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
> +struct clk_regmap aud_eqdrc_clk_div =
> + AUD_MST_MCLK_DIV(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
> +struct clk_regmap aud_eqdrc_clk =
> + AUD_MST_MCLK_GATE(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
> +
> +struct clk_regmap aud_resample_clk_sel =
> + AUD_MUX(resample_clk_sel, AUDIO_CLK_RESAMPLEA_CTRL, 0xf, 24,
> + CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, 0);
> +struct clk_regmap aud_resample_clk_div =
> + AUD_DIV(resample_clk_div, AUDIO_CLK_RESAMPLEA_CTRL, 0, 8,
> + CLK_DIVIDER_ROUND_CLOSEST, aud_resample_clk_sel,
> + CLK_SET_RATE_PARENT);
> +struct clk_regmap aud_resample_clk =
> + AUD_GATE(resample_clk, AUDIO_CLK_RESAMPLEA_CTRL, 31,
> + aud_resample_clk_div, CLK_SET_RATE_PARENT);
> +
> +struct clk_regmap aud_locker_in_clk_sel =
> + AUD_MUX(locker_in_clk_sel, AUDIO_CLK_LOCKER_CTRL, 0xf, 8,
> + CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, 0);
> +struct clk_regmap aud_locker_in_clk_div =
> + AUD_DIV(locker_in_clk_div, AUDIO_CLK_LOCKER_CTRL, 0, 8,
> + CLK_DIVIDER_ROUND_CLOSEST, aud_locker_in_clk_sel,
> + CLK_SET_RATE_PARENT);
> +struct clk_regmap aud_locker_in_clk =
> + AUD_GATE(locker_in_clk, AUDIO_CLK_LOCKER_CTRL, 15,
> + aud_locker_in_clk_div, CLK_SET_RATE_PARENT);
> +
> +struct clk_regmap aud_locker_out_clk_sel =
> + AUD_MUX(locker_out_clk_sel, AUDIO_CLK_LOCKER_CTRL, 0xf, 24,
> + CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, 0);
> +struct clk_regmap aud_locker_out_clk_div =
> + AUD_DIV(locker_out_clk_div, AUDIO_CLK_LOCKER_CTRL, 16, 8,
> + CLK_DIVIDER_ROUND_CLOSEST, aud_locker_out_clk_sel,
> + CLK_SET_RATE_PARENT);
> +struct clk_regmap aud_locker_out_clk =
> + AUD_GATE(locker_out_clk, AUDIO_CLK_LOCKER_CTRL, 31,
> + aud_locker_out_clk_div, CLK_SET_RATE_PARENT);
> +
> +struct clk_regmap aud_vad_mclk_sel =
> + AUD_MST_MCLK_MUX(vad_mclk, AUDIO2_MCLK_VAD_CTRL);
> +struct clk_regmap aud_vad_mclk_div =
> + AUD_MST_MCLK_DIV(vad_mclk, AUDIO2_MCLK_VAD_CTRL);
> +struct clk_regmap aud_vad_mclk =
> + AUD_MST_MCLK_GATE(vad_mclk, AUDIO2_MCLK_VAD_CTRL);
> +
> +struct clk_regmap aud_vad_clk_sel =
> + AUD_MST_MCLK_MUX(vad_clk, AUDIO2_CLK_VAD_CTRL);
> +struct clk_regmap aud_vad_clk_div =
> + AUD_MST_MCLK_DIV(vad_clk, AUDIO2_CLK_VAD_CTRL);
> +struct clk_regmap aud_vad_clk =
> + AUD_MST_MCLK_GATE(vad_clk, AUDIO2_CLK_VAD_CTRL);
> +
> +struct clk_regmap aud_vad_pdm_dclk_sel =
> + AUD_MST_MCLK_MUX(vad_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
> +struct clk_regmap aud_vad_pdm_dclk_div =
> + AUD_MST_MCLK_DIV(vad_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
> +struct clk_regmap aud_vad_pdm_dclk =
> + AUD_MST_MCLK_GATE(vad_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
> +
> +struct clk_regmap aud_vad_pdm_sysclk_sel =
> + AUD_MST_MCLK_MUX(vad_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
> +struct clk_regmap aud_vad_pdm_sysclk_div =
> + AUD_MST_MCLK_DIV(vad_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
> +struct clk_regmap aud_vad_pdm_sysclk =
> + AUD_MST_MCLK_GATE(vad_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
> +
> +#define AUD_MST_SCLK_PRE_EN(_name, _reg, _pname) \
> + AUD_GATE(_name##_pre_en, _reg, 31, \
> + aud_##_pname, 0)
> +#define AUD_MST_SCLK_DIV(_name, _reg) \
> + AUD_SCLK_DIV(_name##_div, _reg, 20, 10, 0, 0, \
> + aud_##_name##_pre_en, CLK_SET_RATE_PARENT)
> +#define AUD_MST_SCLK_POST_EN(_name, _reg) \
> + AUD_GATE(_name##_post_en, _reg, 30, \
> + aud_##_name##_div, CLK_SET_RATE_PARENT)
> +#define AUD_MST_SCLK(_name, _reg) \
> + AUD_TRIPHASE(_name, _reg, 1, 0, 2, 4, \
> + aud_##_name##_post_en, CLK_SET_RATE_PARENT)
> +
> +struct clk_regmap aud_mst_a_sclk_pre_en =
> + AUD_MST_SCLK_PRE_EN(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0, mst_a_mclk);
> +struct clk_regmap aud_mst_a_sclk_div =
> + AUD_MST_SCLK_DIV(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0);
> +struct clk_regmap aud_mst_a_sclk_post_en =
> + AUD_MST_SCLK_POST_EN(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0);
> +struct clk_regmap aud_mst_a_sclk =
> + AUD_MST_SCLK(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL1);
> +
> +struct clk_regmap aud_mst_b_sclk_pre_en =
> + AUD_MST_SCLK_PRE_EN(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0, mst_b_mclk);
> +struct clk_regmap aud_mst_b_sclk_div =
> + AUD_MST_SCLK_DIV(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0);
> +struct clk_regmap aud_mst_b_sclk_post_en =
> + AUD_MST_SCLK_POST_EN(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0);
> +struct clk_regmap aud_mst_b_sclk =
> + AUD_MST_SCLK(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL1);
> +
> +struct clk_regmap aud_mst_c_sclk_pre_en =
> + AUD_MST_SCLK_PRE_EN(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0, mst_c_mclk);
> +struct clk_regmap aud_mst_c_sclk_div =
> + AUD_MST_SCLK_DIV(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0);
> +struct clk_regmap aud_mst_c_sclk_post_en =
> + AUD_MST_SCLK_POST_EN(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0);
> +struct clk_regmap aud_mst_c_sclk =
> + AUD_MST_SCLK(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL1);
> +
> +struct clk_regmap aud_mst_d_sclk_pre_en =
> + AUD_MST_SCLK_PRE_EN(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0, mst_d_mclk);
> +struct clk_regmap aud_mst_d_sclk_div =
> + AUD_MST_SCLK_DIV(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0);
> +struct clk_regmap aud_mst_d_sclk_post_en =
> + AUD_MST_SCLK_POST_EN(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0);
> +struct clk_regmap aud_mst_d_sclk =
> + AUD_MST_SCLK(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL1);
> +
> +#define AUD_MST_LRCLK_DIV(_name, _reg, _pname) \
> + AUD_SCLK_DIV(_name##_div, _reg, 0, 10, 10, 10, \
> + aud_##_pname, 0)
> +#define AUD_MST_LRCLK(_name, _reg) \
> + AUD_TRIPHASE(_name, _reg, 1, 1, 3, 5, \
> + aud_##_name##_div, CLK_SET_RATE_PARENT)
> +
> +struct clk_regmap aud_mst_a_lrclk_div =
> + AUD_MST_LRCLK_DIV(mst_a_lrclk, AUDIO_MST_A_SCLK_CTRL0,
> + mst_a_sclk_post_en);
> +struct clk_regmap aud_mst_a_lrclk =
> + AUD_MST_LRCLK(mst_a_lrclk, AUDIO_MST_A_SCLK_CTRL1);
> +
> +struct clk_regmap aud_mst_b_lrclk_div =
> + AUD_MST_LRCLK_DIV(mst_b_lrclk, AUDIO_MST_B_SCLK_CTRL0,
> + mst_b_sclk_post_en);
> +struct clk_regmap aud_mst_b_lrclk =
> + AUD_MST_LRCLK(mst_b_lrclk, AUDIO_MST_B_SCLK_CTRL1);
> +
> +struct clk_regmap aud_mst_c_lrclk_div =
> + AUD_MST_LRCLK_DIV(mst_c_lrclk, AUDIO_MST_C_SCLK_CTRL0,
> + mst_c_sclk_post_en);
> +struct clk_regmap aud_mst_c_lrclk =
> + AUD_MST_LRCLK(mst_c_lrclk, AUDIO_MST_C_SCLK_CTRL1);
> +
> +struct clk_regmap aud_mst_d_lrclk_div =
> + AUD_MST_LRCLK_DIV(mst_d_lrclk, AUDIO_MST_D_SCLK_CTRL0,
> + mst_d_sclk_post_en);
> +struct clk_regmap aud_mst_d_lrclk =
> + AUD_MST_LRCLK(mst_d_lrclk, AUDIO_MST_D_SCLK_CTRL1);
> +
> +static const struct clk_parent_data a1_mst_sclk_pdata[] = {
> + { .hw = &aud_mst_a_sclk.hw, .index = -1 },
> + { .hw = &aud_mst_b_sclk.hw, .index = -1 },
> + { .hw = &aud_mst_c_sclk.hw, .index = -1 },
> + { .hw = &aud_mst_d_sclk.hw, .index = -1 },
> + { .fw_name = "slv_sclk0" },
> + { .fw_name = "slv_sclk1" },
> + { .fw_name = "slv_sclk2" },
> + { .fw_name = "slv_sclk3" },
> + { .fw_name = "slv_sclk4" },
> + { .fw_name = "slv_sclk5" },
> + { .fw_name = "slv_sclk6" },
> + { .fw_name = "slv_sclk7" },
> + { .fw_name = "slv_sclk8" },
> + { .fw_name = "slv_sclk9" },
> +};
> +
> +static u32 a1_mst_sclk_table[] = {
> + 0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
> +};

This is a clear indication that the bindings of axg and a1 are indeed
the same. Master clocks are optional.

> +
> +static const struct clk_parent_data a1_mst_lrclk_pdata[] = {
> + { .hw = &aud_mst_a_lrclk.hw, .index = -1 },
> + { .hw = &aud_mst_b_lrclk.hw, .index = -1 },
> + { .hw = &aud_mst_c_lrclk.hw, .index = -1 },
> + { .hw = &aud_mst_d_lrclk.hw, .index = -1 },
> + { .fw_name = "slv_lrclk0" },
> + { .fw_name = "slv_lrclk1" },
> + { .fw_name = "slv_lrclk2" },
> + { .fw_name = "slv_lrclk3" },
> + { .fw_name = "slv_lrclk4" },
> + { .fw_name = "slv_lrclk5" },
> + { .fw_name = "slv_lrclk6" },
> + { .fw_name = "slv_lrclk7" },
> + { .fw_name = "slv_lrclk8" },
> + { .fw_name = "slv_lrclk9" },
> +};
> +
> +static u32 a1_mst_lrclk_table[] = {
> + 0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
> +};
> +
> +#define AUD_TDM_SCLK_MUX(_name, _reg) \
> + AUD_MUX_TABLE(_name##_sel, _reg, a1_mst_sclk_table, 0xf, 24, \
> + CLK_MUX_ROUND_CLOSEST, a1_mst_sclk_pdata, 0)
> +#define AUD_TDM_SCLK_PRE_EN(_name, _reg) \
> + AUD_GATE(_name##_pre_en, _reg, 31, \
> + aud_##_name##_sel, CLK_SET_RATE_PARENT)
> +#define AUD_TDM_SCLK_POST_EN(_name, _reg) \
> + AUD_GATE(_name##_post_en, _reg, 30, \
> + aud_##_name##_pre_en, CLK_SET_RATE_PARENT)
> +#define AUD_TDM_SCLK_WS(_name, _reg) \
> + AUD_SCLK_WS(_name, _reg, 1, 29, 28, \
> + aud_##_name##_post_en, \
> + CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)
> +
> +#define AUD_TDM_LRLCK(_name, _reg) \
> + AUD_MUX_TABLE(_name, _reg, a1_mst_lrclk_table, 0xf, 20, \
> + CLK_MUX_ROUND_CLOSEST, a1_mst_lrclk_pdata, \
> + CLK_SET_RATE_PARENT)
> +
> +struct clk_regmap aud_tdmin_a_sclk_sel =
> + AUD_TDM_SCLK_MUX(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
> +struct clk_regmap aud_tdmin_a_sclk_pre_en =
> + AUD_TDM_SCLK_PRE_EN(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
> +struct clk_regmap aud_tdmin_a_sclk_post_en =
> + AUD_TDM_SCLK_POST_EN(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
> +struct clk_regmap aud_tdmin_a_sclk =
> + AUD_TDM_SCLK_WS(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
> +struct clk_regmap aud_tdmin_a_lrclk =
> + AUD_TDM_LRLCK(tdmin_a_lrclk, AUDIO_CLK_TDMIN_A_CTRL);
> +
> +struct clk_regmap aud_tdmin_b_sclk_sel =
> + AUD_TDM_SCLK_MUX(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
> +struct clk_regmap aud_tdmin_b_sclk_pre_en =
> + AUD_TDM_SCLK_PRE_EN(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
> +struct clk_regmap aud_tdmin_b_sclk_post_en =
> + AUD_TDM_SCLK_POST_EN(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
> +struct clk_regmap aud_tdmin_b_sclk =
> + AUD_TDM_SCLK_WS(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
> +struct clk_regmap aud_tdmin_b_lrclk =
> + AUD_TDM_LRLCK(tdmin_b_lrclk, AUDIO_CLK_TDMIN_B_CTRL);
> +
> +struct clk_regmap aud_tdmin_lb_sclk_sel =
> + AUD_TDM_SCLK_MUX(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
> +struct clk_regmap aud_tdmin_lb_sclk_pre_en =
> + AUD_TDM_SCLK_PRE_EN(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
> +struct clk_regmap aud_tdmin_lb_sclk_post_en =
> + AUD_TDM_SCLK_POST_EN(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
> +struct clk_regmap aud_tdmin_lb_sclk =
> + AUD_TDM_SCLK_WS(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
> +struct clk_regmap aud_tdmin_lb_lrclk =
> + AUD_TDM_LRLCK(tdmin_lb_lrclk, AUDIO_CLK_TDMIN_LB_CTRL);
> +
> +struct clk_regmap aud_tdmout_a_sclk_sel =
> + AUD_TDM_SCLK_MUX(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
> +struct clk_regmap aud_tdmout_a_sclk_pre_en =
> + AUD_TDM_SCLK_PRE_EN(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
> +struct clk_regmap aud_tdmout_a_sclk_post_en =
> + AUD_TDM_SCLK_POST_EN(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
> +struct clk_regmap aud_tdmout_a_sclk =
> + AUD_TDM_SCLK_WS(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
> +struct clk_regmap aud_tdmout_a_lrclk =
> + AUD_TDM_LRLCK(tdmout_a_lrclk, AUDIO_CLK_TDMOUT_A_CTRL);
> +
> +struct clk_regmap aud_tdmout_b_sclk_sel =
> + AUD_TDM_SCLK_MUX(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
> +struct clk_regmap aud_tdmout_b_sclk_pre_en =
> + AUD_TDM_SCLK_PRE_EN(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
> +struct clk_regmap aud_tdmout_b_sclk_post_en =
> + AUD_TDM_SCLK_POST_EN(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
> +struct clk_regmap aud_tdmout_b_sclk =
> + AUD_TDM_SCLK_WS(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
> +struct clk_regmap aud_tdmout_b_lrclk =
> + AUD_TDM_LRLCK(tdmout_b_lrclk, AUDIO_CLK_TDMOUT_B_CTRL);
> +
> +static struct clk_hw *a1_audio_hw_clks[] = {
> + [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw,
> + [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw,
> + [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw,
> + [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw,
> + [AUD_CLKID_LOOPBACK] = &aud_loopback.hw,
> + [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw,
> + [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw,
> + [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw,
> + [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw,
> + [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw,
> + [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw,
> + [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw,
> + [AUD_CLKID_RESAMPLE] = &aud_resample.hw,
> + [AUD_CLKID_EQDRC] = &aud_eqdrc.hw,
> + [AUD_CLKID_LOCKER] = &aud_audiolocker.hw,
> + [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_sel.hw,
> + [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw,
> + [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw,
> + [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_sel.hw,
> + [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw,
> + [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw,
> + [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_sel.hw,
> + [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw,
> + [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw,
> + [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_sel.hw,
> + [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw,
> + [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw,
> + [AUD_CLKID_RESAMPLE_CLK_SEL] = &aud_resample_clk_sel.hw,
> + [AUD_CLKID_RESAMPLE_CLK_DIV] = &aud_resample_clk_div.hw,
> + [AUD_CLKID_RESAMPLE_CLK] = &aud_resample_clk.hw,
> + [AUD_CLKID_LOCKER_IN_CLK_SEL] = &aud_locker_in_clk_sel.hw,
> + [AUD_CLKID_LOCKER_IN_CLK_DIV] = &aud_locker_in_clk_div.hw,
> + [AUD_CLKID_LOCKER_IN_CLK] = &aud_locker_in_clk.hw,
> + [AUD_CLKID_LOCKER_OUT_CLK_SEL] = &aud_locker_out_clk_sel.hw,
> + [AUD_CLKID_LOCKER_OUT_CLK_DIV] = &aud_locker_out_clk_div.hw,
> + [AUD_CLKID_LOCKER_OUT_CLK] = &aud_locker_out_clk.hw,
> + [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_sel.hw,
> + [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw,
> + [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw,
> + [AUD_CLKID_EQDRC_CLK_SEL] = &aud_eqdrc_clk_sel.hw,
> + [AUD_CLKID_EQDRC_CLK_DIV] = &aud_eqdrc_clk_div.hw,
> + [AUD_CLKID_EQDRC_CLK] = &aud_eqdrc_clk.hw,
> + [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw,
> + [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw,
> + [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw,
> + [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw,
> + [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw,
> + [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw,
> + [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw,
> + [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw,
> + [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw,
> + [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw,
> + [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw,
> + [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw,
> + [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw,
> + [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw,
> + [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw,
> + [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw,
> + [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw,
> + [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw,
> + [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw,
> + [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw,
> + [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw,
> + [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw,
> + [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw,
> + [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw,
> + [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_sel.hw,
> + [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw,
> + [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw,
> + [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw,
> + [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw,
> + [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_sel.hw,
> + [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw,
> + [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw,
> + [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw,
> + [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw,
> + [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_sel.hw,
> + [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw,
> + [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw,
> + [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw,
> + [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw,
> + [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_sel.hw,
> + [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw,
> + [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw,
> + [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw,
> + [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw,
> + [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_sel.hw,
> + [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw,
> + [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw,
> + [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw,
> + [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw,
> +};
> +
> +static struct clk_hw *a1_audio_vad_hw_clks[] = {
> + [AUD_CLKID_VAD_DDR_ARB] = &aud_vad_ddr_arb.hw,
> + [AUD_CLKID_VAD_PDM] = &aud_vad_pdm.hw,
> + [AUD_CLKID_VAD_TDMIN] = &aud_vad_tdmin_vad.hw,
> + [AUD_CLKID_VAD_TODDR] = &aud_vad_toddr_vad.hw,
> + [AUD_CLKID_VAD] = &aud_vad.hw,
> + [AUD_CLKID_VAD_AUDIOTOP] = &aud_vad_audiotop.hw,
> + [AUD_CLKID_VAD_MCLK_SEL] = &aud_vad_mclk_sel.hw,
> + [AUD_CLKID_VAD_MCLK_DIV] = &aud_vad_mclk_div.hw,
> + [AUD_CLKID_VAD_MCLK] = &aud_vad_mclk.hw,
> + [AUD_CLKID_VAD_CLK_SEL] = &aud_vad_clk_sel.hw,
> + [AUD_CLKID_VAD_CLK_DIV] = &aud_vad_clk_div.hw,
> + [AUD_CLKID_VAD_CLK] = &aud_vad_clk.hw,
> + [AUD_CLKID_VAD_PDM_DCLK_SEL] = &aud_vad_pdm_dclk_sel.hw,
> + [AUD_CLKID_VAD_PDM_DCLK_DIV] = &aud_vad_pdm_dclk_div.hw,
> + [AUD_CLKID_VAD_PDM_DCLK] = &aud_vad_pdm_dclk.hw,
> + [AUD_CLKID_VAD_PDM_SYSCLK_SEL] = &aud_vad_pdm_sysclk_sel.hw,
> + [AUD_CLKID_VAD_PDM_SYSCLK_DIV] = &aud_vad_pdm_sysclk_div.hw,
> + [AUD_CLKID_VAD_PDM_SYSCLK] = &aud_vad_pdm_sysclk.hw,
> +};

Again, I asked you to make separate driver for the a1 and a1-vad.

To be clear: different files for a1 and a1-vad.

> +
> +struct a1_audio_data {
> + struct meson_clk_hw_data hw_clks;
> + const char *reset_name;
> +};
> +
> +static const struct regmap_config a1_audio_regmap_cfg = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> +};
> +
> +static int a1_audio_clkc_probe(struct platform_device *pdev)
> +{
> + const struct a1_audio_data *data;
> + struct regmap *map;
> + void __iomem *base;
> + struct clk *clk;
> + unsigned int i;
> + int ret;
> +
> + data = of_device_get_match_data(&pdev->dev);
> + if (!data)
> + return -EINVAL;
> +
> + clk = devm_clk_get_enabled(&pdev->dev, "pclk");
> + if (IS_ERR(clk))
> + return PTR_ERR(clk);
> +
> + base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + map = devm_regmap_init_mmio(&pdev->dev, base, &a1_audio_regmap_cfg);
> + if (IS_ERR(map))
> + return PTR_ERR(map);
> +
> + for (i = 0; i < data->hw_clks.num; i++) {
> + struct clk_hw *hw = data->hw_clks.hws[i];
> + struct clk_regmap *clk_regmap = to_clk_regmap(hw);
> +
> + if (!hw)
> + continue;
> +
> + clk_regmap->map = map;
> +
> + ret = devm_clk_hw_register(&pdev->dev, hw);
> + if (ret)
> + return ret;
> + }
> +
> + ret = devm_of_clk_add_hw_provider(&pdev->dev, meson_clk_hw_get,
> + (void *)&data->hw_clks);
> + if (ret)
> + return ret;
> +
> + if (!data->reset_name)
> + return 0;
> +
> + return meson_audio_reset_register(&pdev->dev, data->reset_name);
> +}
> +
> +struct a1_audio_data a1_audio_data = {
> + .hw_clks = {
> + .hws = a1_audio_hw_clks,
> + .num = ARRAY_SIZE(a1_audio_hw_clks),
> + },
> + .reset_name = "a1",
> +};
> +
> +struct a1_audio_data a1_audio_vad_data = {
> + .hw_clks = {
> + .hws = a1_audio_vad_hw_clks,
> + .num = ARRAY_SIZE(a1_audio_vad_hw_clks),
> + },
> +};
> +
> +static const struct of_device_id a1_audio_clkc_match_table[] = {
> + {
> + .compatible = "amlogic,a1-audio-clkc",
> + .data = &a1_audio_data,
> + },
> + {
> + .compatible = "amlogic,a1-audio-vad-clkc",
> + .data = &a1_audio_vad_data,
> + },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, a1_audio_clkc_match_table);
> +
> +static struct platform_driver a1_audio_clkc_driver = {
> + .probe = a1_audio_clkc_probe,
> + .driver = {
> + .name = "a1-audio-clkc",
> + .of_match_table = a1_audio_clkc_match_table,
> + },
> +};
> +module_platform_driver(a1_audio_clkc_driver);
> +
> +MODULE_DESCRIPTION("Amlogic A1 Audio Clock driver");
> +MODULE_AUTHOR("Jan Dakinevich <[email protected]>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/reset/reset-meson-audio.c b/drivers/reset/reset-meson-audio.c
> index aaea9931cfe2..faf098012721 100644
> --- a/drivers/reset/reset-meson-audio.c
> +++ b/drivers/reset/reset-meson-audio.c
> @@ -145,6 +145,12 @@ static const struct meson_audio_reset_info meson_audio_reset_info_sm1 = {
> .reset_offset = 0x028,
> .reset_num = 39,
> };
> +
> +static const struct meson_audio_reset_info meson_audio_reset_info_a1 = {
> + .reset_offset = 0x028,
> + .reset_num = 32,
> +};
> +
> static const struct auxiliary_device_id meson_audio_reset_id[] = {
> {
> .name = "reset_meson_audio.g12a",
> @@ -154,6 +160,10 @@ static const struct auxiliary_device_id meson_audio_reset_id[] = {
> .name = "reset_meson_audio.sm1",
> .driver_data = (kernel_ulong_t)&meson_audio_reset_info_sm1,
> },
> + {
> + .name = "reset_meson_audio.a1",
> + .driver_data = (kernel_ulong_t)&meson_audio_reset_info_a1,
> + },
> {},
> };
> MODULE_DEVICE_TABLE(auxiliary, meson_audio_reset_id);


--
Jerome

2024-04-22 08:08:29

by Jerome Brunet

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver


On Mon 22 Apr 2024 at 09:16, Jerome Brunet <[email protected]> wrote:

> On Sun 21 Apr 2024 at 20:14, Krzysztof Kozlowski <[email protected]> wrote:
>
>> On 20/04/2024 18:15, Jan Dakinevich wrote:
>>>
>>>
>>> On 4/20/24 00:09, Rob Herring wrote:
>>>> On Fri, Apr 19, 2024 at 03:58:10PM +0300, Jan Dakinevich wrote:
>>>>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>>>>
>>>>> Signed-off-by: Jan Dakinevich <[email protected]>
>>>>> ---
>>>>>
>>>>> This controller has 6 mandatory and up to 20 optional clocks. To describe
>>>>> this, I use 'additionalItems'. It produces correct processed-schema.json:
>>>>>
>>>>> "clock-names": {
>>>>> "maxItems": 26,
>>>>> "items": [
>>>>> {
>>>>> "const": "pclk"
>>>>> },
>>>>> {
>>>>> "const": "dds_in"
>>>>> },
>>>>> {
>>>>> "const": "fclk_div2"
>>>>> },
>>>>> {
>>>>> "const": "fclk_div3"
>>>>> },
>>>>> {
>>>>> "const": "hifi_pll"
>>>>> },
>>>>> {
>>>>> "const": "xtal"
>>>>> }
>>>>> ],
>>>>> "additionalItems": {
>>>>> "oneOf": [
>>>>> {
>>>>> "pattern": "^slv_sclk[0-9]$"
>>>>> },
>>>>> {
>>>>> "pattern": "^slv_lrclk[0-9]$"
>>>>> }
>>>>> ]
>>>>> },
>>>>> "type": "array",
>>>>> "minItems": 6
>>>>> },
>>>>>
>>>>> and it behaves as expected. However, the checking is followed by
>>>>> complaints like this:
>>>>>
>>>>> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>>>>>
>>>>> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
>>>>> do it right?
>>>>
>>>> The meta-schemas are written both to prevent nonsense that json-schema
>>>> allows by default (e.g additionalitems (wrong case)) and constraints to
>>>> follow the patterns we expect. I'm happy to loosen the latter case if
>>>> there's really a need.
>>>>
>>>> Generally, most bindings shouldn't be using 'additionalItems' at all as
>>>> all entries should be defined, but there's a few exceptions. Here, the
>>>> only reasoning I see is 26 entries is a lot to write out, but that
>>>> wouldn't really justify it.
>>>
>>> Writing a lot of entries don't scary me too much, but the reason is that
>>> the existence of optional clock sources depends on schematics. Also, we
>>
>> Aren't you documenting SoC component, not a board? So how exactly it
>> depends on schematics? SoC is done or not done...
>>
>>> unable to declare dt-nodes for 'clocks' array in any generic way,
>>> because their declaration would depends on that what is actually
>>> connected to the SoC (dt-node could be "fixed-clock" with specific rate
>>> or something else).
>>
>> So these are clock inputs to the SoC?
>>
>
> Yes, possibly.
> Like an external crystal or a set clocks provided by an external codec
> where the codec is the clock master of the link.
>
> This is same case as the AXG that was discussed here:
> https://lore.kernel.org/linux-devicetree/[email protected]/
>
> IMO, like the AXG, only the pclk is a required clock.
> All the others - master and slave clocks - are optional.
> The controller is designed to operate with grounded inputs

Looking again at the implementation of the controller, there is a clear
indication in patch 3 that the controller interface is the same as the
AXG and that the above statement is true.

The AXG had 8 master clocks wired in. The A1 just has 5 - and 3 grounded
master clocks. This is why you to had to provide a mux input table to
skip the grounded inputs. You would not have to do so if the controller was
properly declared with the 8 master clock input, as it actually is.

It also shows that it is a bad idea to name input after what is coming
in (like you do with "dds_in" or "fclk_div2") instead of what they
actually are like in the AXG (mst0, mst1, etc ...)

>
>>>
>>> By the way, I don't know any example (neither for A1 SoC nor for other
>>> Amlogic's SoCs) where these optional clocks are used, but they are
>>> allowed by hw.
>
> Those scenario exists and have been tested. There is just no dts using
> that upstream because they are all mostly copy of the AML ref design.
>
>>>
>>> This is my understanding of this controller. I hope, Jerome Brunet will
>>> clarify how it actually works.
>>
>
> I think the simpliest way to deal with this to just list all the clocks
> with 'minItems = 1'. It is going be hard to read with a lot of '<0>,' in
> the DTS when do need those slave clocks but at least the binding doc
> will be simple.
>
>> Best regards,
>> Krzysztof
>
> If you are going ahead with this, please name the file
> amlogic,axg-audio-clkc.yaml because this is really the first controller
> of the type and is meant to be documented in the same file.
>
> You are free to handle the conversion of the AXG at the same time if
> you'd like. It would be much appreciated if you do.


--
Jerome

2024-04-22 13:53:28

by Jan Dakinevich

[permalink] [raw]
Subject: Re: [RFC PATCH v3 5/6] clk: meson: a1: add the audio clock controller driver



On 4/22/24 10:53, Jerome Brunet wrote:
>
> On Fri 19 Apr 2024 at 15:58, Jan Dakinevich <[email protected]> wrote:
>
>> This controller provides clocks and reset functionality for audio
>> peripherals on Amlogic A1 SoC family.
>>
>> The driver is almost identical to 'axg-audio', however it would be better
>> to keep it separate due to following reasons:
>>
>> - significant amount of bits has another definition. I will bring there
>> a mess of new defines with A1_ suffixes.
>>
>> - registers of this controller are located in two separate regions. It
>> will give a lot of complications for 'axg-audio' to support this.
>>
>> Signed-off-by: Jan Dakinevich <[email protected]>
>> ---
>> drivers/clk/meson/Kconfig | 14 +
>> drivers/clk/meson/Makefile | 1 +
>> drivers/clk/meson/a1-audio.c | 651 ++++++++++++++++++++++++++++++
>> drivers/reset/reset-meson-audio.c | 10 +
>> 4 files changed, 676 insertions(+)
>> create mode 100644 drivers/clk/meson/a1-audio.c
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index 33614f8b8cf7..8aa2b38914fc 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -130,6 +130,20 @@ config COMMON_CLK_A1_PERIPHERALS
>> device, A1 SoC Family. Say Y if you want A1 Peripherals clock
>> controller to work.
>>
>> +config COMMON_CLK_A1_AUDIO
>> + tristate "Amlogic A1 SoC Audio clock controller support"
>> + depends on ARM64
>> + select COMMON_CLK_MESON_REGMAP
>> + select COMMON_CLK_MESON_CLKC_UTILS
>> + select COMMON_CLK_MESON_PHASE
>> + select COMMON_CLK_MESON_SCLK_DIV
>> + select RESET_CONTROLLER
>> + select RESET_MESON_AUDIO
>> + help
>> + Support for the Audio clock controller on Amlogic A113L based
>> + device, A1 SoC Family. Say Y if you want A1 Audio clock controller
>> + to work.
>> +
>> config COMMON_CLK_G12A
>> tristate "G12 and SM1 SoC clock controllers support"
>> depends on ARM64
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index 9ee4b954c896..5e0260cef111 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -19,6 +19,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>> obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
>> +obj-$(CONFIG_COMMON_CLK_A1_AUDIO) += a1-audio.o
>> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>> obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>> obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
>> diff --git a/drivers/clk/meson/a1-audio.c b/drivers/clk/meson/a1-audio.c
>> new file mode 100644
>> index 000000000000..bf08e354f32d
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1-audio.c
>> @@ -0,0 +1,651 @@
>> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
>> +/*
>> + * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
>> + *
>> + * Author: Jan Dakinevich <[email protected]>
>> + */
>> +
>> +#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/reset-controller.h>
>> +#include <linux/slab.h>
>> +
>> +#include <soc/amlogic/meson-audio-reset.h>
>> +#include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
>> +
>> +#include "meson-clkc-utils.h"
>> +#include "meson-audio.h"
>> +#include "clk-regmap.h"
>> +#include "clk-phase.h"
>> +#include "sclk-div.h"
>> +
>> +#define AUDIO_CLK_GATE_EN0 0x000
>> +#define AUDIO_MCLK_A_CTRL 0x008
>> +#define AUDIO_MCLK_B_CTRL 0x00c
>> +#define AUDIO_MCLK_C_CTRL 0x010
>> +#define AUDIO_MCLK_D_CTRL 0x014
>> +#define AUDIO_SW_RESET0 0x028
>> +#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_CLK_TDMIN_A_CTRL 0x080
>> +#define AUDIO_CLK_TDMIN_B_CTRL 0x084
>> +#define AUDIO_CLK_TDMIN_LB_CTRL 0x08c
>> +#define AUDIO_CLK_TDMOUT_A_CTRL 0x090
>> +#define AUDIO_CLK_TDMOUT_B_CTRL 0x094
>> +#define AUDIO_CLK_SPDIFIN_CTRL 0x09c
>> +#define AUDIO_CLK_RESAMPLEA_CTRL 0x0a4
>> +#define AUDIO_CLK_LOCKER_CTRL 0x0a8
>> +#define AUDIO_CLK_EQDRC_CTRL 0x0c0
>> +
>> +#define AUDIO2_CLK_GATE_EN0 0x00c
>> +#define AUDIO2_MCLK_VAD_CTRL 0x040
>> +#define AUDIO2_CLK_VAD_CTRL 0x044
>> +#define AUDIO2_CLK_PDMIN_CTRL0 0x058
>> +#define AUDIO2_CLK_PDMIN_CTRL1 0x05c
>> +
>> +static const struct clk_parent_data a1_pclk_pdata[] = {
>> + { .fw_name = "pclk" },
>> +};
>> +
>> +#define AUD_PCLK_GATE(_name, _reg, _bit) { \
>> + .data = &(struct clk_regmap_gate_data){ \
>> + .offset = (_reg), \
>> + .bit_idx = (_bit), \
>> + }, \
>> + .hw.init = &(struct clk_init_data) { \
>> + .name = "aud_"#_name, \
>> + .ops = &clk_regmap_gate_ops, \
>> + .parent_data = a1_pclk_pdata, \
>> + .num_parents = 1, \
>> + }, \
>> +}
>> +
>> +struct clk_regmap aud_ddr_arb =
>> + AUD_PCLK_GATE(ddr_arb, AUDIO_CLK_GATE_EN0, 0);
>> +struct clk_regmap aud_tdmin_a =
>> + AUD_PCLK_GATE(tdmin_a, AUDIO_CLK_GATE_EN0, 1);
>> +struct clk_regmap aud_tdmin_b =
>> + AUD_PCLK_GATE(tdmin_b, AUDIO_CLK_GATE_EN0, 2);
>> +struct clk_regmap aud_tdmin_lb =
>> + AUD_PCLK_GATE(tdmin_lb, AUDIO_CLK_GATE_EN0, 3);
>> +struct clk_regmap aud_loopback =
>> + AUD_PCLK_GATE(loopback, AUDIO_CLK_GATE_EN0, 4);
>> +struct clk_regmap aud_tdmout_a =
>> + AUD_PCLK_GATE(tdmout_a, AUDIO_CLK_GATE_EN0, 5);
>> +struct clk_regmap aud_tdmout_b =
>> + AUD_PCLK_GATE(tdmout_b, AUDIO_CLK_GATE_EN0, 6);
>> +struct clk_regmap aud_frddr_a =
>> + AUD_PCLK_GATE(frddr_a, AUDIO_CLK_GATE_EN0, 7);
>> +struct clk_regmap aud_frddr_b =
>> + AUD_PCLK_GATE(frddr_b, AUDIO_CLK_GATE_EN0, 8);
>> +struct clk_regmap aud_toddr_a =
>> + AUD_PCLK_GATE(toddr_a, AUDIO_CLK_GATE_EN0, 9);
>> +struct clk_regmap aud_toddr_b =
>> + AUD_PCLK_GATE(toddr_b, AUDIO_CLK_GATE_EN0, 10);
>> +struct clk_regmap aud_spdifin =
>> + AUD_PCLK_GATE(spdifin, AUDIO_CLK_GATE_EN0, 11);
>> +struct clk_regmap aud_resample =
>> + AUD_PCLK_GATE(resample, AUDIO_CLK_GATE_EN0, 12);
>> +struct clk_regmap aud_eqdrc =
>> + AUD_PCLK_GATE(eqdrc, AUDIO_CLK_GATE_EN0, 13);
>> +struct clk_regmap aud_audiolocker =
>> + AUD_PCLK_GATE(audiolocker, AUDIO_CLK_GATE_EN0, 14);
>> +
>> +struct clk_regmap aud_vad_ddr_arb =
>> + AUD_PCLK_GATE(vad_ddr_arb, AUDIO2_CLK_GATE_EN0, 0);
>> +struct clk_regmap aud_vad_pdm =
>> + AUD_PCLK_GATE(vad_pdm, AUDIO2_CLK_GATE_EN0, 1);
>> +struct clk_regmap aud_vad_tdmin_vad =
>> + AUD_PCLK_GATE(vad_tdmin_vad, AUDIO2_CLK_GATE_EN0, 2);
>> +struct clk_regmap aud_vad_toddr_vad =
>> + AUD_PCLK_GATE(vad_toddr_vad, AUDIO2_CLK_GATE_EN0, 3);
>> +struct clk_regmap aud_vad =
>> + AUD_PCLK_GATE(vad, AUDIO2_CLK_GATE_EN0, 4);
>> +struct clk_regmap aud_vad_audiotop =
>> + AUD_PCLK_GATE(vad_audiotop, AUDIO2_CLK_GATE_EN0, 7);
>> +
>> +static const struct clk_parent_data a1_mst_pdata[] = {
>> + { .fw_name = "dds_in" },
>> + { .fw_name = "fclk_div2" },
>> + { .fw_name = "fclk_div3" },
>> + { .fw_name = "hifi_pll" },
>> + { .fw_name = "xtal" },
>> +};
>> +
>> +#define AUD_MST_MCLK_MUX(_name, _reg) \
>> + AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
>> + a1_mst_pdata, 0)
>> +#define AUD_MST_MCLK_DIV(_name, _reg) \
>> + AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
>> + aud_##_name##_sel, CLK_SET_RATE_PARENT)
>> +#define AUD_MST_MCLK_GATE(_name, _reg) \
>> + AUD_GATE(_name, _reg, 31, aud_##_name##_div, \
>> + CLK_SET_RATE_PARENT)
>> +
>> +struct clk_regmap aud_mst_a_mclk_sel =
>> + AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL);
>> +struct clk_regmap aud_mst_a_mclk_div =
>> + AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL);
>> +struct clk_regmap aud_mst_a_mclk =
>> + AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL);
>> +
>> +struct clk_regmap aud_mst_b_mclk_sel =
>> + AUD_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL);
>> +struct clk_regmap aud_mst_b_mclk_div =
>> + AUD_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL);
>> +struct clk_regmap aud_mst_b_mclk =
>> + AUD_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL);
>> +
>> +struct clk_regmap aud_mst_c_mclk_sel =
>> + AUD_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL);
>> +struct clk_regmap aud_mst_c_mclk_div =
>> + AUD_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL);
>> +struct clk_regmap aud_mst_c_mclk =
>> + AUD_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL);
>> +
>> +struct clk_regmap aud_mst_d_mclk_sel =
>> + AUD_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL);
>> +struct clk_regmap aud_mst_d_mclk_div =
>> + AUD_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL);
>> +struct clk_regmap aud_mst_d_mclk =
>> + AUD_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL);
>> +
>> +struct clk_regmap aud_spdifin_clk_sel =
>> + AUD_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
>> +struct clk_regmap aud_spdifin_clk_div =
>> + AUD_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
>> +struct clk_regmap aud_spdifin_clk =
>> + AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
>> +
>> +struct clk_regmap aud_eqdrc_clk_sel =
>> + AUD_MST_MCLK_MUX(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
>> +struct clk_regmap aud_eqdrc_clk_div =
>> + AUD_MST_MCLK_DIV(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
>> +struct clk_regmap aud_eqdrc_clk =
>> + AUD_MST_MCLK_GATE(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
>> +
>> +struct clk_regmap aud_resample_clk_sel =
>> + AUD_MUX(resample_clk_sel, AUDIO_CLK_RESAMPLEA_CTRL, 0xf, 24,
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, 0);
>> +struct clk_regmap aud_resample_clk_div =
>> + AUD_DIV(resample_clk_div, AUDIO_CLK_RESAMPLEA_CTRL, 0, 8,
>> + CLK_DIVIDER_ROUND_CLOSEST, aud_resample_clk_sel,
>> + CLK_SET_RATE_PARENT);
>> +struct clk_regmap aud_resample_clk =
>> + AUD_GATE(resample_clk, AUDIO_CLK_RESAMPLEA_CTRL, 31,
>> + aud_resample_clk_div, CLK_SET_RATE_PARENT);
>> +
>> +struct clk_regmap aud_locker_in_clk_sel =
>> + AUD_MUX(locker_in_clk_sel, AUDIO_CLK_LOCKER_CTRL, 0xf, 8,
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, 0);
>> +struct clk_regmap aud_locker_in_clk_div =
>> + AUD_DIV(locker_in_clk_div, AUDIO_CLK_LOCKER_CTRL, 0, 8,
>> + CLK_DIVIDER_ROUND_CLOSEST, aud_locker_in_clk_sel,
>> + CLK_SET_RATE_PARENT);
>> +struct clk_regmap aud_locker_in_clk =
>> + AUD_GATE(locker_in_clk, AUDIO_CLK_LOCKER_CTRL, 15,
>> + aud_locker_in_clk_div, CLK_SET_RATE_PARENT);
>> +
>> +struct clk_regmap aud_locker_out_clk_sel =
>> + AUD_MUX(locker_out_clk_sel, AUDIO_CLK_LOCKER_CTRL, 0xf, 24,
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, 0);
>> +struct clk_regmap aud_locker_out_clk_div =
>> + AUD_DIV(locker_out_clk_div, AUDIO_CLK_LOCKER_CTRL, 16, 8,
>> + CLK_DIVIDER_ROUND_CLOSEST, aud_locker_out_clk_sel,
>> + CLK_SET_RATE_PARENT);
>> +struct clk_regmap aud_locker_out_clk =
>> + AUD_GATE(locker_out_clk, AUDIO_CLK_LOCKER_CTRL, 31,
>> + aud_locker_out_clk_div, CLK_SET_RATE_PARENT);
>> +
>> +struct clk_regmap aud_vad_mclk_sel =
>> + AUD_MST_MCLK_MUX(vad_mclk, AUDIO2_MCLK_VAD_CTRL);
>> +struct clk_regmap aud_vad_mclk_div =
>> + AUD_MST_MCLK_DIV(vad_mclk, AUDIO2_MCLK_VAD_CTRL);
>> +struct clk_regmap aud_vad_mclk =
>> + AUD_MST_MCLK_GATE(vad_mclk, AUDIO2_MCLK_VAD_CTRL);
>> +
>> +struct clk_regmap aud_vad_clk_sel =
>> + AUD_MST_MCLK_MUX(vad_clk, AUDIO2_CLK_VAD_CTRL);
>> +struct clk_regmap aud_vad_clk_div =
>> + AUD_MST_MCLK_DIV(vad_clk, AUDIO2_CLK_VAD_CTRL);
>> +struct clk_regmap aud_vad_clk =
>> + AUD_MST_MCLK_GATE(vad_clk, AUDIO2_CLK_VAD_CTRL);
>> +
>> +struct clk_regmap aud_vad_pdm_dclk_sel =
>> + AUD_MST_MCLK_MUX(vad_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
>> +struct clk_regmap aud_vad_pdm_dclk_div =
>> + AUD_MST_MCLK_DIV(vad_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
>> +struct clk_regmap aud_vad_pdm_dclk =
>> + AUD_MST_MCLK_GATE(vad_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
>> +
>> +struct clk_regmap aud_vad_pdm_sysclk_sel =
>> + AUD_MST_MCLK_MUX(vad_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
>> +struct clk_regmap aud_vad_pdm_sysclk_div =
>> + AUD_MST_MCLK_DIV(vad_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
>> +struct clk_regmap aud_vad_pdm_sysclk =
>> + AUD_MST_MCLK_GATE(vad_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
>> +
>> +#define AUD_MST_SCLK_PRE_EN(_name, _reg, _pname) \
>> + AUD_GATE(_name##_pre_en, _reg, 31, \
>> + aud_##_pname, 0)
>> +#define AUD_MST_SCLK_DIV(_name, _reg) \
>> + AUD_SCLK_DIV(_name##_div, _reg, 20, 10, 0, 0, \
>> + aud_##_name##_pre_en, CLK_SET_RATE_PARENT)
>> +#define AUD_MST_SCLK_POST_EN(_name, _reg) \
>> + AUD_GATE(_name##_post_en, _reg, 30, \
>> + aud_##_name##_div, CLK_SET_RATE_PARENT)
>> +#define AUD_MST_SCLK(_name, _reg) \
>> + AUD_TRIPHASE(_name, _reg, 1, 0, 2, 4, \
>> + aud_##_name##_post_en, CLK_SET_RATE_PARENT)
>> +
>> +struct clk_regmap aud_mst_a_sclk_pre_en =
>> + AUD_MST_SCLK_PRE_EN(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0, mst_a_mclk);
>> +struct clk_regmap aud_mst_a_sclk_div =
>> + AUD_MST_SCLK_DIV(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_a_sclk_post_en =
>> + AUD_MST_SCLK_POST_EN(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_a_sclk =
>> + AUD_MST_SCLK(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_b_sclk_pre_en =
>> + AUD_MST_SCLK_PRE_EN(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0, mst_b_mclk);
>> +struct clk_regmap aud_mst_b_sclk_div =
>> + AUD_MST_SCLK_DIV(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_b_sclk_post_en =
>> + AUD_MST_SCLK_POST_EN(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_b_sclk =
>> + AUD_MST_SCLK(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_c_sclk_pre_en =
>> + AUD_MST_SCLK_PRE_EN(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0, mst_c_mclk);
>> +struct clk_regmap aud_mst_c_sclk_div =
>> + AUD_MST_SCLK_DIV(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_c_sclk_post_en =
>> + AUD_MST_SCLK_POST_EN(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_c_sclk =
>> + AUD_MST_SCLK(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_d_sclk_pre_en =
>> + AUD_MST_SCLK_PRE_EN(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0, mst_d_mclk);
>> +struct clk_regmap aud_mst_d_sclk_div =
>> + AUD_MST_SCLK_DIV(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_d_sclk_post_en =
>> + AUD_MST_SCLK_POST_EN(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_d_sclk =
>> + AUD_MST_SCLK(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL1);
>> +
>> +#define AUD_MST_LRCLK_DIV(_name, _reg, _pname) \
>> + AUD_SCLK_DIV(_name##_div, _reg, 0, 10, 10, 10, \
>> + aud_##_pname, 0)
>> +#define AUD_MST_LRCLK(_name, _reg) \
>> + AUD_TRIPHASE(_name, _reg, 1, 1, 3, 5, \
>> + aud_##_name##_div, CLK_SET_RATE_PARENT)
>> +
>> +struct clk_regmap aud_mst_a_lrclk_div =
>> + AUD_MST_LRCLK_DIV(mst_a_lrclk, AUDIO_MST_A_SCLK_CTRL0,
>> + mst_a_sclk_post_en);
>> +struct clk_regmap aud_mst_a_lrclk =
>> + AUD_MST_LRCLK(mst_a_lrclk, AUDIO_MST_A_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_b_lrclk_div =
>> + AUD_MST_LRCLK_DIV(mst_b_lrclk, AUDIO_MST_B_SCLK_CTRL0,
>> + mst_b_sclk_post_en);
>> +struct clk_regmap aud_mst_b_lrclk =
>> + AUD_MST_LRCLK(mst_b_lrclk, AUDIO_MST_B_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_c_lrclk_div =
>> + AUD_MST_LRCLK_DIV(mst_c_lrclk, AUDIO_MST_C_SCLK_CTRL0,
>> + mst_c_sclk_post_en);
>> +struct clk_regmap aud_mst_c_lrclk =
>> + AUD_MST_LRCLK(mst_c_lrclk, AUDIO_MST_C_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_d_lrclk_div =
>> + AUD_MST_LRCLK_DIV(mst_d_lrclk, AUDIO_MST_D_SCLK_CTRL0,
>> + mst_d_sclk_post_en);
>> +struct clk_regmap aud_mst_d_lrclk =
>> + AUD_MST_LRCLK(mst_d_lrclk, AUDIO_MST_D_SCLK_CTRL1);
>> +
>> +static const struct clk_parent_data a1_mst_sclk_pdata[] = {
>> + { .hw = &aud_mst_a_sclk.hw, .index = -1 },
>> + { .hw = &aud_mst_b_sclk.hw, .index = -1 },
>> + { .hw = &aud_mst_c_sclk.hw, .index = -1 },
>> + { .hw = &aud_mst_d_sclk.hw, .index = -1 },
>> + { .fw_name = "slv_sclk0" },
>> + { .fw_name = "slv_sclk1" },
>> + { .fw_name = "slv_sclk2" },
>> + { .fw_name = "slv_sclk3" },
>> + { .fw_name = "slv_sclk4" },
>> + { .fw_name = "slv_sclk5" },
>> + { .fw_name = "slv_sclk6" },
>> + { .fw_name = "slv_sclk7" },
>> + { .fw_name = "slv_sclk8" },
>> + { .fw_name = "slv_sclk9" },
>> +};
>> +
>> +static u32 a1_mst_sclk_table[] = {
>> + 0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
>> +};
>
> This is a clear indication that the bindings of axg and a1 are indeed
> the same. Master clocks are optional.
>
>> +
>> +static const struct clk_parent_data a1_mst_lrclk_pdata[] = {
>> + { .hw = &aud_mst_a_lrclk.hw, .index = -1 },
>> + { .hw = &aud_mst_b_lrclk.hw, .index = -1 },
>> + { .hw = &aud_mst_c_lrclk.hw, .index = -1 },
>> + { .hw = &aud_mst_d_lrclk.hw, .index = -1 },
>> + { .fw_name = "slv_lrclk0" },
>> + { .fw_name = "slv_lrclk1" },
>> + { .fw_name = "slv_lrclk2" },
>> + { .fw_name = "slv_lrclk3" },
>> + { .fw_name = "slv_lrclk4" },
>> + { .fw_name = "slv_lrclk5" },
>> + { .fw_name = "slv_lrclk6" },
>> + { .fw_name = "slv_lrclk7" },
>> + { .fw_name = "slv_lrclk8" },
>> + { .fw_name = "slv_lrclk9" },
>> +};
>> +
>> +static u32 a1_mst_lrclk_table[] = {
>> + 0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
>> +};
>> +
>> +#define AUD_TDM_SCLK_MUX(_name, _reg) \
>> + AUD_MUX_TABLE(_name##_sel, _reg, a1_mst_sclk_table, 0xf, 24, \
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_sclk_pdata, 0)
>> +#define AUD_TDM_SCLK_PRE_EN(_name, _reg) \
>> + AUD_GATE(_name##_pre_en, _reg, 31, \
>> + aud_##_name##_sel, CLK_SET_RATE_PARENT)
>> +#define AUD_TDM_SCLK_POST_EN(_name, _reg) \
>> + AUD_GATE(_name##_post_en, _reg, 30, \
>> + aud_##_name##_pre_en, CLK_SET_RATE_PARENT)
>> +#define AUD_TDM_SCLK_WS(_name, _reg) \
>> + AUD_SCLK_WS(_name, _reg, 1, 29, 28, \
>> + aud_##_name##_post_en, \
>> + CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)
>> +
>> +#define AUD_TDM_LRLCK(_name, _reg) \
>> + AUD_MUX_TABLE(_name, _reg, a1_mst_lrclk_table, 0xf, 20, \
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_lrclk_pdata, \
>> + CLK_SET_RATE_PARENT)
>> +
>> +struct clk_regmap aud_tdmin_a_sclk_sel =
>> + AUD_TDM_SCLK_MUX(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +struct clk_regmap aud_tdmin_a_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +struct clk_regmap aud_tdmin_a_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +struct clk_regmap aud_tdmin_a_sclk =
>> + AUD_TDM_SCLK_WS(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +struct clk_regmap aud_tdmin_a_lrclk =
>> + AUD_TDM_LRLCK(tdmin_a_lrclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +
>> +struct clk_regmap aud_tdmin_b_sclk_sel =
>> + AUD_TDM_SCLK_MUX(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +struct clk_regmap aud_tdmin_b_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +struct clk_regmap aud_tdmin_b_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +struct clk_regmap aud_tdmin_b_sclk =
>> + AUD_TDM_SCLK_WS(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +struct clk_regmap aud_tdmin_b_lrclk =
>> + AUD_TDM_LRLCK(tdmin_b_lrclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +
>> +struct clk_regmap aud_tdmin_lb_sclk_sel =
>> + AUD_TDM_SCLK_MUX(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +struct clk_regmap aud_tdmin_lb_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +struct clk_regmap aud_tdmin_lb_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +struct clk_regmap aud_tdmin_lb_sclk =
>> + AUD_TDM_SCLK_WS(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +struct clk_regmap aud_tdmin_lb_lrclk =
>> + AUD_TDM_LRLCK(tdmin_lb_lrclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +
>> +struct clk_regmap aud_tdmout_a_sclk_sel =
>> + AUD_TDM_SCLK_MUX(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +struct clk_regmap aud_tdmout_a_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +struct clk_regmap aud_tdmout_a_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +struct clk_regmap aud_tdmout_a_sclk =
>> + AUD_TDM_SCLK_WS(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +struct clk_regmap aud_tdmout_a_lrclk =
>> + AUD_TDM_LRLCK(tdmout_a_lrclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +
>> +struct clk_regmap aud_tdmout_b_sclk_sel =
>> + AUD_TDM_SCLK_MUX(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +struct clk_regmap aud_tdmout_b_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +struct clk_regmap aud_tdmout_b_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +struct clk_regmap aud_tdmout_b_sclk =
>> + AUD_TDM_SCLK_WS(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +struct clk_regmap aud_tdmout_b_lrclk =
>> + AUD_TDM_LRLCK(tdmout_b_lrclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +
>> +static struct clk_hw *a1_audio_hw_clks[] = {
>> + [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw,
>> + [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw,
>> + [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw,
>> + [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw,
>> + [AUD_CLKID_LOOPBACK] = &aud_loopback.hw,
>> + [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw,
>> + [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw,
>> + [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw,
>> + [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw,
>> + [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw,
>> + [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw,
>> + [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw,
>> + [AUD_CLKID_RESAMPLE] = &aud_resample.hw,
>> + [AUD_CLKID_EQDRC] = &aud_eqdrc.hw,
>> + [AUD_CLKID_LOCKER] = &aud_audiolocker.hw,
>> + [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_sel.hw,
>> + [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw,
>> + [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw,
>> + [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_sel.hw,
>> + [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw,
>> + [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw,
>> + [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_sel.hw,
>> + [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw,
>> + [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw,
>> + [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_sel.hw,
>> + [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw,
>> + [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw,
>> + [AUD_CLKID_RESAMPLE_CLK_SEL] = &aud_resample_clk_sel.hw,
>> + [AUD_CLKID_RESAMPLE_CLK_DIV] = &aud_resample_clk_div.hw,
>> + [AUD_CLKID_RESAMPLE_CLK] = &aud_resample_clk.hw,
>> + [AUD_CLKID_LOCKER_IN_CLK_SEL] = &aud_locker_in_clk_sel.hw,
>> + [AUD_CLKID_LOCKER_IN_CLK_DIV] = &aud_locker_in_clk_div.hw,
>> + [AUD_CLKID_LOCKER_IN_CLK] = &aud_locker_in_clk.hw,
>> + [AUD_CLKID_LOCKER_OUT_CLK_SEL] = &aud_locker_out_clk_sel.hw,
>> + [AUD_CLKID_LOCKER_OUT_CLK_DIV] = &aud_locker_out_clk_div.hw,
>> + [AUD_CLKID_LOCKER_OUT_CLK] = &aud_locker_out_clk.hw,
>> + [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_sel.hw,
>> + [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw,
>> + [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw,
>> + [AUD_CLKID_EQDRC_CLK_SEL] = &aud_eqdrc_clk_sel.hw,
>> + [AUD_CLKID_EQDRC_CLK_DIV] = &aud_eqdrc_clk_div.hw,
>> + [AUD_CLKID_EQDRC_CLK] = &aud_eqdrc_clk.hw,
>> + [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw,
>> + [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw,
>> + [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw,
>> + [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw,
>> + [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw,
>> + [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw,
>> + [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw,
>> + [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw,
>> + [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw,
>> + [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw,
>> + [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw,
>> + [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw,
>> + [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw,
>> + [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw,
>> + [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw,
>> + [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw,
>> + [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw,
>> + [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw,
>> + [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw,
>> + [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw,
>> + [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw,
>> + [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw,
>> + [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw,
>> + [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw,
>> + [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_sel.hw,
>> + [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw,
>> + [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw,
>> + [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw,
>> + [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_sel.hw,
>> + [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw,
>> + [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw,
>> + [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw,
>> + [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_sel.hw,
>> + [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw,
>> + [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw,
>> + [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw,
>> + [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_sel.hw,
>> + [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw,
>> + [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw,
>> + [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw,
>> + [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_sel.hw,
>> + [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw,
>> + [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw,
>> + [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw,
>> +};
>> +
>> +static struct clk_hw *a1_audio_vad_hw_clks[] = {
>> + [AUD_CLKID_VAD_DDR_ARB] = &aud_vad_ddr_arb.hw,
>> + [AUD_CLKID_VAD_PDM] = &aud_vad_pdm.hw,
>> + [AUD_CLKID_VAD_TDMIN] = &aud_vad_tdmin_vad.hw,
>> + [AUD_CLKID_VAD_TODDR] = &aud_vad_toddr_vad.hw,
>> + [AUD_CLKID_VAD] = &aud_vad.hw,
>> + [AUD_CLKID_VAD_AUDIOTOP] = &aud_vad_audiotop.hw,
>> + [AUD_CLKID_VAD_MCLK_SEL] = &aud_vad_mclk_sel.hw,
>> + [AUD_CLKID_VAD_MCLK_DIV] = &aud_vad_mclk_div.hw,
>> + [AUD_CLKID_VAD_MCLK] = &aud_vad_mclk.hw,
>> + [AUD_CLKID_VAD_CLK_SEL] = &aud_vad_clk_sel.hw,
>> + [AUD_CLKID_VAD_CLK_DIV] = &aud_vad_clk_div.hw,
>> + [AUD_CLKID_VAD_CLK] = &aud_vad_clk.hw,
>> + [AUD_CLKID_VAD_PDM_DCLK_SEL] = &aud_vad_pdm_dclk_sel.hw,
>> + [AUD_CLKID_VAD_PDM_DCLK_DIV] = &aud_vad_pdm_dclk_div.hw,
>> + [AUD_CLKID_VAD_PDM_DCLK] = &aud_vad_pdm_dclk.hw,
>> + [AUD_CLKID_VAD_PDM_SYSCLK_SEL] = &aud_vad_pdm_sysclk_sel.hw,
>> + [AUD_CLKID_VAD_PDM_SYSCLK_DIV] = &aud_vad_pdm_sysclk_div.hw,
>> + [AUD_CLKID_VAD_PDM_SYSCLK] = &aud_vad_pdm_sysclk.hw,
>> +};
>
> Again, I asked you to make separate driver for the a1 and a1-vad.
>

Could you please give more recommendations. Should I move
a1_audio_hw_clks/a1_audio_vad_hw_clks to separate files and link them
into single kernel module together with common _probe routine, or you
mean that here should be two file which are linked into independent
kernel modules with own _probe?

> To be clear: different files for a1 and a1-vad.
>
>> +
>> +struct a1_audio_data {
>> + struct meson_clk_hw_data hw_clks;
>> + const char *reset_name;
>> +};
>> +
>> +static const struct regmap_config a1_audio_regmap_cfg = {
>> + .reg_bits = 32,
>> + .val_bits = 32,
>> + .reg_stride = 4,
>> +};
>> +
>> +static int a1_audio_clkc_probe(struct platform_device *pdev)
>> +{
>> + const struct a1_audio_data *data;
>> + struct regmap *map;
>> + void __iomem *base;
>> + struct clk *clk;
>> + unsigned int i;
>> + int ret;
>> +
>> + data = of_device_get_match_data(&pdev->dev);
>> + if (!data)
>> + return -EINVAL;
>> +
>> + clk = devm_clk_get_enabled(&pdev->dev, "pclk");
>> + if (IS_ERR(clk))
>> + return PTR_ERR(clk);
>> +
>> + base = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(base))
>> + return PTR_ERR(base);
>> +
>> + map = devm_regmap_init_mmio(&pdev->dev, base, &a1_audio_regmap_cfg);
>> + if (IS_ERR(map))
>> + return PTR_ERR(map);
>> +
>> + for (i = 0; i < data->hw_clks.num; i++) {
>> + struct clk_hw *hw = data->hw_clks.hws[i];
>> + struct clk_regmap *clk_regmap = to_clk_regmap(hw);
>> +
>> + if (!hw)
>> + continue;
>> +
>> + clk_regmap->map = map;
>> +
>> + ret = devm_clk_hw_register(&pdev->dev, hw);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + ret = devm_of_clk_add_hw_provider(&pdev->dev, meson_clk_hw_get,
>> + (void *)&data->hw_clks);
>> + if (ret)
>> + return ret;
>> +
>> + if (!data->reset_name)
>> + return 0;
>> +
>> + return meson_audio_reset_register(&pdev->dev, data->reset_name);
>> +}
>> +
>> +struct a1_audio_data a1_audio_data = {
>> + .hw_clks = {
>> + .hws = a1_audio_hw_clks,
>> + .num = ARRAY_SIZE(a1_audio_hw_clks),
>> + },
>> + .reset_name = "a1",
>> +};
>> +
>> +struct a1_audio_data a1_audio_vad_data = {
>> + .hw_clks = {
>> + .hws = a1_audio_vad_hw_clks,
>> + .num = ARRAY_SIZE(a1_audio_vad_hw_clks),
>> + },
>> +};
>> +
>> +static const struct of_device_id a1_audio_clkc_match_table[] = {
>> + {
>> + .compatible = "amlogic,a1-audio-clkc",
>> + .data = &a1_audio_data,
>> + },
>> + {
>> + .compatible = "amlogic,a1-audio-vad-clkc",
>> + .data = &a1_audio_vad_data,
>> + },
>> + {}
>> +};
>> +MODULE_DEVICE_TABLE(of, a1_audio_clkc_match_table);
>> +
>> +static struct platform_driver a1_audio_clkc_driver = {
>> + .probe = a1_audio_clkc_probe,
>> + .driver = {
>> + .name = "a1-audio-clkc",
>> + .of_match_table = a1_audio_clkc_match_table,
>> + },
>> +};
>> +module_platform_driver(a1_audio_clkc_driver);
>> +
>> +MODULE_DESCRIPTION("Amlogic A1 Audio Clock driver");
>> +MODULE_AUTHOR("Jan Dakinevich <[email protected]>");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/reset/reset-meson-audio.c b/drivers/reset/reset-meson-audio.c
>> index aaea9931cfe2..faf098012721 100644
>> --- a/drivers/reset/reset-meson-audio.c
>> +++ b/drivers/reset/reset-meson-audio.c
>> @@ -145,6 +145,12 @@ static const struct meson_audio_reset_info meson_audio_reset_info_sm1 = {
>> .reset_offset = 0x028,
>> .reset_num = 39,
>> };
>> +
>> +static const struct meson_audio_reset_info meson_audio_reset_info_a1 = {
>> + .reset_offset = 0x028,
>> + .reset_num = 32,
>> +};
>> +
>> static const struct auxiliary_device_id meson_audio_reset_id[] = {
>> {
>> .name = "reset_meson_audio.g12a",
>> @@ -154,6 +160,10 @@ static const struct auxiliary_device_id meson_audio_reset_id[] = {
>> .name = "reset_meson_audio.sm1",
>> .driver_data = (kernel_ulong_t)&meson_audio_reset_info_sm1,
>> },
>> + {
>> + .name = "reset_meson_audio.a1",
>> + .driver_data = (kernel_ulong_t)&meson_audio_reset_info_a1,
>> + },
>> {},
>> };
>> MODULE_DEVICE_TABLE(auxiliary, meson_audio_reset_id);
>
>

--
Best regards
Jan Dakinevich

2024-04-22 14:33:48

by Jan Dakinevich

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver



On 4/22/24 10:57, Jerome Brunet wrote:
>
> On Mon 22 Apr 2024 at 09:16, Jerome Brunet <[email protected]> wrote:
>
>> On Sun 21 Apr 2024 at 20:14, Krzysztof Kozlowski <[email protected]> wrote:
>>
>>> On 20/04/2024 18:15, Jan Dakinevich wrote:
>>>>
>>>>
>>>> On 4/20/24 00:09, Rob Herring wrote:
>>>>> On Fri, Apr 19, 2024 at 03:58:10PM +0300, Jan Dakinevich wrote:
>>>>>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>>>>>
>>>>>> Signed-off-by: Jan Dakinevich <[email protected]>
>>>>>> ---
>>>>>>
>>>>>> This controller has 6 mandatory and up to 20 optional clocks. To describe
>>>>>> this, I use 'additionalItems'. It produces correct processed-schema.json:
>>>>>>
>>>>>> "clock-names": {
>>>>>> "maxItems": 26,
>>>>>> "items": [
>>>>>> {
>>>>>> "const": "pclk"
>>>>>> },
>>>>>> {
>>>>>> "const": "dds_in"
>>>>>> },
>>>>>> {
>>>>>> "const": "fclk_div2"
>>>>>> },
>>>>>> {
>>>>>> "const": "fclk_div3"
>>>>>> },
>>>>>> {
>>>>>> "const": "hifi_pll"
>>>>>> },
>>>>>> {
>>>>>> "const": "xtal"
>>>>>> }
>>>>>> ],
>>>>>> "additionalItems": {
>>>>>> "oneOf": [
>>>>>> {
>>>>>> "pattern": "^slv_sclk[0-9]$"
>>>>>> },
>>>>>> {
>>>>>> "pattern": "^slv_lrclk[0-9]$"
>>>>>> }
>>>>>> ]
>>>>>> },
>>>>>> "type": "array",
>>>>>> "minItems": 6
>>>>>> },
>>>>>>
>>>>>> and it behaves as expected. However, the checking is followed by
>>>>>> complaints like this:
>>>>>>
>>>>>> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>>>>>>
>>>>>> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
>>>>>> do it right?
>>>>>
>>>>> The meta-schemas are written both to prevent nonsense that json-schema
>>>>> allows by default (e.g additionalitems (wrong case)) and constraints to
>>>>> follow the patterns we expect. I'm happy to loosen the latter case if
>>>>> there's really a need.
>>>>>
>>>>> Generally, most bindings shouldn't be using 'additionalItems' at all as
>>>>> all entries should be defined, but there's a few exceptions. Here, the
>>>>> only reasoning I see is 26 entries is a lot to write out, but that
>>>>> wouldn't really justify it.
>>>>
>>>> Writing a lot of entries don't scary me too much, but the reason is that
>>>> the existence of optional clock sources depends on schematics. Also, we
>>>
>>> Aren't you documenting SoC component, not a board? So how exactly it
>>> depends on schematics? SoC is done or not done...
>>>
>>>> unable to declare dt-nodes for 'clocks' array in any generic way,
>>>> because their declaration would depends on that what is actually
>>>> connected to the SoC (dt-node could be "fixed-clock" with specific rate
>>>> or something else).
>>>
>>> So these are clock inputs to the SoC?
>>>
>>
>> Yes, possibly.
>> Like an external crystal or a set clocks provided by an external codec
>> where the codec is the clock master of the link.
>>
>> This is same case as the AXG that was discussed here:
>> https://lore.kernel.org/linux-devicetree/[email protected]/
>>
>> IMO, like the AXG, only the pclk is a required clock.
>> All the others - master and slave clocks - are optional.
>> The controller is designed to operate with grounded inputs
>
> Looking again at the implementation of the controller, there is a clear
> indication in patch 3 that the controller interface is the same as the
> AXG and that the above statement is true.
> > The AXG had 8 master clocks wired in. The A1 just has 5 - and 3 grounded
> master clocks. This is why you to had to provide a mux input table to
> skip the grounded inputs. You would not have to do so if the controller was
> properly declared with the 8 master clock input, as it actually is.
>

For simplicity, I could make something like this in device tree:

clocks = <&clk0,
&clk1,
&clk2,
&clk3,
&clk4,
0,
0,
0>
clock-names = <"mst_in0",
"mst_in1",
"mst_in2"
"mst_in2"
"mst_in3"
"mst_in4"
"mst_in5"
"mst_in6"
"mst_in7">

But I don't see in the doc that the last 3 clocks are grounded to
anywhere. It will be just community's assumption about internals of the
controller.

Anyway, I still don't understand what to do with external slv_* clocks.
I can do the same as in example above: list slv_(s|lr)clk[0-9] in
"clock-names" and fill the rest if "clocks" by "0" phandles.

> It also shows that it is a bad idea to name input after what is coming
> in (like you do with "dds_in" or "fclk_div2") instead of what they
> actually are like in the AXG (mst0, mst1, etc ...)
>

I agree, these are not the best names.

>>
>>>>
>>>> By the way, I don't know any example (neither for A1 SoC nor for other
>>>> Amlogic's SoCs) where these optional clocks are used, but they are
>>>> allowed by hw.
>>
>> Those scenario exists and have been tested. There is just no dts using
>> that upstream because they are all mostly copy of the AML ref design.
>>
>>>>
>>>> This is my understanding of this controller. I hope, Jerome Brunet will
>>>> clarify how it actually works.
>>>
>>
>> I think the simpliest way to deal with this to just list all the clocks
>> with 'minItems = 1'. It is going be hard to read with a lot of '<0>,' in
>> the DTS when do need those slave clocks but at least the binding doc
>> will be simple.
>>
>>> Best regards,
>>> Krzysztof
>>
>> If you are going ahead with this, please name the file
>> amlogic,axg-audio-clkc.yaml because this is really the first controller
>> of the type and is meant to be documented in the same file.
>>
>> You are free to handle the conversion of the AXG at the same time if
>> you'd like. It would be much appreciated if you do.
>
>

--
Best regards
Jan Dakinevich

2024-04-22 15:46:32

by Jan Dakinevich

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver



On 4/22/24 17:31, Jan Dakinevich wrote:
>
>
> On 4/22/24 10:57, Jerome Brunet wrote:
>>
>> On Mon 22 Apr 2024 at 09:16, Jerome Brunet <[email protected]> wrote:
>>
>>> On Sun 21 Apr 2024 at 20:14, Krzysztof Kozlowski <[email protected]> wrote:
>>>
>>>> On 20/04/2024 18:15, Jan Dakinevich wrote:
>>>>>
>>>>>
>>>>> On 4/20/24 00:09, Rob Herring wrote:
>>>>>> On Fri, Apr 19, 2024 at 03:58:10PM +0300, Jan Dakinevich wrote:
>>>>>>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>>>>>>
>>>>>>> Signed-off-by: Jan Dakinevich <[email protected]>
>>>>>>> ---
>>>>>>>
>>>>>>> This controller has 6 mandatory and up to 20 optional clocks. To describe
>>>>>>> this, I use 'additionalItems'. It produces correct processed-schema.json:
>>>>>>>
>>>>>>> "clock-names": {
>>>>>>> "maxItems": 26,
>>>>>>> "items": [
>>>>>>> {
>>>>>>> "const": "pclk"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "dds_in"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "fclk_div2"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "fclk_div3"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "hifi_pll"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "xtal"
>>>>>>> }
>>>>>>> ],
>>>>>>> "additionalItems": {
>>>>>>> "oneOf": [
>>>>>>> {
>>>>>>> "pattern": "^slv_sclk[0-9]$"
>>>>>>> },
>>>>>>> {
>>>>>>> "pattern": "^slv_lrclk[0-9]$"
>>>>>>> }
>>>>>>> ]
>>>>>>> },
>>>>>>> "type": "array",
>>>>>>> "minItems": 6
>>>>>>> },
>>>>>>>
>>>>>>> and it behaves as expected. However, the checking is followed by
>>>>>>> complaints like this:
>>>>>>>
>>>>>>> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>>>>>>>
>>>>>>> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
>>>>>>> do it right?
>>>>>>
>>>>>> The meta-schemas are written both to prevent nonsense that json-schema
>>>>>> allows by default (e.g additionalitems (wrong case)) and constraints to
>>>>>> follow the patterns we expect. I'm happy to loosen the latter case if
>>>>>> there's really a need.
>>>>>>
>>>>>> Generally, most bindings shouldn't be using 'additionalItems' at all as
>>>>>> all entries should be defined, but there's a few exceptions. Here, the
>>>>>> only reasoning I see is 26 entries is a lot to write out, but that
>>>>>> wouldn't really justify it.
>>>>>
>>>>> Writing a lot of entries don't scary me too much, but the reason is that
>>>>> the existence of optional clock sources depends on schematics. Also, we
>>>>
>>>> Aren't you documenting SoC component, not a board? So how exactly it
>>>> depends on schematics? SoC is done or not done...
>>>>
>>>>> unable to declare dt-nodes for 'clocks' array in any generic way,
>>>>> because their declaration would depends on that what is actually
>>>>> connected to the SoC (dt-node could be "fixed-clock" with specific rate
>>>>> or something else).
>>>>
>>>> So these are clock inputs to the SoC?
>>>>
>>>
>>> Yes, possibly.
>>> Like an external crystal or a set clocks provided by an external codec
>>> where the codec is the clock master of the link.
>>>
>>> This is same case as the AXG that was discussed here:
>>> https://lore.kernel.org/linux-devicetree/[email protected]/
>>>
>>> IMO, like the AXG, only the pclk is a required clock.
>>> All the others - master and slave clocks - are optional.
>>> The controller is designed to operate with grounded inputs
>>
>> Looking again at the implementation of the controller, there is a clear
>> indication in patch 3 that the controller interface is the same as the
>> AXG and that the above statement is true.
>>> The AXG had 8 master clocks wired in. The A1 just has 5 - and 3 grounded
>> master clocks. This is why you to had to provide a mux input table to
>> skip the grounded inputs. You would not have to do so if the controller was
>> properly declared with the 8 master clock input, as it actually is.
>>
>
> For simplicity, I could make something like this in device tree:
>
> clocks = <&clk0,
> &clk1,
> &clk2,
> &clk3,
> &clk4,
> 0,
> 0,
> 0>
> clock-names = <"mst_in0",
> "mst_in1",
> "mst_in2"
> "mst_in2"
> "mst_in3"
> "mst_in4"
> "mst_in5"
> "mst_in6"
> "mst_in7">
>
> But I don't see in the doc that the last 3 clocks are grounded to
> anywhere. It will be just community's assumption about internals of the
> controller.
>
> Anyway, I still don't understand what to do with external slv_* clocks.
> I can do the same as in example above: list slv_(s|lr)clk[0-9] in
> "clock-names" and fill the rest if "clocks" by "0" phandles.
>

Sorry, I missed that you suggested similar thing:

>>> I think the simpliest way to deal with this to just list all the clocks
>>> with 'minItems = 1'. It is going be hard to read with a lot of '<0>,' in
>>> the DTS when do need those slave clocks but at least the binding doc
>>> will be simple.

But, may be it could be better to claim that all clocks are mandatory
and list all of them (including slv_*)? So, 'minItems = 1' can be
omitted. What do you think?

clocks = <&pclk,
&clk0,
&clk1,
&clk2,
&clk3,
&clk4,
0,
0,
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0>;
clock-names = <"pclk",
"mst_in0",
"mst_in1",
"mst_in2"
"mst_in2"
"mst_in3"
"mst_in4"
"mst_in5"
"mst_in6"
"mst_in7",
"slv_sclk0",
"slv_sclk1",
"slv_sclk2",
"slv_sclk3",
"slv_sclk4",
"slv_sclk5",
"slv_sclk6",
"slv_sclk7",
"slv_sclk8",
"slv_sclk9",
"slv_lrclk0",
"slv_lrclk1",
"slv_lrclk2",
"slv_lrclk3",
"slv_lrclk4",
"slv_lrclk5",
"slv_lrclk6",
"slv_lrclk7",
"slv_lrclk8",
"slv_lrclk9">;

>> It also shows that it is a bad idea to name input after what is coming
>> in (like you do with "dds_in" or "fclk_div2") instead of what they
>> actually are like in the AXG (mst0, mst1, etc ...)
>>
>
> I agree, these are not the best names.
>
>>>
>>>>>
>>>>> By the way, I don't know any example (neither for A1 SoC nor for other
>>>>> Amlogic's SoCs) where these optional clocks are used, but they are
>>>>> allowed by hw.
>>>
>>> Those scenario exists and have been tested. There is just no dts using
>>> that upstream because they are all mostly copy of the AML ref design.
>>>
>>>>>
>>>>> This is my understanding of this controller. I hope, Jerome Brunet will
>>>>> clarify how it actually works.
>>>>
>>>
>>> I think the simpliest way to deal with this to just list all the clocks
>>> with 'minItems = 1'. It is going be hard to read with a lot of '<0>,' in
>>> the DTS when do need those slave clocks but at least the binding doc
>>> will be simple.
>>>
>>>> Best regards,
>>>> Krzysztof
>>>
>>> If you are going ahead with this, please name the file
>>> amlogic,axg-audio-clkc.yaml because this is really the first controller
>>> of the type and is meant to be documented in the same file.
>>>
>>> You are free to handle the conversion of the AXG at the same time if
>>> you'd like. It would be much appreciated if you do.
>>
>>
>

--
Best regards
Jan Dakinevich

2024-04-22 16:00:24

by Jerome Brunet

[permalink] [raw]
Subject: Re: [RFC PATCH v3 4/6] dt-bindings: clock: meson: document A1 SoC audio clock controller driver


On Mon 22 Apr 2024 at 17:31, Jan Dakinevich <[email protected]> wrote:

> On 4/22/24 10:57, Jerome Brunet wrote:
>>
>> On Mon 22 Apr 2024 at 09:16, Jerome Brunet <[email protected]> wrote:
>>
>>> On Sun 21 Apr 2024 at 20:14, Krzysztof Kozlowski <[email protected]> wrote:
>>>
>>>> On 20/04/2024 18:15, Jan Dakinevich wrote:
>>>>>
>>>>>
>>>>> On 4/20/24 00:09, Rob Herring wrote:
>>>>>> On Fri, Apr 19, 2024 at 03:58:10PM +0300, Jan Dakinevich wrote:
>>>>>>> Add device tree bindings for A1 SoC audio clock and reset controllers.
>>>>>>>
>>>>>>> Signed-off-by: Jan Dakinevich <[email protected]>
>>>>>>> ---
>>>>>>>
>>>>>>> This controller has 6 mandatory and up to 20 optional clocks. To describe
>>>>>>> this, I use 'additionalItems'. It produces correct processed-schema.json:
>>>>>>>
>>>>>>> "clock-names": {
>>>>>>> "maxItems": 26,
>>>>>>> "items": [
>>>>>>> {
>>>>>>> "const": "pclk"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "dds_in"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "fclk_div2"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "fclk_div3"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "hifi_pll"
>>>>>>> },
>>>>>>> {
>>>>>>> "const": "xtal"
>>>>>>> }
>>>>>>> ],
>>>>>>> "additionalItems": {
>>>>>>> "oneOf": [
>>>>>>> {
>>>>>>> "pattern": "^slv_sclk[0-9]$"
>>>>>>> },
>>>>>>> {
>>>>>>> "pattern": "^slv_lrclk[0-9]$"
>>>>>>> }
>>>>>>> ]
>>>>>>> },
>>>>>>> "type": "array",
>>>>>>> "minItems": 6
>>>>>>> },
>>>>>>>
>>>>>>> and it behaves as expected. However, the checking is followed by
>>>>>>> complaints like this:
>>>>>>>
>>>>>>> Documentation/devicetree/bindings/clock/amlogic,a1-audio-clkc.yaml: properties:clock-names:additionalItems: {'oneOf': [{'pattern': '^slv_sclk[0-9]$'}, {'pattern': '^slv_lrclk[0-9]$'}]} is not of type 'boolean'
>>>>>>>
>>>>>>> And indeed, 'additionalItems' has boolean type in meta-schema. So, how to
>>>>>>> do it right?
>>>>>>
>>>>>> The meta-schemas are written both to prevent nonsense that json-schema
>>>>>> allows by default (e.g additionalitems (wrong case)) and constraints to
>>>>>> follow the patterns we expect. I'm happy to loosen the latter case if
>>>>>> there's really a need.
>>>>>>
>>>>>> Generally, most bindings shouldn't be using 'additionalItems' at all as
>>>>>> all entries should be defined, but there's a few exceptions. Here, the
>>>>>> only reasoning I see is 26 entries is a lot to write out, but that
>>>>>> wouldn't really justify it.
>>>>>
>>>>> Writing a lot of entries don't scary me too much, but the reason is that
>>>>> the existence of optional clock sources depends on schematics. Also, we
>>>>
>>>> Aren't you documenting SoC component, not a board? So how exactly it
>>>> depends on schematics? SoC is done or not done...
>>>>
>>>>> unable to declare dt-nodes for 'clocks' array in any generic way,
>>>>> because their declaration would depends on that what is actually
>>>>> connected to the SoC (dt-node could be "fixed-clock" with specific rate
>>>>> or something else).
>>>>
>>>> So these are clock inputs to the SoC?
>>>>
>>>
>>> Yes, possibly.
>>> Like an external crystal or a set clocks provided by an external codec
>>> where the codec is the clock master of the link.
>>>
>>> This is same case as the AXG that was discussed here:
>>> https://lore.kernel.org/linux-devicetree/[email protected]/
>>>
>>> IMO, like the AXG, only the pclk is a required clock.
>>> All the others - master and slave clocks - are optional.
>>> The controller is designed to operate with grounded inputs
>>
>> Looking again at the implementation of the controller, there is a clear
>> indication in patch 3 that the controller interface is the same as the
>> AXG and that the above statement is true.
>> > The AXG had 8 master clocks wired in. The A1 just has 5 - and 3 grounded
>> master clocks. This is why you to had to provide a mux input table to
>> skip the grounded inputs. You would not have to do so if the controller was
>> properly declared with the 8 master clock input, as it actually is.
>>
>
> For simplicity, I could make something like this in device tree:
>
> clocks = <&clk0,
> &clk1,
> &clk2,
> &clk3,
> &clk4,
> 0,
> 0,
> 0>
> clock-names = <"mst_in0",
> "mst_in1",
> "mst_in2"
> "mst_in2"
> "mst_in3"
> "mst_in4"
> "mst_in5"
> "mst_in6"
> "mst_in7">
>
> But I don't see in the doc that the last 3 clocks are grounded to
> anywhere. It will be just community's assumption about internals of the
> controller.

Maybe so. Given how much we know about the amlogic HW, there will always be
assumptions (... and corrections). It is a fare assumption to
make. Looking at definitions for the master clocks or the TDM clocks,
you can see that the HW is same, only what is wired in has changed.

The register definition of the master clocks is still the same.
You may still put a '6' in the register, you just don't know where it
goes. Physically it may exist IMO.

I'll agree only the 5 first mst inputs are documented ATM.
Go ahead with a different interface but at least fix the names please.

>
> Anyway, I still don't understand what to do with external slv_* clocks.
> I can do the same as in example above: list slv_(s|lr)clk[0-9] in
> "clock-names" and fill the rest if "clocks" by "0" phandles.
>

You don't have to put them in the example when there is only <0> to the end.

>> It also shows that it is a bad idea to name input after what is coming
>> in (like you do with "dds_in" or "fclk_div2") instead of what they
>> actually are like in the AXG (mst0, mst1, etc ...)
>>
>
> I agree, these are not the best names.
>
>>>
>>>>>
>>>>> By the way, I don't know any example (neither for A1 SoC nor for other
>>>>> Amlogic's SoCs) where these optional clocks are used, but they are
>>>>> allowed by hw.
>>>
>>> Those scenario exists and have been tested. There is just no dts using
>>> that upstream because they are all mostly copy of the AML ref design.
>>>
>>>>>
>>>>> This is my understanding of this controller. I hope, Jerome Brunet will
>>>>> clarify how it actually works.
>>>>
>>>
>>> I think the simpliest way to deal with this to just list all the clocks
>>> with 'minItems = 1'. It is going be hard to read with a lot of '<0>,' in
>>> the DTS when do need those slave clocks but at least the binding doc
>>> will be simple.
>>>
>>>> Best regards,
>>>> Krzysztof
>>>
>>> If you are going ahead with this, please name the file
>>> amlogic,axg-audio-clkc.yaml because this is really the first controller
>>> of the type and is meant to be documented in the same file.
>>>
>>> You are free to handle the conversion of the AXG at the same time if
>>> you'd like. It would be much appreciated if you do.
>>
>>


--
Jerome