2016-11-03 07:56:18

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 00/14] ASoC: sun4i-codec: Add support for A31 Codec

Hi everyone,

This is v2 of my Allwinner A31 audio codec support series. The ASoC DAPM
stereo control patches in v1 were split out and merged already. These
remaining patches depend on them.

The A31's internal codec is similar (in terms of DMA, interface and
control layouts) to the one found in the A10/A13/A20 SoCs. However
it has more external inputs and outputs, the mixer controls are now
stereo (left/right separated), and it also has some audio processing
features (not supported yet).

Changes since v1:

- Patches 1, 2, 3 and 4 were split out from patch 6.

- Reworked handling of register offset differences with regmap_field,
as suggested by Maxime.

- Added support for an optional (in the driver) reset control (patch 5)

- Added required reset control for sun6i-a31-codec

- Added more comments for sun6i registers

- Added HPCOM (direct drive mode) support

- Renamed sun6i audio card name to "A31 Audio Codec"

- Added example for allwinner,sun6i-a31-codec device tree

- Fixed line out volume control scale

- Added external amplifier enable GPIO for Hummingbird A31

- Added patch to enable audio codec on Sinlinx SinA31s

Patch 1 moves some code around to facilitate patch 2. No code was
changed

Patch 2 expands the quirks to handle different register offsets for

- ADC FIFO controls, using regmap_field's

- RX/TX FIFO addresses, with offsets stored directly, as these
are only used to setup DMA and not actually accessed by the
driver

- card setup functions, as the newer codecs have a very different
layout

Patch 3 fixes some of the comments in the register definition section,
so the separation of different functions is clearer.

Patch 4 increases the maximum DMA burst size from 4 to 8. 4 is not
a valid size on later SoCs.

Patch 5 adds driver support for an optional reset control.

Patches 6 through 11 add support for the A31's internal codec, one
feature per patch. Hopefully this makes it easier to review. Some
features, such as PHONE inputs/outputs, audio processing, headset
jack detection and buttons, aren't supported yet.

Patch 12 adds a device node for the codec to the A31 dtsi.

Patch 13 enables the codec for the Hummingbird A31 board.

Patch 14 enables the codec for the Sinlinx SinA31s board.


Please let me know what you think.

Regards
ChenYu


Chen-Yu Tsai (14):
ASoC: sun4i-codec: Move data structures to add create_card call to
quirks
ASoC: sun4i-codec: Expand quirks to handle register offsets and card
creation
ASoC: sun4i-codec: Revise comments for register definition macros
ASoC: sun4i-codec: Increase DMA max burst to 8
ASoC: sun4i-codec: Add support for optional reset control to quirks
ASoC: sun4i-codec: Add support for A31 playback through headphone
output
ASoC: sun4i-codec: Add support for A31 Line In playback
ASoC: sun4i-codec: Add support for A31 Line Out playback
ASoC: sun4i-codec: Add support for A31 analog microphone inputs
ASoC: sun4i-codec: Add support for A31 ADC capture path
ASoC: sun4i-codec: Add support for A31 board level audio routing
ARM: dts: sun6i: Add audio codec device node
ARM: dts: sun6i: hummingbird: Enable internal audio codec
ARM: dts: sun6i: sina31s: Enable internal audio codec

.../devicetree/bindings/sound/sun4i-codec.txt | 55 +-
arch/arm/boot/dts/sun6i-a31-hummingbird.dts | 20 +
arch/arm/boot/dts/sun6i-a31.dtsi | 13 +
arch/arm/boot/dts/sun6i-a31s-sina31s.dts | 8 +
sound/soc/sunxi/sun4i-codec.c | 688 ++++++++++++++++++---
5 files changed, 706 insertions(+), 78 deletions(-)

--
2.10.2


2016-11-03 07:56:24

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 14/14] ARM: dts: sun6i: sina31s: Enable internal audio codec

The SinA31s routes the SoC's LINEOUT pins to a line out jack, and MIC1
to a microphone jack, with MBIAS providing phantom power.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
arch/arm/boot/dts/sun6i-a31s-sina31s.dts | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
index 6ead2f5c847a..c35ec112f5a0 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
@@ -65,6 +65,14 @@
};
};

+&codec {
+ allwinner,audio-routing =
+ "Line Out", "LINEOUT",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
&ehci0 {
/* USB 2.0 4 port hub IC */
status = "okay";
--
2.10.2

2016-11-03 07:56:19

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 02/14] ASoC: sun4i-codec: Expand quirks to handle register offsets and card creation

The A31 has a similar codec to the A10/A20. The PCM parts are very
similar, with just different register offsets. The analog paths are
very different. There are more inputs and outputs.

The A31s, A23, and H3 have a similar PCM interface, again with register
offsets slightly rearranged. The analog path controls, while very
similar between them and the A31, have been moved a separate bus which
is accessed through a message box like interface in the PRCM address
range. This would be handled by a separate auxiliary device tied in
through the device tree in its supporting create_card function.

The quirks structure is expanded to include different register offsets
and separate callbacks for creating the ASoC card. The regmap_config,
quirks, and of_device_match tables have been moved to facilitate this.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 87 +++++++++++++++++++++++++++++--------------
1 file changed, 60 insertions(+), 27 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 249fa5033361..dbb47f255bd8 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -3,6 +3,7 @@
* Copyright 2014 Jon Smirl <[email protected]>
* Copyright 2015 Maxime Ripard <[email protected]>
* Copyright 2015 Adam Sampson <[email protected]>
+ * Copyright 2016 Chen-Yu Tsai <[email protected]>
*
* Based on the Allwinner SDK driver, released under the GPL.
*
@@ -24,8 +25,9 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/regmap.h>
#include <linux/gpio/consumer.h>
@@ -106,6 +108,9 @@ struct sun4i_codec {
struct clk *clk_module;
struct gpio_desc *gpio_pa;

+ /* ADC_FIFOC register is at different offset on different SoCs */
+ struct regmap_field *reg_adc_fifoc;
+
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
};
@@ -134,16 +139,16 @@ static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
{
/* Enable ADC DRQ */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
- BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
+ BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
}

static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
{
/* Disable ADC DRQ */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
}

static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -186,15 +191,15 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,


/* Flush RX FIFO */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
- BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
+ BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));


/* Set RX FIFO trigger level */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
- 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
+ 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);

/*
* FIXME: Undocumented in the datasheet, but
@@ -213,9 +218,9 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
0x1 << 8);

/* Fill most significant bits with valid data MSB */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));

return 0;
}
@@ -342,18 +347,19 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
unsigned int hwrate)
{
/* Set ADC sample rate */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
- hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
+ hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);

/* Set the number of channels we want to use */
if (params_channels(params) == 1)
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
- BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
else
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0);
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
+ 0);

return 0;
}
@@ -758,14 +764,29 @@ static const struct regmap_config sun7i_codec_regmap_config = {

struct sun4i_codec_quirks {
const struct regmap_config *regmap_config;
+ const struct snd_soc_codec_driver *codec;
+ struct snd_soc_card * (*create_card)(struct device *dev);
+ struct reg_field reg_adc_fifoc; /* used for regmap_field */
+ unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */
+ unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */
};

static const struct sun4i_codec_quirks sun4i_codec_quirks = {
.regmap_config = &sun4i_codec_regmap_config,
+ .codec = &sun4i_codec_codec,
+ .create_card = sun4i_codec_create_card,
+ .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
+ .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
+ .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
};

static const struct sun4i_codec_quirks sun7i_codec_quirks = {
.regmap_config = &sun7i_codec_regmap_config,
+ .codec = &sun4i_codec_codec,
+ .create_card = sun4i_codec_create_card,
+ .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
+ .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
+ .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
};

static const struct of_device_id sun4i_codec_of_match[] = {
@@ -838,6 +859,17 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return ret;
}

+ /* reg_field setup */
+ scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
+ scodec->regmap,
+ quirks->reg_adc_fifoc);
+ if (IS_ERR(scodec->reg_adc_fifoc)) {
+ ret = PTR_ERR(scodec->reg_adc_fifoc);
+ dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
+ ret);
+ return ret;
+ }
+
/* Enable the bus clock */
if (clk_prepare_enable(scodec->clk_apb)) {
dev_err(&pdev->dev, "Failed to enable the APB clock\n");
@@ -845,16 +877,16 @@ static int sun4i_codec_probe(struct platform_device *pdev)
}

/* DMA configuration for TX FIFO */
- scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
+ scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
scodec->playback_dma_data.maxburst = 4;
scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;

/* DMA configuration for RX FIFO */
- scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA;
+ scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
scodec->capture_dma_data.maxburst = 4;
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;

- ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec,
+ ret = snd_soc_register_codec(&pdev->dev, quirks->codec,
&sun4i_codec_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register our codec\n");
@@ -875,7 +907,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
goto err_unregister_codec;
}

- card = sun4i_codec_create_card(&pdev->dev);
+ card = quirks->create_card(&pdev->dev);
if (IS_ERR(card)) {
ret = PTR_ERR(card);
dev_err(&pdev->dev, "Failed to create our card\n");
@@ -926,4 +958,5 @@ MODULE_DESCRIPTION("Allwinner A10 codec driver");
MODULE_AUTHOR("Emilio López <[email protected]>");
MODULE_AUTHOR("Jon Smirl <[email protected]>");
MODULE_AUTHOR("Maxime Ripard <[email protected]>");
+MODULE_AUTHOR("Chen-Yu Tsai <[email protected]>");
MODULE_LICENSE("GPL");
--
2.10.2

2016-11-03 07:56:23

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 13/14] ARM: dts: sun6i: hummingbird: Enable internal audio codec

The Hummingbird A31 has headset and line in audio jacks and an onboard
mic routed to the pins for the SoC's internal codec. The line out pins
are routed to an onboard speaker amp, whose output is available on a
pin header.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
arch/arm/boot/dts/sun6i-a31-hummingbird.dts | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 9a74637f677f..48c041b75aab 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -69,6 +69,19 @@
};
};

+&codec {
+ allwinner,audio-routing =
+ "Headphone", "HP",
+ "Speaker", "LINEOUT",
+ "LINEIN", "Line In",
+ "MIC1", "Mic",
+ "MIC2", "Headset Mic",
+ "Mic", "MBIAS",
+ "Headset Mic", "HBIAS";
+ allwinner,pa-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc3>;
};
@@ -152,6 +165,13 @@
};

&pio {
+ codec_pa_pin: codec_pa_pin@0 {
+ allwinner,pins = "PH22";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
gmac_phy_reset_pin_hummingbird: gmac_phy_reset_pin@0 {
allwinner,pins = "PA21";
allwinner,function = "gpio_out";
--
2.10.2

2016-11-03 07:56:22

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 11/14] ASoC: sun4i-codec: Add support for A31 board level audio routing

The A31 SoC's codec has various inputs, outputs and microphone bias
supplies. These can be routed on the board in different ways, such as:

- HPCOM may be connected to have the headphone DC coupled.

- Microphones all use the MBIAS main microphone supply or one mic may
use the HBIAS supply, which supports headset detection and buttons.

- Line Out may be routed to an audio jack, or an onboard speaker amp
with power controls.

Add support for specifying the audio routes in the device tree.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
.../devicetree/bindings/sound/sun4i-codec.txt | 33 ++++++++++++++++++++++
sound/soc/sunxi/sun4i-codec.c | 21 ++++++++++++--
2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index bf480e9683a3..d91a95377f49 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -22,6 +22,31 @@ Optional properties:
Required properties for the following compatibles:
- "allwinner,sun6i-a31-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
+ connection's sink, the second being the connection's
+ source. Valid names include:
+
+ Audio pins on the SoC:
+ "HP"
+ "HPCOM"
+ "LINEIN"
+ "LINEOUT"
+ "MIC1"
+ "MIC2"
+ "MIC3"
+
+ Microphone biases from the SoC:
+ "HBIAS"
+ "MBIAS"
+
+ Board connectors:
+ "Headphone"
+ "Headset Mic"
+ "Line In"
+ "Line Out"
+ "Mic"
+ "Speaker"

Example:
codec: codec@01c22c00 {
@@ -45,4 +70,12 @@ codec: codec@01c22c00 {
resets = <&ccu RST_APB1_CODEC>;
dmas = <&dma 15>, <&dma 15>;
dma-names = "rx", "tx";
+ allwinner,audio-routing =
+ "Headphone", "HP",
+ "Speaker", "LINEOUT",
+ "LINEIN", "Line In",
+ "MIC1", "MBIAS",
+ "MIC1", "Mic",
+ "MIC2", "HBIAS",
+ "MIC2", "Headset Mic";
};
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 0cb728964ff0..6379efd21f00 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -1171,9 +1171,19 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
return card;
};

+static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Mic", NULL),
+ SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
+};
+
static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
{
struct snd_soc_card *card;
+ int ret;

card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card)
@@ -1183,8 +1193,15 @@ static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
if (!card->dai_link)
return ERR_PTR(-ENOMEM);

- card->dev = dev;
- card->name = "A31 Audio Codec";
+ card->dev = dev;
+ card->name = "A31 Audio Codec";
+ card->dapm_widgets = sun6i_codec_card_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
+ 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;
};
--
2.10.2

2016-11-03 07:56:17

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 01/14] ASoC: sun4i-codec: Move data structures to add create_card call to quirks

The audio codec on later Allwinner SoCs have a different layout and
audio path compared to the A10/A20. However the PCM parts are still
the same.

The different layout and audio paths mean we need a different
create_card function for different families, so they can create
DAPM endpoint widgets and routes.

This patch moves the regmap configs, quirks and of_device_id
structures to just before the probe function, so we can, among other
things, include a pointer for the create_card function. None of the
lines of code were changed.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 78 +++++++++++++++++++++----------------------
1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 56ed9472e89f..249fa5033361 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -678,45 +678,6 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
},
};

-static const struct regmap_config sun4i_codec_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = SUN4I_CODEC_ADC_RXCNT,
-};
-
-static const struct regmap_config sun7i_codec_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL,
-};
-
-struct sun4i_codec_quirks {
- const struct regmap_config *regmap_config;
-};
-
-static const struct sun4i_codec_quirks sun4i_codec_quirks = {
- .regmap_config = &sun4i_codec_regmap_config,
-};
-
-static const struct sun4i_codec_quirks sun7i_codec_quirks = {
- .regmap_config = &sun7i_codec_regmap_config,
-};
-
-static const struct of_device_id sun4i_codec_of_match[] = {
- {
- .compatible = "allwinner,sun4i-a10-codec",
- .data = &sun4i_codec_quirks,
- },
- {
- .compatible = "allwinner,sun7i-a20-codec",
- .data = &sun7i_codec_quirks,
- },
- {}
-};
-MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
-
static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
int *num_links)
{
@@ -781,6 +742,45 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
return card;
};

+static const struct regmap_config sun4i_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN4I_CODEC_ADC_RXCNT,
+};
+
+static const struct regmap_config sun7i_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL,
+};
+
+struct sun4i_codec_quirks {
+ const struct regmap_config *regmap_config;
+};
+
+static const struct sun4i_codec_quirks sun4i_codec_quirks = {
+ .regmap_config = &sun4i_codec_regmap_config,
+};
+
+static const struct sun4i_codec_quirks sun7i_codec_quirks = {
+ .regmap_config = &sun7i_codec_regmap_config,
+};
+
+static const struct of_device_id sun4i_codec_of_match[] = {
+ {
+ .compatible = "allwinner,sun4i-a10-codec",
+ .data = &sun4i_codec_quirks,
+ },
+ {
+ .compatible = "allwinner,sun7i-a20-codec",
+ .data = &sun7i_codec_quirks,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
+
static int sun4i_codec_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
--
2.10.2

2016-11-03 07:58:22

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 09/14] ASoC: sun4i-codec: Add support for A31 analog microphone inputs

The A31 internal codec has 3 microphone outputs, of which MIC2 and MIC3
are muxed internally. The resulting two microphone inputs have separate
gain controls and mixer inputs.

The codec also has 2 microphone bias pins. HBIAS is specifically for the
headphone jack, which also supports headphone detection and control
buttons. These extra functions are not supported yet. The other, MBIAS,
is for all other analog microphones.

There is also mention of digital microphone support, but documentation
is scarce, and no hardware with it is available.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 70 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 8ba7804a68ed..a0fedb059f1b 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -778,6 +778,14 @@ static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
SUN6I_CODEC_OM_DACA_CTRL,
SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL,
SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0),
+ SOC_DAPM_DOUBLE("Mic1 Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0),
+ SOC_DAPM_DOUBLE("Mic2 Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0),
};

/* headphone controls */
@@ -796,6 +804,21 @@ static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
sun6i_codec_hp_src_enum),
};

+/* microphone controls */
+static const char * const sun6i_codec_mic2_src_enum_text[] = {
+ "Mic2", "Mic3",
+};
+
+static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum,
+ SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC2SLT,
+ sun6i_codec_mic2_src_enum_text);
+
+static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = {
+ SOC_DAPM_ENUM("Mic2 Amplifier Source Route",
+ sun6i_codec_mic2_src_enum),
+};
+
/* line out controls */
static const char * const sun6i_codec_lineout_src_enum_text[] = {
"Stereo", "Mono Differential",
@@ -821,6 +844,10 @@ static const DECLARE_TLV_DB_RANGE(sun6i_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 DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale,
+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
+);

static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
@@ -846,9 +873,42 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
SOC_SINGLE_TLV("Line In Playback Volume",
SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
0x7, 0, sun6i_codec_out_mixer_pregain_scale),
+ SOC_SINGLE_TLV("Mic1 Playback Volume",
+ SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G,
+ 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
+ SOC_SINGLE_TLV("Mic2 Playback Volume",
+ SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G,
+ 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
+
+ /* Microphone Amp boost gains */
+ SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0,
+ sun6i_codec_mic_gain_scale),
+ SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0,
+ sun6i_codec_mic_gain_scale),
};

static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
+ /* Microphone inputs */
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("MIC3"),
+
+ /* Microphone Bias */
+ SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0),
+
+ /* Mic input path */
+ SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route",
+ SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src),
+ SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0),
+
/* Line In */
SND_SOC_DAPM_INPUT("LINEIN"),

@@ -895,15 +955,25 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Left DAC", NULL, "DAC Enable" },
{ "Right DAC", NULL, "DAC Enable" },

+ /* Microphone Routes */
+ { "Mic1 Amplifier", NULL, "MIC1"},
+ { "Mic2 Amplifier Source Route", "Mic2", "MIC2" },
+ { "Mic2 Amplifier Source Route", "Mic3", "MIC3" },
+ { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"},
+
/* Left Mixer Routes */
{ "Left Mixer", "DAC Playback Switch", "Left DAC" },
{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
{ "Left Mixer", "Line In Playback Switch", "LINEIN" },
+ { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
+ { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },

/* Right Mixer Routes */
{ "Right Mixer", "DAC Playback Switch", "Right DAC" },
{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
{ "Right Mixer", "Line In Playback Switch", "LINEIN" },
+ { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
+ { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },

/* Headphone Routes */
{ "Headphone Source Playback Route", "DAC", "Left DAC" },
--
2.10.2

2016-11-03 07:58:21

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 12/14] ARM: dts: sun6i: Add audio codec device node

The A31 SoC includes the Allwinner audio codec, capable of 24-bit
playback up to 192 kHz and 24-bit capture up to 48 kHz.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
arch/arm/boot/dts/sun6i-a31.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 2e8bf93dcfb2..f68e6102b01b 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -784,6 +784,19 @@
reset-names = "ahb";
};

+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun6i-a31-codec";
+ reg = <0x01c22c00 0x98>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_APB1_CODEC>, <&ccu CLK_CODEC>;
+ clock-names = "apb", "codec";
+ resets = <&ccu RST_APB1_CODEC>;
+ dmas = <&dma 15>, <&dma 15>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
timer@01c60000 {
compatible = "allwinner,sun6i-a31-hstimer",
"allwinner,sun7i-a20-hstimer";
--
2.10.2

2016-11-03 07:58:54

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 08/14] ASoC: sun4i-codec: Add support for A31 Line Out playback

The A31 integrated codec has a second "Line Out" output which does not
include an integrated amplifier in its path. This path does have a
separate volume control.

This patch adds support for the playback path from the DAC to the Line
Out pins.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 4abac9962165..8ba7804a68ed 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -796,11 +796,31 @@ static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
sun6i_codec_hp_src_enum),
};

+/* line out controls */
+static const char * const sun6i_codec_lineout_src_enum_text[] = {
+ "Stereo", "Mono Differential",
+};
+
+static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum,
+ SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC,
+ sun6i_codec_lineout_src_enum_text);
+
+static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = {
+ SOC_DAPM_ENUM("Line Out Source Playback Route",
+ sun6i_codec_lineout_src_enum),
+};
+
/* volume / mute controls */
static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale,
-450, 150, 0);
+static const DECLARE_TLV_DB_RANGE(sun6i_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 sun6i_codec_codec_widgets[] = {
SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
@@ -810,10 +830,18 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
SUN6I_CODEC_OM_DACA_CTRL,
SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
sun6i_codec_hp_vol_scale),
+ SOC_SINGLE_TLV("Line Out Playback Volume",
+ SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0,
+ sun6i_codec_lineout_vol_scale),
SOC_DOUBLE("Headphone Playback Switch",
SUN6I_CODEC_OM_DACA_CTRL,
SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
+ SOC_DOUBLE("Line Out Playback Switch",
+ SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTLEN,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0),
/* Mixer pre-gains */
SOC_SINGLE_TLV("Line In Playback Volume",
SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
@@ -855,6 +883,11 @@ static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
SND_SOC_DAPM_OUTPUT("HP"),
+
+ /* Line Out path */
+ SND_SOC_DAPM_MUX("Line Out Source Playback Route",
+ SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src),
+ SND_SOC_DAPM_OUTPUT("LINEOUT"),
};

static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
@@ -880,6 +913,12 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Headphone Amp", NULL, "Headphone Source Playback Route" },
{ "HP", NULL, "Headphone Amp" },
{ "HPCOM", NULL, "HPCOM Protection" },
+
+ /* Line Out 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" },
+ { "LINEOUT", NULL, "Line Out Source Playback Route" },
};

static struct snd_soc_codec_driver sun6i_codec_codec = {
--
2.10.2

2016-11-03 07:58:53

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 07/14] ASoC: sun4i-codec: Add support for A31 Line In playback

The A31 integrated codec has a stereo "Line In" input. Add support for
it to the playback paths.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 12b9e08a3e64..4abac9962165 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -774,6 +774,10 @@ static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
SUN6I_CODEC_OM_DACA_CTRL,
SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR,
SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0),
+ SOC_DAPM_DOUBLE("Line In Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0),
};

/* headphone controls */
@@ -795,6 +799,8 @@ static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
/* volume / mute controls */
static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
+static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale,
+ -450, 150, 0);

static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
@@ -808,9 +814,16 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
SUN6I_CODEC_OM_DACA_CTRL,
SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
+ /* Mixer pre-gains */
+ SOC_SINGLE_TLV("Line In Playback Volume",
+ SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
+ 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
};

static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
+ /* Line In */
+ SND_SOC_DAPM_INPUT("LINEIN"),
+
/* Digital parts of the DACs */
SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
SUN4I_CODEC_DAC_DPC_EN_DA, 0,
@@ -852,10 +865,12 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
/* Left Mixer Routes */
{ "Left Mixer", "DAC Playback Switch", "Left DAC" },
{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
+ { "Left Mixer", "Line In Playback Switch", "LINEIN" },

/* Right Mixer Routes */
{ "Right Mixer", "DAC Playback Switch", "Right DAC" },
{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
+ { "Right Mixer", "Line In Playback Switch", "LINEIN" },

/* Headphone Routes */
{ "Headphone Source Playback Route", "DAC", "Left DAC" },
--
2.10.2

2016-11-03 07:58:51

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 05/14] ASoC: sun4i-codec: Add support for optional reset control to quirks

The later Allwinner SoCs have a dedicated reset controller, and
peripherals have dedicated reset controls which need to be deasserted
before the associated peripheral can be used.

Add support for this to the quirks structure and probe/remove functions.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index d867b96d367b..e502966abf8e 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -30,6 +30,7 @@
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/gpio/consumer.h>

#include <sound/core.h>
@@ -114,6 +115,7 @@ struct sun4i_codec {
struct regmap *regmap;
struct clk *clk_apb;
struct clk *clk_module;
+ struct reset_control *rst;
struct gpio_desc *gpio_pa;

/* ADC_FIFOC register is at different offset on different SoCs */
@@ -777,6 +779,7 @@ struct sun4i_codec_quirks {
struct reg_field reg_adc_fifoc; /* used for regmap_field */
unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */
unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */
+ bool has_reset;
};

static const struct sun4i_codec_quirks sun4i_codec_quirks = {
@@ -858,6 +861,14 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return PTR_ERR(scodec->clk_module);
}

+ if (quirks->has_reset) {
+ scodec->rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(scodec->rst)) {
+ dev_err(&pdev->dev, "Failed to get reset control\n");
+ return PTR_ERR(scodec->rst);
+ }
+ };
+
scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
GPIOD_OUT_LOW);
if (IS_ERR(scodec->gpio_pa)) {
@@ -884,6 +895,16 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return -EINVAL;
}

+ /* Deassert the reset control */
+ if (scodec->rst) {
+ ret = reset_control_deassert(scodec->rst);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to deassert the reset control\n");
+ goto err_clk_disable;
+ }
+ }
+
/* DMA configuration for TX FIFO */
scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
scodec->playback_dma_data.maxburst = 8;
@@ -898,7 +919,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
&sun4i_codec_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register our codec\n");
- goto err_clk_disable;
+ goto err_assert_reset;
}

ret = devm_snd_soc_register_component(&pdev->dev,
@@ -935,6 +956,9 @@ static int sun4i_codec_probe(struct platform_device *pdev)

err_unregister_codec:
snd_soc_unregister_codec(&pdev->dev);
+err_assert_reset:
+ if (scodec->rst)
+ reset_control_assert(scodec->rst);
err_clk_disable:
clk_disable_unprepare(scodec->clk_apb);
return ret;
@@ -947,6 +971,8 @@ static int sun4i_codec_remove(struct platform_device *pdev)

snd_soc_unregister_card(card);
snd_soc_unregister_codec(&pdev->dev);
+ if (scodec->rst)
+ reset_control_assert(scodec->rst);
clk_disable_unprepare(scodec->clk_apb);

return 0;
--
2.10.2

2016-11-03 07:58:49

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 10/14] ASoC: sun4i-codec: Add support for A31 ADC capture path

The A31's internal codec capture path has a mixer in front of the ADC
for each channel, capable of selecting various inputs, including
microphones, line in, phone in, and the main output mixer.

This patch adds the various controls, widgets and routes needed for
audio capture from the already supported inputs on the A31.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 65 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index a0fedb059f1b..0cb728964ff0 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -788,6 +788,30 @@ static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0),
};

+/* ADC mixer controls */
+static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = {
+ SOC_DAPM_DOUBLE("Mixer Capture Switch",
+ SUN6I_CODEC_ADC_ACTL,
+ SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL,
+ SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0),
+ SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch",
+ SUN6I_CODEC_ADC_ACTL,
+ SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR,
+ SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0),
+ SOC_DAPM_DOUBLE("Line In Capture Switch",
+ SUN6I_CODEC_ADC_ACTL,
+ SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL,
+ SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0),
+ SOC_DAPM_DOUBLE("Mic1 Capture Switch",
+ SUN6I_CODEC_ADC_ACTL,
+ SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1,
+ SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0),
+ SOC_DAPM_DOUBLE("Mic2 Capture Switch",
+ SUN6I_CODEC_ADC_ACTL,
+ SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2,
+ SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0),
+};
+
/* headphone controls */
static const char * const sun6i_codec_hp_src_enum_text[] = {
"DAC", "Mixer",
@@ -887,6 +911,10 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL,
SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0,
sun6i_codec_mic_gain_scale),
+ SOC_DOUBLE_TLV("ADC Capture Volume",
+ SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG,
+ SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0,
+ sun6i_codec_out_mixer_pregain_scale),
};

static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
@@ -912,6 +940,23 @@ static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
/* Line In */
SND_SOC_DAPM_INPUT("LINEIN"),

+ /* Digital parts of the ADCs */
+ SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
+ SUN6I_CODEC_ADC_FIFOC_EN_AD, 0,
+ NULL, 0),
+
+ /* Analog parts of the ADCs */
+ SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
+ SUN6I_CODEC_ADC_ACTL_ADCLEN, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
+ SUN6I_CODEC_ADC_ACTL_ADCREN, 0),
+
+ /* ADC Mixers */
+ SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+ sun6i_codec_adc_mixer_controls),
+ SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+ sun6i_codec_adc_mixer_controls),
+
/* Digital parts of the DACs */
SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
SUN4I_CODEC_DAC_DPC_EN_DA, 0,
@@ -975,6 +1020,20 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
{ "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },

+ /* Left ADC Mixer Routes */
+ { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
+ { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
+ { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
+ { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
+ { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
+
+ /* Right ADC Mixer Routes */
+ { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
+ { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
+ { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
+ { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
+ { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
+
/* Headphone Routes */
{ "Headphone Source Playback Route", "DAC", "Left DAC" },
{ "Headphone Source Playback Route", "DAC", "Right DAC" },
@@ -989,6 +1048,12 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Line Out Source Playback Route", "Stereo", "Right Mixer" },
{ "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
{ "LINEOUT", NULL, "Line Out Source Playback Route" },
+
+ /* ADC Routes */
+ { "Left ADC", NULL, "ADC Enable" },
+ { "Right ADC", NULL, "ADC Enable" },
+ { "Left ADC", NULL, "Left ADC Mixer" },
+ { "Right ADC", NULL, "Right ADC Mixer" },
};

static struct snd_soc_codec_driver sun6i_codec_codec = {
--
2.10.2

2016-11-03 07:56:16

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 03/14] ASoC: sun4i-codec: Revise comments for register definition macros

This revises existing comments in the register definition macros
section, and adds a few more, so that readers can clearly identify
the types of control registers.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index dbb47f255bd8..61ae502a5061 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -40,7 +40,7 @@
#include <sound/initval.h>
#include <sound/dmaengine_pcm.h>

-/* Codec DAC register offsets and bit fields */
+/* Codec DAC digital controls and FIFO registers */
#define SUN4I_CODEC_DAC_DPC (0x00)
#define SUN4I_CODEC_DAC_DPC_EN_DA (31)
#define SUN4I_CODEC_DAC_DPC_DVOL (12)
@@ -57,6 +57,8 @@
#define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH (0)
#define SUN4I_CODEC_DAC_FIFOS (0x08)
#define SUN4I_CODEC_DAC_TXDATA (0x0c)
+
+/* Codec DAC side analog signal controls */
#define SUN4I_CODEC_DAC_ACTL (0x10)
#define SUN4I_CODEC_DAC_ACTL_DACAENR (31)
#define SUN4I_CODEC_DAC_ACTL_DACAENL (30)
@@ -71,7 +73,7 @@
#define SUN4I_CODEC_DAC_TUNE (0x14)
#define SUN4I_CODEC_DAC_DEBUG (0x18)

-/* Codec ADC register offsets and bit fields */
+/* Codec ADC digital controls and FIFO registers */
#define SUN4I_CODEC_ADC_FIFOC (0x1c)
#define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29)
#define SUN4I_CODEC_ADC_FIFOC_EN_AD (28)
@@ -83,6 +85,8 @@
#define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH (0)
#define SUN4I_CODEC_ADC_FIFOS (0x20)
#define SUN4I_CODEC_ADC_RXDATA (0x24)
+
+/* Codec ADC side analog signal controls */
#define SUN4I_CODEC_ADC_ACTL (0x28)
#define SUN4I_CODEC_ADC_ACTL_ADC_R_EN (31)
#define SUN4I_CODEC_ADC_ACTL_ADC_L_EN (30)
@@ -95,10 +99,14 @@
#define SUN4I_CODEC_ADC_ACTL_DDE (3)
#define SUN4I_CODEC_ADC_DEBUG (0x2c)

-/* Other various ADC registers */
+/* FIFO counters */
#define SUN4I_CODEC_DAC_TXCNT (0x30)
#define SUN4I_CODEC_ADC_RXCNT (0x34)
+
+/* Calibration register (sun7i only) */
#define SUN7I_CODEC_AC_DAC_CAL (0x38)
+
+/* Microphone controls (sun7i only) */
#define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c)

struct sun4i_codec {
--
2.10.2

2016-11-03 07:59:44

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 06/14] ASoC: sun4i-codec: Add support for A31 playback through headphone output

The A31 has a similar codec to the A10/A20. The PCM parts are very
similar, with different register offsets. The analog paths are very
different. There are more inputs and outputs. The ADC mux has been
replaced with a proper mixer.

This patch adds support for the basic playback path of the A31 codec,
from the DAC to the headphones. Headphone detection, microphone,
signaling, other inputs/outputs and capture will be added later.

Signed-off-by: Chen-Yu Tsai <[email protected]>
---
.../devicetree/bindings/sound/sun4i-codec.txt | 22 +-
sound/soc/sunxi/sun4i-codec.c | 271 ++++++++++++++++++++-
2 files changed, 287 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index 0dce690f78f5..bf480e9683a3 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -1,8 +1,10 @@
* Allwinner A10 Codec

Required properties:
-- compatible: must be either "allwinner,sun4i-a10-codec" or
- "allwinner,sun7i-a20-codec"
+- compatible: must be one of the following compatibles:
+ - "allwinner,sun4i-a10-codec"
+ - "allwinner,sun6i-a31-codec"
+ - "allwinner,sun7i-a20-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,
@@ -17,6 +19,10 @@ Required properties:
Optional properties:
- allwinner,pa-gpios: gpio to enable external amplifier

+Required properties for the following compatibles:
+ - "allwinner,sun6i-a31-codec"
+- resets: phandle to the reset control for this device
+
Example:
codec: codec@01c22c00 {
#sound-dai-cells = <0>;
@@ -28,3 +34,15 @@ codec: codec@01c22c00 {
dmas = <&dma 0 19>, <&dma 0 19>;
dma-names = "rx", "tx";
};
+
+codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun6i-a31-codec";
+ reg = <0x01c22c00 0x98>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_APB1_CODEC>, <&ccu CLK_CODEC>;
+ clock-names = "apb", "codec";
+ resets = <&ccu RST_APB1_CODEC>;
+ dmas = <&dma 15>, <&dma 15>;
+ dma-names = "rx", "tx";
+};
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index e502966abf8e..12b9e08a3e64 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -110,6 +110,109 @@
/* Microphone controls (sun7i only) */
#define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c)

+/*
+ * sun6i specific registers
+ *
+ * sun6i shares the same digital control and FIFO registers as sun4i,
+ * but only the DAC digital controls are at the same offset. The others
+ * have been moved around to accommodate extra analog controls.
+ */
+
+/* Codec DAC digital controls and FIFO registers */
+#define SUN6I_CODEC_ADC_FIFOC (0x10)
+#define SUN6I_CODEC_ADC_FIFOC_EN_AD (28)
+#define SUN6I_CODEC_ADC_FIFOS (0x14)
+#define SUN6I_CODEC_ADC_RXDATA (0x18)
+
+/* Output mixer and gain controls */
+#define SUN6I_CODEC_OM_DACA_CTRL (0x20)
+#define SUN6I_CODEC_OM_DACA_CTRL_DACAREN (31)
+#define SUN6I_CODEC_OM_DACA_CTRL_DACALEN (30)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN (29)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN (28)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1 (23)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2 (22)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE (21)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP (20)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR (19)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR (18)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL (17)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1 (16)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2 (15)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE (14)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN (13)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL (12)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL (11)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR (10)
+#define SUN6I_CODEC_OM_DACA_CTRL_RHPIS (9)
+#define SUN6I_CODEC_OM_DACA_CTRL_LHPIS (8)
+#define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE (7)
+#define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE (6)
+#define SUN6I_CODEC_OM_DACA_CTRL_HPVOL (0)
+#define SUN6I_CODEC_OM_PA_CTRL (0x24)
+#define SUN6I_CODEC_OM_PA_CTRL_HPPAEN (31)
+#define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL (29)
+#define SUN6I_CODEC_OM_PA_CTRL_COMPTEN (28)
+#define SUN6I_CODEC_OM_PA_CTRL_MIC1G (15)
+#define SUN6I_CODEC_OM_PA_CTRL_MIC2G (12)
+#define SUN6I_CODEC_OM_PA_CTRL_LINEING (9)
+#define SUN6I_CODEC_OM_PA_CTRL_PHONEG (6)
+#define SUN6I_CODEC_OM_PA_CTRL_PHONEPG (3)
+#define SUN6I_CODEC_OM_PA_CTRL_PHONENG (0)
+
+/* Microphone, line out and phone out controls */
+#define SUN6I_CODEC_MIC_CTRL (0x28)
+#define SUN6I_CODEC_MIC_CTRL_HBIASEN (31)
+#define SUN6I_CODEC_MIC_CTRL_MBIASEN (30)
+#define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN (28)
+#define SUN6I_CODEC_MIC_CTRL_MIC1BOOST (25)
+#define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN (24)
+#define SUN6I_CODEC_MIC_CTRL_MIC2BOOST (21)
+#define SUN6I_CODEC_MIC_CTRL_MIC2SLT (20)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN (19)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTREN (18)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC (17)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC (16)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTVC (11)
+#define SUN6I_CODEC_MIC_CTRL_PHONEPREG (8)
+
+/* ADC mixer controls */
+#define SUN6I_CODEC_ADC_ACTL (0x2c)
+#define SUN6I_CODEC_ADC_ACTL_ADCREN (31)
+#define SUN6I_CODEC_ADC_ACTL_ADCLEN (30)
+#define SUN6I_CODEC_ADC_ACTL_ADCRG (27)
+#define SUN6I_CODEC_ADC_ACTL_ADCLG (24)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1 (13)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2 (12)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE (11)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP (10)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR (9)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR (8)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL (7)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1 (6)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2 (5)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE (4)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN (3)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL (2)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL (1)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR (0)
+
+/* Analog performance tuning controls */
+#define SUN6I_CODEC_ADDA_TUNE (0x30)
+
+/* Calibration controls */
+#define SUN6I_CODEC_CALIBRATION (0x34)
+
+/* FIFO counters */
+#define SUN6I_CODEC_DAC_TXCNT (0x40)
+#define SUN6I_CODEC_ADC_RXCNT (0x44)
+
+/* headset jack detection and button support registers */
+#define SUN6I_CODEC_HMIC_CTL (0x50)
+#define SUN6I_CODEC_HMIC_DATA (0x54)
+
+/* TODO sun6i DAP (Digital Audio Processing) bits */
+
struct sun4i_codec {
struct device *dev;
struct regmap *regmap;
@@ -216,9 +319,14 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
* Allwinner's code mentions that it is related
* related to microphone gain
*/
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
- 0x3 << 25,
- 0x1 << 25);
+ if (of_device_is_compatible(scodec->dev->of_node,
+ "allwinner,sun4i-a10-codec") ||
+ of_device_is_compatible(scodec->dev->of_node,
+ "allwinner,sun7i-a20-codec")) {
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
+ 0x3 << 25,
+ 0x1 << 25);
+ }

if (of_device_is_compatible(scodec->dev->of_node,
"allwinner,sun7i-a20-codec"))
@@ -518,7 +626,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
},
};

-/*** Codec ***/
+/*** sun4i Codec ***/
static const struct snd_kcontrol_new sun4i_codec_pa_mute =
SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
@@ -654,6 +762,122 @@ static struct snd_soc_codec_driver sun4i_codec_codec = {
},
};

+/*** sun6i Codec ***/
+
+/* mixer controls */
+static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
+ SOC_DAPM_DOUBLE("DAC Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0),
+ SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0),
+};
+
+/* headphone controls */
+static const char * const sun6i_codec_hp_src_enum_text[] = {
+ "DAC", "Mixer",
+};
+
+static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
+ SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
+ sun6i_codec_hp_src_enum_text);
+
+static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
+ SOC_DAPM_ENUM("Headphone Source Playback Route",
+ sun6i_codec_hp_src_enum),
+};
+
+/* volume / mute controls */
+static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
+static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
+
+static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
+ SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
+ sun6i_codec_dvol_scale),
+ SOC_SINGLE_TLV("Headphone Playback Volume",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
+ sun6i_codec_hp_vol_scale),
+ SOC_DOUBLE("Headphone Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
+ SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
+ /* Digital parts of the DACs */
+ SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_EN_DA, 0,
+ NULL, 0),
+
+ /* Analog parts of the DACs */
+ SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0),
+
+ /* Mixers */
+ SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0,
+ sun6i_codec_mixer_controls),
+ SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0,
+ sun6i_codec_mixer_controls),
+
+ /* Headphone output path */
+ SND_SOC_DAPM_MUX("Headphone Source Playback Route",
+ SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),
+ SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL,
+ SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL,
+ SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
+ SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
+ SND_SOC_DAPM_OUTPUT("HP"),
+};
+
+static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
+ /* DAC Routes */
+ { "Left DAC", NULL, "DAC Enable" },
+ { "Right DAC", NULL, "DAC Enable" },
+
+ /* Left Mixer Routes */
+ { "Left Mixer", "DAC Playback Switch", "Left DAC" },
+ { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
+
+ /* Right Mixer Routes */
+ { "Right Mixer", "DAC Playback Switch", "Right DAC" },
+ { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
+
+ /* 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" },
+ { "HPCOM", NULL, "HPCOM Protection" },
+};
+
+static struct snd_soc_codec_driver sun6i_codec_codec = {
+ .component_driver = {
+ .controls = sun6i_codec_codec_widgets,
+ .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets),
+ .dapm_widgets = sun6i_codec_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
+ .dapm_routes = sun6i_codec_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
+ },
+};
+
static const struct snd_soc_component_driver sun4i_codec_component = {
.name = "sun4i-codec",
};
@@ -758,6 +982,24 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
return card;
};

+static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
+{
+ struct snd_soc_card *card;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return ERR_PTR(-ENOMEM);
+
+ card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
+ if (!card->dai_link)
+ return ERR_PTR(-ENOMEM);
+
+ card->dev = dev;
+ card->name = "A31 Audio Codec";
+
+ return card;
+};
+
static const struct regmap_config sun4i_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -765,6 +1007,13 @@ static const struct regmap_config sun4i_codec_regmap_config = {
.max_register = SUN4I_CODEC_ADC_RXCNT,
};

+static const struct regmap_config sun6i_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN6I_CODEC_HMIC_DATA,
+};
+
static const struct regmap_config sun7i_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -791,6 +1040,16 @@ static const struct sun4i_codec_quirks sun4i_codec_quirks = {
.reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
};

+static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
+ .regmap_config = &sun6i_codec_regmap_config,
+ .codec = &sun6i_codec_codec,
+ .create_card = sun6i_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 sun4i_codec_quirks sun7i_codec_quirks = {
.regmap_config = &sun7i_codec_regmap_config,
.codec = &sun4i_codec_codec,
@@ -806,6 +1065,10 @@ static const struct of_device_id sun4i_codec_of_match[] = {
.data = &sun4i_codec_quirks,
},
{
+ .compatible = "allwinner,sun6i-a31-codec",
+ .data = &sun6i_a31_codec_quirks,
+ },
+ {
.compatible = "allwinner,sun7i-a20-codec",
.data = &sun7i_codec_quirks,
},
--
2.10.2

2016-11-03 08:00:05

by Chen-Yu Tsai

[permalink] [raw]
Subject: [PATCH v2 04/14] ASoC: sun4i-codec: Increase DMA max burst to 8

According to the DMA engine API documentation, maxburst denotes the
largest possible size of a single transfer, so as not to overflow
destination FIFOs as explained in this excerpt from dmaengine.h

* @src_maxburst: the maximum number of words (note: words, as in
* units of the src_addr_width member, not bytes) that can be sent
* in one burst to the device. Typically something like half the
* FIFO depth on I/O peripherals so you don't overflow it. This
* may or may not be applicable on memory sources.
* @dst_maxburst: same as src_maxburst but for destination target
* mutatis mutandis.

The TX FIFO is 64 samples deep for stereo, and the RX FIFO is 16
samples deep. So maxburst could be 32 and 8 for TX and RX respectively.

Unfortunately the sunxi DMA controller driver takes maxburst as
the requested burst size, rather than a limit, and returns an error
for unsupported values. The original value was 4, but some later
SoCs do not officially support this burst size.

This patch increases maxburst on the TX side to 8, which is supported
by all variants of the sunxi DMA controller.

Cc: Vinod Koul <[email protected]>
Signed-off-by: Chen-Yu Tsai <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 61ae502a5061..d867b96d367b 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -886,12 +886,12 @@ static int sun4i_codec_probe(struct platform_device *pdev)

/* DMA configuration for TX FIFO */
scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
- scodec->playback_dma_data.maxburst = 4;
+ scodec->playback_dma_data.maxburst = 8;
scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;

/* DMA configuration for RX FIFO */
scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
- scodec->capture_dma_data.maxburst = 4;
+ scodec->capture_dma_data.maxburst = 8;
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;

ret = snd_soc_register_codec(&pdev->dev, quirks->codec,
--
2.10.2

2016-11-03 08:23:21

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 01/14] ASoC: sun4i-codec: Move data structures to add create_card call to quirks

On Thu, Nov 03, 2016 at 03:55:43PM +0800, Chen-Yu Tsai wrote:
> The audio codec on later Allwinner SoCs have a different layout and
> audio path compared to the A10/A20. However the PCM parts are still
> the same.
>
> The different layout and audio paths mean we need a different
> create_card function for different families, so they can create
> DAPM endpoint widgets and routes.
>
> This patch moves the regmap configs, quirks and of_device_id
> structures to just before the probe function, so we can, among other
> things, include a pointer for the create_card function. None of the
> lines of code were changed.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Thanks!
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (844.00 B)
signature.asc (801.00 B)
Download all attachments

2016-11-03 08:25:04

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 03/14] ASoC: sun4i-codec: Revise comments for register definition macros

On Thu, Nov 03, 2016 at 03:55:45PM +0800, Chen-Yu Tsai wrote:
> This revises existing comments in the register definition macros
> section, and adds a few more, so that readers can clearly identify
> the types of control registers.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Thanks!
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (456.00 B)
signature.asc (801.00 B)
Download all attachments

2016-11-03 08:26:14

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 04/14] ASoC: sun4i-codec: Increase DMA max burst to 8

On Thu, Nov 03, 2016 at 03:55:46PM +0800, Chen-Yu Tsai wrote:
> According to the DMA engine API documentation, maxburst denotes the
> largest possible size of a single transfer, so as not to overflow
> destination FIFOs as explained in this excerpt from dmaengine.h
>
> * @src_maxburst: the maximum number of words (note: words, as in
> * units of the src_addr_width member, not bytes) that can be sent
> * in one burst to the device. Typically something like half the
> * FIFO depth on I/O peripherals so you don't overflow it. This
> * may or may not be applicable on memory sources.
> * @dst_maxburst: same as src_maxburst but for destination target
> * mutatis mutandis.
>
> The TX FIFO is 64 samples deep for stereo, and the RX FIFO is 16
> samples deep. So maxburst could be 32 and 8 for TX and RX respectively.
>
> Unfortunately the sunxi DMA controller driver takes maxburst as
> the requested burst size, rather than a limit, and returns an error
> for unsupported values. The original value was 4, but some later
> SoCs do not officially support this burst size.
>
> This patch increases maxburst on the TX side to 8, which is supported
> by all variants of the sunxi DMA controller.
>
> Cc: Vinod Koul <[email protected]>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Thanks,
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (1.43 kB)
signature.asc (801.00 B)
Download all attachments

2016-11-03 08:27:01

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 05/14] ASoC: sun4i-codec: Add support for optional reset control to quirks

On Thu, Nov 03, 2016 at 03:55:47PM +0800, Chen-Yu Tsai wrote:
> The later Allwinner SoCs have a dedicated reset controller, and
> peripherals have dedicated reset controls which need to be deasserted
> before the associated peripheral can be used.
>
> Add support for this to the quirks structure and probe/remove functions.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Thanks,
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (550.00 B)
signature.asc (801.00 B)
Download all attachments

2016-11-03 08:29:30

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 07/14] ASoC: sun4i-codec: Add support for A31 Line In playback

On Thu, Nov 03, 2016 at 03:55:49PM +0800, Chen-Yu Tsai wrote:
> The A31 integrated codec has a stereo "Line In" input. Add support for
> it to the playback paths.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Thanks,
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (387.00 B)
signature.asc (801.00 B)
Download all attachments

2016-11-03 08:30:21

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 10/14] ASoC: sun4i-codec: Add support for A31 ADC capture path

On Thu, Nov 03, 2016 at 03:55:52PM +0800, Chen-Yu Tsai wrote:
> The A31's internal codec capture path has a mixer in front of the ADC
> for each channel, capable of selecting various inputs, including
> microphones, line in, phone in, and the main output mixer.
>
> This patch adds the various controls, widgets and routes needed for
> audio capture from the already supported inputs on the A31.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>
Thanks,
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (620.00 B)
signature.asc (801.00 B)
Download all attachments

2016-11-03 08:31:21

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 11/14] ASoC: sun4i-codec: Add support for A31 board level audio routing

On Thu, Nov 03, 2016 at 03:55:53PM +0800, Chen-Yu Tsai wrote:
> The A31 SoC's codec has various inputs, outputs and microphone bias
> supplies. These can be routed on the board in different ways, such as:
>
> - HPCOM may be connected to have the headphone DC coupled.
>
> - Microphones all use the MBIAS main microphone supply or one mic may
> use the HBIAS supply, which supports headset detection and buttons.
>
> - Line Out may be routed to an audio jack, or an onboard speaker amp
> with power controls.
>
> Add support for specifying the audio routes in the device tree.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Thanks,
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (818.00 B)
signature.asc (801.00 B)
Download all attachments

2016-11-03 08:45:50

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 13/14] ARM: dts: sun6i: hummingbird: Enable internal audio codec

On Thu, Nov 03, 2016 at 03:55:55PM +0800, Chen-Yu Tsai wrote:
> The Hummingbird A31 has headset and line in audio jacks and an onboard
> mic routed to the pins for the SoC's internal codec. The line out pins
> are routed to an onboard speaker amp, whose output is available on a
> pin header.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> ---
> arch/arm/boot/dts/sun6i-a31-hummingbird.dts | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
> index 9a74637f677f..48c041b75aab 100644
> --- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
> +++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
> @@ -69,6 +69,19 @@
> };
> };
>
> +&codec {
> + allwinner,audio-routing =
> + "Headphone", "HP",
> + "Speaker", "LINEOUT",
> + "LINEIN", "Line In",
> + "MIC1", "Mic",
> + "MIC2", "Headset Mic",
> + "Mic", "MBIAS",
> + "Headset Mic", "HBIAS";
> + allwinner,pa-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
> + status = "okay";
> +};
> +
> &cpu0 {
> cpu-supply = <&reg_dcdc3>;
> };
> @@ -152,6 +165,13 @@
> };
>
> &pio {
> + codec_pa_pin: codec_pa_pin@0 {
> + allwinner,pins = "PH22";
> + allwinner,function = "gpio_out";
> + allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> + allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> + };
> +

This pin group isn't used anywhere. Because of the strict thing in
pinctrl, I'd say it's better to not set it, but then, the pin group is
useless.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (1.58 kB)
signature.asc (801.00 B)
Download all attachments

2016-11-03 08:51:05

by Priit Laes

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v2 04/14] ASoC: sun4i-codec: Increase DMA max burst to 8

On Thu, 2016-11-03 at 15:55 +0800, Chen-Yu Tsai wrote:
> According to the DMA engine API documentation, maxburst denotes the
> largest possible size of a single transfer, so as not to overflow
> destination FIFOs as explained in this excerpt from dmaengine.h
>
>  * @src_maxburst: the maximum number of words (note: words, as in
>  * units of the src_addr_width member, not bytes) that can be sent
>  * in one burst to the device. Typically something like half the
>  * FIFO depth on I/O peripherals so you don't overflow it. This
>  * may or may not be applicable on memory sources.
>  * @dst_maxburst: same as src_maxburst but for destination target

>  * mutatis mutandis.

^^ :)

>
> The TX FIFO is 64 samples deep for stereo, and the RX FIFO is 16
> samples deep. So maxburst could be 32 and 8 for TX and RX
> respectively.
>
> Unfortunately the sunxi DMA controller driver takes maxburst as
> the requested burst size, rather than a limit, and returns an error
> for unsupported values. The original value was 4, but some later
> SoCs do not officially support this burst size.
>
> This patch increases maxburst on the TX side to 8, which is supported
> by all variants of the sunxi DMA controller.
>
> Cc: Vinod Koul <[email protected]>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> ---
>  sound/soc/sunxi/sun4i-codec.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-
> codec.c
> index 61ae502a5061..d867b96d367b 100644
> --- a/sound/soc/sunxi/sun4i-codec.c
> +++ b/sound/soc/sunxi/sun4i-codec.c
> @@ -886,12 +886,12 @@ static int sun4i_codec_probe(struct
> platform_device *pdev)
>  
>   /* DMA configuration for TX FIFO */
>   scodec->playback_dma_data.addr = res->start + quirks-
> >reg_dac_txdata;
> - scodec->playback_dma_data.maxburst = 4;
> + scodec->playback_dma_data.maxburst = 8;
>   scodec->playback_dma_data.addr_width =
> DMA_SLAVE_BUSWIDTH_2_BYTES;
>  
>   /* DMA configuration for RX FIFO */
>   scodec->capture_dma_data.addr = res->start + quirks-
> >reg_adc_rxdata;
> - scodec->capture_dma_data.maxburst = 4;
> + scodec->capture_dma_data.maxburst = 8;
>   scodec->capture_dma_data.addr_width =
> DMA_SLAVE_BUSWIDTH_2_BYTES;
>  
>   ret = snd_soc_register_codec(&pdev->dev, quirks->codec,
> -- 
> 2.10.2
>

2016-11-03 17:27:00

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-codec: Move data structures to add create_card call to quirks" to the asoc tree

The patch

ASoC: sun4i-codec: Move data structures to add create_card call to quirks

has been applied to the asoc tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 2f2a3462bc15e9613412ca186bf8a6611afa66c7 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <[email protected]>
Date: Thu, 3 Nov 2016 15:55:43 +0800
Subject: [PATCH] ASoC: sun4i-codec: Move data structures to add create_card
call to quirks

The audio codec on later Allwinner SoCs have a different layout and
audio path compared to the A10/A20. However the PCM parts are still
the same.

The different layout and audio paths mean we need a different
create_card function for different families, so they can create
DAPM endpoint widgets and routes.

This patch moves the regmap configs, quirks and of_device_id
structures to just before the probe function, so we can, among other
things, include a pointer for the create_card function. None of the
lines of code were changed.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 78 +++++++++++++++++++++----------------------
1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index a60707761abf..7b78f4045d38 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -678,45 +678,6 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
},
};

-static const struct regmap_config sun4i_codec_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = SUN4I_CODEC_ADC_RXCNT,
-};
-
-static const struct regmap_config sun7i_codec_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL,
-};
-
-struct sun4i_codec_quirks {
- const struct regmap_config *regmap_config;
-};
-
-static const struct sun4i_codec_quirks sun4i_codec_quirks = {
- .regmap_config = &sun4i_codec_regmap_config,
-};
-
-static const struct sun4i_codec_quirks sun7i_codec_quirks = {
- .regmap_config = &sun7i_codec_regmap_config,
-};
-
-static const struct of_device_id sun4i_codec_of_match[] = {
- {
- .compatible = "allwinner,sun4i-a10-codec",
- .data = &sun4i_codec_quirks,
- },
- {
- .compatible = "allwinner,sun7i-a20-codec",
- .data = &sun7i_codec_quirks,
- },
- {}
-};
-MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
-
static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
int *num_links)
{
@@ -781,6 +742,45 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
return card;
};

+static const struct regmap_config sun4i_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN4I_CODEC_ADC_RXCNT,
+};
+
+static const struct regmap_config sun7i_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL,
+};
+
+struct sun4i_codec_quirks {
+ const struct regmap_config *regmap_config;
+};
+
+static const struct sun4i_codec_quirks sun4i_codec_quirks = {
+ .regmap_config = &sun4i_codec_regmap_config,
+};
+
+static const struct sun4i_codec_quirks sun7i_codec_quirks = {
+ .regmap_config = &sun7i_codec_regmap_config,
+};
+
+static const struct of_device_id sun4i_codec_of_match[] = {
+ {
+ .compatible = "allwinner,sun4i-a10-codec",
+ .data = &sun4i_codec_quirks,
+ },
+ {
+ .compatible = "allwinner,sun7i-a20-codec",
+ .data = &sun7i_codec_quirks,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
+
static int sun4i_codec_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
--
2.10.1

2016-11-03 17:34:19

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 02/14] ASoC: sun4i-codec: Expand quirks to handle register offsets and card creation

On Thu, Nov 03, 2016 at 03:55:44PM +0800, Chen-Yu Tsai wrote:
> The A31 has a similar codec to the A10/A20. The PCM parts are very
> similar, with just different register offsets. The analog paths are
> very different. There are more inputs and outputs.
>
> The A31s, A23, and H3 have a similar PCM interface, again with register
> offsets slightly rearranged. The analog path controls, while very
> similar between them and the A31, have been moved a separate bus which
> is accessed through a message box like interface in the PRCM address
> range. This would be handled by a separate auxiliary device tied in
> through the device tree in its supporting create_card function.
>
> The quirks structure is expanded to include different register offsets
> and separate callbacks for creating the ASoC card. The regmap_config,
> quirks, and of_device_match tables have been moved to facilitate this.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Thanks!
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (1.10 kB)
signature.asc (801.00 B)
Download all attachments

2016-11-03 17:36:06

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 06/14] ASoC: sun4i-codec: Add support for A31 playback through headphone output

Hi,

On Thu, Nov 03, 2016 at 03:55:48PM +0800, Chen-Yu Tsai wrote:
> +/* headphone controls */
> +static const char * const sun6i_codec_hp_src_enum_text[] = {
> + "DAC", "Mixer",
> +};
> +
> +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
> + SUN6I_CODEC_OM_DACA_CTRL,
> + SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
> + SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
> + sun6i_codec_hp_src_enum_text);
> +
> +static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
> + SOC_DAPM_ENUM("Headphone Source Playback Route",
> + sun6i_codec_hp_src_enum),
> +};

What is that route exactly? A muxer?

Thanks,
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (724.00 B)
signature.asc (801.00 B)
Download all attachments

2016-11-03 20:34:35

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-codec: Revise comments for register definition macros" to the asoc tree

The patch

ASoC: sun4i-codec: Revise comments for register definition macros

has been applied to the asoc tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From bd720ecf4ec6923207b4059ff4b4a43ee25ac891 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <[email protected]>
Date: Thu, 3 Nov 2016 15:55:45 +0800
Subject: [PATCH] ASoC: sun4i-codec: Revise comments for register definition
macros

This revises existing comments in the register definition macros
section, and adds a few more, so that readers can clearly identify
the types of control registers.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 7b78f4045d38..969d86b4cd44 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -38,7 +38,7 @@
#include <sound/initval.h>
#include <sound/dmaengine_pcm.h>

-/* Codec DAC register offsets and bit fields */
+/* Codec DAC digital controls and FIFO registers */
#define SUN4I_CODEC_DAC_DPC (0x00)
#define SUN4I_CODEC_DAC_DPC_EN_DA (31)
#define SUN4I_CODEC_DAC_DPC_DVOL (12)
@@ -55,6 +55,8 @@
#define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH (0)
#define SUN4I_CODEC_DAC_FIFOS (0x08)
#define SUN4I_CODEC_DAC_TXDATA (0x0c)
+
+/* Codec DAC side analog signal controls */
#define SUN4I_CODEC_DAC_ACTL (0x10)
#define SUN4I_CODEC_DAC_ACTL_DACAENR (31)
#define SUN4I_CODEC_DAC_ACTL_DACAENL (30)
@@ -69,7 +71,7 @@
#define SUN4I_CODEC_DAC_TUNE (0x14)
#define SUN4I_CODEC_DAC_DEBUG (0x18)

-/* Codec ADC register offsets and bit fields */
+/* Codec ADC digital controls and FIFO registers */
#define SUN4I_CODEC_ADC_FIFOC (0x1c)
#define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29)
#define SUN4I_CODEC_ADC_FIFOC_EN_AD (28)
@@ -81,6 +83,8 @@
#define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH (0)
#define SUN4I_CODEC_ADC_FIFOS (0x20)
#define SUN4I_CODEC_ADC_RXDATA (0x24)
+
+/* Codec ADC side analog signal controls */
#define SUN4I_CODEC_ADC_ACTL (0x28)
#define SUN4I_CODEC_ADC_ACTL_ADC_R_EN (31)
#define SUN4I_CODEC_ADC_ACTL_ADC_L_EN (30)
@@ -93,10 +97,14 @@
#define SUN4I_CODEC_ADC_ACTL_DDE (3)
#define SUN4I_CODEC_ADC_DEBUG (0x2c)

-/* Other various ADC registers */
+/* FIFO counters */
#define SUN4I_CODEC_DAC_TXCNT (0x30)
#define SUN4I_CODEC_ADC_RXCNT (0x34)
+
+/* Calibration register (sun7i only) */
#define SUN7I_CODEC_AC_DAC_CAL (0x38)
+
+/* Microphone controls (sun7i only) */
#define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c)

struct sun4i_codec {
--
2.10.1

2016-11-03 20:34:47

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-codec: Add support for A31 playback through headphone output" to the asoc tree

The patch

ASoC: sun4i-codec: Add support for A31 playback through headphone output

has been applied to the asoc tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 8d9e4c9e993f34e7f74bf36f417920a01a42c4b0 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <[email protected]>
Date: Thu, 3 Nov 2016 15:55:48 +0800
Subject: [PATCH] ASoC: sun4i-codec: Add support for A31 playback through
headphone output

The A31 has a similar codec to the A10/A20. The PCM parts are very
similar, with different register offsets. The analog paths are very
different. There are more inputs and outputs. The ADC mux has been
replaced with a proper mixer.

This patch adds support for the basic playback path of the A31 codec,
from the DAC to the headphones. Headphone detection, microphone,
signaling, other inputs/outputs and capture will be added later.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
.../devicetree/bindings/sound/sun4i-codec.txt | 22 +-
sound/soc/sunxi/sun4i-codec.c | 271 ++++++++++++++++++++-
2 files changed, 287 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index 0dce690f78f5..bf480e9683a3 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -1,8 +1,10 @@
* Allwinner A10 Codec

Required properties:
-- compatible: must be either "allwinner,sun4i-a10-codec" or
- "allwinner,sun7i-a20-codec"
+- compatible: must be one of the following compatibles:
+ - "allwinner,sun4i-a10-codec"
+ - "allwinner,sun6i-a31-codec"
+ - "allwinner,sun7i-a20-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,
@@ -17,6 +19,10 @@ Required properties:
Optional properties:
- allwinner,pa-gpios: gpio to enable external amplifier

+Required properties for the following compatibles:
+ - "allwinner,sun6i-a31-codec"
+- resets: phandle to the reset control for this device
+
Example:
codec: codec@01c22c00 {
#sound-dai-cells = <0>;
@@ -28,3 +34,15 @@ codec: codec@01c22c00 {
dmas = <&dma 0 19>, <&dma 0 19>;
dma-names = "rx", "tx";
};
+
+codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun6i-a31-codec";
+ reg = <0x01c22c00 0x98>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_APB1_CODEC>, <&ccu CLK_CODEC>;
+ clock-names = "apb", "codec";
+ resets = <&ccu RST_APB1_CODEC>;
+ dmas = <&dma 15>, <&dma 15>;
+ dma-names = "rx", "tx";
+};
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index d867b96d367b..d4b2186b5d84 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -109,6 +109,109 @@
/* Microphone controls (sun7i only) */
#define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c)

+/*
+ * sun6i specific registers
+ *
+ * sun6i shares the same digital control and FIFO registers as sun4i,
+ * but only the DAC digital controls are at the same offset. The others
+ * have been moved around to accommodate extra analog controls.
+ */
+
+/* Codec DAC digital controls and FIFO registers */
+#define SUN6I_CODEC_ADC_FIFOC (0x10)
+#define SUN6I_CODEC_ADC_FIFOC_EN_AD (28)
+#define SUN6I_CODEC_ADC_FIFOS (0x14)
+#define SUN6I_CODEC_ADC_RXDATA (0x18)
+
+/* Output mixer and gain controls */
+#define SUN6I_CODEC_OM_DACA_CTRL (0x20)
+#define SUN6I_CODEC_OM_DACA_CTRL_DACAREN (31)
+#define SUN6I_CODEC_OM_DACA_CTRL_DACALEN (30)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN (29)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN (28)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1 (23)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2 (22)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE (21)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP (20)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR (19)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR (18)
+#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL (17)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1 (16)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2 (15)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE (14)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN (13)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL (12)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL (11)
+#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR (10)
+#define SUN6I_CODEC_OM_DACA_CTRL_RHPIS (9)
+#define SUN6I_CODEC_OM_DACA_CTRL_LHPIS (8)
+#define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE (7)
+#define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE (6)
+#define SUN6I_CODEC_OM_DACA_CTRL_HPVOL (0)
+#define SUN6I_CODEC_OM_PA_CTRL (0x24)
+#define SUN6I_CODEC_OM_PA_CTRL_HPPAEN (31)
+#define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL (29)
+#define SUN6I_CODEC_OM_PA_CTRL_COMPTEN (28)
+#define SUN6I_CODEC_OM_PA_CTRL_MIC1G (15)
+#define SUN6I_CODEC_OM_PA_CTRL_MIC2G (12)
+#define SUN6I_CODEC_OM_PA_CTRL_LINEING (9)
+#define SUN6I_CODEC_OM_PA_CTRL_PHONEG (6)
+#define SUN6I_CODEC_OM_PA_CTRL_PHONEPG (3)
+#define SUN6I_CODEC_OM_PA_CTRL_PHONENG (0)
+
+/* Microphone, line out and phone out controls */
+#define SUN6I_CODEC_MIC_CTRL (0x28)
+#define SUN6I_CODEC_MIC_CTRL_HBIASEN (31)
+#define SUN6I_CODEC_MIC_CTRL_MBIASEN (30)
+#define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN (28)
+#define SUN6I_CODEC_MIC_CTRL_MIC1BOOST (25)
+#define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN (24)
+#define SUN6I_CODEC_MIC_CTRL_MIC2BOOST (21)
+#define SUN6I_CODEC_MIC_CTRL_MIC2SLT (20)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN (19)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTREN (18)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC (17)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC (16)
+#define SUN6I_CODEC_MIC_CTRL_LINEOUTVC (11)
+#define SUN6I_CODEC_MIC_CTRL_PHONEPREG (8)
+
+/* ADC mixer controls */
+#define SUN6I_CODEC_ADC_ACTL (0x2c)
+#define SUN6I_CODEC_ADC_ACTL_ADCREN (31)
+#define SUN6I_CODEC_ADC_ACTL_ADCLEN (30)
+#define SUN6I_CODEC_ADC_ACTL_ADCRG (27)
+#define SUN6I_CODEC_ADC_ACTL_ADCLG (24)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1 (13)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2 (12)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE (11)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP (10)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR (9)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR (8)
+#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL (7)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1 (6)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2 (5)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE (4)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN (3)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL (2)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL (1)
+#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR (0)
+
+/* Analog performance tuning controls */
+#define SUN6I_CODEC_ADDA_TUNE (0x30)
+
+/* Calibration controls */
+#define SUN6I_CODEC_CALIBRATION (0x34)
+
+/* FIFO counters */
+#define SUN6I_CODEC_DAC_TXCNT (0x40)
+#define SUN6I_CODEC_ADC_RXCNT (0x44)
+
+/* headset jack detection and button support registers */
+#define SUN6I_CODEC_HMIC_CTL (0x50)
+#define SUN6I_CODEC_HMIC_DATA (0x54)
+
+/* TODO sun6i DAP (Digital Audio Processing) bits */
+
struct sun4i_codec {
struct device *dev;
struct regmap *regmap;
@@ -214,9 +317,14 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
* Allwinner's code mentions that it is related
* related to microphone gain
*/
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
- 0x3 << 25,
- 0x1 << 25);
+ if (of_device_is_compatible(scodec->dev->of_node,
+ "allwinner,sun4i-a10-codec") ||
+ of_device_is_compatible(scodec->dev->of_node,
+ "allwinner,sun7i-a20-codec")) {
+ regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
+ 0x3 << 25,
+ 0x1 << 25);
+ }

if (of_device_is_compatible(scodec->dev->of_node,
"allwinner,sun7i-a20-codec"))
@@ -516,7 +624,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
},
};

-/*** Codec ***/
+/*** sun4i Codec ***/
static const struct snd_kcontrol_new sun4i_codec_pa_mute =
SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
@@ -652,6 +760,122 @@ static struct snd_soc_codec_driver sun4i_codec_codec = {
},
};

+/*** sun6i Codec ***/
+
+/* mixer controls */
+static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
+ SOC_DAPM_DOUBLE("DAC Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0),
+ SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0),
+};
+
+/* headphone controls */
+static const char * const sun6i_codec_hp_src_enum_text[] = {
+ "DAC", "Mixer",
+};
+
+static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
+ SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
+ sun6i_codec_hp_src_enum_text);
+
+static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
+ SOC_DAPM_ENUM("Headphone Source Playback Route",
+ sun6i_codec_hp_src_enum),
+};
+
+/* volume / mute controls */
+static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
+static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
+
+static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
+ SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
+ sun6i_codec_dvol_scale),
+ SOC_SINGLE_TLV("Headphone Playback Volume",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
+ sun6i_codec_hp_vol_scale),
+ SOC_DOUBLE("Headphone Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
+ SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
+ /* Digital parts of the DACs */
+ SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_EN_DA, 0,
+ NULL, 0),
+
+ /* Analog parts of the DACs */
+ SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0),
+
+ /* Mixers */
+ SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0,
+ sun6i_codec_mixer_controls),
+ SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0,
+ sun6i_codec_mixer_controls),
+
+ /* Headphone output path */
+ SND_SOC_DAPM_MUX("Headphone Source Playback Route",
+ SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),
+ SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL,
+ SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL,
+ SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
+ SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
+ SND_SOC_DAPM_OUTPUT("HP"),
+};
+
+static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
+ /* DAC Routes */
+ { "Left DAC", NULL, "DAC Enable" },
+ { "Right DAC", NULL, "DAC Enable" },
+
+ /* Left Mixer Routes */
+ { "Left Mixer", "DAC Playback Switch", "Left DAC" },
+ { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
+
+ /* Right Mixer Routes */
+ { "Right Mixer", "DAC Playback Switch", "Right DAC" },
+ { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
+
+ /* 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" },
+ { "HPCOM", NULL, "HPCOM Protection" },
+};
+
+static struct snd_soc_codec_driver sun6i_codec_codec = {
+ .component_driver = {
+ .controls = sun6i_codec_codec_widgets,
+ .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets),
+ .dapm_widgets = sun6i_codec_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
+ .dapm_routes = sun6i_codec_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
+ },
+};
+
static const struct snd_soc_component_driver sun4i_codec_component = {
.name = "sun4i-codec",
};
@@ -756,6 +980,24 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
return card;
};

+static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
+{
+ struct snd_soc_card *card;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return ERR_PTR(-ENOMEM);
+
+ card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
+ if (!card->dai_link)
+ return ERR_PTR(-ENOMEM);
+
+ card->dev = dev;
+ card->name = "A31 Audio Codec";
+
+ return card;
+};
+
static const struct regmap_config sun4i_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -763,6 +1005,13 @@ static const struct regmap_config sun4i_codec_regmap_config = {
.max_register = SUN4I_CODEC_ADC_RXCNT,
};

+static const struct regmap_config sun6i_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN6I_CODEC_HMIC_DATA,
+};
+
static const struct regmap_config sun7i_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -788,6 +1037,16 @@ static const struct sun4i_codec_quirks sun4i_codec_quirks = {
.reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
};

+static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
+ .regmap_config = &sun6i_codec_regmap_config,
+ .codec = &sun6i_codec_codec,
+ .create_card = sun6i_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 sun4i_codec_quirks sun7i_codec_quirks = {
.regmap_config = &sun7i_codec_regmap_config,
.codec = &sun4i_codec_codec,
@@ -803,6 +1062,10 @@ static const struct of_device_id sun4i_codec_of_match[] = {
.data = &sun4i_codec_quirks,
},
{
+ .compatible = "allwinner,sun6i-a31-codec",
+ .data = &sun6i_a31_codec_quirks,
+ },
+ {
.compatible = "allwinner,sun7i-a20-codec",
.data = &sun7i_codec_quirks,
},
--
2.10.1

2016-11-03 20:34:57

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-codec: Expand quirks to handle register offsets and card creation" to the asoc tree

The patch

ASoC: sun4i-codec: Expand quirks to handle register offsets and card creation

has been applied to the asoc tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From bc03f0d576000739694ed95e89c71cda78964224 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <[email protected]>
Date: Thu, 3 Nov 2016 15:55:44 +0800
Subject: [PATCH] ASoC: sun4i-codec: Expand quirks to handle register offsets
and card creation

The A31 has a similar codec to the A10/A20. The PCM parts are very
similar, with just different register offsets. The analog paths are
very different. There are more inputs and outputs.

The A31s, A23, and H3 have a similar PCM interface, again with register
offsets slightly rearranged. The analog path controls, while very
similar between them and the A31, have been moved a separate bus which
is accessed through a message box like interface in the PRCM address
range. This would be handled by a separate auxiliary device tied in
through the device tree in its supporting create_card function.

The quirks structure is expanded to include different register offsets
and separate callbacks for creating the ASoC card. The regmap_config,
quirks, and of_device_match tables have been moved to facilitate this.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 87 +++++++++++++++++++++++++++++--------------
1 file changed, 60 insertions(+), 27 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 5ff071fd4996..61ae502a5061 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -3,6 +3,7 @@
* Copyright 2014 Jon Smirl <[email protected]>
* Copyright 2015 Maxime Ripard <[email protected]>
* Copyright 2015 Adam Sampson <[email protected]>
+ * Copyright 2016 Chen-Yu Tsai <[email protected]>
*
* Based on the Allwinner SDK driver, released under the GPL.
*
@@ -24,8 +25,9 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/regmap.h>
#include <linux/gpio/consumer.h>
@@ -114,6 +116,9 @@ struct sun4i_codec {
struct clk *clk_module;
struct gpio_desc *gpio_pa;

+ /* ADC_FIFOC register is at different offset on different SoCs */
+ struct regmap_field *reg_adc_fifoc;
+
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
};
@@ -142,16 +147,16 @@ static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
{
/* Enable ADC DRQ */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
- BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
+ BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
}

static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
{
/* Disable ADC DRQ */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
}

static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -194,15 +199,15 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,


/* Flush RX FIFO */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
- BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
+ BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));


/* Set RX FIFO trigger level */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
- 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
+ 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);

/*
* FIXME: Undocumented in the datasheet, but
@@ -221,9 +226,9 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
0x1 << 8);

/* Fill most significant bits with valid data MSB */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));

return 0;
}
@@ -350,18 +355,19 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
unsigned int hwrate)
{
/* Set ADC sample rate */
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
- hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
+ hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);

/* Set the number of channels we want to use */
if (params_channels(params) == 1)
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
- BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
else
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC,
- BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0);
+ regmap_field_update_bits(scodec->reg_adc_fifoc,
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
+ 0);

return 0;
}
@@ -766,14 +772,29 @@ static const struct regmap_config sun7i_codec_regmap_config = {

struct sun4i_codec_quirks {
const struct regmap_config *regmap_config;
+ const struct snd_soc_codec_driver *codec;
+ struct snd_soc_card * (*create_card)(struct device *dev);
+ struct reg_field reg_adc_fifoc; /* used for regmap_field */
+ unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */
+ unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */
};

static const struct sun4i_codec_quirks sun4i_codec_quirks = {
.regmap_config = &sun4i_codec_regmap_config,
+ .codec = &sun4i_codec_codec,
+ .create_card = sun4i_codec_create_card,
+ .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
+ .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
+ .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
};

static const struct sun4i_codec_quirks sun7i_codec_quirks = {
.regmap_config = &sun7i_codec_regmap_config,
+ .codec = &sun4i_codec_codec,
+ .create_card = sun4i_codec_create_card,
+ .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
+ .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
+ .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
};

static const struct of_device_id sun4i_codec_of_match[] = {
@@ -846,6 +867,17 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return ret;
}

+ /* reg_field setup */
+ scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
+ scodec->regmap,
+ quirks->reg_adc_fifoc);
+ if (IS_ERR(scodec->reg_adc_fifoc)) {
+ ret = PTR_ERR(scodec->reg_adc_fifoc);
+ dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
+ ret);
+ return ret;
+ }
+
/* Enable the bus clock */
if (clk_prepare_enable(scodec->clk_apb)) {
dev_err(&pdev->dev, "Failed to enable the APB clock\n");
@@ -853,16 +885,16 @@ static int sun4i_codec_probe(struct platform_device *pdev)
}

/* DMA configuration for TX FIFO */
- scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
+ scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
scodec->playback_dma_data.maxburst = 4;
scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;

/* DMA configuration for RX FIFO */
- scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA;
+ scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
scodec->capture_dma_data.maxburst = 4;
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;

- ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec,
+ ret = snd_soc_register_codec(&pdev->dev, quirks->codec,
&sun4i_codec_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register our codec\n");
@@ -883,7 +915,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
goto err_unregister_codec;
}

- card = sun4i_codec_create_card(&pdev->dev);
+ card = quirks->create_card(&pdev->dev);
if (IS_ERR(card)) {
ret = PTR_ERR(card);
dev_err(&pdev->dev, "Failed to create our card\n");
@@ -934,4 +966,5 @@ MODULE_DESCRIPTION("Allwinner A10 codec driver");
MODULE_AUTHOR("Emilio López <[email protected]>");
MODULE_AUTHOR("Jon Smirl <[email protected]>");
MODULE_AUTHOR("Maxime Ripard <[email protected]>");
+MODULE_AUTHOR("Chen-Yu Tsai <[email protected]>");
MODULE_LICENSE("GPL");
--
2.10.1

2016-11-03 20:34:55

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-codec: Increase DMA max burst to 8" to the asoc tree

The patch

ASoC: sun4i-codec: Increase DMA max burst to 8

has been applied to the asoc tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 730e2dd0cbc7a7ec10174d9d291cdd8e8082a948 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <[email protected]>
Date: Thu, 3 Nov 2016 15:55:46 +0800
Subject: [PATCH] ASoC: sun4i-codec: Increase DMA max burst to 8

According to the DMA engine API documentation, maxburst denotes the
largest possible size of a single transfer, so as not to overflow
destination FIFOs as explained in this excerpt from dmaengine.h

* @src_maxburst: the maximum number of words (note: words, as in
* units of the src_addr_width member, not bytes) that can be sent
* in one burst to the device. Typically something like half the
* FIFO depth on I/O peripherals so you don't overflow it. This
* may or may not be applicable on memory sources.
* @dst_maxburst: same as src_maxburst but for destination target
* mutatis mutandis.

The TX FIFO is 64 samples deep for stereo, and the RX FIFO is 16
samples deep. So maxburst could be 32 and 8 for TX and RX respectively.

Unfortunately the sunxi DMA controller driver takes maxburst as
the requested burst size, rather than a limit, and returns an error
for unsupported values. The original value was 4, but some later
SoCs do not officially support this burst size.

This patch increases maxburst on the TX side to 8, which is supported
by all variants of the sunxi DMA controller.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 61ae502a5061..d867b96d367b 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -886,12 +886,12 @@ static int sun4i_codec_probe(struct platform_device *pdev)

/* DMA configuration for TX FIFO */
scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
- scodec->playback_dma_data.maxburst = 4;
+ scodec->playback_dma_data.maxburst = 8;
scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;

/* DMA configuration for RX FIFO */
scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
- scodec->capture_dma_data.maxburst = 4;
+ scodec->capture_dma_data.maxburst = 8;
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;

ret = snd_soc_register_codec(&pdev->dev, quirks->codec,
--
2.10.1

2016-11-04 01:08:38

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH v2 06/14] ASoC: sun4i-codec: Add support for A31 playback through headphone output

On Fri, Nov 4, 2016 at 1:36 AM, Maxime Ripard
<[email protected]> wrote:
> Hi,
>
> On Thu, Nov 03, 2016 at 03:55:48PM +0800, Chen-Yu Tsai wrote:
>> +/* headphone controls */
>> +static const char * const sun6i_codec_hp_src_enum_text[] = {
>> + "DAC", "Mixer",
>> +};
>> +
>> +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
>> + SUN6I_CODEC_OM_DACA_CTRL,
>> + SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
>> + SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
>> + sun6i_codec_hp_src_enum_text);
>> +
>> +static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
>> + SOC_DAPM_ENUM("Headphone Source Playback Route",
>> + sun6i_codec_hp_src_enum),
>> +};
>
> What is that route exactly? A muxer?

Yup. The following is part of the widgets list later in the code:

+ /* Headphone output path */
+ SND_SOC_DAPM_MUX("Headphone Source Playback Route",
+ SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),

ChenYu

2016-11-04 08:12:43

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH v2 13/14] ARM: dts: sun6i: hummingbird: Enable internal audio codec

On Thu, Nov 3, 2016 at 4:45 PM, Maxime Ripard
<[email protected]> wrote:
> On Thu, Nov 03, 2016 at 03:55:55PM +0800, Chen-Yu Tsai wrote:
>> The Hummingbird A31 has headset and line in audio jacks and an onboard
>> mic routed to the pins for the SoC's internal codec. The line out pins
>> are routed to an onboard speaker amp, whose output is available on a
>> pin header.
>>
>> Signed-off-by: Chen-Yu Tsai <[email protected]>
>> ---
>> arch/arm/boot/dts/sun6i-a31-hummingbird.dts | 20 ++++++++++++++++++++
>> 1 file changed, 20 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
>> index 9a74637f677f..48c041b75aab 100644
>> --- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
>> +++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
>> @@ -69,6 +69,19 @@
>> };
>> };
>>
>> +&codec {
>> + allwinner,audio-routing =
>> + "Headphone", "HP",
>> + "Speaker", "LINEOUT",
>> + "LINEIN", "Line In",
>> + "MIC1", "Mic",
>> + "MIC2", "Headset Mic",
>> + "Mic", "MBIAS",
>> + "Headset Mic", "HBIAS";
>> + allwinner,pa-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
>> + status = "okay";
>> +};
>> +
>> &cpu0 {
>> cpu-supply = <&reg_dcdc3>;
>> };
>> @@ -152,6 +165,13 @@
>> };
>>
>> &pio {
>> + codec_pa_pin: codec_pa_pin@0 {
>> + allwinner,pins = "PH22";
>> + allwinner,function = "gpio_out";
>> + allwinner,drive = <SUN4I_PINCTRL_10_MA>;
>> + allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
>> + };
>> +
>
> This pin group isn't used anywhere. Because of the strict thing in
> pinctrl, I'd say it's better to not set it, but then, the pin group is
> useless.

I'll drop the pinmux setting then.

ChenYu

2016-11-04 20:40:35

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-codec: Add support for A31 Line Out playback" to the asoc tree

The patch

ASoC: sun4i-codec: Add support for A31 Line Out playback

has been applied to the asoc tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 0f909f98d7cbabc3641a45da9c6891444b929a92 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <[email protected]>
Date: Thu, 3 Nov 2016 15:55:50 +0800
Subject: [PATCH] ASoC: sun4i-codec: Add support for A31 Line Out playback

The A31 integrated codec has a second "Line Out" output which does not
include an integrated amplifier in its path. This path does have a
separate volume control.

This patch adds support for the playback path from the DAC to the Line
Out pins.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 72a84f76aa57..a10251f4932e 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -794,11 +794,31 @@ static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
sun6i_codec_hp_src_enum),
};

+/* line out controls */
+static const char * const sun6i_codec_lineout_src_enum_text[] = {
+ "Stereo", "Mono Differential",
+};
+
+static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum,
+ SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC,
+ sun6i_codec_lineout_src_enum_text);
+
+static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = {
+ SOC_DAPM_ENUM("Line Out Source Playback Route",
+ sun6i_codec_lineout_src_enum),
+};
+
/* volume / mute controls */
static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale,
-450, 150, 0);
+static const DECLARE_TLV_DB_RANGE(sun6i_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 sun6i_codec_codec_widgets[] = {
SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
@@ -808,10 +828,18 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
SUN6I_CODEC_OM_DACA_CTRL,
SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
sun6i_codec_hp_vol_scale),
+ SOC_SINGLE_TLV("Line Out Playback Volume",
+ SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0,
+ sun6i_codec_lineout_vol_scale),
SOC_DOUBLE("Headphone Playback Switch",
SUN6I_CODEC_OM_DACA_CTRL,
SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
+ SOC_DOUBLE("Line Out Playback Switch",
+ SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTLEN,
+ SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0),
/* Mixer pre-gains */
SOC_SINGLE_TLV("Line In Playback Volume",
SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
@@ -853,6 +881,11 @@ static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
SND_SOC_DAPM_OUTPUT("HP"),
+
+ /* Line Out path */
+ SND_SOC_DAPM_MUX("Line Out Source Playback Route",
+ SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src),
+ SND_SOC_DAPM_OUTPUT("LINEOUT"),
};

static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
@@ -878,6 +911,12 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Headphone Amp", NULL, "Headphone Source Playback Route" },
{ "HP", NULL, "Headphone Amp" },
{ "HPCOM", NULL, "HPCOM Protection" },
+
+ /* Line Out 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" },
+ { "LINEOUT", NULL, "Line Out Source Playback Route" },
};

static struct snd_soc_codec_driver sun6i_codec_codec = {
--
2.10.1

2016-11-04 20:41:07

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-codec: Add support for A31 board level audio routing" to the asoc tree

The patch

ASoC: sun4i-codec: Add support for A31 board level audio routing

has been applied to the asoc tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 300a18d13f7eaec789e79dc45bce026e098b45da Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <[email protected]>
Date: Thu, 3 Nov 2016 15:55:53 +0800
Subject: [PATCH] ASoC: sun4i-codec: Add support for A31 board level audio
routing

The A31 SoC's codec has various inputs, outputs and microphone bias
supplies. These can be routed on the board in different ways, such as:

- HPCOM may be connected to have the headphone DC coupled.

- Microphones all use the MBIAS main microphone supply or one mic may
use the HBIAS supply, which supports headset detection and buttons.

- Line Out may be routed to an audio jack, or an onboard speaker amp
with power controls.

Add support for specifying the audio routes in the device tree.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
.../devicetree/bindings/sound/sun4i-codec.txt | 33 ++++++++++++++++++++++
sound/soc/sunxi/sun4i-codec.c | 21 ++++++++++++--
2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index bf480e9683a3..d91a95377f49 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -22,6 +22,31 @@ Optional properties:
Required properties for the following compatibles:
- "allwinner,sun6i-a31-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
+ connection's sink, the second being the connection's
+ source. Valid names include:
+
+ Audio pins on the SoC:
+ "HP"
+ "HPCOM"
+ "LINEIN"
+ "LINEOUT"
+ "MIC1"
+ "MIC2"
+ "MIC3"
+
+ Microphone biases from the SoC:
+ "HBIAS"
+ "MBIAS"
+
+ Board connectors:
+ "Headphone"
+ "Headset Mic"
+ "Line In"
+ "Line Out"
+ "Mic"
+ "Speaker"

Example:
codec: codec@01c22c00 {
@@ -45,4 +70,12 @@ codec: codec@01c22c00 {
resets = <&ccu RST_APB1_CODEC>;
dmas = <&dma 15>, <&dma 15>;
dma-names = "rx", "tx";
+ allwinner,audio-routing =
+ "Headphone", "HP",
+ "Speaker", "LINEOUT",
+ "LINEIN", "Line In",
+ "MIC1", "MBIAS",
+ "MIC1", "Mic",
+ "MIC2", "HBIAS",
+ "MIC2", "Headset Mic";
};
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index f55718fe7c5b..1934db29b2b5 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -1104,9 +1104,19 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
return card;
};

+static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Mic", NULL),
+ SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
+};
+
static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
{
struct snd_soc_card *card;
+ int ret;

card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card)
@@ -1116,8 +1126,15 @@ static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
if (!card->dai_link)
return ERR_PTR(-ENOMEM);

- card->dev = dev;
- card->name = "A31 Audio Codec";
+ card->dev = dev;
+ card->name = "A31 Audio Codec";
+ card->dapm_widgets = sun6i_codec_card_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
+ 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;
};
--
2.10.1

2016-11-04 20:41:19

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-codec: Add support for A31 analog microphone inputs" to the asoc tree

The patch

ASoC: sun4i-codec: Add support for A31 analog microphone inputs

has been applied to the asoc tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From ecd5cdb4fd818b1cec55863d5de3683dad1c2f53 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <[email protected]>
Date: Thu, 3 Nov 2016 15:55:51 +0800
Subject: [PATCH] ASoC: sun4i-codec: Add support for A31 analog microphone
inputs

The A31 internal codec has 3 microphone outputs, of which MIC2 and MIC3
are muxed internally. The resulting two microphone inputs have separate
gain controls and mixer inputs.

The codec also has 2 microphone bias pins. HBIAS is specifically for the
headphone jack, which also supports headphone detection and control
buttons. These extra functions are not supported yet. The other, MBIAS,
is for all other analog microphones.

There is also mention of digital microphone support, but documentation
is scarce, and no hardware with it is available.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 70 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index a10251f4932e..f55718fe7c5b 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -776,6 +776,14 @@ static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
SUN6I_CODEC_OM_DACA_CTRL,
SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL,
SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0),
+ SOC_DAPM_DOUBLE("Mic1 Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0),
+ SOC_DAPM_DOUBLE("Mic2 Playback Switch",
+ SUN6I_CODEC_OM_DACA_CTRL,
+ SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2,
+ SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0),
};

/* headphone controls */
@@ -794,6 +802,21 @@ static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
sun6i_codec_hp_src_enum),
};

+/* microphone controls */
+static const char * const sun6i_codec_mic2_src_enum_text[] = {
+ "Mic2", "Mic3",
+};
+
+static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum,
+ SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC2SLT,
+ sun6i_codec_mic2_src_enum_text);
+
+static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = {
+ SOC_DAPM_ENUM("Mic2 Amplifier Source Route",
+ sun6i_codec_mic2_src_enum),
+};
+
/* line out controls */
static const char * const sun6i_codec_lineout_src_enum_text[] = {
"Stereo", "Mono Differential",
@@ -819,6 +842,10 @@ static const DECLARE_TLV_DB_RANGE(sun6i_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 DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale,
+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
+);

static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
@@ -844,9 +871,42 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
SOC_SINGLE_TLV("Line In Playback Volume",
SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
0x7, 0, sun6i_codec_out_mixer_pregain_scale),
+ SOC_SINGLE_TLV("Mic1 Playback Volume",
+ SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G,
+ 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
+ SOC_SINGLE_TLV("Mic2 Playback Volume",
+ SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G,
+ 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
+
+ /* Microphone Amp boost gains */
+ SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0,
+ sun6i_codec_mic_gain_scale),
+ SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0,
+ sun6i_codec_mic_gain_scale),
};

static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
+ /* Microphone inputs */
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("MIC3"),
+
+ /* Microphone Bias */
+ SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0),
+
+ /* Mic input path */
+ SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route",
+ SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src),
+ SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL,
+ SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0),
+
/* Line In */
SND_SOC_DAPM_INPUT("LINEIN"),

@@ -893,15 +953,25 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Left DAC", NULL, "DAC Enable" },
{ "Right DAC", NULL, "DAC Enable" },

+ /* Microphone Routes */
+ { "Mic1 Amplifier", NULL, "MIC1"},
+ { "Mic2 Amplifier Source Route", "Mic2", "MIC2" },
+ { "Mic2 Amplifier Source Route", "Mic3", "MIC3" },
+ { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"},
+
/* Left Mixer Routes */
{ "Left Mixer", "DAC Playback Switch", "Left DAC" },
{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
{ "Left Mixer", "Line In Playback Switch", "LINEIN" },
+ { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
+ { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },

/* Right Mixer Routes */
{ "Right Mixer", "DAC Playback Switch", "Right DAC" },
{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
{ "Right Mixer", "Line In Playback Switch", "LINEIN" },
+ { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
+ { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },

/* Headphone Routes */
{ "Headphone Source Playback Route", "DAC", "Left DAC" },
--
2.10.1

2016-11-06 18:58:08

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 06/14] ASoC: sun4i-codec: Add support for A31 playback through headphone output

On Fri, Nov 04, 2016 at 09:08:11AM +0800, Chen-Yu Tsai wrote:
> On Fri, Nov 4, 2016 at 1:36 AM, Maxime Ripard
> <[email protected]> wrote:
> > Hi,
> >
> > On Thu, Nov 03, 2016 at 03:55:48PM +0800, Chen-Yu Tsai wrote:
> >> +/* headphone controls */
> >> +static const char * const sun6i_codec_hp_src_enum_text[] = {
> >> + "DAC", "Mixer",
> >> +};
> >> +
> >> +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
> >> + SUN6I_CODEC_OM_DACA_CTRL,
> >> + SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
> >> + SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
> >> + sun6i_codec_hp_src_enum_text);
> >> +
> >> +static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
> >> + SOC_DAPM_ENUM("Headphone Source Playback Route",
> >> + sun6i_codec_hp_src_enum),
> >> +};
> >
> > What is that route exactly? A muxer?
>
> Yup. The following is part of the widgets list later in the code:
>
> + /* Headphone output path */
> + SND_SOC_DAPM_MUX("Headphone Source Playback Route",
> + SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),

Oh, right.

You can add my Acked-by on this one and the other patches too.

Thanks!
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com


Attachments:
(No filename) (1.32 kB)
signature.asc (801.00 B)
Download all attachments

2016-11-07 01:51:59

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH v2 06/14] ASoC: sun4i-codec: Add support for A31 playback through headphone output

On Mon, Nov 7, 2016 at 2:57 AM, Maxime Ripard
<[email protected]> wrote:
> On Fri, Nov 04, 2016 at 09:08:11AM +0800, Chen-Yu Tsai wrote:
>> On Fri, Nov 4, 2016 at 1:36 AM, Maxime Ripard
>> <[email protected]> wrote:
>> > Hi,
>> >
>> > On Thu, Nov 03, 2016 at 03:55:48PM +0800, Chen-Yu Tsai wrote:
>> >> +/* headphone controls */
>> >> +static const char * const sun6i_codec_hp_src_enum_text[] = {
>> >> + "DAC", "Mixer",
>> >> +};
>> >> +
>> >> +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
>> >> + SUN6I_CODEC_OM_DACA_CTRL,
>> >> + SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
>> >> + SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
>> >> + sun6i_codec_hp_src_enum_text);
>> >> +
>> >> +static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
>> >> + SOC_DAPM_ENUM("Headphone Source Playback Route",
>> >> + sun6i_codec_hp_src_enum),
>> >> +};
>> >
>> > What is that route exactly? A muxer?
>>
>> Yup. The following is part of the widgets list later in the code:
>>
>> + /* Headphone output path */
>> + SND_SOC_DAPM_MUX("Headphone Source Playback Route",
>> + SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),
>
> Oh, right.
>
> You can add my Acked-by on this one and the other patches too.

Thanks. Mark already merged all the driver patches though.

ChenYu

2016-11-09 14:59:53

by Mark Brown

[permalink] [raw]
Subject: Applied "ASoC: sun4i-codec: Add support for optional reset control to quirks" to the asoc tree

The patch

ASoC: sun4i-codec: Add support for optional reset control to quirks

has been applied to the asoc tree at

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 9aead156c0665a362c8b007b51fe3396fea4d346 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <[email protected]>
Date: Mon, 7 Nov 2016 18:06:58 +0800
Subject: [PATCH] ASoC: sun4i-codec: Add support for optional reset control to
quirks

The later Allwinner SoCs have a dedicated reset controller, and
peripherals have dedicated reset controls which need to be deasserted
before the associated peripheral can be used.

Add support for this to the quirks structure and probe/remove functions.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Acked-by: Maxime Ripard <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
sound/soc/sunxi/sun4i-codec.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 735115244b17..6379efd21f00 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -30,6 +30,7 @@
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/gpio/consumer.h>

#include <sound/core.h>
@@ -217,6 +218,7 @@ struct sun4i_codec {
struct regmap *regmap;
struct clk *clk_apb;
struct clk *clk_module;
+ struct reset_control *rst;
struct gpio_desc *gpio_pa;

/* ADC_FIFOC register is at different offset on different SoCs */
@@ -1232,6 +1234,7 @@ struct sun4i_codec_quirks {
struct reg_field reg_adc_fifoc; /* used for regmap_field */
unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */
unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */
+ bool has_reset;
};

static const struct sun4i_codec_quirks sun4i_codec_quirks = {
@@ -1327,6 +1330,14 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return PTR_ERR(scodec->clk_module);
}

+ if (quirks->has_reset) {
+ scodec->rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(scodec->rst)) {
+ dev_err(&pdev->dev, "Failed to get reset control\n");
+ return PTR_ERR(scodec->rst);
+ }
+ };
+
scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
GPIOD_OUT_LOW);
if (IS_ERR(scodec->gpio_pa)) {
@@ -1353,6 +1364,16 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return -EINVAL;
}

+ /* Deassert the reset control */
+ if (scodec->rst) {
+ ret = reset_control_deassert(scodec->rst);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to deassert the reset control\n");
+ goto err_clk_disable;
+ }
+ }
+
/* DMA configuration for TX FIFO */
scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
scodec->playback_dma_data.maxburst = 8;
@@ -1367,7 +1388,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
&sun4i_codec_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register our codec\n");
- goto err_clk_disable;
+ goto err_assert_reset;
}

ret = devm_snd_soc_register_component(&pdev->dev,
@@ -1404,6 +1425,9 @@ static int sun4i_codec_probe(struct platform_device *pdev)

err_unregister_codec:
snd_soc_unregister_codec(&pdev->dev);
+err_assert_reset:
+ if (scodec->rst)
+ reset_control_assert(scodec->rst);
err_clk_disable:
clk_disable_unprepare(scodec->clk_apb);
return ret;
@@ -1416,6 +1440,8 @@ static int sun4i_codec_remove(struct platform_device *pdev)

snd_soc_unregister_card(card);
snd_soc_unregister_codec(&pdev->dev);
+ if (scodec->rst)
+ reset_control_assert(scodec->rst);
clk_disable_unprepare(scodec->clk_apb);

return 0;
--
2.10.2