[alsa-devel] [PATCH 0/9] Add audiocodec support for A64 SoC
This series adds A64 audiocodec support into sun4i-i2s, sun8i-codec and sun8i-codec-analog drivers and enables sound on Pine64 and SoPine boards.
Marcus Cooper (3): ASoC: sun4i-i2s: Add compatibility with A64 codec I2S ASoC: sun8i-codec-analog: Use callbacks to add headphones and lineout outputs ASoC: sun8i-codec-analog: Add support for A64 SoC
Vasily Khoruzhick (6): ASoC: sun4i-i2s: Add quirk to handle fixed WSS ASoC: sun8i-codec: Add quirk to specify aif1_lrck_div value ASoC: sun8i-codec: Add support for A64 SoC ASoC: sun8i-codec-analog: Add component driver field to quirks structure arm64: dts: allwinner: a64: Add nodes necessary for analog sound support arm64: dts: allwinner: a64: Enable sound on Pine64 and SoPine
.../devicetree/bindings/sound/sun4i-i2s.txt | 2 + .../bindings/sound/sun8i-codec-analog.txt | 1 + .../sound/{sun8i-a33-codec.txt => sun8i-codec.txt} | 6 +- .../arm64/boot/dts/allwinner/sun50i-a64-pine64.dts | 16 ++ .../dts/allwinner/sun50i-a64-sopine-baseboard.dts | 16 ++ arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 52 ++++ sound/soc/sunxi/Kconfig | 2 +- sound/soc/sunxi/sun4i-i2s.c | 53 +++- sound/soc/sunxi/sun8i-codec-analog.c | 307 ++++++++++++++++++--- sound/soc/sunxi/sun8i-codec.c | 47 +++- 10 files changed, 458 insertions(+), 44 deletions(-) rename Documentation/devicetree/bindings/sound/{sun8i-a33-codec.txt => sun8i-codec.txt} (91%)
I2S for audio codec on sun50i-A64 always uses fixed word select size value, no matter what is sample width. Add quirk to support that.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- sound/soc/sunxi/sun4i-i2s.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 04f92583a969..54c16eb64713 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -132,6 +132,8 @@ * @mclk_offset: Value by which mclkdiv needs to be adjusted. * @bclk_offset: Value by which bclkdiv needs to be adjusted. * @fmt_offset: Value by which wss and sr needs to be adjusted. + * @fixed_wss: Hardcoded 'word select size' value needs to be used + * @wss_value: Value to be used as WSS if fixed_wss is set * @field_clkdiv_mclk_en: regmap field to enable mclk output. * @field_fmt_wss: regmap field to set word select size. * @field_fmt_sr: regmap field to set sample resolution. @@ -150,11 +152,13 @@ struct sun4i_i2s_quirks { bool has_chcfg; bool has_chsel_tx_chen; bool has_chsel_offset; + bool fixed_wss; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; unsigned int mclk_offset; unsigned int bclk_offset; unsigned int fmt_offset; + unsigned int wss_value;
/* Register fields for i2s */ struct reg_field field_clkdiv_mclk_en; @@ -345,7 +349,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - int sr, wss, channels; + int sr, wss, channels, pwidth; u32 width;
channels = params_channels(params); @@ -386,7 +390,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, } i2s->playback_dma_data.addr_width = width;
- switch (params_width(params)) { + pwidth = params_width(params); + switch (pwidth) { case 16: sr = 0; wss = 0; @@ -396,13 +401,30 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; }
+ if (i2s->variant->fixed_wss) { + wss = i2s->variant->wss_value; + switch (wss) { + case 0: + pwidth = 16; + break; + case 1: + pwidth = 20; + break; + case 2: + pwidth = 24; + break; + case 3: + pwidth = 32; + break; + } + } + regmap_field_write(i2s->field_fmt_wss, wss + i2s->variant->fmt_offset); regmap_field_write(i2s->field_fmt_sr, sr + i2s->variant->fmt_offset);
- return sun4i_i2s_set_clk_rate(i2s, params_rate(params), - params_width(params)); + return sun4i_i2s_set_clk_rate(i2s, params_rate(params), pwidth); }
static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
Hi,
On Mon, Dec 4, 2017 at 4:41 AM, Vasily Khoruzhick anarsoul@gmail.com wrote:
I2S for audio codec on sun50i-A64 always uses fixed word select size value, no matter what is sample width. Add quirk to support that.
Please clarify on this. Does this mean the WSS bitfield is useless and it always sends out the same sample sizes regardless of the setting? Or it's the codec that can only use a fixed sample width?
As far as I can tell, the code you added in this patch points to the latter. In that case. this is the wrong way to go about it. The limitation is a property of the codec, not the I2S controller. If the codec assumes 32 bits per sample, then that is what you should setup in the code driver. See sun8i_codec_dai in sound/soc/sunxi/sun8i-codec.c where you can set the format. You'll likely need to make a copy of the data structure for A64, and tie it to the compatible.
ChenYu
From: Marcus Cooper codekipper@gmail.com
The I2S block used for the audio codec in the A64 is very similar to what is used by the A10(sun4i) devices. However, its TX FIFO is located at a different address.
[vasilykh: - added fixed_wss and wss_value to A64 quirks, - changed compatible to 'allwinner,sun50i-a64-acodec-i2s, since A64 has 3 more I2S blocks that are not compatible with audio codec I2S]
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- .../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 05d7135a8d2f..ab86f266962a 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -9,6 +9,7 @@ Required properties: - "allwinner,sun4i-a10-i2s" - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s" + - "allwinner,sun50i-a64-acodec-i2s" - reg: physical base address of the controller and length of memory mapped region. - interrupts: should contain the I2S interrupt. @@ -24,6 +25,7 @@ Required properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s" + - "allwinner,sun50i-a64-acodec-i2s" - resets: phandle to the reset line for this codec
Example: diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 54c16eb64713..2c060e015725 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -942,6 +942,25 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), };
+static const struct sun4i_i2s_quirks sun50i_a64_acodec_i2s_quirks = { + .has_reset = true, + .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, + .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, + .has_slave_select_bit = true, + .fixed_wss = true, + .wss_value = 3, + .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), + .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), + .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), + .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), + .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), + .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), + .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), + .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), + .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), + .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), +}; + static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1146,6 +1165,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, }, + { + .compatible = "allwinner,sun50i-a64-acodec-i2s", + .data = &sun50i_a64_acodec_i2s_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
On 3 December 2017 at 21:41, Vasily Khoruzhick anarsoul@gmail.com wrote:
From: Marcus Cooper codekipper@gmail.com
The I2S block used for the audio codec in the A64 is very similar to what is used by the A10(sun4i) devices. However, its TX FIFO is located at a different address.
[vasilykh: - added fixed_wss and wss_value to A64 quirks, - changed compatible to 'allwinner,sun50i-a64-acodec-i2s, since A64 has 3 more I2S blocks that are not compatible with audio codec I2S]
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
.../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 05d7135a8d2f..ab86f266962a 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -9,6 +9,7 @@ Required properties: - "allwinner,sun4i-a10-i2s" - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
- reg: physical base address of the controller and length of memory mapped region.
- interrupts: should contain the I2S interrupt.
@@ -24,6 +25,7 @@ Required properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
I would keep the compatible format the same. ie. allwinner,sun50i-a64-i2s. The A33 for example uses the sun6i-a31-i2s for it's dai.
- resets: phandle to the reset line for this codec
Example: diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 54c16eb64713..2c060e015725 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -942,6 +942,25 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), };
+static const struct sun4i_i2s_quirks sun50i_a64_acodec_i2s_quirks = {
ditto
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
.has_slave_select_bit = true,
.fixed_wss = true,
.wss_value = 3,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+};
static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1146,6 +1165,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, },
{
.compatible = "allwinner,sun50i-a64-acodec-i2s",
.data = &sun50i_a64_acodec_i2s_quirks,
ditto BR, CK
}, {}
}; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); -- 2.15.0
I'd keep it sun50i_a64_acodec_i2s, since other 3 I2S modules aren't compatible with this one, but similar to H3.
On Sun, Dec 3, 2017 at 10:42 PM, Code Kipper codekipper@gmail.com wrote:
On 3 December 2017 at 21:41, Vasily Khoruzhick anarsoul@gmail.com wrote:
From: Marcus Cooper codekipper@gmail.com
The I2S block used for the audio codec in the A64 is very similar to what is used by the A10(sun4i) devices. However, its TX FIFO is located at a different address.
[vasilykh: - added fixed_wss and wss_value to A64 quirks, - changed compatible to 'allwinner,sun50i-a64-acodec-i2s, since A64 has 3 more I2S blocks that are not compatible with audio codec I2S]
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
.../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 05d7135a8d2f..ab86f266962a 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -9,6 +9,7 @@ Required properties: - "allwinner,sun4i-a10-i2s" - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
- reg: physical base address of the controller and length of memory mapped region.
- interrupts: should contain the I2S interrupt.
@@ -24,6 +25,7 @@ Required properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
I would keep the compatible format the same. ie. allwinner,sun50i-a64-i2s. The A33 for example uses the sun6i-a31-i2s for it's dai.
- resets: phandle to the reset line for this codec
Example: diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 54c16eb64713..2c060e015725 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -942,6 +942,25 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), };
+static const struct sun4i_i2s_quirks sun50i_a64_acodec_i2s_quirks = {
ditto
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
.has_slave_select_bit = true,
.fixed_wss = true,
.wss_value = 3,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+};
static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1146,6 +1165,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, },
{
.compatible = "allwinner,sun50i-a64-acodec-i2s",
.data = &sun50i_a64_acodec_i2s_quirks,
ditto BR, CK
}, {}
}; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); -- 2.15.0
Hi,
On Sun, Dec 03, 2017 at 11:34:06PM -0800, Vasily Khoruzhick wrote:
I'd keep it sun50i_a64_acodec_i2s, since other 3 I2S modules aren't compatible with this one, but similar to H3.
Please don't top-post.
What are those differences? Maxime
On Tue, Dec 5, 2017 at 12:01 AM, Maxime Ripard maxime.ripard@free-electrons.com wrote:
Hi,
On Sun, Dec 03, 2017 at 11:34:06PM -0800, Vasily Khoruzhick wrote:
I'd keep it sun50i_a64_acodec_i2s, since other 3 I2S modules aren't compatible with this one, but similar to H3.
Please don't top-post.
What are those differences?
Different registers and their locations. Compare quirks for sun50i_a64_acodec_i2s and sun8i_h3_i2s fro details.
Maxime
-- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
On Tue, Dec 05, 2017 at 03:04:19PM -0800, Vasily Khoruzhick wrote:
On Tue, Dec 5, 2017 at 12:01 AM, Maxime Ripard maxime.ripard@free-electrons.com wrote:
Hi,
On Sun, Dec 03, 2017 at 11:34:06PM -0800, Vasily Khoruzhick wrote:
I'd keep it sun50i_a64_acodec_i2s, since other 3 I2S modules aren't compatible with this one, but similar to H3.
Please don't top-post.
What are those differences?
Different registers and their locations. Compare quirks for sun50i_a64_acodec_i2s and sun8i_h3_i2s fro details.
Whatever differences should also be mentionned in your commit log.
Maxime
On 4 December 2017 at 08:34, Vasily Khoruzhick anarsoul@gmail.com wrote:
I'd keep it sun50i_a64_acodec_i2s, since other 3 I2S modules aren't compatible with this one, but similar to H3.
Well I wouldn't and the description of it is usage is clearly stated in the devicetree for the dai.
On Sun, Dec 3, 2017 at 10:42 PM, Code Kipper codekipper@gmail.com wrote:
On 3 December 2017 at 21:41, Vasily Khoruzhick anarsoul@gmail.com wrote:
From: Marcus Cooper codekipper@gmail.com
The I2S block used for the audio codec in the A64 is very similar to what is used by the A10(sun4i) devices. However, its TX FIFO is located at a different address.
[vasilykh: - added fixed_wss and wss_value to A64 quirks, - changed compatible to 'allwinner,sun50i-a64-acodec-i2s, since A64 has 3 more I2S blocks that are not compatible with audio codec I2S]
This needs to be investigated more...I'm suspicious of the SUN8I_I2S_FMT0_LRCK_PERIOD value which is hardcoded to 0x1f. I've made this following change https://github.com/codekipper/linux-sunxi/commit/4c5fe5f5576cfbb2e1e94a99cd1... which seems to work for me but I would like to look at it with a logic analyser and test other sample depths. CK
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
.../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 05d7135a8d2f..ab86f266962a 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -9,6 +9,7 @@ Required properties: - "allwinner,sun4i-a10-i2s" - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
- reg: physical base address of the controller and length of memory mapped region.
- interrupts: should contain the I2S interrupt.
@@ -24,6 +25,7 @@ Required properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
I would keep the compatible format the same. ie. allwinner,sun50i-a64-i2s. The A33 for example uses the sun6i-a31-i2s for it's dai.
- resets: phandle to the reset line for this codec
Example: diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 54c16eb64713..2c060e015725 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -942,6 +942,25 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), };
+static const struct sun4i_i2s_quirks sun50i_a64_acodec_i2s_quirks = {
ditto
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
.has_slave_select_bit = true,
.fixed_wss = true,
.wss_value = 3,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+};
static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1146,6 +1165,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, },
{
.compatible = "allwinner,sun50i-a64-acodec-i2s",
.data = &sun50i_a64_acodec_i2s_quirks,
ditto BR, CK
}, {}
}; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); -- 2.15.0
On Thu, Dec 7, 2017 at 5:21 PM, Code Kipper codekipper@gmail.com wrote:
On 4 December 2017 at 08:34, Vasily Khoruzhick anarsoul@gmail.com wrote:
I'd keep it sun50i_a64_acodec_i2s, since other 3 I2S modules aren't compatible with this one, but similar to H3.
Well I wouldn't and the description of it is usage is clearly stated in the devicetree for the dai.
On Sun, Dec 3, 2017 at 10:42 PM, Code Kipper codekipper@gmail.com wrote:
On 3 December 2017 at 21:41, Vasily Khoruzhick anarsoul@gmail.com wrote:
From: Marcus Cooper codekipper@gmail.com
The I2S block used for the audio codec in the A64 is very similar to what is used by the A10(sun4i) devices. However, its TX FIFO is located at a different address.
[vasilykh: - added fixed_wss and wss_value to A64 quirks, - changed compatible to 'allwinner,sun50i-a64-acodec-i2s, since A64 has 3 more I2S blocks that are not compatible with audio codec I2S]
This needs to be investigated more...I'm suspicious of the SUN8I_I2S_FMT0_LRCK_PERIOD value which is hardcoded to 0x1f. I've made this following change https://github.com/codekipper/linux-sunxi/commit/4c5fe5f5576cfbb2e1e94a99cd1... which seems to work for me but I would like to look at it with a logic analyser and test other sample depths. CK
Another good reason not to have hard-coded values for things that are rightly configurable. :)
ChenYu
On Thu, Dec 7, 2017 at 1:21 AM, Code Kipper codekipper@gmail.com wrote:
On 4 December 2017 at 08:34, Vasily Khoruzhick anarsoul@gmail.com wrote:
I'd keep it sun50i_a64_acodec_i2s, since other 3 I2S modules aren't compatible with this one, but similar to H3.
Well I wouldn't and the description of it is usage is clearly stated in the devicetree for the dai.
OK, how would you name 3 other I2S modules that are present in A64?
On Sun, Dec 3, 2017 at 10:42 PM, Code Kipper codekipper@gmail.com wrote:
On 3 December 2017 at 21:41, Vasily Khoruzhick anarsoul@gmail.com wrote:
From: Marcus Cooper codekipper@gmail.com
The I2S block used for the audio codec in the A64 is very similar to what is used by the A10(sun4i) devices. However, its TX FIFO is located at a different address.
[vasilykh: - added fixed_wss and wss_value to A64 quirks, - changed compatible to 'allwinner,sun50i-a64-acodec-i2s, since A64 has 3 more I2S blocks that are not compatible with audio codec I2S]
This needs to be investigated more...I'm suspicious of the SUN8I_I2S_FMT0_LRCK_PERIOD value which is hardcoded to 0x1f. I've made this following change https://github.com/codekipper/linux-sunxi/commit/4c5fe5f5576cfbb2e1e94a99cd1... which seems to work for me but I would like to look at it with a logic analyser and test other sample depths. CK
I'm afraid it's not possible to get inside of SoC, since internal I2S pins do not go out. And other 3 I2S modules are different from one for internal codec.
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
.../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 05d7135a8d2f..ab86f266962a 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -9,6 +9,7 @@ Required properties: - "allwinner,sun4i-a10-i2s" - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
- reg: physical base address of the controller and length of memory mapped region.
- interrupts: should contain the I2S interrupt.
@@ -24,6 +25,7 @@ Required properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
I would keep the compatible format the same. ie. allwinner,sun50i-a64-i2s. The A33 for example uses the sun6i-a31-i2s for it's dai.
- resets: phandle to the reset line for this codec
Example: diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 54c16eb64713..2c060e015725 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -942,6 +942,25 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), };
+static const struct sun4i_i2s_quirks sun50i_a64_acodec_i2s_quirks = {
ditto
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
.has_slave_select_bit = true,
.fixed_wss = true,
.wss_value = 3,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+};
static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1146,6 +1165,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, },
{
.compatible = "allwinner,sun50i-a64-acodec-i2s",
.data = &sun50i_a64_acodec_i2s_quirks,
ditto BR, CK
}, {}
}; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); -- 2.15.0
On 7 December 2017 at 23:48, Vasily Khoruzhick anarsoul@gmail.com wrote:
On Thu, Dec 7, 2017 at 1:21 AM, Code Kipper codekipper@gmail.com wrote:
On 4 December 2017 at 08:34, Vasily Khoruzhick anarsoul@gmail.com wrote:
I'd keep it sun50i_a64_acodec_i2s, since other 3 I2S modules aren't compatible with this one, but similar to H3.
Well I wouldn't and the description of it is usage is clearly stated in the devicetree for the dai.
OK, how would you name 3 other I2S modules that are present in A64?
https://github.com/codekipper/linux-sunxi/commit/34f37778fbc08247e3bd1556f7e...
On Sun, Dec 3, 2017 at 10:42 PM, Code Kipper codekipper@gmail.com wrote:
On 3 December 2017 at 21:41, Vasily Khoruzhick anarsoul@gmail.com wrote:
From: Marcus Cooper codekipper@gmail.com
The I2S block used for the audio codec in the A64 is very similar to what is used by the A10(sun4i) devices. However, its TX FIFO is located at a different address.
[vasilykh: - added fixed_wss and wss_value to A64 quirks, - changed compatible to 'allwinner,sun50i-a64-acodec-i2s, since A64 has 3 more I2S blocks that are not compatible with audio codec I2S]
This needs to be investigated more...I'm suspicious of the SUN8I_I2S_FMT0_LRCK_PERIOD value which is hardcoded to 0x1f. I've made this following change https://github.com/codekipper/linux-sunxi/commit/4c5fe5f5576cfbb2e1e94a99cd1... which seems to work for me but I would like to look at it with a logic analyser and test other sample depths. CK
I'm afraid it's not possible to get inside of SoC, since internal I2S pins do not go out. And other 3 I2S modules are different from one for internal codec.
I just think this needs more of an investigation, I've git a similar patch https://github.com/codekipper/linux-sunxi/commit/282d986b6f9ed441ecdc996c6dc... which I've not delivered for that very reason. CK
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
.../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 05d7135a8d2f..ab86f266962a 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -9,6 +9,7 @@ Required properties: - "allwinner,sun4i-a10-i2s" - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
- reg: physical base address of the controller and length of memory mapped region.
- interrupts: should contain the I2S interrupt.
@@ -24,6 +25,7 @@ Required properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
I would keep the compatible format the same. ie. allwinner,sun50i-a64-i2s. The A33 for example uses the sun6i-a31-i2s for it's dai.
- resets: phandle to the reset line for this codec
Example: diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 54c16eb64713..2c060e015725 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -942,6 +942,25 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), };
+static const struct sun4i_i2s_quirks sun50i_a64_acodec_i2s_quirks = {
ditto
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
.has_slave_select_bit = true,
.fixed_wss = true,
.wss_value = 3,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+};
static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1146,6 +1165,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, },
{
.compatible = "allwinner,sun50i-a64-acodec-i2s",
.data = &sun50i_a64_acodec_i2s_quirks,
ditto BR, CK
}, {}
}; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); -- 2.15.0
On Thu, Dec 7, 2017 at 10:40 PM, Code Kipper codekipper@gmail.com wrote:
On 7 December 2017 at 23:48, Vasily Khoruzhick anarsoul@gmail.com wrote:
On Thu, Dec 7, 2017 at 1:21 AM, Code Kipper codekipper@gmail.com wrote:
On 4 December 2017 at 08:34, Vasily Khoruzhick anarsoul@gmail.com wrote:
I'd keep it sun50i_a64_acodec_i2s, since other 3 I2S modules aren't compatible with this one, but similar to H3.
Well I wouldn't and the description of it is usage is clearly stated in the devicetree for the dai.
OK, how would you name 3 other I2S modules that are present in A64?
https://github.com/codekipper/linux-sunxi/commit/34f37778fbc08247e3bd1556f7e...
On Sun, Dec 3, 2017 at 10:42 PM, Code Kipper codekipper@gmail.com wrote:
On 3 December 2017 at 21:41, Vasily Khoruzhick anarsoul@gmail.com wrote:
From: Marcus Cooper codekipper@gmail.com
The I2S block used for the audio codec in the A64 is very similar to what is used by the A10(sun4i) devices. However, its TX FIFO is located at a different address.
[vasilykh: - added fixed_wss and wss_value to A64 quirks, - changed compatible to 'allwinner,sun50i-a64-acodec-i2s, since A64 has 3 more I2S blocks that are not compatible with audio codec I2S]
This needs to be investigated more...I'm suspicious of the SUN8I_I2S_FMT0_LRCK_PERIOD value which is hardcoded to 0x1f. I've made this following change https://github.com/codekipper/linux-sunxi/commit/4c5fe5f5576cfbb2e1e94a99cd1... which seems to work for me but I would like to look at it with a logic
I tried this change and now it works fine for me as well without hardcoded WSS value. So problem was in hardcoded LRCK period. Are you OK with me submitting this patch as a part of my A64 audio series?
analyser and test other sample depths. CK
I'm afraid it's not possible to get inside of SoC, since internal I2S pins do not go out. And other 3 I2S modules are different from one for internal codec.
I just think this needs more of an investigation, I've git a similar patch https://github.com/codekipper/linux-sunxi/commit/282d986b6f9ed441ecdc996c6dc... which I've not delivered for that very reason. CK
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
.../devicetree/bindings/sound/sun4i-i2s.txt | 2 ++ sound/soc/sunxi/sun4i-i2s.c | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 05d7135a8d2f..ab86f266962a 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -9,6 +9,7 @@ Required properties: - "allwinner,sun4i-a10-i2s" - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
- reg: physical base address of the controller and length of memory mapped region.
- interrupts: should contain the I2S interrupt.
@@ -24,6 +25,7 @@ Required properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" - "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-acodec-i2s"
I would keep the compatible format the same. ie. allwinner,sun50i-a64-i2s. The A33 for example uses the sun6i-a31-i2s for it's dai.
- resets: phandle to the reset line for this codec
Example: diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 54c16eb64713..2c060e015725 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -942,6 +942,25 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), };
+static const struct sun4i_i2s_quirks sun50i_a64_acodec_i2s_quirks = {
ditto
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
.has_slave_select_bit = true,
.fixed_wss = true,
.wss_value = 3,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
.field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
.field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
.field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
.field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
+};
static int sun4i_i2s_init_regmap_fields(struct device *dev, struct sun4i_i2s *i2s) { @@ -1146,6 +1165,10 @@ static const struct of_device_id sun4i_i2s_match[] = { .compatible = "allwinner,sun8i-h3-i2s", .data = &sun8i_h3_i2s_quirks, },
{
.compatible = "allwinner,sun50i-a64-acodec-i2s",
.data = &sun50i_a64_acodec_i2s_quirks,
ditto BR, CK
}, {}
}; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); -- 2.15.0
LRCK divider for A64 differs from A33, so add a quirk to support that.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- sound/soc/sunxi/sun8i-codec.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 3dd183be08a4..054201d1de03 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -24,6 +24,7 @@ #include <linux/io.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/of_device.h>
#include <sound/pcm_params.h> #include <sound/soc.h> @@ -75,11 +76,22 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9)
+/* + * struct sun8i_codec_quirks - Differences between SoC variants. + * + * @aif1_lrck_div: LRCK divider + */ +struct sun8i_codec_quirks { + unsigned int aif1_lrck_div; +}; + + struct sun8i_codec { - struct device *dev; - struct regmap *regmap; - struct clk *clk_module; - struct clk *clk_bus; + struct device *dev; + struct regmap *regmap; + struct clk *clk_module; + struct clk *clk_bus; + const struct sun8i_codec_quirks *variant; };
static int sun8i_codec_runtime_resume(struct device *dev) @@ -305,7 +317,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, - SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16); + scodec->variant->aif1_lrck_div);
sample_rate = sun8i_codec_get_hw_rate(params); if (sample_rate < 0) @@ -440,6 +452,10 @@ static const struct regmap_config sun8i_codec_regmap_config = { .cache_type = REGCACHE_FLAT, };
+static const struct sun8i_codec_quirks sun8i_a33_codec_quirks = { + .aif1_lrck_div = SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16, +}; + static int sun8i_codec_probe(struct platform_device *pdev) { struct resource *res_base; @@ -453,6 +469,13 @@ static int sun8i_codec_probe(struct platform_device *pdev)
scodec->dev = &pdev->dev;
+ scodec->variant = of_device_get_match_data(&pdev->dev); + if (!scodec->variant) { + dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); + return -ENODEV; + } + + scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(scodec->clk_module)) { dev_err(&pdev->dev, "Failed to get the module clock\n"); @@ -524,7 +547,10 @@ static int sun8i_codec_remove(struct platform_device *pdev) }
static const struct of_device_id sun8i_codec_of_match[] = { - { .compatible = "allwinner,sun8i-a33-codec" }, + { + .compatible = "allwinner,sun8i-a33-codec", + .data = &sun8i_a33_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
On 3 December 2017 at 21:41, Vasily Khoruzhick anarsoul@gmail.com wrote:
LRCK divider for A64 differs from A33, so add a quirk to support that.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
sound/soc/sunxi/sun8i-codec.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 3dd183be08a4..054201d1de03 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -24,6 +24,7 @@ #include <linux/io.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/of_device.h>
#include <sound/pcm_params.h> #include <sound/soc.h> @@ -75,11 +76,22 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9)
+/*
- struct sun8i_codec_quirks - Differences between SoC variants.
- @aif1_lrck_div: LRCK divider
- */
+struct sun8i_codec_quirks {
unsigned int aif1_lrck_div;
+};
Extra line
struct sun8i_codec {
struct device *dev;
struct regmap *regmap;
struct clk *clk_module;
struct clk *clk_bus;
struct device *dev;
struct regmap *regmap;
struct clk *clk_module;
struct clk *clk_bus;
const struct sun8i_codec_quirks *variant;
};
static int sun8i_codec_runtime_resume(struct device *dev) @@ -305,7 +317,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
scodec->variant->aif1_lrck_div); sample_rate = sun8i_codec_get_hw_rate(params); if (sample_rate < 0)
@@ -440,6 +452,10 @@ static const struct regmap_config sun8i_codec_regmap_config = { .cache_type = REGCACHE_FLAT, };
+static const struct sun8i_codec_quirks sun8i_a33_codec_quirks = {
.aif1_lrck_div = SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16,
+};
static int sun8i_codec_probe(struct platform_device *pdev) { struct resource *res_base; @@ -453,6 +469,13 @@ static int sun8i_codec_probe(struct platform_device *pdev)
scodec->dev = &pdev->dev;
scodec->variant = of_device_get_match_data(&pdev->dev);
if (!scodec->variant) {
dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
return -ENODEV;
}
ditto
scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(scodec->clk_module)) { dev_err(&pdev->dev, "Failed to get the module clock\n");
@@ -524,7 +547,10 @@ static int sun8i_codec_remove(struct platform_device *pdev) }
static const struct of_device_id sun8i_codec_of_match[] = {
{ .compatible = "allwinner,sun8i-a33-codec" },
{
.compatible = "allwinner,sun8i-a33-codec",
.data = &sun8i_a33_codec_quirks,
}, {}
}; MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); -- 2.15.0
On Mon, Dec 4, 2017 at 4:41 AM, Vasily Khoruzhick anarsoul@gmail.com wrote:
LRCK divider for A64 differs from A33, so add a quirk to support that.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
sound/soc/sunxi/sun8i-codec.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 3dd183be08a4..054201d1de03 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -24,6 +24,7 @@ #include <linux/io.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/of_device.h>
Please keep them sorted in alphabetical order.
#include <sound/pcm_params.h> #include <sound/soc.h> @@ -75,11 +76,22 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9)
+/*
- struct sun8i_codec_quirks - Differences between SoC variants.
- @aif1_lrck_div: LRCK divider
- */
+struct sun8i_codec_quirks {
unsigned int aif1_lrck_div;
+};
struct sun8i_codec {
struct device *dev;
struct regmap *regmap;
struct clk *clk_module;
struct clk *clk_bus;
struct device *dev;
struct regmap *regmap;
struct clk *clk_module;
struct clk *clk_bus;
const struct sun8i_codec_quirks *variant;
};
static int sun8i_codec_runtime_resume(struct device *dev) @@ -305,7 +317,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
scodec->variant->aif1_lrck_div);
Hard coding a fixed divider is generally a bad idea. You adding another fixed value for this is evidence of this.
The BCK:LRCK divider is equal to sample width * 2. You should have that instead.
Also I see no evidence that either the I2S controller (see my comment on patch 1) or the codec is limited to a certain sample width in hardware, other than your claims, which are vague at best.
The user manual for both the A33 and A64 list many possible widths and dividers. If the user manual is wrong, please provide solid evidence proving it wrong.
Either way this series will not be accepted in its current form.
ChenYu
sample_rate = sun8i_codec_get_hw_rate(params); if (sample_rate < 0)
@@ -440,6 +452,10 @@ static const struct regmap_config sun8i_codec_regmap_config = { .cache_type = REGCACHE_FLAT, };
+static const struct sun8i_codec_quirks sun8i_a33_codec_quirks = {
.aif1_lrck_div = SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16,
+};
static int sun8i_codec_probe(struct platform_device *pdev) { struct resource *res_base; @@ -453,6 +469,13 @@ static int sun8i_codec_probe(struct platform_device *pdev)
scodec->dev = &pdev->dev;
scodec->variant = of_device_get_match_data(&pdev->dev);
if (!scodec->variant) {
dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
return -ENODEV;
}
scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(scodec->clk_module)) { dev_err(&pdev->dev, "Failed to get the module clock\n");
@@ -524,7 +547,10 @@ static int sun8i_codec_remove(struct platform_device *pdev) }
static const struct of_device_id sun8i_codec_of_match[] = {
{ .compatible = "allwinner,sun8i-a33-codec" },
{
.compatible = "allwinner,sun8i-a33-codec",
.data = &sun8i_a33_codec_quirks,
}, {}
}; MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); -- 2.15.0
On Mon, Dec 4, 2017 at 3:38 PM, Chen-Yu Tsai wens@csie.org wrote:
On Mon, Dec 4, 2017 at 4:41 AM, Vasily Khoruzhick anarsoul@gmail.com wrote:
LRCK divider for A64 differs from A33, so add a quirk to support that.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
sound/soc/sunxi/sun8i-codec.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 3dd183be08a4..054201d1de03 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -24,6 +24,7 @@ #include <linux/io.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/of_device.h>
Please keep them sorted in alphabetical order.
#include <sound/pcm_params.h> #include <sound/soc.h> @@ -75,11 +76,22 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9)
+/*
- struct sun8i_codec_quirks - Differences between SoC variants.
- @aif1_lrck_div: LRCK divider
- */
+struct sun8i_codec_quirks {
unsigned int aif1_lrck_div;
+};
struct sun8i_codec {
struct device *dev;
struct regmap *regmap;
struct clk *clk_module;
struct clk *clk_bus;
struct device *dev;
struct regmap *regmap;
struct clk *clk_module;
struct clk *clk_bus;
const struct sun8i_codec_quirks *variant;
};
static int sun8i_codec_runtime_resume(struct device *dev) @@ -305,7 +317,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
scodec->variant->aif1_lrck_div);
Hard coding a fixed divider is generally a bad idea. You adding another fixed value for this is evidence of this.
The BCK:LRCK divider is equal to sample width * 2. You should have that instead.
Also I see no evidence that either the I2S controller (see my comment on patch 1) or the codec is limited to a certain sample width in hardware, other than your claims, which are vague at best.
The user manual for both the A33 and A64 list many possible widths and dividers. If the user manual is wrong, please provide solid evidence proving it wrong.
Either way this series will not be accepted in its current form.
So following up on the discussion on IRC, please add the relevant information to the commit messages:
- Why is this hard-coded value needed? i.e. does it not work with standard values generated by the framework from the format value?
This is the most important part. This might also include:
* What you have done to test the non-working values
Other things worth mentioning:
- Where the hard-coded values came from?
- Why a special quirk is needed, instead of say, limiting the supported format to SNDRV_PCM_FMTBIT_S32_LE, which produces the correct wss and lrck_div values
- Anything else you think is relevant to the patch or hardware
You should also leave a comment explaining why the quirk is needed just before the code where you handle the quirks. Otherwise it makes little sense to people that don't have the context about this.
Regards ChenYu
ChenYu
sample_rate = sun8i_codec_get_hw_rate(params); if (sample_rate < 0)
@@ -440,6 +452,10 @@ static const struct regmap_config sun8i_codec_regmap_config = { .cache_type = REGCACHE_FLAT, };
+static const struct sun8i_codec_quirks sun8i_a33_codec_quirks = {
.aif1_lrck_div = SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16,
+};
static int sun8i_codec_probe(struct platform_device *pdev) { struct resource *res_base; @@ -453,6 +469,13 @@ static int sun8i_codec_probe(struct platform_device *pdev)
scodec->dev = &pdev->dev;
scodec->variant = of_device_get_match_data(&pdev->dev);
if (!scodec->variant) {
dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
return -ENODEV;
}
scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(scodec->clk_module)) { dev_err(&pdev->dev, "Failed to get the module clock\n");
@@ -524,7 +547,10 @@ static int sun8i_codec_remove(struct platform_device *pdev) }
static const struct of_device_id sun8i_codec_of_match[] = {
{ .compatible = "allwinner,sun8i-a33-codec" },
{
.compatible = "allwinner,sun8i-a33-codec",
.data = &sun8i_a33_codec_quirks,
}, {}
}; MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); -- 2.15.0
Digital part of audio codec block in the A64 is very similar to what is used by the A33(sun8i) devices. However, it uses different LRCK divider.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- .../bindings/sound/{sun8i-a33-codec.txt => sun8i-codec.txt} | 6 ++++-- sound/soc/sunxi/sun8i-codec.c | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) rename Documentation/devicetree/bindings/sound/{sun8i-a33-codec.txt => sun8i-codec.txt} (91%)
diff --git a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt b/Documentation/devicetree/bindings/sound/sun8i-codec.txt similarity index 91% rename from Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt rename to Documentation/devicetree/bindings/sound/sun8i-codec.txt index 2ca3d138528e..ffcf9079a67c 100644 --- a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun8i-codec.txt @@ -1,7 +1,7 @@ Allwinner SUN8I audio codec ------------------------------------
-On Sun8i-A33 SoCs, the audio is separated in different parts: +On Sun8i-A33 and Sun50i-A64 SoCs, the audio is separated in different parts: - A DAI driver. It uses the "sun4i-i2s" driver which is documented here: Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -16,7 +16,9 @@ On Sun8i-A33 SoCs, the audio is separated in different parts: This bindings documentation exposes Sun8i codec (digital part).
Required properties: -- compatible: must be "allwinner,sun8i-a33-codec" +- compatible: should be one of the following: + - "allwinner,sun8i-a33-codec" + - "allwinner,sun50i-a64-codec" - reg: must contain the registers location and length - interrupts: must contain the codec interrupt - clocks: a list of phandle + clock-specifer pairs, one for each entry diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 054201d1de03..0e2a5adcfb96 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -52,6 +52,7 @@ #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16 (1 << 6) +#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_64 (2 << 6) #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4) #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 @@ -456,6 +457,10 @@ static const struct sun8i_codec_quirks sun8i_a33_codec_quirks = { .aif1_lrck_div = SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16, };
+static const struct sun8i_codec_quirks sun50i_a64_codec_quirks = { + .aif1_lrck_div = SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_64, +}; + static int sun8i_codec_probe(struct platform_device *pdev) { struct resource *res_base; @@ -551,6 +556,10 @@ static const struct of_device_id sun8i_codec_of_match[] = { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_codec_quirks, }, + { + .compatible = "allwinner,sun50i-a64-codec", + .data = &sun50i_a64_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
On Sun, Dec 03, 2017 at 12:41:52PM -0800, Vasily Khoruzhick wrote:
Digital part of audio codec block in the A64 is very similar to what is used by the A33(sun8i) devices. However, it uses different LRCK divider.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
What makes it impossible to derive from the sample rate and number of channels?
Have you tried other sampling rates?
Maxime
On Tue, Dec 5, 2017 at 12:04 AM, Maxime Ripard maxime.ripard@free-electrons.com wrote:
On Sun, Dec 03, 2017 at 12:41:52PM -0800, Vasily Khoruzhick wrote:
Digital part of audio codec block in the A64 is very similar to what is used by the A33(sun8i) devices. However, it uses different LRCK divider.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
What makes it impossible to derive from the sample rate and number of channels?
It's BCLK / LRCK ratio as per A64 user manual, so it doesn't depend on sample rate. BSP driver always uses a fixed value of 64 here.
Have you tried other sampling rates?
I tried speaker-test with a number of sampling rates and had no issues. I couldn't try it in mono, since sun4i-i2s supports minimum of 2 channels.
Maxime
-- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
On Tue, Dec 05, 2017 at 03:17:39PM -0800, Vasily Khoruzhick wrote:
On Tue, Dec 5, 2017 at 12:04 AM, Maxime Ripard maxime.ripard@free-electrons.com wrote:
On Sun, Dec 03, 2017 at 12:41:52PM -0800, Vasily Khoruzhick wrote:
Digital part of audio codec block in the A64 is very similar to what is used by the A33(sun8i) devices. However, it uses different LRCK divider.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
What makes it impossible to derive from the sample rate and number of channels?
It's BCLK / LRCK ratio as per A64 user manual, so it doesn't depend on sample rate. BSP driver always uses a fixed value of 64 here.
Well, it kind of does.
BCLK is sample rate * sample size * channels, and LRCK is running at the sample rate. So the ratio is the sample size * channels.
Anything deviating from those standard i2s concepts should at least be documented, with arguments to back them off.
Maxime
On Wed, Dec 06, 2017 at 04:32:05PM +0100, Maxime Ripard wrote:
BCLK is sample rate * sample size * channels, and LRCK is running at the sample rate. So the ratio is the sample size * channels.
Anything deviating from those standard i2s concepts should at least be documented, with arguments to back them off.
BCLK can be higher than the minimum there in most formats, though some hardware is more restrictive so we tend to go for the minimum clock rate.
On Wed, Dec 06, 2017 at 03:48:10PM +0000, Mark Brown wrote:
On Wed, Dec 06, 2017 at 04:32:05PM +0100, Maxime Ripard wrote:
BCLK is sample rate * sample size * channels, and LRCK is running at the sample rate. So the ratio is the sample size * channels.
Anything deviating from those standard i2s concepts should at least be documented, with arguments to back them off.
BCLK can be higher than the minimum there in most formats, though some hardware is more restrictive so we tend to go for the minimum clock rate.
How does that work in such a case? Is LRCK faster as well, and we're keeping the same ratio, or will the codec buffer the current sample until the next word?
Is it usually a property of the codec or the DAI?
Thanks! Maxime
On Wed, Dec 06, 2017 at 07:53:08PM +0100, Maxime Ripard wrote:
On Wed, Dec 06, 2017 at 03:48:10PM +0000, Mark Brown wrote:
BCLK can be higher than the minimum there in most formats, though some hardware is more restrictive so we tend to go for the minimum clock rate.
How does that work in such a case? Is LRCK faster as well, and we're keeping the same ratio, or will the codec buffer the current sample until the next word?
No, the extra clock cycles just get ignored - most of the formats define the location of the data in terms of LRCLK edges, any extra BCLK edges shouldn't do anything.
Is it usually a property of the codec or the DAI?
Things that require extra cycles for some reason tend to be CODECs, but this can also be done just because whatever the clock master is doesn't have very flexible dividers.
From: Marcus Cooper codekipper@gmail.com
Widgets for headphones and lineout outputs on A64 are different enough and use different regs, so move addition of these outputs into callback to simplify upcoming A64 support.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com Signed-off-by: Marcus Cooper codekipper@gmail.com --- sound/soc/sunxi/sun8i-codec-analog.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 485e79f292c4..384f582b6f69 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -397,7 +397,7 @@ static const struct snd_soc_dapm_route sun8i_codec_mixer_routes[] = {
/* headphone specific controls, widgets, and routes */ static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1); -static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = { +static const struct snd_kcontrol_new sun8i_a23_codec_hp_ctrls[] = { SOC_SINGLE_TLV("Headphone Playback Volume", SUN8I_ADDA_HP_VOLC, SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0, @@ -447,7 +447,7 @@ static int sun8i_headphone_amp_event(struct snd_soc_dapm_widget *w, return 0; }
-static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = { +static const struct snd_soc_dapm_widget sun8i_a23_codec_hp_widgets[] = { SND_SOC_DAPM_MUX("Headphone Source Playback Route", SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src), SND_SOC_DAPM_OUT_DRV_E("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL, @@ -471,22 +471,24 @@ static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = { { "HP", NULL, "Headphone Amp" }, };
-static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt) +static int sun8i_a23_codec_add_headphone(struct snd_soc_component *cmpnt) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); struct device *dev = cmpnt->dev; int ret;
ret = snd_soc_add_component_controls(cmpnt, - sun8i_codec_headphone_controls, - ARRAY_SIZE(sun8i_codec_headphone_controls)); + sun8i_a23_codec_hp_ctrls, + ARRAY_SIZE( + sun8i_a23_codec_hp_ctrls)); if (ret) { dev_err(dev, "Failed to add Headphone controls: %d\n", ret); return ret; }
- ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets, - ARRAY_SIZE(sun8i_codec_headphone_widgets)); + ret = snd_soc_dapm_new_controls(dapm, + sun8i_a23_codec_hp_widgets, + ARRAY_SIZE(sun8i_a23_codec_hp_widgets)); if (ret) { dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret); return ret; @@ -604,6 +606,7 @@ static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale, 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), ); + static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = { SOC_SINGLE_TLV("Line Out Playback Volume", SUN8I_ADDA_PHONE_GAIN_CTRL, @@ -648,7 +651,7 @@ static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = { { "LINEOUT", NULL, "Line Out Enable", }, };
-static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt) +static int sun8i_h3_codec_add_lineout(struct snd_soc_component *cmpnt) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); struct device *dev = cmpnt->dev; @@ -751,6 +754,9 @@ struct sun8i_codec_analog_quirks { bool has_lineout; bool has_mbias; bool has_mic2; + const struct snd_soc_component_driver *cmpnt_drv; + int (*add_headphone)(struct snd_soc_component *cmpnt); + int (*add_lineout)(struct snd_soc_component *cmpnt); };
static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { @@ -759,6 +765,7 @@ static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { .has_linein = true, .has_mbias = true, .has_mic2 = true, + .add_headphone = sun8i_a23_codec_add_headphone, };
static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { @@ -766,8 +773,10 @@ static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { .has_lineout = true, .has_mbias = true, .has_mic2 = true, + .add_lineout = sun8i_h3_codec_add_lineout, };
+ static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt, const struct sun8i_codec_analog_quirks *quirks) { @@ -834,7 +843,7 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) return ret;
if (quirks->has_headphone) { - ret = sun8i_codec_add_headphone(cmpnt); + ret = quirks->add_headphone(cmpnt); if (ret) return ret; } @@ -852,7 +861,7 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) }
if (quirks->has_lineout) { - ret = sun8i_codec_add_lineout(cmpnt); + ret = quirks->add_lineout(cmpnt); if (ret) return ret; }
This is necessary for upcoming addition of A64 support. A64 uses the same DAPM routes, but slightly different widgets. Use approach from sun4i-codec driver and pass appropriate component driver through quirks.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- sound/soc/sunxi/sun8i-codec-analog.c | 57 +++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 24 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 384f582b6f69..4e39d2668286 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -759,24 +759,6 @@ struct sun8i_codec_analog_quirks { int (*add_lineout)(struct snd_soc_component *cmpnt); };
-static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { - .has_headphone = true, - .has_hmic = true, - .has_linein = true, - .has_mbias = true, - .has_mic2 = true, - .add_headphone = sun8i_a23_codec_add_headphone, -}; - -static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { - .has_linein = true, - .has_lineout = true, - .has_mbias = true, - .has_mic2 = true, - .add_lineout = sun8i_h3_codec_add_lineout, -}; - - static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt, const struct sun8i_codec_analog_quirks *quirks) { @@ -819,11 +801,6 @@ static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt, return 0; }
-static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = { - .has_headphone = true, - .has_hmic = true, -}; - static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) { struct device *dev = cmpnt->dev; @@ -891,6 +868,31 @@ static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = { .probe = sun8i_codec_analog_cmpnt_probe, };
+static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { + .has_headphone = true, + .has_hmic = true, + .has_linein = true, + .has_mbias = true, + .has_mic2 = true, + .add_headphone = sun8i_a23_codec_add_headphone, + .cmpnt_drv = &sun8i_codec_analog_cmpnt_drv, +}; + +static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { + .has_linein = true, + .has_lineout = true, + .has_mbias = true, + .has_mic2 = true, + .add_lineout = sun8i_h3_codec_add_lineout, + .cmpnt_drv = &sun8i_codec_analog_cmpnt_drv, +}; + +static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = { + .has_headphone = true, + .has_hmic = true, + .cmpnt_drv = &sun8i_codec_analog_cmpnt_drv, +}; + static const struct of_device_id sun8i_codec_analog_of_match[] = { { .compatible = "allwinner,sun8i-a23-codec-analog", @@ -913,6 +915,13 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev) struct resource *res; struct regmap *regmap; void __iomem *base; + const struct sun8i_codec_analog_quirks *quirks; + + quirks = of_device_get_match_data(&pdev->dev); + if (quirks == NULL) { + dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); + return -ENODEV; + }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); @@ -928,7 +937,7 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev) }
return devm_snd_soc_register_component(&pdev->dev, - &sun8i_codec_analog_cmpnt_drv, + quirks->cmpnt_drv, NULL, 0); }
From: Marcus Cooper codekipper@gmail.com
Analog part of audiocodec is very similar to other codecs supports by this driver, but has different registers
Signed-off-by: Marcus Cooper codekipper@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- .../bindings/sound/sun8i-codec-analog.txt | 1 + sound/soc/sunxi/Kconfig | 2 +- sound/soc/sunxi/sun8i-codec-analog.c | 227 +++++++++++++++++++++ 3 files changed, 229 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt index 07356758bd91..f38896850e4d 100644 --- a/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt +++ b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt @@ -5,6 +5,7 @@ Required properties: - "allwinner,sun8i-a23-codec-analog" - "allwinner,sun8i-h3-codec-analog" - "allwinner,sun8i-v3s-codec-analog" + - "allwinner,sun50i-a64-codec-analog"
Required properties if not a sub-node of the PRCM node: - reg: must contain the registers location and length diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 22408bc2d6ec..26072b74e47f 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -12,7 +12,7 @@ config SND_SUN4I_CODEC config SND_SUN8I_CODEC tristate "Allwinner SUN8I audio codec" depends on OF - depends on MACH_SUN8I || COMPILE_TEST + depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST select REGMAP_MMIO help This option enables the digital part of the internal audio codec for diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 4e39d2668286..adb7fe087c73 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -30,6 +30,7 @@ /* Codec analog control register offsets and bit fields */ #define SUN8I_ADDA_HP_VOLC 0x00 #define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7 +#define SUN50I_ADDA_HP_VOLC_HPPAEN 6 #define SUN8I_ADDA_HP_VOLC_HP_VOL 0 #define SUN8I_ADDA_LOMIXSC 0x01 #define SUN8I_ADDA_LOMIXSC_MIC1 6 @@ -48,6 +49,7 @@ #define SUN8I_ADDA_ROMIXSC_DACR 1 #define SUN8I_ADDA_ROMIXSC_DACL 0 #define SUN8I_ADDA_DAC_PA_SRC 0x03 +#define SUN50I_ADDA_DAC_PA_SRC 0x0a #define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7 #define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6 #define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5 @@ -62,9 +64,16 @@ #define SUN8I_ADDA_LINEIN_GCTRL 0x05 #define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4 #define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0 +#define SUN50I_ADDA_LINEOUT_CTRL0 0x05 +#define SUN50I_ADDA_LINEOUT_CTRL0_LEN 7 +#define SUN50I_ADDA_LINEOUT_CTRL0_REN 6 +#define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL 5 +#define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL 4 #define SUN8I_ADDA_MICIN_GCTRL 0x06 #define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4 #define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0 +#define SUN50I_ADDA_LINEOUT_CTRL1 0x06 +#define SUN50I_ADDA_LINEOUT_CTRL1_VOL 0 #define SUN8I_ADDA_PAEN_HP_CTRL 0x07 #define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7 #define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */ @@ -364,6 +373,61 @@ static const struct snd_soc_dapm_widget sun8i_v3s_codec_mixer_widgets[] = { ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)), };
+static const struct snd_soc_dapm_widget sun50i_codec_common_widgets[] = { + /* ADC */ + SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0), + SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0), + + /* DAC */ + SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0), + SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0), + /* + * Due to this component and the codec belonging to separate DAPM + * contexts, we need to manually link the above widgets to their + * stream widgets at the card level. + */ + + /* Line In */ + SND_SOC_DAPM_INPUT("LINEIN"), + + /* Microphone inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN, + 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0), + + /* Mixers */ + SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, + sun8i_codec_mixer_controls, + ARRAY_SIZE(sun8i_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0, + sun8i_codec_mixer_controls, + ARRAY_SIZE(sun8i_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0, + sun8i_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0, + sun8i_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), +}; + static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { /* Microphone Routes */ { "Mic1 Amplifier", NULL, "MIC1"}, @@ -408,6 +472,17 @@ static const struct snd_kcontrol_new sun8i_a23_codec_hp_ctrls[] = { SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0), };
+static const struct snd_kcontrol_new sun50i_a64_codec_hp_ctrls[] = { + SOC_SINGLE_TLV("Headphone Playback Volume", + SUN8I_ADDA_HP_VOLC, + SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0, + sun8i_codec_hp_vol_scale), + SOC_DOUBLE("Headphone Playback Switch", + SUN50I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE, + SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0), +}; + static const char * const sun8i_codec_hp_src_enum_text[] = { "DAC", "Mixer", }; @@ -461,6 +536,14 @@ static const struct snd_soc_dapm_widget sun8i_a23_codec_hp_widgets[] = { SND_SOC_DAPM_OUTPUT("HP"), };
+static const struct snd_soc_dapm_widget sun50i_a64_codec_hp_widgets[] = { + SND_SOC_DAPM_MUX("Headphone Source Playback Route", + SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src), + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_HP_VOLC, + SUN50I_ADDA_HP_VOLC_HPPAEN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("HP"), +}; + static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = { { "Headphone Source Playback Route", "DAC", "Left DAC" }, { "Headphone Source Playback Route", "DAC", "Right DAC" }, @@ -471,6 +554,15 @@ static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = { { "HP", NULL, "Headphone Amp" }, };
+static const struct snd_soc_dapm_route sun50i_codec_headphone_routes[] = { + { "Headphone Source Playback Route", "DAC", "Left DAC" }, + { "Headphone Source Playback Route", "DAC", "Right DAC" }, + { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, + { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, + { "Headphone Amp", NULL, "Headphone Source Playback Route" }, + { "HP", NULL, "Headphone Amp" }, +}; + static int sun8i_a23_codec_add_headphone(struct snd_soc_component *cmpnt) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); @@ -525,6 +617,41 @@ static int sun8i_codec_add_mbias(struct snd_soc_component *cmpnt) return ret; }
+static int sun50i_a64_codec_add_headphone(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun50i_a64_codec_hp_ctrls, + ARRAY_SIZE( + sun50i_a64_codec_hp_ctrls)); + if (ret) { + dev_err(dev, "Failed to add Headphone controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, + sun50i_a64_codec_hp_widgets, + ARRAY_SIZE( + sun50i_a64_codec_hp_widgets)); + if (ret) { + dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun50i_codec_headphone_routes, + ARRAY_SIZE( + sun50i_codec_headphone_routes)); + if (ret) { + dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + /* hmic specific widget */ static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = { SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, @@ -618,6 +745,17 @@ static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = { SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0), };
+static const struct snd_kcontrol_new sun50i_codec_lineout_ctrls[] = { + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN50I_ADDA_LINEOUT_CTRL1, + SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0, + sun8i_codec_lineout_vol_scale), + SOC_DOUBLE("Line Out Playback Switch", + SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_REN, + SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0), +}; + static const char * const sun8i_codec_lineout_src_enum_text[] = { "Stereo", "Mono Differential", }; @@ -628,11 +766,22 @@ static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum, SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC, sun8i_codec_lineout_src_enum_text);
+static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum, + SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL, + SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL, + sun8i_codec_lineout_src_enum_text); + static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = { SOC_DAPM_ENUM("Line Out Source Playback Route", sun8i_codec_lineout_src_enum), };
+static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun50i_codec_lineout_src_enum), +}; + static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = { SND_SOC_DAPM_MUX("Line Out Source Playback Route", SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src), @@ -642,6 +791,17 @@ static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = { SND_SOC_DAPM_OUTPUT("LINEOUT"), };
+static const struct snd_soc_dapm_widget sun50i_codec_lineout_widgets[] = { + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src), + /* It is unclear if this is a buffer or gate, model it as a supply */ + SND_SOC_DAPM_SUPPLY("Left Line Out Enable", SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_LEN, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Right Line Out Enable", SUN50I_ADDA_LINEOUT_CTRL0, + SUN50I_ADDA_LINEOUT_CTRL0_REN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("LINEOUT"), +}; + static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = { { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, @@ -651,6 +811,17 @@ static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = { { "LINEOUT", NULL, "Line Out Enable", }, };
+static const struct snd_soc_dapm_route sun50i_codec_lineout_routes[] = { + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", + "Right Mixer" }, + { "LINEOUT", NULL, "Line Out Source Playback Route" }, + { "LINEOUT", NULL, "Left Line Out Enable", }, + { "LINEOUT", NULL, "Right Line Out Enable", }, +}; + static int sun8i_h3_codec_add_lineout(struct snd_soc_component *cmpnt) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); @@ -747,6 +918,39 @@ static int sun8i_codec_add_mic2(struct snd_soc_component *cmpnt) return 0; }
+static int sun50i_a64_codec_add_lineout(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun50i_codec_lineout_ctrls, + ARRAY_SIZE( + sun50i_codec_lineout_ctrls)); + if (ret) { + dev_err(dev, "Failed to add Line Out controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, sun50i_codec_lineout_widgets, + ARRAY_SIZE( + sun50i_codec_lineout_widgets)); + if (ret) { + dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun50i_codec_lineout_routes, + ARRAY_SIZE(sun50i_codec_lineout_routes)); + if (ret) { + dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + struct sun8i_codec_analog_quirks { bool has_headphone; bool has_hmic; @@ -868,6 +1072,16 @@ static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = { .probe = sun8i_codec_analog_cmpnt_probe, };
+static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { + .controls = sun8i_codec_common_controls, + .num_controls = ARRAY_SIZE(sun8i_codec_common_controls), + .dapm_widgets = sun50i_codec_common_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun50i_codec_common_widgets), + .dapm_routes = sun8i_codec_common_routes, + .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes), + .probe = sun8i_codec_analog_cmpnt_probe, +}; + static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { .has_headphone = true, .has_hmic = true, @@ -893,6 +1107,15 @@ static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = { .cmpnt_drv = &sun8i_codec_analog_cmpnt_drv, };
+static const struct sun8i_codec_analog_quirks sun50i_a64_quirks = { + .has_headphone = true, + .has_hmic = false, + .has_lineout = true, + .add_headphone = sun50i_a64_codec_add_headphone, + .add_lineout = sun50i_a64_codec_add_lineout, + .cmpnt_drv = &sun50i_codec_analog_cmpnt_drv, +}; + static const struct of_device_id sun8i_codec_analog_of_match[] = { { .compatible = "allwinner,sun8i-a23-codec-analog", @@ -906,6 +1129,10 @@ static const struct of_device_id sun8i_codec_analog_of_match[] = { .compatible = "allwinner,sun8i-v3s-codec-analog", .data = &sun8i_v3s_quirks, }, + { + .compatible = "allwinner,sun50i-a64-codec-analog", + .data = &sun50i_a64_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
Add nodes for i2s, digital and analog parts of audiocodec on A64
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index d783d164b9c3..504f16e3d92d 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -112,6 +112,28 @@ method = "smc"; };
+ sound: sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "SUN50i Audio Card"; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&cpudai>; + simple-audio-card,bitclock-master = <&cpudai>; + simple-audio-card,mclk-fs = <512>; + simple-audio-card,aux-devs = <&codec_analog>; + simple-audio-card,routing = + "Left DAC", "AIF1 Slot 0 Left", + "Right DAC", "AIF1 Slot 0 Right"; + status = "disabled"; + + cpudai: simple-audio-card,cpu { + sound-dai = <&dai>; + }; + + link_codec: simple-audio-card,codec { + sound-dai = <&codec>; + }; + }; + timer { compatible = "arm,armv8-timer"; interrupts = <GIC_PPI 13 @@ -382,6 +404,30 @@ }; };
+ dai: dai@1c22c00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun50i-a64-acodec-i2s"; + reg = <0x01c22c00 0x200>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "apb", "mod"; + resets = <&ccu RST_BUS_CODEC>; + reset-names = "rst"; + dmas = <&dma 15>, <&dma 15>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + codec: codec@1c22e00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun50i-a64-codec"; + reg = <0x01c22e00 0x600>; + interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "bus", "mod"; + status = "disabled"; + }; + uart0: serial@1c28000 { compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; @@ -563,6 +609,12 @@ #reset-cells = <1>; };
+ codec_analog: codec-analog@1f015c0 { + compatible = "allwinner,sun50i-a64-codec-analog"; + reg = <0x01f015c0 0x4>; + status = "disabled"; + }; + r_pio: pinctrl@1f02c00 { compatible = "allwinner,sun50i-a64-r-pinctrl"; reg = <0x01f02c00 0x400>;
This commit enables I2S, digital and analog parts of audiocodec on Pine64 and SoPine boards.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts | 16 ++++++++++++++++ .../boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts | 16 ++++++++++++++++ 2 files changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts index 806442d3e846..369d9b749521 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts @@ -64,6 +64,18 @@ }; };
+&codec { + status = "okay"; +}; + +&codec_analog { + status = "okay"; +}; + +&dai { + status = "okay"; +}; + &ehci0 { status = "okay"; }; @@ -229,6 +241,10 @@ regulator-name = "vcc-rtc"; };
+&sound { + status = "okay"; +}; + /* On Exp and Euler connectors */ &uart0 { pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts index 0eb2acedf8c3..9de5ddcc3656 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts @@ -69,6 +69,18 @@ }; };
+&codec { + status = "okay"; +}; + +&codec_analog { + status = "okay"; +}; + +&dai { + status = "okay"; +}; + &ehci0 { status = "okay"; }; @@ -133,6 +145,10 @@ regulator-name = "vcc-wifi"; };
+&sound { + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>;
On Mon, Dec 4, 2017 at 4:41 AM, Vasily Khoruzhick anarsoul@gmail.com wrote:
This commit enables I2S, digital and analog parts of audiocodec on Pine64 and SoPine boards.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts | 16 ++++++++++++++++ .../boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts | 16 ++++++++++++++++ 2 files changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts index 806442d3e846..369d9b749521 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts @@ -64,6 +64,18 @@ }; };
+&codec {
status = "okay";
+};
+&codec_analog {
status = "okay";
+};
+&dai {
status = "okay";
+};
&ehci0 { status = "okay"; }; @@ -229,6 +241,10 @@ regulator-name = "vcc-rtc"; };
+&sound {
status = "okay";
This is missing all the board level widgets and routing. Yes I know that it works right now, but that's because simple-card isn't a strict card, i.e. it doesn't force the need for actual inputs and outputs at both ends of the DAPM graph.
Later on you'll find that missing the routing leaves the microphone unusable, because the microphone bias is not turned on.
ChenYu
+};
/* On Exp and Euler connectors */ &uart0 { pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts index 0eb2acedf8c3..9de5ddcc3656 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts @@ -69,6 +69,18 @@ }; };
+&codec {
status = "okay";
+};
+&codec_analog {
status = "okay";
+};
+&dai {
status = "okay";
+};
&ehci0 { status = "okay"; }; @@ -133,6 +145,10 @@ regulator-name = "vcc-wifi"; };
+&sound {
status = "okay";
+};
&uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; -- 2.15.0
On Mon, Dec 4, 2017 at 7:24 PM, Chen-Yu Tsai wens@csie.org wrote:
On Mon, Dec 4, 2017 at 4:41 AM, Vasily Khoruzhick anarsoul@gmail.com wrote:
This commit enables I2S, digital and analog parts of audiocodec on Pine64 and SoPine boards.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts | 16 ++++++++++++++++ .../boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts | 16 ++++++++++++++++ 2 files changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts index 806442d3e846..369d9b749521 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts @@ -64,6 +64,18 @@ }; };
+&codec {
status = "okay";
+};
+&codec_analog {
status = "okay";
+};
+&dai {
status = "okay";
+};
&ehci0 { status = "okay"; }; @@ -229,6 +241,10 @@ regulator-name = "vcc-rtc"; };
+&sound {
status = "okay";
This is missing all the board level widgets and routing. Yes I know that it works right now, but that's because simple-card isn't a strict card, i.e. it doesn't force the need for actual inputs and outputs at both ends of the DAPM graph.
Later on you'll find that missing the routing leaves the microphone unusable, because the microphone bias is not turned on.
sun8i-codec driver doesn't support capture at the moment. What else it could be missing?
ChenYu
+};
/* On Exp and Euler connectors */ &uart0 { pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts index 0eb2acedf8c3..9de5ddcc3656 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts @@ -69,6 +69,18 @@ }; };
+&codec {
status = "okay";
+};
+&codec_analog {
status = "okay";
+};
+&dai {
status = "okay";
+};
&ehci0 { status = "okay"; }; @@ -133,6 +145,10 @@ regulator-name = "vcc-wifi"; };
+&sound {
status = "okay";
+};
&uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; -- 2.15.0
participants (5)
-
Chen-Yu Tsai
-
Code Kipper
-
Mark Brown
-
Maxime Ripard
-
Vasily Khoruzhick