2019-08-12 12:34:24

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 0/2] clk: meson: axg-audio: add reset support

This patchset adds support for the reset provided in the register space
of the g12a audio clock controller

Changes since v1 [0]:
* Fix typo reported by Stephen

[0]: https://lkml.kernel.org/r/[email protected]

Jerome Brunet (2):
dt-bindings: clock: meson: add resets to the audio clock controller
clk: meson: axg-audio: add g12a reset support

.../bindings/clock/amlogic,axg-audio-clkc.txt | 1 +
drivers/clk/meson/axg-audio.c | 107 +++++++++++++++++-
drivers/clk/meson/axg-audio.h | 1 +
.../reset/amlogic,meson-g12a-audio-reset.h | 38 +++++++
4 files changed, 145 insertions(+), 2 deletions(-)
create mode 100644 include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h

--
2.21.0


2019-08-12 12:34:37

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 2/2] clk: meson: axg-audio: add g12a reset support

On the g12a, the register space dedicated to the audio clock also
provides some resets. Let the clock controller register a reset
provider as well for this SoC family.

the axg SoC family does not appear to provide this feature.

Signed-off-by: Jerome Brunet <[email protected]>
---
drivers/clk/meson/axg-audio.c | 107 +++++++++++++++++++++++++++++++++-
drivers/clk/meson/axg-audio.h | 1 +
2 files changed, 106 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
index 741df7e955ca..6be9df1efce5 100644
--- a/drivers/clk/meson/axg-audio.c
+++ b/drivers/clk/meson/axg-audio.c
@@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
+#include <linux/reset-controller.h>
#include <linux/slab.h>

#include "axg-audio.h"
@@ -918,6 +919,84 @@ static int devm_clk_get_enable(struct device *dev, char *id)
return 0;
}

+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,
@@ -927,12 +1006,15 @@ static const struct regmap_config axg_audio_regmap_cfg = {

struct audioclk_data {
struct clk_hw_onecell_data *hw_onecell_data;
+ unsigned int reset_offset;
+ unsigned int reset_num;
};

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;
struct resource *res;
void __iomem *regs;
@@ -984,8 +1066,27 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
}
}

- return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
- data->hw_onecell_data);
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ data->hw_onecell_data);
+ if (ret)
+ return ret;
+
+ /* Stop here if there is no reset */
+ if (!data->reset_num)
+ 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);
}

static const struct audioclk_data axg_audioclk_data = {
@@ -994,6 +1095,8 @@ static const struct audioclk_data axg_audioclk_data = {

static const struct audioclk_data g12a_audioclk_data = {
.hw_onecell_data = &g12a_audio_hw_onecell_data,
+ .reset_offset = AUDIO_SW_RESET,
+ .reset_num = 26,
};

static const struct of_device_id clkc_match_table[] = {
diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h
index 5d972d55d6c7..c00e28b2e1a9 100644
--- a/drivers/clk/meson/axg-audio.h
+++ b/drivers/clk/meson/axg-audio.h
@@ -22,6 +22,7 @@
#define AUDIO_MCLK_F_CTRL 0x018
#define AUDIO_MST_PAD_CTRL0 0x01c
#define AUDIO_MST_PAD_CTRL1 0x020
+#define AUDIO_SW_RESET 0x024
#define AUDIO_MST_A_SCLK_CTRL0 0x040
#define AUDIO_MST_A_SCLK_CTRL1 0x044
#define AUDIO_MST_B_SCLK_CTRL0 0x048
--
2.21.0

2019-08-12 12:35:15

by Jerome Brunet

[permalink] [raw]
Subject: [PATCH v2 1/2] dt-bindings: clock: meson: add resets to the audio clock controller

Add the documentation and bindings for the resets provided by the g12a
audio clock controller

Signed-off-by: Jerome Brunet <[email protected]>
---
.../bindings/clock/amlogic,axg-audio-clkc.txt | 1 +
.../reset/amlogic,meson-g12a-audio-reset.h | 38 +++++++++++++++++++
2 files changed, 39 insertions(+)
create mode 100644 include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h

diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
index 0f777749f4f1..b3957d10d241 100644
--- a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
+++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
@@ -22,6 +22,7 @@ Required Properties:
components.
- resets : phandle of the internal reset line
- #clock-cells : should be 1.
+- #reset-cells : should be 1 on the g12a (and following) soc family

Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
diff --git a/include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h b/include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h
new file mode 100644
index 000000000000..14b78dabed0e
--- /dev/null
+++ b/include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 BayLibre, SAS.
+ * Author: Jerome Brunet <[email protected]>
+ *
+ */
+
+#ifndef _DT_BINDINGS_AMLOGIC_MESON_G12A_AUDIO_RESET_H
+#define _DT_BINDINGS_AMLOGIC_MESON_G12A_AUDIO_RESET_H
+
+#define AUD_RESET_PDM 0
+#define AUD_RESET_TDMIN_A 1
+#define AUD_RESET_TDMIN_B 2
+#define AUD_RESET_TDMIN_C 3
+#define AUD_RESET_TDMIN_LB 4
+#define AUD_RESET_LOOPBACK 5
+#define AUD_RESET_TODDR_A 6
+#define AUD_RESET_TODDR_B 7
+#define AUD_RESET_TODDR_C 8
+#define AUD_RESET_FRDDR_A 9
+#define AUD_RESET_FRDDR_B 10
+#define AUD_RESET_FRDDR_C 11
+#define AUD_RESET_TDMOUT_A 12
+#define AUD_RESET_TDMOUT_B 13
+#define AUD_RESET_TDMOUT_C 14
+#define AUD_RESET_SPDIFOUT 15
+#define AUD_RESET_SPDIFOUT_B 16
+#define AUD_RESET_SPDIFIN 17
+#define AUD_RESET_EQDRC 18
+#define AUD_RESET_RESAMPLE 19
+#define AUD_RESET_DDRARB 20
+#define AUD_RESET_POWDET 21
+#define AUD_RESET_TORAM 22
+#define AUD_RESET_TOACODEC 23
+#define AUD_RESET_TOHDMITX 24
+#define AUD_RESET_CLKTREE 25
+
+#endif
--
2.21.0

2019-08-14 13:47:15

by Neil Armstrong

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] dt-bindings: clock: meson: add resets to the audio clock controller

On 12/08/2019 14:32, Jerome Brunet wrote:
> Add the documentation and bindings for the resets provided by the g12a
> audio clock controller
>
> Signed-off-by: Jerome Brunet <[email protected]>
> ---
> .../bindings/clock/amlogic,axg-audio-clkc.txt | 1 +
> .../reset/amlogic,meson-g12a-audio-reset.h | 38 +++++++++++++++++++
> 2 files changed, 39 insertions(+)
> create mode 100644 include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h
>
> diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> index 0f777749f4f1..b3957d10d241 100644
> --- a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt
> @@ -22,6 +22,7 @@ Required Properties:
> components.
> - resets : phandle of the internal reset line
> - #clock-cells : should be 1.
> +- #reset-cells : should be 1 on the g12a (and following) soc family
>
> Each clock is assigned an identifier and client nodes can use this identifier
> to specify the clock which they consume. All available clocks are defined as
> diff --git a/include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h b/include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h
> new file mode 100644
> index 000000000000..14b78dabed0e
> --- /dev/null
> +++ b/include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h
> @@ -0,0 +1,38 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2019 BayLibre, SAS.
> + * Author: Jerome Brunet <[email protected]>
> + *
> + */
> +
> +#ifndef _DT_BINDINGS_AMLOGIC_MESON_G12A_AUDIO_RESET_H
> +#define _DT_BINDINGS_AMLOGIC_MESON_G12A_AUDIO_RESET_H
> +
> +#define AUD_RESET_PDM 0
> +#define AUD_RESET_TDMIN_A 1
> +#define AUD_RESET_TDMIN_B 2
> +#define AUD_RESET_TDMIN_C 3
> +#define AUD_RESET_TDMIN_LB 4
> +#define AUD_RESET_LOOPBACK 5
> +#define AUD_RESET_TODDR_A 6
> +#define AUD_RESET_TODDR_B 7
> +#define AUD_RESET_TODDR_C 8
> +#define AUD_RESET_FRDDR_A 9
> +#define AUD_RESET_FRDDR_B 10
> +#define AUD_RESET_FRDDR_C 11
> +#define AUD_RESET_TDMOUT_A 12
> +#define AUD_RESET_TDMOUT_B 13
> +#define AUD_RESET_TDMOUT_C 14
> +#define AUD_RESET_SPDIFOUT 15
> +#define AUD_RESET_SPDIFOUT_B 16
> +#define AUD_RESET_SPDIFIN 17
> +#define AUD_RESET_EQDRC 18
> +#define AUD_RESET_RESAMPLE 19
> +#define AUD_RESET_DDRARB 20
> +#define AUD_RESET_POWDET 21
> +#define AUD_RESET_TORAM 22
> +#define AUD_RESET_TOACODEC 23
> +#define AUD_RESET_TOHDMITX 24
> +#define AUD_RESET_CLKTREE 25
> +
> +#endif
>

Reviewed-by: Neil Armstrong <[email protected]>

2019-08-14 13:49:22

by Neil Armstrong

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] clk: meson: axg-audio: add g12a reset support

On 12/08/2019 14:32, Jerome Brunet wrote:
> On the g12a, the register space dedicated to the audio clock also
> provides some resets. Let the clock controller register a reset
> provider as well for this SoC family.
>
> the axg SoC family does not appear to provide this feature.
>
> Signed-off-by: Jerome Brunet <[email protected]>
> ---
> drivers/clk/meson/axg-audio.c | 107 +++++++++++++++++++++++++++++++++-
> drivers/clk/meson/axg-audio.h | 1 +
> 2 files changed, 106 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
> index 741df7e955ca..6be9df1efce5 100644
> --- a/drivers/clk/meson/axg-audio.c
> +++ b/drivers/clk/meson/axg-audio.c
> @@ -12,6 +12,7 @@
> #include <linux/platform_device.h>
> #include <linux/regmap.h>
> #include <linux/reset.h>
> +#include <linux/reset-controller.h>
> #include <linux/slab.h>
>
> #include "axg-audio.h"
> @@ -918,6 +919,84 @@ static int devm_clk_get_enable(struct device *dev, char *id)
> return 0;
> }
>
> +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,
> @@ -927,12 +1006,15 @@ static const struct regmap_config axg_audio_regmap_cfg = {
>
> struct audioclk_data {
> struct clk_hw_onecell_data *hw_onecell_data;
> + unsigned int reset_offset;
> + unsigned int reset_num;
> };
>
> 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;
> struct resource *res;
> void __iomem *regs;
> @@ -984,8 +1066,27 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
> }
> }
>
> - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> - data->hw_onecell_data);
> + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> + data->hw_onecell_data);
> + if (ret)
> + return ret;
> +
> + /* Stop here if there is no reset */
> + if (!data->reset_num)
> + 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);
> }
>
> static const struct audioclk_data axg_audioclk_data = {
> @@ -994,6 +1095,8 @@ static const struct audioclk_data axg_audioclk_data = {
>
> static const struct audioclk_data g12a_audioclk_data = {
> .hw_onecell_data = &g12a_audio_hw_onecell_data,
> + .reset_offset = AUDIO_SW_RESET,
> + .reset_num = 26,
> };
>
> static const struct of_device_id clkc_match_table[] = {
> diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h
> index 5d972d55d6c7..c00e28b2e1a9 100644
> --- a/drivers/clk/meson/axg-audio.h
> +++ b/drivers/clk/meson/axg-audio.h
> @@ -22,6 +22,7 @@
> #define AUDIO_MCLK_F_CTRL 0x018
> #define AUDIO_MST_PAD_CTRL0 0x01c
> #define AUDIO_MST_PAD_CTRL1 0x020
> +#define AUDIO_SW_RESET 0x024
> #define AUDIO_MST_A_SCLK_CTRL0 0x040
> #define AUDIO_MST_A_SCLK_CTRL1 0x044
> #define AUDIO_MST_B_SCLK_CTRL0 0x048
>

Reviewed-by: Neil Armstrong <[email protected]>

2019-08-20 09:54:06

by Jerome Brunet

[permalink] [raw]
Subject: Re: [PATCH v2 0/2] clk: meson: axg-audio: add reset support

On Mon 12 Aug 2019 at 14:32, Jerome Brunet <[email protected]> wrote:

> This patchset adds support for the reset provided in the register space
> of the g12a audio clock controller
>
> Changes since v1 [0]:
> * Fix typo reported by Stephen
>
> [0]: https://lkml.kernel.org/r/[email protected]
>
> Jerome Brunet (2):
> dt-bindings: clock: meson: add resets to the audio clock controller
> clk: meson: axg-audio: add g12a reset support
>
> .../bindings/clock/amlogic,axg-audio-clkc.txt | 1 +
> drivers/clk/meson/axg-audio.c | 107 +++++++++++++++++-
> drivers/clk/meson/axg-audio.h | 1 +
> .../reset/amlogic,meson-g12a-audio-reset.h | 38 +++++++
> 4 files changed, 145 insertions(+), 2 deletions(-)
> create mode 100644 include/dt-bindings/reset/amlogic,meson-g12a-audio-reset.h
>

Applied

> --
> 2.21.0