diff mbox series

[3/7] clk: meson: add triple phase clock driver

Message ID 20180425163304.10852-4-jbrunet@baylibre.com
State Accepted
Commit e8dd9207763e0317ac256c78dcd50dca7826f2f6
Headers show
Series [1/7] clk: meson: clean-up meson clock configuration | expand

Commit Message

Jerome Brunet April 25, 2018, 4:33 p.m. UTC
Add a driver to control the output of the sample clock generator found
in the axg audio clock controller.

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

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>

---
 drivers/clk/meson/Kconfig        |  5 +++
 drivers/clk/meson/Makefile       |  1 +
 drivers/clk/meson/clk-triphase.c | 68 ++++++++++++++++++++++++++++++++++++++++
 drivers/clk/meson/clkc-audio.h   | 20 ++++++++++++
 4 files changed, 94 insertions(+)
 create mode 100644 drivers/clk/meson/clk-triphase.c
 create mode 100644 drivers/clk/meson/clkc-audio.h

-- 
2.14.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Neil Armstrong April 26, 2018, 8:50 a.m. UTC | #1
On 26/04/2018 10:47, Neil Armstrong wrote:
> On 25/04/2018 18:33, Jerome Brunet wrote:

>> Add a driver to control the output of the sample clock generator found

>> in the axg audio clock controller.

>>

>> The goal of this driver is to coherently control the phase provided to

>> the different element using the sample clock generator. This simplify

>> the usage of the sample clock generator a lot, without comprising the

>> ability of the SoC.

>>

>> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>

>> ---

>>  drivers/clk/meson/Kconfig        |  5 +++

>>  drivers/clk/meson/Makefile       |  1 +

>>  drivers/clk/meson/clk-triphase.c | 68 ++++++++++++++++++++++++++++++++++++++++

>>  drivers/clk/meson/clkc-audio.h   | 20 ++++++++++++

>>  4 files changed, 94 insertions(+)

>>  create mode 100644 drivers/clk/meson/clk-triphase.c

>>  create mode 100644 drivers/clk/meson/clkc-audio.h

>>

>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig

>> index 87d69573e172..7f7fd6fb3809 100644

>> --- a/drivers/clk/meson/Kconfig

>> +++ b/drivers/clk/meson/Kconfig

>> @@ -3,6 +3,11 @@ config COMMON_CLK_AMLOGIC

>>  	depends on ARCH_MESON || COMPILE_TEST

>>  	select COMMON_CLK_REGMAP_MESON

>>  

>> +config COMMON_CLK_AMLOGIC_AUDIO

>> +	bool

>> +	depends on ARCH_MESON || COMPILE_TEST

>> +	select COMMON_CLK_AMLOGIC

>> +

>>  config COMMON_CLK_REGMAP_MESON

>>  	bool

>>  	select REGMAP

>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile

>> index 352fb848c406..64bb917fe1f0 100644

>> --- a/drivers/clk/meson/Makefile

>> +++ b/drivers/clk/meson/Makefile

>> @@ -4,6 +4,7 @@

>>  

>>  obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o

>>  obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-phase.o

>> +obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO)	+= clk-triphase.o

>>  obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o

>>  obj-$(CONFIG_COMMON_CLK_GXBB)	 += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o

>>  obj-$(CONFIG_COMMON_CLK_AXG)	 += axg.o

>> diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c

>> new file mode 100644

>> index 000000000000..9508c03c73c1

>> --- /dev/null

>> +++ b/drivers/clk/meson/clk-triphase.c

>> @@ -0,0 +1,68 @@

>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)

>> +/*

>> + * Copyright (c) 2018 BayLibre, SAS.

>> + * Author: Jerome Brunet <jbrunet@baylibre.com>

>> + */

>> +

>> +#include <linux/clk-provider.h>

>> +#include "clkc-audio.h"

>> +

>> +/*

>> + * This is a special clock for the audio controller.

>> + * The phase of mst_sclk clock output can be controlled independently

>> + * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2).

>> + * Controlling these 3 phases as just one makes things simpler and

>> + * give the same clock view to all the element on the i2s bus.

>> + * If necessary, we can still control the phase in the tdm block

>> + * which makes these independent control redundant.

>> + */

>> +static inline struct meson_clk_triphase_data *

>> +meson_clk_triphase_data(struct clk_regmap *clk)

>> +{

>> +	return (struct meson_clk_triphase_data *)clk->data;

>> +}

>> +

>> +static void meson_clk_triphase_sync(struct clk_hw *hw)

>> +{

>> +	struct clk_regmap *clk = to_clk_regmap(hw);

>> +	struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);

>> +	unsigned int val;

>> +

>> +	/* Get phase 0 and sync it to phase 1 and 2 */

>> +	val = meson_parm_read(clk->map, &tph->ph0);

>> +	meson_parm_write(clk->map, &tph->ph1, val);

>> +	meson_parm_write(clk->map, &tph->ph2, val);

>> +}

>> +

>> +static int meson_clk_triphase_get_phase(struct clk_hw *hw)

>> +{

>> +	struct clk_regmap *clk = to_clk_regmap(hw);

>> +	struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);

>> +	unsigned int val;

>> +

>> +	/* Phase are in sync, reading phase 0 is enough */

>> +	val = meson_parm_read(clk->map, &tph->ph0);

>> +

>> +	return meson_clk_degrees_from_val(val, tph->ph0.width);

>> +}

>> +

>> +static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees)

>> +{

>> +	struct clk_regmap *clk = to_clk_regmap(hw);

>> +	struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);

>> +	unsigned int val;

>> +

>> +	val = meson_clk_degrees_to_val(degrees, tph->ph0.width);

>> +	meson_parm_write(clk->map, &tph->ph0, val);

>> +	meson_parm_write(clk->map, &tph->ph1, val);

>> +	meson_parm_write(clk->map, &tph->ph2, val);

>> +

>> +	return 0;

>> +}

>> +

>> +const struct clk_ops meson_clk_triphase_ops = {

>> +	.init		= meson_clk_triphase_sync,

>> +	.get_phase	= meson_clk_triphase_get_phase,

>> +	.set_phase	= meson_clk_triphase_set_phase,

>> +};

>> +EXPORT_SYMBOL_GPL(meson_clk_triphase_ops);

>> diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h

>> new file mode 100644

>> index 000000000000..286ff1201258

>> --- /dev/null

>> +++ b/drivers/clk/meson/clkc-audio.h

>> @@ -0,0 +1,20 @@

>> +/* SPDX-License-Identifier: GPL-2.0 */

> 

> // SPDX-License-Identifier: GPL-2.0

> 

> Checkpatch should have warned about this !


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

> 

>> +/*

>> + * Copyright (c) 2018 BayLibre, SAS.

>> + * Author: Jerome Brunet <jbrunet@baylibre.com>

>> + */

>> +

>> +#ifndef __MESON_CLKC_AUDIO_H

>> +#define __MESON_CLKC_AUDIO_H

>> +

>> +#include "clkc.h"

>> +

>> +struct meson_clk_triphase_data {

>> +	struct parm ph0;

>> +	struct parm ph1;

>> +	struct parm ph2;

>> +};

>> +

>> +extern const struct clk_ops meson_clk_triphase_ops;

>> +

>> +#endif /* __MESON_CLKC_AUDIO_H */

>>

> 

> Apart that :

> 

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

> 


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox series

Patch

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