[alsa-devel] [PATCH v2 0/8] ASoC: sunxi: Add support for audio codec in A23/H3 SoCs
Hi everyone,
This is v2 of my Allwinner A23 and H3 audio codec support series.
Changes since v1:
- Use DEFINE_RES_MEM for the analog path controls block resources. - Added Rob's ack.
This series adds support for the audio codec found in Allwinner A23 and H3 SoCs. The design and data paths are similar to the audio codec found in earlier SoCs such as the A31. The analog audio paths are symmetrical with left/right channels and down-mix selectors for mono differential output.
What deviates from previous SoCs is that the analog path controls have been moved to a separate control bus, accessed through a message box like register interface in the PRCM block. This necessitates writing a separate component driver for it, which is then tied into the sound card as an ASoC auxiliary device.
Patch 1 adds the analog path controls block to the sun6i-prcm driver as a sub-device, for the A23. The H3 currently does not use the PRCM driver.
Patch 2 adds PCM and card support for the A23 codec to the sun4i-codec driver.
Patch 3 adds a device node for the analog path controls block to the A23 dtsi.
Patch 4 adds a device node for the audio codec, and the phandle for the analog path controls block to the A23 dtsi.
Patch 5 enables the audio codec for the A23 Q8 tablets. On these tablets the headphone output is driven in DC coupled, or "direct drive", mode.
Patch 6 adds PCM and card support for the H3 codec to the sun4i-codec driver.
Patch 7 adds device nodes for the audio codec and analog path controls block to the H3 dtsi.
Patch 8 enables the audio codec on the Orange Pi PC. The audio output jack on the board is tied to the line out pins on the SoC.
Please take a look and let me know what you think.
In addition, the sun4i-codec driver is getting pretty large. Maybe we want to split the different parts into different files?
Regards ChenYu
Chen-Yu Tsai (8): mfd: sun6i-prcm: Add codec analog controls sub-device for Allwinner A23 ASoC: sun4i-codec: Add support for A23 codec ARM: dts: sun8i: Add codec analog path controls node in PRCM for A23/A33 ARM: dts: sun8i-a23: Add device node for internal audio codec ARM: dts: sun8i-a23: q8-tablet: Enable internal audio codec ASoC: sun4i-codec: Add support for H3 codec ARM: dts: sun8i-h3: Add device nodes for audio codec and its analog controls ARM: dts: sun8i-h3: orange-pi-pc: Enable audio codec
.../devicetree/bindings/sound/sun4i-codec.txt | 14 +- arch/arm/boot/dts/sun8i-a23-a33.dtsi | 4 + arch/arm/boot/dts/sun8i-a23-q8-tablet.dts | 23 +++ arch/arm/boot/dts/sun8i-a23.dtsi | 16 ++ arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 8 + arch/arm/boot/dts/sun8i-h3.dtsi | 19 +++ drivers/mfd/sun6i-prcm.c | 13 ++ sound/soc/sunxi/sun4i-codec.c | 179 +++++++++++++++++++++ 8 files changed, 274 insertions(+), 2 deletions(-)
The PRCM block on the A23 contains a message box like interface to the registers for the analog path controls of the internal codec.
Add a sub-device for it.
Signed-off-by: Chen-Yu Tsai wens@csie.org --- drivers/mfd/sun6i-prcm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c index 011fcc555945..2b658bed47db 100644 --- a/drivers/mfd/sun6i-prcm.c +++ b/drivers/mfd/sun6i-prcm.c @@ -12,6 +12,9 @@ #include <linux/init.h> #include <linux/of.h>
+#define SUN8I_CODEC_ANALOG_BASE 0x1c0 +#define SUN8I_CODEC_ANALOG_SIZE 0x4 + struct prcm_data { int nsubdevs; const struct mfd_cell *subdevs; @@ -57,6 +60,10 @@ static const struct resource sun6i_a31_apb0_rstc_res[] = { }, };
+static const struct resource sun8i_codec_analog_res[] = { + DEFINE_RES_MEM(SUN8I_CODEC_ANALOG_BASE, SUN8I_CODEC_ANALOG_SIZE), +}; + static const struct mfd_cell sun6i_a31_prcm_subdevs[] = { { .name = "sun6i-a31-ar100-clk", @@ -109,6 +116,12 @@ static const struct mfd_cell sun8i_a23_prcm_subdevs[] = { .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res), .resources = sun6i_a31_apb0_rstc_res, }, + { + .name = "sun8i-codec-analog", + .of_compatible = "allwinner,sun8i-a23-codec-analog", + .num_resources = ARRAY_SIZE(sun8i_codec_analog_res), + .resources = sun8i_codec_analog_res, + }, };
static const struct prcm_data sun6i_a31_prcm_data = {
On Fri, Nov 25, 2016 at 08:34:35PM +0800, Chen-Yu Tsai wrote:
The PRCM block on the A23 contains a message box like interface to the registers for the analog path controls of the internal codec.
Add a sub-device for it.
Signed-off-by: Chen-Yu Tsai wens@csie.org
Acked-by: Maxime Ripard maxime.ripard@free-electrons.com
Maxime
On Fri, 25 Nov 2016, Chen-Yu Tsai wrote:
The PRCM block on the A23 contains a message box like interface to the registers for the analog path controls of the internal codec.
Add a sub-device for it.
Signed-off-by: Chen-Yu Tsai wens@csie.org
drivers/mfd/sun6i-prcm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
Applied for v4.11, thanks.
diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c index 011fcc555945..2b658bed47db 100644 --- a/drivers/mfd/sun6i-prcm.c +++ b/drivers/mfd/sun6i-prcm.c @@ -12,6 +12,9 @@ #include <linux/init.h> #include <linux/of.h>
+#define SUN8I_CODEC_ANALOG_BASE 0x1c0 +#define SUN8I_CODEC_ANALOG_SIZE 0x4
struct prcm_data { int nsubdevs; const struct mfd_cell *subdevs; @@ -57,6 +60,10 @@ static const struct resource sun6i_a31_apb0_rstc_res[] = { }, };
+static const struct resource sun8i_codec_analog_res[] = {
- DEFINE_RES_MEM(SUN8I_CODEC_ANALOG_BASE, SUN8I_CODEC_ANALOG_SIZE),
+};
static const struct mfd_cell sun6i_a31_prcm_subdevs[] = { { .name = "sun6i-a31-ar100-clk", @@ -109,6 +116,12 @@ static const struct mfd_cell sun8i_a23_prcm_subdevs[] = { .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res), .resources = sun6i_a31_apb0_rstc_res, },
- {
.name = "sun8i-codec-analog",
.of_compatible = "allwinner,sun8i-a23-codec-analog",
.num_resources = ARRAY_SIZE(sun8i_codec_analog_res),
.resources = sun8i_codec_analog_res,
- },
};
static const struct prcm_data sun6i_a31_prcm_data = {
The codec in the A23 is similar to the one found on the A31. One key difference is the analog path controls are routed through the PRCM block. This is supported by the sun8i-codec-analog driver, and tied into this codec driver with the audio card's aux_dev.
In addition, the A23 does not have LINEOUT, and it does not support headset jack detection or buttons.
Signed-off-by: Chen-Yu Tsai wens@csie.org Acked-by: Rob Herring robh@kernel.org --- .../devicetree/bindings/sound/sun4i-codec.txt | 11 ++- sound/soc/sunxi/sun4i-codec.c | 108 +++++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt index d91a95377f49..f7a548b604fc 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt @@ -5,6 +5,7 @@ Required properties: - "allwinner,sun4i-a10-codec" - "allwinner,sun6i-a31-codec" - "allwinner,sun7i-a20-codec" + - "allwinner,sun8i-a23-codec" - reg: must contain the registers location and length - interrupts: must contain the codec interrupt - dmas: DMA channels for tx and rx dma. See the DMA client binding, @@ -21,6 +22,7 @@ Optional properties:
Required properties for the following compatibles: - "allwinner,sun6i-a31-codec" + - "allwinner,sun8i-a23-codec" - resets: phandle to the reset control for this device - allwinner,audio-routing: A list of the connections between audio components. Each entry is a pair of strings, the first being the @@ -31,10 +33,10 @@ Required properties for the following compatibles: "HP" "HPCOM" "LINEIN" - "LINEOUT" + "LINEOUT" (not on sun8i-a23) "MIC1" "MIC2" - "MIC3" + "MIC3" (sun6i-a31 only)
Microphone biases from the SoC: "HBIAS" @@ -48,6 +50,11 @@ Required properties for the following compatibles: "Mic" "Speaker"
+Required properties for the following compatibles: + - "allwinner,sun8i-a23-codec" +- allwinner,codec-analog-controls: A phandle to the codec analog controls + block in the PRCM. + Example: codec: codec@01c22c00 { #sound-dai-cells = <0>; diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 092fdcf6de95..ada5fa055950 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -213,6 +213,10 @@
/* TODO sun6i DAP (Digital Audio Processing) bits */
+/* FIFO counters moved on A23 */ +#define SUN8I_A23_CODEC_DAC_TXCNT (0x1c) +#define SUN8I_A23_CODEC_ADC_RXCNT (0x20) + struct sun4i_codec { struct device *dev; struct regmap *regmap; @@ -1067,6 +1071,32 @@ static struct snd_soc_codec_driver sun6i_codec_codec = { }, };
+/* sun8i A23 codec */ +static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, + sun6i_codec_dvol_scale), +}; + +static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = { + /* Digital parts of the ADCs */ + SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC, + SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0), + /* Digital parts of the DACs */ + SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0), + +}; + +static struct snd_soc_codec_driver sun8i_a23_codec_codec = { + .component_driver = { + .controls = sun8i_a23_codec_codec_controls, + .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls), + .dapm_widgets = sun8i_a23_codec_codec_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets), + }, +}; + static const struct snd_soc_component_driver sun4i_codec_component = { .name = "sun4i-codec", }; @@ -1206,6 +1236,63 @@ static struct snd_soc_card *sun6i_codec_create_card(struct device *dev) return card; };
+/* Connect digital side enables to analog side widgets */ +static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = { + /* ADC Routes */ + { "Left ADC", NULL, "ADC Enable" }, + { "Right ADC", NULL, "ADC Enable" }, + { "Codec Capture", NULL, "Left ADC" }, + { "Codec Capture", NULL, "Right ADC" }, + + /* DAC Routes */ + { "Left DAC", NULL, "DAC Enable" }, + { "Right DAC", NULL, "DAC Enable" }, + { "Left DAC", NULL, "Codec Playback" }, + { "Right DAC", NULL, "Codec Playback" }, +}; + +static struct snd_soc_aux_dev aux_dev = { + .name = "Codec Analog Controls", +}; + +static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + "allwinner,codec-analog-controls", + 0); + if (!aux_dev.codec_of_node) { + dev_err(dev, "Can't find analog controls for codec.\n"); + return ERR_PTR(-EINVAL); + }; + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dev = dev; + card->name = "A23 Audio Codec"; + card->dapm_widgets = sun6i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); + card->dapm_routes = sun8i_codec_card_routes; + card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); + card->aux_dev = &aux_dev; + card->num_aux_devs = 1; + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1227,6 +1314,13 @@ static const struct regmap_config sun7i_codec_regmap_config = { .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL, };
+static const struct regmap_config sun8i_a23_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN8I_A23_CODEC_ADC_RXCNT, +}; + struct sun4i_codec_quirks { const struct regmap_config *regmap_config; const struct snd_soc_codec_driver *codec; @@ -1265,6 +1359,16 @@ static const struct sun4i_codec_quirks sun7i_codec_quirks = { .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, };
+static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { + .regmap_config = &sun8i_a23_codec_regmap_config, + .codec = &sun8i_a23_codec_codec, + .create_card = sun8i_a23_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, + .has_reset = true, +}; + static const struct of_device_id sun4i_codec_of_match[] = { { .compatible = "allwinner,sun4i-a10-codec", @@ -1278,6 +1382,10 @@ static const struct of_device_id sun4i_codec_of_match[] = { .compatible = "allwinner,sun7i-a20-codec", .data = &sun7i_codec_quirks, }, + { + .compatible = "allwinner,sun8i-a23-codec", + .data = &sun8i_a23_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
On Fri, Nov 25, 2016 at 08:34:36PM +0800, Chen-Yu Tsai wrote:
The codec in the A23 is similar to the one found on the A31. One key difference is the analog path controls are routed through the PRCM block. This is supported by the sun8i-codec-analog driver, and tied into this codec driver with the audio card's aux_dev.
In addition, the A23 does not have LINEOUT, and it does not support headset jack detection or buttons.
Signed-off-by: Chen-Yu Tsai wens@csie.org Acked-by: Rob Herring robh@kernel.org
Acked-by: Maxime Ripard maxime.ripard@free-electrons.com
Thanks! Maxime
On the A23/A33, the internal codec's analog path controls are located in the PRCM node.
Add a sub-device node to the PRCM for it.
Signed-off-by: Chen-Yu Tsai wens@csie.org --- arch/arm/boot/dts/sun8i-a23-a33.dtsi | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi index bc3e936edfcf..d9c6f16f95f1 100644 --- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi +++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi @@ -538,6 +538,10 @@ compatible = "allwinner,sun6i-a31-clock-reset"; #reset-cells = <1>; }; + + codec_analog: codec-analog { + compatible = "allwinner,sun8i-a23-codec-analog"; + }; };
cpucfg@01f01c00 {
Now that we have a device tree binding and driver for the A23's internal audio codec, add a device node for it.
Signed-off-by: Chen-Yu Tsai wens@csie.org --- arch/arm/boot/dts/sun8i-a23.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi index 54d045dab825..4d1f929780a8 100644 --- a/arch/arm/boot/dts/sun8i-a23.dtsi +++ b/arch/arm/boot/dts/sun8i-a23.dtsi @@ -48,6 +48,22 @@ memory { reg = <0x40000000 0x40000000>; }; + + soc@01c00000 { + codec: codec@01c22c00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a23-codec"; + reg = <0x01c22c00 0x400>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "apb", "codec"; + resets = <&ccu RST_BUS_CODEC>; + dmas = <&dma 15>, <&dma 15>; + dma-names = "rx", "tx"; + allwinner,codec-analog-controls = <&codec_analog>; + status = "disabled"; + }; + }; };
&ccu {
The A23 Q8 tablets have an internal mono speaker w/ external amp which has a shutdown control tied to a GPIO pin. Both the speaker amp and the headphone jack are tied to the HP output pins. While the speaker is mono, the headset jack is stereo. Unfortunately the driver does not support automatic switching of this.
In addition, the headset is DC coupled, or "direct drive" enabled. The headset's microphone is tied to MIC2 with HBIAS providing power. A separate internal microphone is tied to MIC1 with MBIAS providing power.
Signed-off-by: Chen-Yu Tsai wens@csie.org --- arch/arm/boot/dts/sun8i-a23-q8-tablet.dts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts index 956320a6cc78..3ab5c0c09d93 100644 --- a/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts +++ b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts @@ -48,3 +48,26 @@ model = "Q8 A23 Tablet"; compatible = "allwinner,q8-a23", "allwinner,sun8i-a23"; }; + +&codec { + pinctrl-0 = <&codec_pa_pin>; + allwinner,pa-gpios = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */ + allwinner,audio-routing = + "Headphone", "HP", + "Headphone", "HPCOM", + "Speaker", "HP", + "MIC1", "Mic", + "MIC2", "Headset Mic", + "Mic", "MBIAS", + "Headset Mic", "HBIAS"; + status = "okay"; +}; + +&pio { + codec_pa_pin: codec_pa_pin@0 { + allwinner,pins = "PH9"; + allwinner,function = "gpio_out"; + allwinner,drive = <SUN4I_PINCTRL_10_MA>; + allwinner,pull = <SUN4I_PINCTRL_NO_PULL>; + }; +};
The codec on the H3 is similar to the one found on the A31. One key difference is the analog path controls are routed through the PRCM block. This is supported by the sun8i-codec-analog driver, and tied into this codec driver with the audio card's aux_dev.
In addition, the H3 has no HP (headphone) and HBIAS support, and no MIC3 input. The FIFO related registers are slightly rearranged.
Signed-off-by: Chen-Yu Tsai wens@csie.org Acked-by: Rob Herring robh@kernel.org --- .../devicetree/bindings/sound/sun4i-codec.txt | 3 + sound/soc/sunxi/sun4i-codec.c | 71 ++++++++++++++++++++++ 2 files changed, 74 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt index f7a548b604fc..3033bd8aab0f 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt @@ -6,6 +6,7 @@ Required properties: - "allwinner,sun6i-a31-codec" - "allwinner,sun7i-a20-codec" - "allwinner,sun8i-a23-codec" + - "allwinner,sun8i-h3-codec" - reg: must contain the registers location and length - interrupts: must contain the codec interrupt - dmas: DMA channels for tx and rx dma. See the DMA client binding, @@ -23,6 +24,7 @@ Optional properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-codec" - "allwinner,sun8i-a23-codec" + - "allwinner,sun8i-h3-codec" - resets: phandle to the reset control for this device - allwinner,audio-routing: A list of the connections between audio components. Each entry is a pair of strings, the first being the @@ -52,6 +54,7 @@ Required properties for the following compatibles:
Required properties for the following compatibles: - "allwinner,sun8i-a23-codec" + - "allwinner,sun8i-h3-codec" - allwinner,codec-analog-controls: A phandle to the codec analog controls block in the PRCM.
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index ada5fa055950..848af01692a0 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -217,6 +217,13 @@ #define SUN8I_A23_CODEC_DAC_TXCNT (0x1c) #define SUN8I_A23_CODEC_ADC_RXCNT (0x20)
+/* TX FIFO moved on H3 */ +#define SUN8I_H3_CODEC_DAC_TXDATA (0x20) +#define SUN8I_H3_CODEC_DAC_DBG (0x48) +#define SUN8I_H3_CODEC_ADC_DBG (0x4c) + +/* TODO H3 DAP (Digital Audio Processing) bits */ + struct sun4i_codec { struct device *dev; struct regmap *regmap; @@ -1293,6 +1300,44 @@ static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) return card; };
+static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + "allwinner,codec-analog-controls", + 0); + if (!aux_dev.codec_of_node) { + dev_err(dev, "Can't find analog controls for codec.\n"); + return ERR_PTR(-EINVAL); + }; + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dev = dev; + card->name = "H3 Audio Codec"; + card->dapm_widgets = sun6i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); + card->dapm_routes = sun8i_codec_card_routes; + card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); + card->aux_dev = &aux_dev; + card->num_aux_devs = 1; + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1321,6 +1366,13 @@ static const struct regmap_config sun8i_a23_codec_regmap_config = { .max_register = SUN8I_A23_CODEC_ADC_RXCNT, };
+static const struct regmap_config sun8i_h3_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN8I_H3_CODEC_ADC_DBG, +}; + struct sun4i_codec_quirks { const struct regmap_config *regmap_config; const struct snd_soc_codec_driver *codec; @@ -1369,6 +1421,21 @@ static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { .has_reset = true, };
+static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { + .regmap_config = &sun8i_h3_codec_regmap_config, + /* + * TODO Share the codec structure with A23 for now. + * This should be split out when adding digital audio + * processing support for the H3. + */ + .codec = &sun8i_a23_codec_codec, + .create_card = sun8i_h3_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, + .has_reset = true, +}; + static const struct of_device_id sun4i_codec_of_match[] = { { .compatible = "allwinner,sun4i-a10-codec", @@ -1386,6 +1453,10 @@ static const struct of_device_id sun4i_codec_of_match[] = { .compatible = "allwinner,sun8i-a23-codec", .data = &sun8i_a23_codec_quirks, }, + { + .compatible = "allwinner,sun8i-h3-codec", + .data = &sun8i_h3_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
On Fri, Nov 25, 2016 at 08:34:40PM +0800, Chen-Yu Tsai wrote:
The codec on the H3 is similar to the one found on the A31. One key difference is the analog path controls are routed through the PRCM block. This is supported by the sun8i-codec-analog driver, and tied into this codec driver with the audio card's aux_dev.
In addition, the H3 has no HP (headphone) and HBIAS support, and no MIC3 input. The FIFO related registers are slightly rearranged.
Signed-off-by: Chen-Yu Tsai wens@csie.org Acked-by: Rob Herring robh@kernel.org
Acked-by: Maxime Ripard maxime.ripard@free-electrons.com
Thanks, Maxime
Now that we support the audio codec found on the Allwinner H3 SoC, add device nodes for it.
Signed-off-by: Chen-Yu Tsai wens@csie.org --- arch/arm/boot/dts/sun8i-h3.dtsi | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi index fca66bf2dec5..496efc564bbe 100644 --- a/arch/arm/boot/dts/sun8i-h3.dtsi +++ b/arch/arm/boot/dts/sun8i-h3.dtsi @@ -465,6 +465,20 @@ status = "disabled"; };
+ codec: codec@01c22c00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-h3-codec"; + reg = <0x01c22c00 0x400>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "apb", "codec"; + resets = <&ccu RST_BUS_CODEC>; + dmas = <&dma 15>, <&dma 15>; + dma-names = "rx", "tx"; + allwinner,codec-analog-controls = <&codec_analog>; + status = "disabled"; + }; + uart0: serial@01c28000 { compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; @@ -580,6 +594,11 @@ #reset-cells = <1>; };
+ codec_analog: codec-analog@01f015c0 { + compatible = "allwinner,sun8i-h3-codec-analog"; + reg = <0x01f015c0 0x4>; + }; + ir: ir@01f02000 { compatible = "allwinner,sun5i-a13-ir"; clocks = <&apb0_gates 1>, <&ir_clk>;
The Orange Pi PC routes the LINEOUT pins to the audio out jack on the board. The onboard microphone is routed to MIC1, with MBIAS providing power.
Signed-off-by: Chen-Yu Tsai wens@csie.org --- arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts index 98b85be61e17..d43978d3294e 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts @@ -90,6 +90,14 @@ }; };
+&codec { + allwinner,audio-routing = + "Line Out", "LINEOUT", + "MIC1", "Mic", + "Mic", "MBIAS"; + status = "okay"; +}; + &ehci1 { status = "okay"; };
participants (3)
-
Chen-Yu Tsai
-
Lee Jones
-
Maxime Ripard