[alsa-devel] [PATCH v3 0/8] Add sun8i A33 audio driver
Hello everyone,
This a V3 of my Allwinner A33 (sun8i) audio codec driver. Tested on linux-next-20170131 tag.
Changes since V2: - Removed patches from v2 already merged: commit ebad64d193779 ("ASoC: sun4i-i2s: Increase DMA max burst to 8") commit 603a0c8af9cb2 ("clk: sunxi-ng: a33: Add CLK_SET_RATE_PARENT to ac-dig") - Removed "reset-names" from sun4i-i2s driver - Fixed the build warning from sun8i-codec - Fixed some various topics such as subject line for dt bindings patch, renamed the simple-card and disabled the simple-card.
Changes since V1: - Remove the analog codec driver as a better version has been committed by Chen-Yu Tsai and is already merged. - Remove the audio-card as simple-card can be used - The DMA maxburst is set to 8 in the sun4i-i2s instead of adding the maxburst of 4 in Sun6i dma engine. - Create a new compatible for sun4i-i2s to handle the reset line. - Fix various problems in sun8i-codec driver according to V1's reviews - Add the pm_runtime hooks in sun8i-codec driver to prepare/ unprepare clocks. - Update the DTS according to Chen-Yu's analog codec driver. - Rename sun8i-codec's clocks to "bus" and "mod" - The first "delay" issue from V1 is fixed by using a delay when enabling the headphone amplifier to let the amplifier being up.
Patches 1 and 2 add a new compatible "allwinner,sun6i-a31-i2s" to handle the reset line for sun4i-i2s driver. It uses a quirk to use a version with or without reset lines.
Patch 3 adds the sun8i codec driver which represents the digital part of the A33 codec. It supports only playback features.
Path 4 fixes the previous issue of a "first time delay" in V1 (see cover letter). Do not hesitate if you have comments on this patch.
Patches 5 adds the dt-bindings documentation for new audio driver added in this serie (sun8i-codec).
Patch 6 adds the cpu DAI, codec and audio nodes to sun8i-a33 device tree.
Patches 7 and 8 enable the audio on Parrot and Sinlinx's boards.
The DAI for this A33 codec is the same than for A20: "sun4i-i2s". Currently, the sun8i-a33 codec driver handles only the playback feature. The other ones (such as capture) and all other interfaces except headphone are not supported. I will send a patch to handle the capture with microphones in next few weeks.
Examples of amixer commands: amixer set 'Headphone' 75% amixer set 'Headphone' on amixer set 'DAC' on amixer set 'Right DAC Mixer RSlot 0' on amixer set 'Left DAC Mixer LSlot 0' on
It was tested on Parrot and Sinlinx boards.
Let me know if you have any comments on this serie.
Thank you in advance, Best regards,
Mylène Josserand (8): ASoC: sun4i-i2s: Update binding documentation to include A31 ASoC: sun4i-i2s: Add quirks to handle a31 compatible ASoC: Add sun8i digital audio codec ASoC: sun8i-codec-analog: Add amplifier event to fix first delay ASoC: codecs: Add sun8i-a33 binding documentation ARM: dts: sun8i: Add audio codec, dai and card for A33 ARM: dts: sun8i: parrot: Enable audio nodes ARM: dts: sun8i: sinlinx: Enable audio nodes
.../devicetree/bindings/sound/sun4i-i2s.txt | 5 + .../devicetree/bindings/sound/sun8i-a33-codec.txt | 75 ++++ arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts | 12 + arch/arm/boot/dts/sun8i-a33.dtsi | 45 ++ arch/arm/boot/dts/sun8i-r16-parrot.dts | 12 + sound/soc/sunxi/Kconfig | 11 + sound/soc/sunxi/Makefile | 1 + sound/soc/sunxi/sun4i-i2s.c | 57 ++- sound/soc/sunxi/sun8i-codec-analog.c | 30 +- sound/soc/sunxi/sun8i-codec.c | 499 +++++++++++++++++++++ 10 files changed, 743 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt create mode 100644 sound/soc/sunxi/sun8i-codec.c
Add a new compatible for sun4i-i2s driver to handle some SoCs that have a reset line that must be asserted/deasserted.
This new compatible, "allwinner,sun6i-a31-i2s", requires the property "resets" which should be a phandle to the reset line. Except these differences, the compatible is identical to previous one which will not handle a reset line.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com --- Documentation/devicetree/bindings/sound/sun4i-i2s.txt | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 7a2c0945fd22..b71df552bc0c 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -7,6 +7,7 @@ Required properties:
- compatible: should be one of the following: - "allwinner,sun4i-a10-i2s" + - "allwinner,sun6i-a31-i2s" - reg: physical base address of the controller and length of memory mapped region. - interrupts: should contain the I2S interrupt. @@ -19,6 +20,10 @@ Required properties: - "mod" : module clock for the I2S controller - #sound-dai-cells : Must be equal to 0
+Required properties for the following compatibles: + - "allwinner,sun6i-a31-i2s" +- resets: phandle to the reset line for this codec + Example:
i2s0: i2s@01c22400 {
On Tue, Jan 31, 2017 at 11:05:45AM +0100, Mylène Josserand wrote:
Add a new compatible for sun4i-i2s driver to handle some SoCs that have a reset line that must be asserted/deasserted.
This new compatible, "allwinner,sun6i-a31-i2s", requires the property "resets" which should be a phandle to the reset line. Except these differences, the compatible is identical to previous one which will not handle a reset line.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com
Acked-by: Maxime Ripard maxime.ripard@free-electrons.com
Thanks, Maxime
On Tue, Jan 31, 2017 at 11:05:45AM +0100, Mylène Josserand wrote:
Add a new compatible for sun4i-i2s driver to handle some SoCs that have a reset line that must be asserted/deasserted.
This doesn't apply against current code, please check and resend.
Hello,
On 31/01/2017 22:17, Mark Brown wrote:
On Tue, Jan 31, 2017 at 11:05:45AM +0100, Mylène Josserand wrote:
Add a new compatible for sun4i-i2s driver to handle some SoCs that have a reset line that must be asserted/deasserted.
This doesn't apply against current code, please check and resend.
I based my series on linux-next 20170131. Which one I should use?
Thank you in advance,
Best regards,
On Wed, Feb 01, 2017 at 08:44:56AM +0100, Mylene Josserand wrote:
On 31/01/2017 22:17, Mark Brown wrote:
On Tue, Jan 31, 2017 at 11:05:45AM +0100, Mylène Josserand wrote:
Add a new compatible for sun4i-i2s driver to handle some SoCs that have a reset line that must be asserted/deasserted.
This doesn't apply against current code, please check and resend.
I based my series on linux-next 20170131. Which one I should use?
You should be submitting against my git tree (which should be what's in -next...).
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Hi,
On 01/02/2017 12:59, Mark Brown wrote:
On Wed, Feb 01, 2017 at 08:44:56AM +0100, Mylene Josserand wrote:
On 31/01/2017 22:17, Mark Brown wrote:
On Tue, Jan 31, 2017 at 11:05:45AM +0100, Mylène Josserand wrote:
Add a new compatible for sun4i-i2s driver to handle some SoCs that have a reset line that must be asserted/deasserted.
This doesn't apply against current code, please check and resend.
I based my series on linux-next 20170131. Which one I should use?
You should be submitting against my git tree (which should be what's in -next...).
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Okay, thank you! I will update my series according to your branch.
Best regards,
On Tue, Jan 31, 2017 at 11:05:45AM +0100, Mylène Josserand wrote:
Add a new compatible for sun4i-i2s driver to handle some SoCs that have a reset line that must be asserted/deasserted.
This new compatible, "allwinner,sun6i-a31-i2s", requires the property "resets" which should be a phandle to the reset line. Except these differences, the compatible is identical to previous one which will not handle a reset line.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com
Documentation/devicetree/bindings/sound/sun4i-i2s.txt | 5 +++++ 1 file changed, 5 insertions(+)
Acked-by: Rob Herring robh@kernel.org
Some SoCs have a reset line that must be asserted/deasserted. This patch adds a quirk to handle the new compatible "allwinner,sun6i-a31-i2s" which will deassert the reset line on probe function and assert it on remove's one.
This new compatible is useful in case of A33 codec driver, for example.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com --- sound/soc/sunxi/sun4i-i2s.c | 57 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 4237323ef594..3635bbc72cbc 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -14,9 +14,11 @@ #include <linux/clk.h> #include <linux/dmaengine.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/reset.h>
#include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h> @@ -92,6 +94,7 @@ struct sun4i_i2s { struct clk *bus_clk; struct clk *mod_clk; struct regmap *regmap; + struct reset_control *rst;
unsigned int mclk_freq;
@@ -651,9 +654,22 @@ static int sun4i_i2s_runtime_suspend(struct device *dev) return 0; }
+struct sun4i_i2s_quirks { + bool has_reset; +}; + +static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { + .has_reset = false, +}; + +static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { + .has_reset = true, +}; + static int sun4i_i2s_probe(struct platform_device *pdev) { struct sun4i_i2s *i2s; + const struct sun4i_i2s_quirks *quirks; struct resource *res; void __iomem *regs; int irq, ret; @@ -674,6 +690,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev) return irq; }
+ quirks = of_device_get_match_data(&pdev->dev); + if (!quirks) { + dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); + return -ENODEV; + } + i2s->bus_clk = devm_clk_get(&pdev->dev, "apb"); if (IS_ERR(i2s->bus_clk)) { dev_err(&pdev->dev, "Can't get our bus clock\n"); @@ -692,7 +714,24 @@ static int sun4i_i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Can't get our mod clock\n"); return PTR_ERR(i2s->mod_clk); } - + + if (quirks->has_reset) { + i2s->rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(i2s->rst)) { + dev_err(&pdev->dev, "Failed to get reset control\n"); + return PTR_ERR(i2s->rst); + } + } + + if (!IS_ERR(i2s->rst)) { + ret = reset_control_deassert(i2s->rst); + if (ret) { + dev_err(&pdev->dev, + "Failed to deassert the reset control\n"); + return -EINVAL; + } + } + i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; i2s->playback_dma_data.maxburst = 8;
@@ -727,23 +766,37 @@ static int sun4i_i2s_probe(struct platform_device *pdev) sun4i_i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); + if (!IS_ERR(i2s->rst)) + reset_control_assert(i2s->rst);
return ret; }
static int sun4i_i2s_remove(struct platform_device *pdev) { + struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev); + snd_dmaengine_pcm_unregister(&pdev->dev);
pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) sun4i_i2s_runtime_suspend(&pdev->dev);
+ if (!IS_ERR(i2s->rst)) + reset_control_assert(i2s->rst); + return 0; }
static const struct of_device_id sun4i_i2s_match[] = { - { .compatible = "allwinner,sun4i-a10-i2s", }, + { + .compatible = "allwinner,sun4i-a10-i2s", + .data = &sun4i_a10_i2s_quirks, + }, + { + .compatible = "allwinner,sun6i-a31-i2s", + .data = &sun6i_a31_i2s_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
On Tue, Jan 31, 2017 at 11:05:46AM +0100, Mylène Josserand wrote:
Some SoCs have a reset line that must be asserted/deasserted. This patch adds a quirk to handle the new compatible "allwinner,sun6i-a31-i2s" which will deassert the reset line on probe function and assert it on remove's one.
This new compatible is useful in case of A33 codec driver, for example.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com
Acked-by: Maxime Ripard maxime.ripard@free-electrons.com
Maxime
Add the sun8i audio codec which handles the digital register of A33 codec. The driver handles only the basic playback from the DAC to headphones. All other features (microphone, capture, etc) will be added later.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com --- sound/soc/sunxi/Kconfig | 11 + sound/soc/sunxi/Makefile | 1 + sound/soc/sunxi/sun8i-codec.c | 499 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 511 insertions(+) create mode 100644 sound/soc/sunxi/sun8i-codec.c
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 6c344e16aca4..13a8267f17c7 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -9,6 +9,17 @@ config SND_SUN4I_CODEC Select Y or M to add support for the Codec embedded in the Allwinner A10 and affiliated SoCs.
+config SND_SUN8I_CODEC + tristate "Allwinner SUN8I audio codec" + depends on OF + depends on MACH_SUN8I || COMPILE_TEST + select REGMAP_MMIO + help + This option enables the digital part of the internal audio codec for + Allwinner sun8i SoC (and particularly A33). + + Say Y or M if you want to add sun8i digital audio codec support. + config SND_SUN8I_CODEC_ANALOG tristate "Allwinner sun8i Codec Analog Controls Support" depends on MACH_SUN8I || COMPILE_TEST diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index 241c0df9ca0c..1f1af6271731 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o +obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c new file mode 100644 index 000000000000..27fede54671b --- /dev/null +++ b/sound/soc/sunxi/sun8i-codec.c @@ -0,0 +1,499 @@ +/* + * This driver supports the digital controls for the internal codec + * found in Allwinner's A33 SoCs. + * + * (C) Copyright 2010-2016 + * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com> + * huangxin huangxin@Reuuimllatech.com + * Mylène Josserand mylene.josserand@free-electrons.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> + +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#define SUN8I_SYSCLK_CTL 0x00c +#define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11 +#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL 9 +#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC 8 +#define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3 +#define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0 +#define SUN8I_MOD_CLK_ENA 0x010 +#define SUN8I_MOD_CLK_ENA_AIF1 15 +#define SUN8I_MOD_CLK_ENA_DAC 2 +#define SUN8I_MOD_RST_CTL 0x014 +#define SUN8I_MOD_RST_CTL_AIF1 15 +#define SUN8I_MOD_RST_CTL_DAC 2 +#define SUN8I_SYS_SR_CTRL 0x018 +#define SUN8I_SYS_SR_CTRL_AIF1_FS 12 +#define SUN8I_SYS_SR_CTRL_AIF2_FS 8 +#define SUN8I_AIF1CLK_CTRL 0x040 +#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD 15 +#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV 14 +#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13 +#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_WORD_SIZ 4 +#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4) +#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2 +#define SUN8I_AIF1_DACDAT_CTRL 0x048 +#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15 +#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14 +#define SUN8I_DAC_DIG_CTRL 0x120 +#define SUN8I_DAC_DIG_CTRL_ENDA 15 +#define SUN8I_DAC_MXR_SRC 0x130 +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15 +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14 +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13 +#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12 +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11 +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10 +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9 +#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8 + +#define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12) +#define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8) +#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4) +#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6) + +struct sun8i_codec { + struct device *dev; + struct regmap *regmap; + struct clk *clk_module; + struct clk *clk_bus; +}; + +static int sun8i_codec_runtime_resume(struct device *dev) +{ + struct sun8i_codec *scodec = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(scodec->clk_module); + if (ret) { + dev_err(dev, "Failed to enable the module clock\n"); + return ret; + } + + ret = clk_prepare_enable(scodec->clk_bus); + if (ret) { + dev_err(dev, "Failed to enable the bus clock\n"); + goto err_disable_modclk; + } + + regcache_cache_only(scodec->regmap, false); + + ret = regcache_sync(scodec->regmap); + if (ret) { + dev_err(dev, "Failed to sync regmap cache\n"); + goto err_disable_clk; + } + + return 0; + +err_disable_clk: + clk_disable_unprepare(scodec->clk_bus); + +err_disable_modclk: + clk_disable_unprepare(scodec->clk_module); + + return ret; +} + +static int sun8i_codec_runtime_suspend(struct device *dev) +{ + struct sun8i_codec *scodec = dev_get_drvdata(dev); + + regcache_cache_only(scodec->regmap, true); + regcache_mark_dirty(scodec->regmap); + + clk_disable_unprepare(scodec->clk_module); + clk_disable_unprepare(scodec->clk_bus); + + return 0; +} + +static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params) +{ + unsigned int rate = params_rate(params); + + switch (rate) { + case 8000: + case 7350: + return 0x0; + case 11025: + return 0x1; + case 12000: + return 0x2; + case 16000: + return 0x3; + case 22050: + return 0x4; + case 24000: + return 0x5; + case 32000: + return 0x6; + case 44100: + return 0x7; + case 48000: + return 0x8; + case 96000: + return 0x9; + case 192000: + return 0xa; + default: + return -EINVAL; + } +} + +static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec); + u32 value; + + /* clock masters */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: /* DAI Slave */ + value = 0x0; /* Codec Master */ + break; + case SND_SOC_DAIFMT_CBM_CFM: /* DAI Master */ + value = 0x1; /* Codec Slave */ + break; + default: + return -EINVAL; + } + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, + BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD), + value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD); + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: /* Normal */ + value = 0x0; + break; + case SND_SOC_DAIFMT_IB_IF: /* Inversion */ + value = 0x1; + break; + default: + return -EINVAL; + } + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, + BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV), + value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV); + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, + BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV), + value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV); + + /* DAI format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + value = 0x0; + break; + case SND_SOC_DAIFMT_LEFT_J: + value = 0x1; + break; + case SND_SOC_DAIFMT_RIGHT_J: + value = 0x2; + break; + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + value = 0x3; + break; + default: + return -EINVAL; + } + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, + BIT(SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT), + value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT); + + return 0; +} + +static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec); + int sample_rate; + + /* + * The CPU DAI handles only a sample of 16 bits. Configure the + * codec to handle this type of sample resolution. + */ + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, + SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK, + SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16); + + regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL, + SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK, + SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16); + + sample_rate = sun8i_codec_get_hw_rate(params); + if (sample_rate < 0) + return sample_rate; + + regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, + SUN8I_SYS_SR_CTRL_AIF1_FS_MASK, + sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS); + regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, + SUN8I_SYS_SR_CTRL_AIF2_FS_MASK, + sample_rate << SUN8I_SYS_SR_CTRL_AIF2_FS); + + return 0; +} + +static const struct snd_kcontrol_new sun8i_output_left_mixer_controls[] = { + SOC_DAPM_SINGLE("LSlot 0", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L, 1, 0), + SOC_DAPM_SINGLE("LSlot 1", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L, 1, 0), + SOC_DAPM_SINGLE("DACL", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL, 1, 0), + SOC_DAPM_SINGLE("ADCL", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL, 1, 0), +}; + +static const struct snd_kcontrol_new sun8i_output_right_mixer_controls[] = { + SOC_DAPM_SINGLE("RSlot 0", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0), + SOC_DAPM_SINGLE("RSlot 1", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0), + SOC_DAPM_SINGLE("DACR", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0), + SOC_DAPM_SINGLE("ADCR", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { + /* Digital parts of the DACs */ + SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA, + 0, NULL, 0), + + /* Analog DAC */ + SND_SOC_DAPM_DAC("Digital Left DAC", "Playback", SUN8I_AIF1_DACDAT_CTRL, + SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), + SND_SOC_DAPM_DAC("Digital Right DAC", "Playback", SUN8I_AIF1_DACDAT_CTRL, + SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), + + /* DAC Mixers */ + SND_SOC_DAPM_MIXER("Left DAC Mixer", SND_SOC_NOPM, 0, 0, + sun8i_output_left_mixer_controls, + ARRAY_SIZE(sun8i_output_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right DAC Mixer", SND_SOC_NOPM, 0, 0, + sun8i_output_right_mixer_controls, + ARRAY_SIZE(sun8i_output_right_mixer_controls)), + + /* Clocks */ + SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA, + SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA, + SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("AIF1", SUN8I_SYSCLK_CTL, + SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL, + SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("AIF1 PLL", SUN8I_SYSCLK_CTL, + SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL, 0, NULL, 0), + /* Inversion as 0=AIF1, 1=AIF2 */ + SND_SOC_DAPM_SUPPLY("SYSCLK AIF1", SUN8I_SYSCLK_CTL, + SUN8I_SYSCLK_CTL_SYSCLK_SRC, 1, NULL, 0), + + /* Module reset */ + SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL, + SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL, + SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("HP"), +}; + +static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { + /* Clock Routes */ + { "AIF1", NULL, "SYSCLK AIF1" }, + { "AIF1 PLL", NULL, "AIF1" }, + { "RST AIF1", NULL, "AIF1 PLL" }, + { "MODCLK AFI1", NULL, "RST AIF1" }, + { "DAC", NULL, "MODCLK AFI1" }, + + { "RST DAC", NULL, "SYSCLK" }, + { "MODCLK DAC", NULL, "RST DAC" }, + { "DAC", NULL, "MODCLK DAC" }, + + /* DAC Routes */ + { "Digital Left DAC", NULL, "DAC" }, + { "Digital Right DAC", NULL, "DAC" }, + + /* DAC Mixer Routes */ + { "Left DAC Mixer", "LSlot 0", "Digital Left DAC"}, + { "Right DAC Mixer", "RSlot 0", "Digital Right DAC"}, + + /* End of route : HP out */ + { "HP", NULL, "Left DAC Mixer" }, + { "HP", NULL, "Right DAC Mixer" }, +}; + +static struct snd_soc_dai_ops sun8i_codec_dai_ops = { + .hw_params = sun8i_codec_hw_params, + .set_fmt = sun8i_set_fmt, +}; + +static struct snd_soc_dai_driver sun8i_codec_dai = { + .name = "sun8i", + /* playback capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + /* pcm operations */ + .ops = &sun8i_codec_dai_ops, +}; + +static struct snd_soc_codec_driver sun8i_soc_codec = { + .component_driver = { + .dapm_widgets = sun8i_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), + .dapm_routes = sun8i_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes), + }, +}; + +static const struct regmap_config sun8i_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN8I_DAC_MXR_SRC, + + .cache_type = REGCACHE_FLAT, +}; + +static int sun8i_codec_probe(struct platform_device *pdev) +{ + struct resource *res_base; + struct sun8i_codec *scodec; + void __iomem *base; + int ret; + + scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL); + if (!scodec) + return -ENOMEM; + + scodec->dev = &pdev->dev; + + 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"); + return PTR_ERR(scodec->clk_module); + } + + scodec->clk_bus = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(scodec->clk_bus)) { + dev_err(&pdev->dev, "Failed to get the bus clock\n"); + return PTR_ERR(scodec->clk_bus); + } + + res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res_base); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed to map the registers\n"); + return PTR_ERR(base); + } + + scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &sun8i_codec_regmap_config); + if (IS_ERR(scodec->regmap)) { + dev_err(&pdev->dev, "Failed to create our regmap\n"); + return PTR_ERR(scodec->regmap); + } + + platform_set_drvdata(pdev, scodec); + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = sun8i_codec_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + ret = snd_soc_register_codec(&pdev->dev, &sun8i_soc_codec, + &sun8i_codec_dai, 1); + if (ret) { + dev_err(&pdev->dev, "Failed to register codec\n"); + goto err_suspend; + } + + return ret; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + sun8i_codec_runtime_suspend(&pdev->dev); + +err_pm_disable: + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int sun8i_codec_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct sun8i_codec *scodec = snd_soc_card_get_drvdata(card); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + sun8i_codec_runtime_suspend(&pdev->dev); + + snd_soc_unregister_codec(&pdev->dev); + clk_disable_unprepare(scodec->clk_module); + clk_disable_unprepare(scodec->clk_bus); + + return 0; +} + +static const struct of_device_id sun8i_codec_of_match[] = { + { .compatible = "allwinner,sun8i-a33-codec" }, + {} +}; +MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); + +static const struct dev_pm_ops sun8i_codec_pm_ops = { + SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend, + sun8i_codec_runtime_resume, NULL) +}; + +static struct platform_driver sun8i_codec_driver = { + .driver = { + .name = "sun8i-codec", + .owner = THIS_MODULE, + .of_match_table = sun8i_codec_of_match, + .pm = &sun8i_codec_pm_ops, + }, + .probe = sun8i_codec_probe, + .remove = sun8i_codec_remove, +}; +module_platform_driver(sun8i_codec_driver); + +MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver"); +MODULE_AUTHOR("Mylène Josserand mylene.josserand@free-electrons.com"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sun8i-codec");
On Tue, Jan 31, 2017 at 11:05:47AM +0100, Mylène Josserand wrote:
Add the sun8i audio codec which handles the digital register of A33 codec. The driver handles only the basic playback from the DAC to headphones. All other features (microphone, capture, etc) will be added later.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com
Acked-by: Maxime Ripard maxime.ripard@free-electrons.com
Maxime
sound/soc/sunxi/sun8i-codec.c:487:3-8: No need to set .owner here. The core will do it.
Remove .owner field if calls are used which set it automatically
Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci
CC: Mylène Josserand mylene.josserand@free-electrons.com Signed-off-by: Fengguang Wu fengguang.wu@intel.com ---
sun8i-codec.c | 1 - 1 file changed, 1 deletion(-)
--- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -484,7 +484,6 @@ static const struct dev_pm_ops sun8i_cod static struct platform_driver sun8i_codec_driver = { .driver = { .name = "sun8i-codec", - .owner = THIS_MODULE, .of_match_table = sun8i_codec_of_match, .pm = &sun8i_codec_pm_ops, },
Hi Mylène,
[auto build test WARNING on next-20170130] [also build test WARNING on v4.10-rc6] [cannot apply to asoc/for-next robh/for-next mripard/sunxi/for-next v4.9-rc8 v4.9-rc7 v4.9-rc6] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Myl-ne-Josserand/Add-sun8i-A33-audi...
coccinelle warnings: (new ones prefixed by >>)
sound/soc/sunxi/sun8i-codec.c:487:3-8: No need to set .owner here. The core will do it.
Please review and possibly fold the followup patch.
--- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
When playing a sound for the first time, a short delay, where the audio file is not played, can be noticed. On a second play (right after), the sound is played correctly. If we wait a short time (~5 sec which corresponds to the aplay timeout), the delay is back.
This patch fixes it by using an event on headphone amplifier. It allows to keep the amplifier enable while playing a sound. A delay of 700ms allows to wait that the amplifier is powered-up before playing the sound.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com --- sound/soc/sunxi/sun8i-codec-analog.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index af02290ebe49..72331332b72e 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -398,11 +398,37 @@ static const struct snd_kcontrol_new sun8i_codec_hp_src[] = { sun8i_codec_hp_src_enum), };
+static int sun8i_headphone_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL, + BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN), + BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN)); + /* + * Need a delay to have the amplifier up. 700ms seems the best + * compromise between the time to let the amplifier up and the + * time not to feel this delay while playing a sound. + */ + msleep(700); + } else if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL, + BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN), + 0x0); + } + + return 0; +} + static const struct snd_soc_dapm_widget sun8i_codec_headphone_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_PAEN_HP_CTRL, - SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV_E("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL, + SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0, + sun8i_headphone_amp_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL, SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0), SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL,
On Tue, Jan 31, 2017 at 11:05:48AM +0100, Mylène Josserand wrote:
When playing a sound for the first time, a short delay, where the audio file is not played, can be noticed. On a second play (right after), the sound is played correctly. If we wait a short time (~5 sec which corresponds to the aplay timeout), the delay is back.
This patch fixes it by using an event on headphone amplifier. It allows to keep the amplifier enable while playing a sound. A delay of 700ms allows to wait that the amplifier is powered-up before playing the sound.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com
Acked-by: Maxime Ripard maxime.ripard@free-electrons.com
Maxime
Add the documentation for dt-binding of the digital audio codec driver and the audio card driver for Sun8i-a33 SoCs.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com --- .../devicetree/bindings/sound/sun8i-a33-codec.txt | 75 ++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt
diff --git a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt b/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt new file mode 100644 index 000000000000..2425c74bce7e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt @@ -0,0 +1,75 @@ +Allwinner SUN8I audio codec +------------------------------------ + +On Sun8i-A33 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 + - An analog part of the codec which is handled as PRCM registers. + See Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt + - An digital part of the codec which is documented in this current + binding documentation. + - And finally, an audio card which links all the above components. + The simple-audio card will be used. + See Documentation/devicetree/bindings/sound/simple-card.txt + +This bindings documentation exposes Sun8i codec (digital part). + +Required properties: +- compatible: must be "allwinner,sun8i-a33-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 + in clock-names. +- clock-names: should contain followings: + - "bus": the parent APB clock for this controller + - "mod": the parent module clock + +Example: +codec: codec@01c22e00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a33-codec"; + reg = <0x01c22e00 0x400>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "bus", "mod"; + status = "disabled"; +}; + +Here is an example to add a sound card and the codec binding on sun8i SoCs that +are similar to A33 using simple-card: + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "sun8i-a33-audio"; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&link_codec>; + simple-audio-card,bitclock-master = <&link_codec>; + simple-audio-card,mclk-fs = <512>; + simple-audio-card,aux-devs = <&codec_analog>; + simple-audio-card,routing = + "Left DAC", "Digital Left DAC", + "Right DAC", "Digital Right DAC"; + + simple-audio-card,cpu { + sound-dai = <&dai>; + }; + + link_codec: simple-audio-card,codec { + sound-dai = <&codec>; + }; + + soc@01c00000 { + [...] + + codec: codec@01c22e00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a33-codec"; + reg = <0x01c22e00 0x400>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "bus", "mod"; + status = "disabled"; + }; + }; +
On Tue, Jan 31, 2017 at 11:05:49AM +0100, Mylène Josserand wrote:
Add the documentation for dt-binding of the digital audio codec driver and the audio card driver for Sun8i-a33 SoCs.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com
Acked-by: Maxime Ripard maxime.ripard@free-electrons.com
Maxime
On Tue, Jan 31, 2017 at 11:05:49AM +0100, Mylène Josserand wrote:
Add the documentation for dt-binding of the digital audio codec driver and the audio card driver for Sun8i-a33 SoCs.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com
.../devicetree/bindings/sound/sun8i-a33-codec.txt | 75 ++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt
diff --git a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt b/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt new file mode 100644 index 000000000000..2425c74bce7e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt @@ -0,0 +1,75 @@ +Allwinner SUN8I audio codec +------------------------------------
+On Sun8i-A33 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
- An analog part of the codec which is handled as PRCM registers.
See Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
- An digital part of the codec which is documented in this current
binding documentation.
- And finally, an audio card which links all the above components.
The simple-audio card will be used.
See Documentation/devicetree/bindings/sound/simple-card.txt
+This bindings documentation exposes Sun8i codec (digital part).
+Required properties: +- compatible: must be "allwinner,sun8i-a33-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
- in clock-names.
+- clock-names: should contain followings:
- "bus": the parent APB clock for this controller
- "mod": the parent module clock
+Example: +codec: codec@01c22e00 {
This is redundant with the full example below.
- #sound-dai-cells = <0>;
- compatible = "allwinner,sun8i-a33-codec";
- reg = <0x01c22e00 0x400>;
- interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
- clock-names = "bus", "mod";
- status = "disabled";
+};
+Here is an example to add a sound card and the codec binding on sun8i SoCs that +are similar to A33 using simple-card:
- sound {
compatible = "simple-audio-card";
simple-audio-card,name = "sun8i-a33-audio";
simple-audio-card,format = "i2s";
simple-audio-card,frame-master = <&link_codec>;
simple-audio-card,bitclock-master = <&link_codec>;
simple-audio-card,mclk-fs = <512>;
simple-audio-card,aux-devs = <&codec_analog>;
simple-audio-card,routing =
"Left DAC", "Digital Left DAC",
"Right DAC", "Digital Right DAC";
simple-audio-card,cpu {
sound-dai = <&dai>;
};
link_codec: simple-audio-card,codec {
sound-dai = <&codec>;
};
- soc@01c00000 {
[...]
codec: codec@01c22e00 {
audio-codec@... and drop the leading 0.
#sound-dai-cells = <0>;
compatible = "allwinner,sun8i-a33-codec";
reg = <0x01c22e00 0x400>;
interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
clock-names = "bus", "mod";
status = "disabled";
Drop status from examples.
};
- };
-- 2.11.0
Add the audio codec, dai and a simple card to be able to use the audio stream of the builtin codec on sun8i SoC.
This commit adds also an audio-routing for the sound card node to link the analog DAPM widgets (Right/Left DAC) and the digital one's as they are created in different drivers.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com --- arch/arm/boot/dts/sun8i-a33.dtsi | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi index 5a9ba43ccb07..18c174fef84f 100644 --- a/arch/arm/boot/dts/sun8i-a33.dtsi +++ b/arch/arm/boot/dts/sun8i-a33.dtsi @@ -104,6 +104,28 @@ reg = <0x40000000 0x80000000>; };
+ sound: sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "sun8i-a33-audio"; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&link_codec>; + simple-audio-card,bitclock-master = <&link_codec>; + simple-audio-card,mclk-fs = <512>; + simple-audio-card,aux-devs = <&codec_analog>; + simple-audio-card,routing = + "Left DAC", "Digital Left DAC", + "Right DAC", "Digital Right DAC"; + status = "disabled"; + + simple-audio-card,cpu { + sound-dai = <&dai>; + }; + + link_codec: simple-audio-card,codec { + sound-dai = <&codec>; + }; + }; + soc@01c00000 { tcon0: lcd-controller@01c0c000 { compatible = "allwinner,sun8i-a33-tcon"; @@ -151,6 +173,29 @@ reset-names = "ahb"; };
+ dai: dai@01c22c00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun6i-a31-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>; + dmas = <&dma 15>, <&dma 15>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + codec: codec@01c22e00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a33-codec"; + reg = <0x01c22e00 0x400>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "bus", "mod"; + status = "disabled"; + }; + fe0: display-frontend@01e00000 { compatible = "allwinner,sun8i-a33-display-frontend"; reg = <0x01e00000 0x20000>;
Enable the audio codec and the audio dai for the sun8i R16 Parrot board.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com --- arch/arm/boot/dts/sun8i-r16-parrot.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-r16-parrot.dts b/arch/arm/boot/dts/sun8i-r16-parrot.dts index e4da572427b1..472c03b7aeab 100644 --- a/arch/arm/boot/dts/sun8i-r16-parrot.dts +++ b/arch/arm/boot/dts/sun8i-r16-parrot.dts @@ -84,6 +84,14 @@
};
+&codec { + status = "okay"; +}; + +&dai { + status = "okay"; +}; + &ehci0 { status = "okay"; }; @@ -317,6 +325,10 @@ status = "okay"; };
+&sound { + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_b>;
Enable the audio codec and the audio dai for the sun8i A33 sinlinx board.
Signed-off-by: Mylène Josserand mylene.josserand@free-electrons.com --- arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts index c206ed693aa2..a52cf675098e 100644 --- a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts +++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts @@ -80,6 +80,14 @@ }; };
+&codec { + status = "okay"; +}; + +&dai { + status = "okay"; +}; + &de { status = "okay"; }; @@ -227,6 +235,10 @@ regulator-name = "vcc-rtc"; };
+&sound { + status = "okay"; +}; + &tcon0 { pinctrl-names = "default"; pinctrl-0 = <&lcd_rgb666_pins>;
participants (5)
-
kbuild test robot
-
Mark Brown
-
Maxime Ripard
-
Mylène Josserand
-
Rob Herring