mirror of
https://git.openwrt.org/openwrt/openwrt.git
synced 2026-05-05 01:46:11 +02:00
d1: drop audio patches from 6.18
These were not in use and can be dropped for now. Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
This commit is contained in:
parent
3d4a51c806
commit
6a025623e1
@ -1,116 +0,0 @@
|
||||
From 3341f884d75929a009801d4299d219e64c64a33c Mon Sep 17 00:00:00 2001
|
||||
From: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
Date: Sat, 5 Aug 2023 21:05:01 +0300
|
||||
Subject: [PATCH 07/14] ASoC: dt-bindings: sun4i-a10-codec: Add binding for
|
||||
Allwinner D1 SoC
|
||||
|
||||
The Allwinner D1 SoC has a internal audio codec that similar to previous
|
||||
ones, but it contains a three ADC channels instead of two, and also has
|
||||
a separate clocks for ADC and DAC modules.
|
||||
|
||||
Signed-off-by: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
Reviewed-by: Rob Herring <robh@kernel.org>
|
||||
---
|
||||
.../sound/allwinner,sun4i-a10-codec.yaml | 64 ++++++++++++++++---
|
||||
1 file changed, 56 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml
|
||||
+++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml
|
||||
@@ -22,6 +22,7 @@ properties:
|
||||
- allwinner,sun8i-a23-codec
|
||||
- allwinner,sun8i-h3-codec
|
||||
- allwinner,sun8i-v3s-codec
|
||||
+ - allwinner,sun20i-d1-codec
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -29,15 +30,9 @@ properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
- clocks:
|
||||
- items:
|
||||
- - description: Bus Clock
|
||||
- - description: Module Clock
|
||||
+ clocks: true
|
||||
|
||||
- clock-names:
|
||||
- items:
|
||||
- - const: apb
|
||||
- - const: codec
|
||||
+ clock-names: true
|
||||
|
||||
dmas:
|
||||
items:
|
||||
@@ -106,11 +101,42 @@ allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
+ const: allwinner,sun20i-d1-codec
|
||||
+ then:
|
||||
+ properties:
|
||||
+ clocks:
|
||||
+ items:
|
||||
+ - description: Bus Clock
|
||||
+ - description: ADC Module Clock
|
||||
+ - description: DAC Module Clock
|
||||
+
|
||||
+ clock-names:
|
||||
+ items:
|
||||
+ - const: apb
|
||||
+ - const: adc
|
||||
+ - const: dac
|
||||
+
|
||||
+ else:
|
||||
+ properties:
|
||||
+ clocks:
|
||||
+ items:
|
||||
+ - description: Bus Clock
|
||||
+ - description: Module Clock
|
||||
+
|
||||
+ clock-names:
|
||||
+ items:
|
||||
+ - const: apb
|
||||
+ - const: codec
|
||||
+
|
||||
+ - if:
|
||||
+ properties:
|
||||
+ compatible:
|
||||
enum:
|
||||
- allwinner,sun6i-a31-codec
|
||||
- allwinner,sun8i-a23-codec
|
||||
- allwinner,sun8i-h3-codec
|
||||
- allwinner,sun8i-v3s-codec
|
||||
+ - allwinner,sun20i-d1-codec
|
||||
|
||||
then:
|
||||
if:
|
||||
@@ -225,6 +251,28 @@ allOf:
|
||||
- Headphone
|
||||
- Headset Mic
|
||||
- Line In
|
||||
+ - Line Out
|
||||
+ - Mic
|
||||
+ - Speaker
|
||||
+
|
||||
+ - if:
|
||||
+ properties:
|
||||
+ compatible:
|
||||
+ enum:
|
||||
+ - allwinner,sun20i-d1-codec
|
||||
+
|
||||
+ then:
|
||||
+ properties:
|
||||
+ allwinner,audio-routing:
|
||||
+ items:
|
||||
+ enum:
|
||||
+ - HP
|
||||
+ - LINEIN
|
||||
+ - MIC3
|
||||
+ - MBIAS
|
||||
+ - Headphone
|
||||
+ - Headset Mic
|
||||
+ - Line In
|
||||
- Line Out
|
||||
- Mic
|
||||
- Speaker
|
||||
@ -1,51 +0,0 @@
|
||||
From 64efc9cc704d27c60dc9c96a02d842f22dbdfeae Mon Sep 17 00:00:00 2001
|
||||
From: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
Date: Sat, 5 Aug 2023 21:05:02 +0300
|
||||
Subject: [PATCH 08/14] ASoC: dt-bindings: Add schema for
|
||||
"allwinner,sun20i-d1-codec-analog"
|
||||
|
||||
Add a DT schema to describe the analog part of the Allwinner D1/T113s
|
||||
internal audio codec.
|
||||
|
||||
Signed-off-by: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
---
|
||||
.../allwinner,sun20i-d1-codec-analog.yaml | 33 +++++++++++++++++++
|
||||
1 file changed, 33 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/sound/allwinner,sun20i-d1-codec-analog.yaml
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/sound/allwinner,sun20i-d1-codec-analog.yaml
|
||||
@@ -0,0 +1,33 @@
|
||||
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/sound/allwinner,sun20i-d1-codec-analog.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Allwinner D1 Analog Codec
|
||||
+
|
||||
+maintainers:
|
||||
+ - Maksim Kiselev <bigunclemax@gmail.com>
|
||||
+
|
||||
+properties:
|
||||
+ compatible:
|
||||
+ const: allwinner,sun20i-d1-codec-analog
|
||||
+
|
||||
+ reg:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+required:
|
||||
+ - compatible
|
||||
+ - reg
|
||||
+
|
||||
+additionalProperties: false
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ codec_analog: codec-analog@2030300 {
|
||||
+ compatible = "allwinner,sun20i-d1-codec-analog";
|
||||
+ reg = <0x02030300 0xd00>;
|
||||
+ };
|
||||
+
|
||||
+...
|
||||
+
|
||||
@ -1,615 +0,0 @@
|
||||
From 0963766bc665769aebf370d44ee3a97facfbca57 Mon Sep 17 00:00:00 2001
|
||||
From: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
Date: Sat, 5 Aug 2023 21:05:03 +0300
|
||||
Subject: [PATCH 09/14] ASoC: sunxi: sun4i-codec: add basic support for D1
|
||||
audio codec
|
||||
|
||||
Allwinner D1 has an audio codec similar to earlier ones, but it comes
|
||||
with 3 channel ADC instead of 2, and many registers are moved.
|
||||
|
||||
Add basic support for it.
|
||||
|
||||
Signed-off-by: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
---
|
||||
sound/soc/sunxi/sun4i-codec.c | 364 ++++++++++++++++++++++++++++------
|
||||
1 file changed, 300 insertions(+), 64 deletions(-)
|
||||
|
||||
--- a/sound/soc/sunxi/sun4i-codec.c
|
||||
+++ b/sound/soc/sunxi/sun4i-codec.c
|
||||
@@ -229,16 +229,66 @@
|
||||
|
||||
/* TODO H3 DAP (Digital Audio Processing) bits */
|
||||
|
||||
+/*
|
||||
+ * sun20i D1 and similar codecs specific registers
|
||||
+ *
|
||||
+ * Almost all registers moved on D1, including ADC digital controls,
|
||||
+ * FIFO and RX data registers. Only DAC control are at the same offset.
|
||||
+ */
|
||||
+
|
||||
+#define SUN20I_D1_CODEC_DAC_VOL_CTRL (0x04)
|
||||
+#define SUN20I_D1_CODEC_DAC_VOL_SEL (16)
|
||||
+#define SUN20I_D1_CODEC_DAC_VOL_L (8)
|
||||
+#define SUN20I_D1_CODEC_DAC_VOL_R (0)
|
||||
+#define SUN20I_D1_CODEC_DAC_FIFOC (0x10)
|
||||
+#define SUN20I_D1_CODEC_ADC_FIFOC (0x30)
|
||||
+#define SUN20I_D1_CODEC_ADC_FIFOC_EN_AD (28)
|
||||
+#define SUN20I_D1_CODEC_ADC_FIFOC_RX_SAMPLE_BITS (16)
|
||||
+#define SUN20I_D1_CODEC_ADC_FIFOC_RX_TRIG_LEVEL (4)
|
||||
+#define SUN20I_D1_CODEC_ADC_FIFOC_ADC_DRQ_EN (3)
|
||||
+#define SUN20I_D1_CODEC_ADC_VOL_CTRL1 (0x34)
|
||||
+#define SUN20I_D1_CODEC_ADC_VOL_CTRL1_ADC3_VOL (16)
|
||||
+#define SUN20I_D1_CODEC_ADC_VOL_CTRL1_ADC2_VOL (8)
|
||||
+#define SUN20I_D1_CODEC_ADC_VOL_CTRL1_ADC1_VOL (0)
|
||||
+#define SUN20I_D1_CODEC_ADC_RXDATA (0x40)
|
||||
+#define SUN20I_D1_CODEC_ADC_DIG_CTRL (0x50)
|
||||
+#define SUN20I_D1_CODEC_ADC_DIG_CTRL_ADC3_CH_EN (2)
|
||||
+#define SUN20I_D1_CODEC_ADC_DIG_CTRL_ADC2_CH_EN (1)
|
||||
+#define SUN20I_D1_CODEC_ADC_DIG_CTRL_ADC1_CH_EN (0)
|
||||
+#define SUN20I_D1_CODEC_VRA1SPEEDUP_DOWN_CTRL (0x54)
|
||||
+
|
||||
+/* TODO D1 DAP (Digital Audio Processing) bits */
|
||||
+
|
||||
+struct sun4i_codec;
|
||||
+
|
||||
+struct sun4i_codec_quirks {
|
||||
+ const struct regmap_config *regmap_config;
|
||||
+ const struct snd_soc_component_driver *codec;
|
||||
+ struct snd_soc_card * (*create_card)(struct device *dev);
|
||||
+ struct reg_field reg_dac_fifoc; /* used for regmap_field */
|
||||
+ struct reg_field reg_adc_fifoc; /* used for regmap_field */
|
||||
+ unsigned int adc_drq_en;
|
||||
+ unsigned int rx_sample_bits;
|
||||
+ unsigned int rx_trig_level;
|
||||
+ 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;
|
||||
+ bool has_dual_clock;
|
||||
+};
|
||||
+
|
||||
struct sun4i_codec {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct clk *clk_apb;
|
||||
- struct clk *clk_module;
|
||||
+ struct clk *clk_module; /* used for ADC if clocks are separate */
|
||||
+ struct clk *clk_module_dac;
|
||||
struct reset_control *rst;
|
||||
struct gpio_desc *gpio_pa;
|
||||
struct gpio_desc *gpio_hp;
|
||||
+ const struct sun4i_codec_quirks *quirks;
|
||||
|
||||
- /* ADC_FIFOC register is at different offset on different SoCs */
|
||||
+ /* DAC/ADC FIFOC registers are at different offset on different SoCs */
|
||||
+ struct regmap_field *reg_dac_fifoc;
|
||||
struct regmap_field *reg_adc_fifoc;
|
||||
|
||||
struct snd_dmaengine_dai_dma_data capture_dma_data;
|
||||
@@ -248,33 +298,33 @@ struct sun4i_codec {
|
||||
static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
|
||||
{
|
||||
/* Flush TX FIFO */
|
||||
- regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
|
||||
+ regmap_field_set_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
|
||||
|
||||
/* Enable DAC DRQ */
|
||||
- regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
|
||||
+ regmap_field_set_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
|
||||
}
|
||||
|
||||
static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
|
||||
{
|
||||
/* Disable DAC DRQ */
|
||||
- regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
|
||||
+ regmap_field_clear_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
|
||||
}
|
||||
|
||||
static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
|
||||
{
|
||||
/* Enable ADC DRQ */
|
||||
regmap_field_set_bits(scodec->reg_adc_fifoc,
|
||||
- BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
|
||||
+ BIT(scodec->quirks->adc_drq_en));
|
||||
}
|
||||
|
||||
static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
|
||||
{
|
||||
/* Disable ADC DRQ */
|
||||
regmap_field_clear_bits(scodec->reg_adc_fifoc,
|
||||
- BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
|
||||
+ BIT(scodec->quirks->adc_drq_en));
|
||||
}
|
||||
|
||||
static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
@@ -323,8 +373,8 @@ static int sun4i_codec_prepare_capture(s
|
||||
|
||||
/* Set RX FIFO trigger 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);
|
||||
+ 0xf << scodec->quirks->rx_trig_level,
|
||||
+ 0x7 << scodec->quirks->rx_trig_level);
|
||||
|
||||
/*
|
||||
* FIXME: Undocumented in the datasheet, but
|
||||
@@ -358,13 +408,13 @@ static int sun4i_codec_prepare_playback(
|
||||
u32 val;
|
||||
|
||||
/* Flush the TX FIFO */
|
||||
- regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
|
||||
+ regmap_field_set_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
|
||||
|
||||
/* Set TX FIFO Empty Trigger Level */
|
||||
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
|
||||
- 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
|
||||
+ regmap_field_update_bits(scodec->reg_dac_fifoc,
|
||||
+ 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
|
||||
+ 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
|
||||
|
||||
if (substream->runtime->rate > 32000)
|
||||
/* Use 64 bits FIR filter */
|
||||
@@ -373,13 +423,12 @@ static int sun4i_codec_prepare_playback(
|
||||
/* Use 32 bits FIR filter */
|
||||
val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION);
|
||||
|
||||
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION),
|
||||
- val);
|
||||
+ regmap_field_update_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), val);
|
||||
|
||||
/* Send zeros when we have an underrun */
|
||||
- regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT));
|
||||
+ regmap_field_clear_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT));
|
||||
|
||||
return 0;
|
||||
};
|
||||
@@ -474,30 +523,32 @@ static int sun4i_codec_hw_params_capture
|
||||
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_field_set_bits(scodec->reg_adc_fifoc,
|
||||
- BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
|
||||
- else
|
||||
- regmap_field_clear_bits(scodec->reg_adc_fifoc,
|
||||
- BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
|
||||
+ if (!scodec->quirks->has_dual_clock) {
|
||||
+ /* Set the number of channels we want to use */
|
||||
+ if (params_channels(params) == 1)
|
||||
+ regmap_field_set_bits(scodec->reg_adc_fifoc,
|
||||
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
|
||||
+ else
|
||||
+ regmap_field_clear_bits(scodec->reg_adc_fifoc,
|
||||
+ BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
|
||||
+ }
|
||||
|
||||
/* Set the number of sample bits to either 16 or 24 bits */
|
||||
if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
|
||||
regmap_field_set_bits(scodec->reg_adc_fifoc,
|
||||
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
|
||||
+ BIT(scodec->quirks->rx_sample_bits));
|
||||
|
||||
regmap_field_clear_bits(scodec->reg_adc_fifoc,
|
||||
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
|
||||
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
|
||||
|
||||
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
} else {
|
||||
regmap_field_clear_bits(scodec->reg_adc_fifoc,
|
||||
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
|
||||
+ BIT(scodec->quirks->rx_sample_bits));
|
||||
|
||||
/* Fill most significant bits with valid data MSB */
|
||||
regmap_field_set_bits(scodec->reg_adc_fifoc,
|
||||
- BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
|
||||
+ BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
|
||||
|
||||
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
}
|
||||
@@ -512,9 +563,9 @@ static int sun4i_codec_hw_params_playbac
|
||||
u32 val;
|
||||
|
||||
/* Set DAC sample rate */
|
||||
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
|
||||
- hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
|
||||
+ regmap_field_update_bits(scodec->reg_dac_fifoc,
|
||||
+ 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
|
||||
+ hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
|
||||
|
||||
/* Set the number of channels we want to use */
|
||||
if (params_channels(params) == 1)
|
||||
@@ -522,27 +573,26 @@ static int sun4i_codec_hw_params_playbac
|
||||
else
|
||||
val = 0;
|
||||
|
||||
- regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN),
|
||||
- val);
|
||||
+ regmap_field_update_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), val);
|
||||
|
||||
/* Set the number of sample bits to either 16 or 24 bits */
|
||||
if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
|
||||
- regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
|
||||
+ regmap_field_set_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
|
||||
|
||||
/* Set TX FIFO mode to padding the LSBs with 0 */
|
||||
- regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
|
||||
+ regmap_field_clear_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
|
||||
|
||||
scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
} else {
|
||||
- regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
|
||||
+ regmap_field_clear_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
|
||||
|
||||
/* Set TX FIFO mode to repeat the MSB */
|
||||
- regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
|
||||
+ regmap_field_set_bits(scodec->reg_dac_fifoc,
|
||||
+ BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
|
||||
|
||||
scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
}
|
||||
@@ -563,7 +613,11 @@ static int sun4i_codec_hw_params(struct
|
||||
if (!clk_freq)
|
||||
return -EINVAL;
|
||||
|
||||
- ret = clk_set_rate(scodec->clk_module, clk_freq);
|
||||
+ if (scodec->clk_module_dac &&
|
||||
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
+ ret = clk_set_rate(scodec->clk_module_dac, clk_freq);
|
||||
+ else
|
||||
+ ret = clk_set_rate(scodec->clk_module, clk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -589,10 +643,14 @@ static int sun4i_codec_startup(struct sn
|
||||
* Stop issuing DRQ when we have room for less than 16 samples
|
||||
* in our TX FIFO
|
||||
*/
|
||||
- regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
|
||||
- 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
|
||||
+ regmap_field_set_bits(scodec->reg_dac_fifoc,
|
||||
+ 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
|
||||
|
||||
- return clk_prepare_enable(scodec->clk_module);
|
||||
+ if (scodec->clk_module_dac &&
|
||||
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
+ return clk_prepare_enable(scodec->clk_module_dac);
|
||||
+ else
|
||||
+ return clk_prepare_enable(scodec->clk_module);
|
||||
}
|
||||
|
||||
static void sun4i_codec_shutdown(struct snd_pcm_substream *substream,
|
||||
@@ -601,7 +659,11 @@ static void sun4i_codec_shutdown(struct
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
- clk_disable_unprepare(scodec->clk_module);
|
||||
+ if (scodec->clk_module_dac &&
|
||||
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
+ clk_disable_unprepare(scodec->clk_module_dac);
|
||||
+ else
|
||||
+ clk_disable_unprepare(scodec->clk_module);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops sun4i_codec_dai_ops = {
|
||||
@@ -1218,6 +1280,55 @@ static const struct snd_soc_component_dr
|
||||
.endianness = 1,
|
||||
};
|
||||
|
||||
+/* sun20i D1 codec */
|
||||
+static const DECLARE_TLV_DB_SCALE(sun20i_d1_codec_dvol_scale, -12000, 75, 1);
|
||||
+
|
||||
+static const struct snd_kcontrol_new sun20i_d1_codec_codec_controls[] = {
|
||||
+ SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
|
||||
+ SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
|
||||
+ sun6i_codec_dvol_scale),
|
||||
+ SOC_DOUBLE_TLV("DAC Front Playback Volume", SUN20I_D1_CODEC_DAC_VOL_CTRL,
|
||||
+ SUN20I_D1_CODEC_DAC_VOL_L, SUN20I_D1_CODEC_DAC_VOL_R,
|
||||
+ 0xFF, 0, sun20i_d1_codec_dvol_scale),
|
||||
+
|
||||
+ SOC_SINGLE_TLV("ADC1 Capture Volume", SUN20I_D1_CODEC_ADC_VOL_CTRL1,
|
||||
+ SUN20I_D1_CODEC_ADC_VOL_CTRL1_ADC1_VOL, 0xff, 0,
|
||||
+ sun20i_d1_codec_dvol_scale),
|
||||
+ SOC_SINGLE_TLV("ADC2 Capture Volume", SUN20I_D1_CODEC_ADC_VOL_CTRL1,
|
||||
+ SUN20I_D1_CODEC_ADC_VOL_CTRL1_ADC2_VOL, 0xff, 0,
|
||||
+ sun20i_d1_codec_dvol_scale),
|
||||
+ SOC_SINGLE_TLV("ADC3 Capture Volume", SUN20I_D1_CODEC_ADC_VOL_CTRL1,
|
||||
+ SUN20I_D1_CODEC_ADC_VOL_CTRL1_ADC3_VOL, 0xff, 0,
|
||||
+ sun20i_d1_codec_dvol_scale),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget sun20i_d1_codec_codec_widgets[] = {
|
||||
+ /* Digital parts of the ADCs */
|
||||
+ SND_SOC_DAPM_SUPPLY("ADC Enable", SUN20I_D1_CODEC_ADC_FIFOC,
|
||||
+ SUN20I_D1_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0),
|
||||
+ SND_SOC_DAPM_SUPPLY("ADC1 CH Enable", SUN20I_D1_CODEC_ADC_DIG_CTRL,
|
||||
+ SUN20I_D1_CODEC_ADC_DIG_CTRL_ADC1_CH_EN, 0, NULL, 0),
|
||||
+ SND_SOC_DAPM_SUPPLY("ADC2 CH Enable", SUN20I_D1_CODEC_ADC_DIG_CTRL,
|
||||
+ SUN20I_D1_CODEC_ADC_DIG_CTRL_ADC2_CH_EN, 0, NULL, 0),
|
||||
+ SND_SOC_DAPM_SUPPLY("ADC3 CH Enable", SUN20I_D1_CODEC_ADC_DIG_CTRL,
|
||||
+ SUN20I_D1_CODEC_ADC_DIG_CTRL_ADC3_CH_EN, 0, NULL, 0),
|
||||
+ /* Digital parts of the DACs */
|
||||
+ SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
|
||||
+ SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0),
|
||||
+ SND_SOC_DAPM_SUPPLY("DAC VOL_SEL Enable", SUN20I_D1_CODEC_DAC_VOL_CTRL,
|
||||
+ SUN20I_D1_CODEC_DAC_VOL_SEL, 0, NULL, 0),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_component_driver sun20i_d1_codec_codec = {
|
||||
+ .controls = sun20i_d1_codec_codec_controls,
|
||||
+ .num_controls = ARRAY_SIZE(sun20i_d1_codec_codec_controls),
|
||||
+ .dapm_widgets = sun20i_d1_codec_codec_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(sun20i_d1_codec_codec_widgets),
|
||||
+ .idle_bias_on = 1,
|
||||
+ .use_pmdown_time = 1,
|
||||
+ .endianness = 1,
|
||||
+};
|
||||
+
|
||||
static const struct snd_soc_component_driver sun4i_codec_component = {
|
||||
.name = "sun4i-codec",
|
||||
.legacy_dai_naming = 1,
|
||||
@@ -1564,6 +1675,66 @@ static struct snd_soc_card *sun8i_v3s_co
|
||||
return card;
|
||||
};
|
||||
|
||||
+static const struct snd_soc_dapm_route sun20i_d1_codec_card_routes[] = {
|
||||
+ /* ADC Routes */
|
||||
+ { "ADC1", NULL, "ADC Enable" },
|
||||
+ { "ADC2", NULL, "ADC Enable" },
|
||||
+ { "ADC3", NULL, "ADC Enable" },
|
||||
+ { "ADC1", NULL, "ADC1 CH Enable" },
|
||||
+ { "ADC2", NULL, "ADC2 CH Enable" },
|
||||
+ { "ADC3", NULL, "ADC3 CH Enable" },
|
||||
+ { "Codec Capture", NULL, "ADC1" },
|
||||
+ { "Codec Capture", NULL, "ADC2" },
|
||||
+ { "Codec Capture", NULL, "ADC3" },
|
||||
+
|
||||
+ /* DAC Routes */
|
||||
+ { "Left DAC", NULL, "DAC Enable" },
|
||||
+ { "Right DAC", NULL, "DAC Enable" },
|
||||
+ { "Left DAC", NULL, "DAC VOL_SEL Enable" },
|
||||
+ { "Right DAC", NULL, "DAC VOL_SEL Enable" },
|
||||
+ { "Left DAC", NULL, "Codec Playback" },
|
||||
+ { "Right DAC", NULL, "Codec Playback" },
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_card *sun20i_d1_codec_create_card(struct device *dev)
|
||||
+{
|
||||
+ struct snd_soc_card *card;
|
||||
+ int ret;
|
||||
+
|
||||
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
|
||||
+ if (!card)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ aux_dev.dlc.of_node = of_parse_phandle(dev->of_node,
|
||||
+ "allwinner,codec-analog-controls",
|
||||
+ 0);
|
||||
+ if (!aux_dev.dlc.of_node) {
|
||||
+ dev_err(dev, "Can't find analog controls for codec.\n");
|
||||
+ return ERR_PTR(-EINVAL);
|
||||
+ }
|
||||
+
|
||||
+ card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
|
||||
+ if (!card->dai_link)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ card->dev = dev;
|
||||
+ card->owner = THIS_MODULE;
|
||||
+ card->name = "D1 Audio Codec";
|
||||
+ card->dapm_widgets = sun6i_codec_card_dapm_widgets;
|
||||
+ card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
|
||||
+ card->dapm_routes = sun20i_d1_codec_card_routes;
|
||||
+ card->num_dapm_routes = ARRAY_SIZE(sun20i_d1_codec_card_routes);
|
||||
+ card->aux_dev = &aux_dev;
|
||||
+ card->num_aux_devs = 1;
|
||||
+ card->fully_routed = true;
|
||||
+
|
||||
+ ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
|
||||
+ if (ret)
|
||||
+ dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
|
||||
+
|
||||
+ return card;
|
||||
+};
|
||||
+
|
||||
static const struct regmap_config sun4i_codec_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
@@ -1606,21 +1777,22 @@ static const struct regmap_config sun8i_
|
||||
.max_register = SUN8I_H3_CODEC_ADC_DBG,
|
||||
};
|
||||
|
||||
-struct sun4i_codec_quirks {
|
||||
- const struct regmap_config *regmap_config;
|
||||
- const struct snd_soc_component_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 */
|
||||
- bool has_reset;
|
||||
+static const struct regmap_config sun20i_d1_codec_regmap_config = {
|
||||
+ .reg_bits = 32,
|
||||
+ .reg_stride = 4,
|
||||
+ .val_bits = 32,
|
||||
+ .max_register = SUN20I_D1_CODEC_VRA1SPEEDUP_DOWN_CTRL,
|
||||
};
|
||||
|
||||
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_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31),
|
||||
.reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
|
||||
+ .adc_drq_en = SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN,
|
||||
+ .rx_sample_bits = SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS,
|
||||
+ .rx_trig_level = SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
|
||||
.reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
|
||||
.reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
|
||||
};
|
||||
@@ -1629,7 +1801,11 @@ static const struct sun4i_codec_quirks s
|
||||
.regmap_config = &sun6i_codec_regmap_config,
|
||||
.codec = &sun6i_codec_codec,
|
||||
.create_card = sun6i_codec_create_card,
|
||||
+ .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31),
|
||||
.reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
|
||||
+ .adc_drq_en = SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN,
|
||||
+ .rx_sample_bits = SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS,
|
||||
+ .rx_trig_level = SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
|
||||
.reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
|
||||
.reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
|
||||
.has_reset = true,
|
||||
@@ -1639,7 +1815,11 @@ static const struct sun4i_codec_quirks s
|
||||
.regmap_config = &sun7i_codec_regmap_config,
|
||||
.codec = &sun7i_codec_codec,
|
||||
.create_card = sun4i_codec_create_card,
|
||||
+ .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31),
|
||||
.reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
|
||||
+ .adc_drq_en = SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN,
|
||||
+ .rx_sample_bits = SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS,
|
||||
+ .rx_trig_level = SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
|
||||
.reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
|
||||
.reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
|
||||
};
|
||||
@@ -1648,7 +1828,11 @@ static const struct sun4i_codec_quirks s
|
||||
.regmap_config = &sun8i_a23_codec_regmap_config,
|
||||
.codec = &sun8i_a23_codec_codec,
|
||||
.create_card = sun8i_a23_codec_create_card,
|
||||
+ .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31),
|
||||
.reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
|
||||
+ .adc_drq_en = SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN,
|
||||
+ .rx_sample_bits = SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS,
|
||||
+ .rx_trig_level = SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
|
||||
.reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
|
||||
.reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
|
||||
.has_reset = true,
|
||||
@@ -1663,7 +1847,11 @@ static const struct sun4i_codec_quirks s
|
||||
*/
|
||||
.codec = &sun8i_a23_codec_codec,
|
||||
.create_card = sun8i_h3_codec_create_card,
|
||||
+ .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31),
|
||||
.reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
|
||||
+ .adc_drq_en = SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN,
|
||||
+ .rx_sample_bits = SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS,
|
||||
+ .rx_trig_level = SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
|
||||
.reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
|
||||
.reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
|
||||
.has_reset = true,
|
||||
@@ -1677,12 +1865,31 @@ static const struct sun4i_codec_quirks s
|
||||
*/
|
||||
.codec = &sun8i_a23_codec_codec,
|
||||
.create_card = sun8i_v3s_codec_create_card,
|
||||
+ .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31),
|
||||
.reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
|
||||
+ .adc_drq_en = SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN,
|
||||
+ .rx_sample_bits = SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS,
|
||||
+ .rx_trig_level = SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
|
||||
.reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
|
||||
.reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
|
||||
.has_reset = true,
|
||||
};
|
||||
|
||||
+static const struct sun4i_codec_quirks sun20i_d1_codec_quirks = {
|
||||
+ .regmap_config = &sun20i_d1_codec_regmap_config,
|
||||
+ .codec = &sun20i_d1_codec_codec,
|
||||
+ .create_card = sun20i_d1_codec_create_card,
|
||||
+ .reg_dac_fifoc = REG_FIELD(SUN20I_D1_CODEC_DAC_FIFOC, 0, 31),
|
||||
+ .reg_adc_fifoc = REG_FIELD(SUN20I_D1_CODEC_ADC_FIFOC, 0, 31),
|
||||
+ .adc_drq_en = SUN20I_D1_CODEC_ADC_FIFOC_ADC_DRQ_EN,
|
||||
+ .rx_sample_bits = SUN20I_D1_CODEC_ADC_FIFOC_RX_SAMPLE_BITS,
|
||||
+ .rx_trig_level = SUN20I_D1_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
|
||||
+ .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
|
||||
+ .reg_adc_rxdata = SUN20I_D1_CODEC_ADC_RXDATA,
|
||||
+ .has_reset = true,
|
||||
+ .has_dual_clock = true,
|
||||
+};
|
||||
+
|
||||
static const struct of_device_id sun4i_codec_of_match[] = {
|
||||
{
|
||||
.compatible = "allwinner,sun4i-a10-codec",
|
||||
@@ -1708,6 +1915,10 @@ static const struct of_device_id sun4i_c
|
||||
.compatible = "allwinner,sun8i-v3s-codec",
|
||||
.data = &sun8i_v3s_codec_quirks,
|
||||
},
|
||||
+ {
|
||||
+ .compatible = "allwinner,sun20i-d1-codec",
|
||||
+ .data = &sun20i_d1_codec_quirks,
|
||||
+ },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
|
||||
@@ -1736,6 +1947,7 @@ static int sun4i_codec_probe(struct plat
|
||||
dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
+ scodec->quirks = quirks;
|
||||
|
||||
scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
quirks->regmap_config);
|
||||
@@ -1751,10 +1963,24 @@ static int sun4i_codec_probe(struct plat
|
||||
return PTR_ERR(scodec->clk_apb);
|
||||
}
|
||||
|
||||
- scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
|
||||
- if (IS_ERR(scodec->clk_module)) {
|
||||
- dev_err(&pdev->dev, "Failed to get the module clock\n");
|
||||
- return PTR_ERR(scodec->clk_module);
|
||||
+ if (quirks->has_dual_clock) {
|
||||
+ scodec->clk_module = devm_clk_get(&pdev->dev, "adc");
|
||||
+ if (IS_ERR(scodec->clk_module)) {
|
||||
+ dev_err(&pdev->dev, "Failed to get the ADC module clock\n");
|
||||
+ return PTR_ERR(scodec->clk_module);
|
||||
+ }
|
||||
+
|
||||
+ scodec->clk_module_dac = devm_clk_get(&pdev->dev, "dac");
|
||||
+ if (IS_ERR(scodec->clk_module_dac)) {
|
||||
+ dev_err(&pdev->dev, "Failed to get the DAC module clock\n");
|
||||
+ return PTR_ERR(scodec->clk_module_dac);
|
||||
+ }
|
||||
+ } else {
|
||||
+ scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
|
||||
+ if (IS_ERR(scodec->clk_module)) {
|
||||
+ dev_err(&pdev->dev, "Failed to get the module clock\n");
|
||||
+ return PTR_ERR(scodec->clk_module);
|
||||
+ }
|
||||
}
|
||||
|
||||
if (quirks->has_reset) {
|
||||
@@ -1790,6 +2016,16 @@ static int sun4i_codec_probe(struct plat
|
||||
dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
+ }
|
||||
+
|
||||
+ scodec->reg_dac_fifoc = devm_regmap_field_alloc(&pdev->dev,
|
||||
+ scodec->regmap,
|
||||
+ quirks->reg_dac_fifoc);
|
||||
+ if (IS_ERR(scodec->reg_dac_fifoc)) {
|
||||
+ ret = PTR_ERR(scodec->reg_dac_fifoc);
|
||||
+ dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
|
||||
+ ret);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
/* Enable the bus clock */
|
||||
@ -1,274 +0,0 @@
|
||||
From c8c3c516ca5c38e7858055ce0137efde17a07190 Mon Sep 17 00:00:00 2001
|
||||
From: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
Date: Sat, 5 Aug 2023 21:05:04 +0300
|
||||
Subject: [PATCH 10/14] ASoC: sunxi: Add new driver for Allwinner D1/T113s
|
||||
codec's analog path controls
|
||||
|
||||
The internal codec on D1/T113s is split into 2 parts like the previous
|
||||
ones. But now analog path controls registers are mapped directly
|
||||
on the bus, right after the registers of the digital part.
|
||||
|
||||
Add an ASoC component driver for it. This should be tied to the codec
|
||||
audio card as an auxiliary device.
|
||||
|
||||
Signed-off-by: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
---
|
||||
sound/soc/sunxi/Kconfig | 11 ++
|
||||
sound/soc/sunxi/Makefile | 1 +
|
||||
sound/soc/sunxi/sun20i-d1-codec-analog.c | 220 +++++++++++++++++++++++
|
||||
3 files changed, 232 insertions(+)
|
||||
create mode 100644 sound/soc/sunxi/sun20i-d1-codec-analog.c
|
||||
|
||||
--- a/sound/soc/sunxi/Kconfig
|
||||
+++ b/sound/soc/sunxi/Kconfig
|
||||
@@ -38,6 +38,17 @@ config SND_SUN50I_CODEC_ANALOG
|
||||
Say Y or M if you want to add support for the analog controls for
|
||||
the codec embedded in Allwinner A64 SoC.
|
||||
|
||||
+config SND_SUN20I_D1_CODEC_ANALOG
|
||||
+ tristate "Allwinner D1 Codec Analog Controls Support"
|
||||
+ depends on ARCH_SUNXI || COMPILE_TEST
|
||||
+ select REGMAP_MMIO
|
||||
+ help
|
||||
+ This option enables the analog controls part of the internal audio
|
||||
+ codec for Allwinner D1/T113s SoCs family.
|
||||
+
|
||||
+ Say Y or M if you want to add support for the analog part of
|
||||
+ the D1/T113s audio codec.
|
||||
+
|
||||
config SND_SUN4I_I2S
|
||||
tristate "Allwinner A10 I2S Support"
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
--- a/sound/soc/sunxi/Makefile
|
||||
+++ b/sound/soc/sunxi/Makefile
|
||||
@@ -4,6 +4,7 @@ obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s
|
||||
obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
|
||||
obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
|
||||
obj-$(CONFIG_SND_SUN50I_CODEC_ANALOG) += sun50i-codec-analog.o
|
||||
+obj-$(CONFIG_SND_SUN20I_D1_CODEC_ANALOG) += sun20i-d1-codec-analog.o
|
||||
obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o
|
||||
obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o
|
||||
obj-$(CONFIG_SND_SUN50I_DMIC) += sun50i-dmic.o
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/sunxi/sun20i-d1-codec-analog.c
|
||||
@@ -0,0 +1,220 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * This driver supports the analog controls for the internal codec
|
||||
+ * found in Allwinner's D1/T113s SoCs family.
|
||||
+ *
|
||||
+ * Based on sun50i-codec-analog.c
|
||||
+ */
|
||||
+
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_device.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dapm.h>
|
||||
+#include <sound/tlv.h>
|
||||
+
|
||||
+/* Codec analog control register offsets and bit fields */
|
||||
+#define SUN20I_D1_ADDA_ADC1 (0x00)
|
||||
+#define SUN20I_D1_ADDA_ADC2 (0x04)
|
||||
+#define SUN20I_D1_ADDA_ADC3 (0x08)
|
||||
+#define SUN20I_D1_ADDA_ADC_EN (31)
|
||||
+#define SUN20I_D1_ADDA_ADC_PGA_EN (30)
|
||||
+#define SUN20I_D1_ADDA_ADC_MIC_SIN_EN (28)
|
||||
+#define SUN20I_D1_ADDA_ADC_LINEINLEN (23)
|
||||
+#define SUN20I_D1_ADDA_ADC_PGA_GAIN (8)
|
||||
+
|
||||
+#define SUN20I_D1_ADDA_DAC (0x10)
|
||||
+#define SUN20I_D1_ADDA_DAC_DACL_EN (15)
|
||||
+#define SUN20I_D1_ADDA_DAC_DACR_EN (14)
|
||||
+
|
||||
+#define SUN20I_D1_ADDA_MICBIAS (0x18)
|
||||
+#define SUN20I_D1_ADDA_MICBIAS_MMICBIASEN (7)
|
||||
+
|
||||
+#define SUN20I_D1_ADDA_RAMP (0x1C)
|
||||
+#define SUN20I_D1_ADDA_RAMP_RD_EN (0)
|
||||
+
|
||||
+#define SUN20I_D1_ADDA_HP2 (0x40)
|
||||
+#define SUN20I_D1_ADDA_HP2_HEADPHONE_GAIN (28)
|
||||
+
|
||||
+#define SUN20I_D1_ADDA_ADC_CUR_REG (0x4C)
|
||||
+
|
||||
+static const DECLARE_TLV_DB_RANGE(sun20i_d1_codec_adc_gain_scale,
|
||||
+ 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
|
||||
+ 1, 3, TLV_DB_SCALE_ITEM(600, 0, 0),
|
||||
+ 4, 4, TLV_DB_SCALE_ITEM(900, 0, 0),
|
||||
+ 5, 31, TLV_DB_SCALE_ITEM(1000, 100, 0),
|
||||
+);
|
||||
+
|
||||
+static const DECLARE_TLV_DB_SCALE(sun20i_d1_codec_hp_vol_scale, -4200, 600, 0);
|
||||
+
|
||||
+/* volume controls */
|
||||
+static const struct snd_kcontrol_new sun20i_d1_codec_controls[] = {
|
||||
+ SOC_SINGLE_TLV("Headphone Playback Volume",
|
||||
+ SUN20I_D1_ADDA_HP2,
|
||||
+ SUN20I_D1_ADDA_HP2_HEADPHONE_GAIN, 0x7, 1,
|
||||
+ sun20i_d1_codec_hp_vol_scale),
|
||||
+ SOC_SINGLE_TLV("ADC1 Gain Capture Volume",
|
||||
+ SUN20I_D1_ADDA_ADC1,
|
||||
+ SUN20I_D1_ADDA_ADC_PGA_GAIN, 0x1f, 0,
|
||||
+ sun20i_d1_codec_adc_gain_scale),
|
||||
+ SOC_SINGLE_TLV("ADC2 Gain Capture Volume",
|
||||
+ SUN20I_D1_ADDA_ADC2,
|
||||
+ SUN20I_D1_ADDA_ADC_PGA_GAIN, 0x1f, 0,
|
||||
+ sun20i_d1_codec_adc_gain_scale),
|
||||
+ SOC_SINGLE_TLV("ADC3 Gain Capture Volume",
|
||||
+ SUN20I_D1_ADDA_ADC3,
|
||||
+ SUN20I_D1_ADDA_ADC_PGA_GAIN, 0x1f, 0,
|
||||
+ sun20i_d1_codec_adc_gain_scale),
|
||||
+};
|
||||
+
|
||||
+/* ADC mixer controls */
|
||||
+static const struct snd_kcontrol_new sun20i_d1_codec_mixer_controls[] = {
|
||||
+ SOC_DAPM_DOUBLE_R("Line In Switch",
|
||||
+ SUN20I_D1_ADDA_ADC1,
|
||||
+ SUN20I_D1_ADDA_ADC2,
|
||||
+ SUN20I_D1_ADDA_ADC_LINEINLEN, 1, 0),
|
||||
+};
|
||||
+
|
||||
+static const char * const sun20i_d1_codec_mic3_src_enum_text[] = {
|
||||
+ "Differential", "Single",
|
||||
+};
|
||||
+
|
||||
+static SOC_ENUM_SINGLE_DECL(sun20i_d1_codec_mic3_src_enum,
|
||||
+ SUN20I_D1_ADDA_ADC3,
|
||||
+ SUN20I_D1_ADDA_ADC_MIC_SIN_EN,
|
||||
+ sun20i_d1_codec_mic3_src_enum_text);
|
||||
+
|
||||
+static const struct snd_kcontrol_new sun20i_d1_codec_mic3_input_src[] = {
|
||||
+ SOC_DAPM_ENUM("MIC3 Source Capture Route",
|
||||
+ sun20i_d1_codec_mic3_src_enum),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget sun20i_d1_codec_widgets[] = {
|
||||
+ /* DAC */
|
||||
+ SND_SOC_DAPM_DAC("Left DAC", NULL, SUN20I_D1_ADDA_DAC,
|
||||
+ SUN20I_D1_ADDA_DAC_DACL_EN, 0),
|
||||
+ SND_SOC_DAPM_DAC("Right DAC", NULL, SUN20I_D1_ADDA_DAC,
|
||||
+ SUN20I_D1_ADDA_DAC_DACR_EN, 0),
|
||||
+ /* ADC */
|
||||
+ SND_SOC_DAPM_ADC("ADC1", NULL, SUN20I_D1_ADDA_ADC1,
|
||||
+ SUN20I_D1_ADDA_ADC_EN, 0),
|
||||
+ SND_SOC_DAPM_ADC("ADC2", NULL, SUN20I_D1_ADDA_ADC2,
|
||||
+ SUN20I_D1_ADDA_ADC_EN, 0),
|
||||
+ SND_SOC_DAPM_ADC("ADC3", NULL, SUN20I_D1_ADDA_ADC3,
|
||||
+ SUN20I_D1_ADDA_ADC_EN, 0),
|
||||
+
|
||||
+ /* ADC Mixers */
|
||||
+ SND_SOC_DAPM_MIXER("ADC1 Mixer", SND_SOC_NOPM, 0, 0,
|
||||
+ sun20i_d1_codec_mixer_controls,
|
||||
+ ARRAY_SIZE(sun20i_d1_codec_mixer_controls)),
|
||||
+ SND_SOC_DAPM_MIXER("ADC2 Mixer", SND_SOC_NOPM, 0, 0,
|
||||
+ sun20i_d1_codec_mixer_controls,
|
||||
+ ARRAY_SIZE(sun20i_d1_codec_mixer_controls)),
|
||||
+
|
||||
+ /* Headphone */
|
||||
+ SND_SOC_DAPM_OUTPUT("HP"),
|
||||
+ SND_SOC_DAPM_SUPPLY("RAMP Enable", SUN20I_D1_ADDA_RAMP,
|
||||
+ SUN20I_D1_ADDA_RAMP_RD_EN, 0, NULL, 0),
|
||||
+
|
||||
+ /* Line input */
|
||||
+ SND_SOC_DAPM_INPUT("LINEIN"),
|
||||
+
|
||||
+ /* Microphone input */
|
||||
+ SND_SOC_DAPM_INPUT("MIC3"),
|
||||
+
|
||||
+ /* Microphone input path */
|
||||
+ SND_SOC_DAPM_MUX("MIC3 Source Capture Route", SND_SOC_NOPM, 0, 0,
|
||||
+ sun20i_d1_codec_mic3_input_src),
|
||||
+
|
||||
+ SND_SOC_DAPM_PGA("Mic3 Amplifier", SUN20I_D1_ADDA_ADC3,
|
||||
+ SUN20I_D1_ADDA_ADC_PGA_EN, 0, NULL, 0),
|
||||
+
|
||||
+ /* Microphone Bias */
|
||||
+ SND_SOC_DAPM_SUPPLY("MBIAS", SUN20I_D1_ADDA_MICBIAS,
|
||||
+ SUN20I_D1_ADDA_MICBIAS_MMICBIASEN, 0, NULL, 0),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_route sun20i_d1_codec_routes[] = {
|
||||
+ /* Headphone Routes */
|
||||
+ { "HP", NULL, "Left DAC" },
|
||||
+ { "HP", NULL, "Right DAC" },
|
||||
+ { "HP", NULL, "RAMP Enable" },
|
||||
+
|
||||
+ /* Line input Routes */
|
||||
+ { "ADC1", NULL, "ADC1 Mixer" },
|
||||
+ { "ADC2", NULL, "ADC2 Mixer" },
|
||||
+ { "ADC1 Mixer", "Line In Switch", "LINEIN" },
|
||||
+ { "ADC2 Mixer", "Line In Switch", "LINEIN" },
|
||||
+
|
||||
+ /* Microphone Routes */
|
||||
+ { "MIC3 Source Capture Route", "Differential", "MIC3" },
|
||||
+ { "MIC3 Source Capture Route", "Single", "MIC3" },
|
||||
+ { "Mic3 Amplifier", NULL, "MIC3 Source Capture Route" },
|
||||
+ { "ADC3", NULL, "Mic3 Amplifier" },
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_component_driver sun20i_d1_codec_analog_cmpnt_drv = {
|
||||
+ .controls = sun20i_d1_codec_controls,
|
||||
+ .num_controls = ARRAY_SIZE(sun20i_d1_codec_controls),
|
||||
+ .dapm_widgets = sun20i_d1_codec_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(sun20i_d1_codec_widgets),
|
||||
+ .dapm_routes = sun20i_d1_codec_routes,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(sun20i_d1_codec_routes),
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id sun20i_d1_codec_analog_of_match[] = {
|
||||
+ {
|
||||
+ .compatible = "allwinner,sun20i-d1-codec-analog",
|
||||
+ },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, sun20i_d1_codec_analog_of_match);
|
||||
+
|
||||
+static const struct regmap_config sun20i_d1_codec_regmap_config = {
|
||||
+ .reg_bits = 32,
|
||||
+ .reg_stride = 4,
|
||||
+ .val_bits = 32,
|
||||
+ .max_register = SUN20I_D1_ADDA_ADC_CUR_REG,
|
||||
+};
|
||||
+
|
||||
+static int sun20i_d1_codec_analog_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct regmap *regmap;
|
||||
+ void __iomem *base;
|
||||
+
|
||||
+ base = devm_platform_ioremap_resource(pdev, 0);
|
||||
+ if (IS_ERR(base)) {
|
||||
+ dev_err(&pdev->dev, "Failed to map the registers\n");
|
||||
+ return PTR_ERR(base);
|
||||
+ }
|
||||
+
|
||||
+ regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
+ &sun20i_d1_codec_regmap_config);
|
||||
+ if (IS_ERR(regmap)) {
|
||||
+ dev_err(&pdev->dev, "Failed to create regmap\n");
|
||||
+ return PTR_ERR(regmap);
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(&pdev->dev,
|
||||
+ &sun20i_d1_codec_analog_cmpnt_drv,
|
||||
+ NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver sun20i_d1_codec_analog_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "sun20i-d1-codec-analog",
|
||||
+ .of_match_table = sun20i_d1_codec_analog_of_match,
|
||||
+ },
|
||||
+ .probe = sun20i_d1_codec_analog_probe,
|
||||
+};
|
||||
+module_platform_driver(sun20i_d1_codec_analog_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for D1");
|
||||
+MODULE_AUTHOR("Maksim Kiselev <bigunclemax@gmail.com>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_ALIAS("platform:sun20i-d1-codec-analog");
|
||||
@ -1,44 +0,0 @@
|
||||
From edebcc9d47f0bfe9bd769a2c578dda16acbfbef2 Mon Sep 17 00:00:00 2001
|
||||
From: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
Date: Sat, 5 Aug 2023 21:05:05 +0300
|
||||
Subject: [PATCH 14/14] riscv: dts: allwinner: d1: Add device nodes for
|
||||
internal audio codec
|
||||
|
||||
Add DT nodes for the internal D1/T113s audio codec and its analog part.
|
||||
|
||||
Signed-off-by: Maksim Kiselev <bigunclemax@gmail.com>
|
||||
---
|
||||
.../boot/dts/allwinner/sunxi-d1s-t113.dtsi | 22 +++++++++++++++++++
|
||||
1 file changed, 22 insertions(+)
|
||||
|
||||
--- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
|
||||
+++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
|
||||
@@ -166,6 +166,28 @@
|
||||
#io-channel-cells = <1>;
|
||||
};
|
||||
|
||||
+ codec: codec@2030000 {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "allwinner,sun20i-d1-codec";
|
||||
+ reg = <0x02030000 0x300>;
|
||||
+ interrupts = <SOC_PERIPHERAL_IRQ(25) IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ clocks = <&ccu CLK_BUS_AUDIO>,
|
||||
+ <&ccu CLK_AUDIO_ADC>,
|
||||
+ <&ccu CLK_AUDIO_DAC>;
|
||||
+ clock-names = "apb", "adc", "dac";
|
||||
+ resets = <&ccu RST_BUS_AUDIO>;
|
||||
+ dmas = <&dma 7>, <&dma 7>;
|
||||
+ dma-names = "rx", "tx";
|
||||
+ allwinner,codec-analog-controls = <&codec_analog>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ codec_analog: codec-analog@2030300 {
|
||||
+ compatible = "allwinner,sun20i-d1-codec-analog";
|
||||
+ reg = <0x02030300 0xd00>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
dmic: dmic@2031000 {
|
||||
compatible = "allwinner,sun20i-d1-dmic",
|
||||
"allwinner,sun50i-h6-dmic";
|
||||
Loading…
x
Reference in New Issue
Block a user