From 324752632a2017cc2e2464d110445328ad2a987c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 19 Nov 2013 01:06:15 -0800 Subject: ASoC: rcar: rename GEN2_SRU to GEN2_SCU Gen2 has SCU. SRU is for Gen1 Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/rcar_snd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index 12afab18945d..a818ff76b138 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -18,7 +18,7 @@ #define RSND_GEN1_ADG 1 #define RSND_GEN1_SSI 2 -#define RSND_GEN2_SRU 0 +#define RSND_GEN2_SCU 0 #define RSND_GEN2_ADG 1 #define RSND_GEN2_SSIU 2 #define RSND_GEN2_SSI 3 -- cgit v1.2.3 From e64001e8efc107992fd835770f6383d0dc731594 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 20 Nov 2013 13:17:07 +0000 Subject: ASoC: wm5110: Add extra AIF2 channels Signed-off-by: D.J. Barrow Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- include/linux/mfd/arizona/registers.h | 121 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.c | 8 +++ sound/soc/codecs/arizona.h | 2 +- sound/soc/codecs/wm5110.c | 48 +++++++++++++- 4 files changed, 176 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 4706d3d46e56..8f4c9d77ab20 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -511,6 +511,38 @@ #define ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME 0x74D #define ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE 0x74E #define ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME 0x74F +#define ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE 0x750 +#define ARIZONA_AIF2TX3MIX_INPUT_1_VOLUME 0x751 +#define ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE 0x752 +#define ARIZONA_AIF2TX3MIX_INPUT_2_VOLUME 0x753 +#define ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE 0x754 +#define ARIZONA_AIF2TX3MIX_INPUT_3_VOLUME 0x755 +#define ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE 0x756 +#define ARIZONA_AIF2TX3MIX_INPUT_4_VOLUME 0x757 +#define ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE 0x758 +#define ARIZONA_AIF2TX4MIX_INPUT_1_VOLUME 0x759 +#define ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE 0x75A +#define ARIZONA_AIF2TX4MIX_INPUT_2_VOLUME 0x75B +#define ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE 0x75C +#define ARIZONA_AIF2TX4MIX_INPUT_3_VOLUME 0x75D +#define ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE 0x75E +#define ARIZONA_AIF2TX4MIX_INPUT_4_VOLUME 0x75F +#define ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE 0x760 +#define ARIZONA_AIF2TX5MIX_INPUT_1_VOLUME 0x761 +#define ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE 0x762 +#define ARIZONA_AIF2TX5MIX_INPUT_2_VOLUME 0x763 +#define ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE 0x764 +#define ARIZONA_AIF2TX5MIX_INPUT_3_VOLUME 0x765 +#define ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE 0x766 +#define ARIZONA_AIF2TX5MIX_INPUT_4_VOLUME 0x767 +#define ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE 0x768 +#define ARIZONA_AIF2TX6MIX_INPUT_1_VOLUME 0x769 +#define ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE 0x76A +#define ARIZONA_AIF2TX6MIX_INPUT_2_VOLUME 0x76B +#define ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE 0x76C +#define ARIZONA_AIF2TX6MIX_INPUT_3_VOLUME 0x76D +#define ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE 0x76E +#define ARIZONA_AIF2TX6MIX_INPUT_4_VOLUME 0x76F #define ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE 0x780 #define ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME 0x781 #define ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE 0x782 @@ -3725,6 +3757,35 @@ #define ARIZONA_AIF2TX2_SLOT_SHIFT 0 /* AIF2TX2_SLOT - [5:0] */ #define ARIZONA_AIF2TX2_SLOT_WIDTH 6 /* AIF2TX2_SLOT - [5:0] */ +/* + * R1355 (0x54B) - AIF2 Frame Ctrl 5 + */ +#define ARIZONA_AIF2TX3_SLOT_MASK 0x003F /* AIF2TX3_SLOT - [5:0] */ +#define ARIZONA_AIF2TX3_SLOT_SHIFT 0 /* AIF2TX3_SLOT - [5:0] */ +#define ARIZONA_AIF2TX3_SLOT_WIDTH 6 /* AIF2TX3_SLOT - [5:0] */ + +/* + * R1356 (0x54C) - AIF2 Frame Ctrl 6 + */ +#define ARIZONA_AIF2TX4_SLOT_MASK 0x003F /* AIF2TX4_SLOT - [5:0] */ +#define ARIZONA_AIF2TX4_SLOT_SHIFT 0 /* AIF2TX4_SLOT - [5:0] */ +#define ARIZONA_AIF2TX4_SLOT_WIDTH 6 /* AIF2TX4_SLOT - [5:0] */ + + +/* + * R1357 (0x54D) - AIF2 Frame Ctrl 7 + */ +#define ARIZONA_AIF2TX5_SLOT_MASK 0x003F /* AIF2TX5_SLOT - [5:0] */ +#define ARIZONA_AIF2TX5_SLOT_SHIFT 0 /* AIF2TX5_SLOT - [5:0] */ +#define ARIZONA_AIF2TX5_SLOT_WIDTH 6 /* AIF2TX5_SLOT - [5:0] */ + +/* + * R1358 (0x54E) - AIF2 Frame Ctrl 8 + */ +#define ARIZONA_AIF2TX6_SLOT_MASK 0x003F /* AIF2TX6_SLOT - [5:0] */ +#define ARIZONA_AIF2TX6_SLOT_SHIFT 0 /* AIF2TX6_SLOT - [5:0] */ +#define ARIZONA_AIF2TX6_SLOT_WIDTH 6 /* AIF2TX6_SLOT - [5:0] */ + /* * R1361 (0x551) - AIF2 Frame Ctrl 11 */ @@ -3739,9 +3800,53 @@ #define ARIZONA_AIF2RX2_SLOT_SHIFT 0 /* AIF2RX2_SLOT - [5:0] */ #define ARIZONA_AIF2RX2_SLOT_WIDTH 6 /* AIF2RX2_SLOT - [5:0] */ +/* + * R1363 (0x553) - AIF2 Frame Ctrl 13 + */ +#define ARIZONA_AIF2RX3_SLOT_MASK 0x003F /* AIF2RX3_SLOT - [5:0] */ +#define ARIZONA_AIF2RX3_SLOT_SHIFT 0 /* AIF2RX3_SLOT - [5:0] */ +#define ARIZONA_AIF2RX3_SLOT_WIDTH 6 /* AIF2RX3_SLOT - [5:0] */ + +/* + * R1364 (0x554) - AIF2 Frame Ctrl 14 + */ +#define ARIZONA_AIF2RX4_SLOT_MASK 0x003F /* AIF2RX4_SLOT - [5:0] */ +#define ARIZONA_AIF2RX4_SLOT_SHIFT 0 /* AIF2RX4_SLOT - [5:0] */ +#define ARIZONA_AIF2RX4_SLOT_WIDTH 6 /* AIF2RX4_SLOT - [5:0] */ + +/* + * R1365 (0x555) - AIF2 Frame Ctrl 15 + */ +#define ARIZONA_AIF2RX5_SLOT_MASK 0x003F /* AIF2RX5_SLOT - [5:0] */ +#define ARIZONA_AIF2RX5_SLOT_SHIFT 0 /* AIF2RX5_SLOT - [5:0] */ +#define ARIZONA_AIF2RX5_SLOT_WIDTH 6 /* AIF2RX5_SLOT - [5:0] */ + +/* + * R1366 (0x556) - AIF2 Frame Ctrl 16 + */ +#define ARIZONA_AIF2RX6_SLOT_MASK 0x003F /* AIF2RX6_SLOT - [5:0] */ +#define ARIZONA_AIF2RX6_SLOT_SHIFT 0 /* AIF2RX6_SLOT - [5:0] */ +#define ARIZONA_AIF2RX6_SLOT_WIDTH 6 /* AIF2RX6_SLOT - [5:0] */ + /* * R1369 (0x559) - AIF2 Tx Enables */ +#define ARIZONA_AIF2TX6_ENA 0x0020 /* AIF2TX6_ENA */ +#define ARIZONA_AIF2TX6_ENA_MASK 0x0020 /* AIF2TX6_ENA */ +#define ARIZONA_AIF2TX6_ENA_SHIFT 5 /* AIF2TX6_ENA */ +#define ARIZONA_AIF2TX6_ENA_WIDTH 1 /* AIF2TX6_ENA */ +#define ARIZONA_AIF2TX5_ENA 0x0010 /* AIF2TX5_ENA */ +#define ARIZONA_AIF2TX5_ENA_MASK 0x0010 /* AIF2TX5_ENA */ +#define ARIZONA_AIF2TX5_ENA_SHIFT 4 /* AIF2TX5_ENA */ +#define ARIZONA_AIF2TX5_ENA_WIDTH 1 /* AIF2TX5_ENA */ +#define ARIZONA_AIF2TX4_ENA 0x0008 /* AIF2TX4_ENA */ +#define ARIZONA_AIF2TX4_ENA_MASK 0x0008 /* AIF2TX4_ENA */ +#define ARIZONA_AIF2TX4_ENA_SHIFT 3 /* AIF2TX4_ENA */ +#define ARIZONA_AIF2TX4_ENA_WIDTH 1 /* AIF2TX4_ENA */ +#define ARIZONA_AIF2TX3_ENA 0x0004 /* AIF2TX3_ENA */ +#define ARIZONA_AIF2TX3_ENA_MASK 0x0004 /* AIF2TX3_ENA */ +#define ARIZONA_AIF2TX3_ENA_SHIFT 2 /* AIF2TX3_ENA */ +#define ARIZONA_AIF2TX3_ENA_WIDTH 1 /* AIF2TX3_ENA */ #define ARIZONA_AIF2TX2_ENA 0x0002 /* AIF2TX2_ENA */ #define ARIZONA_AIF2TX2_ENA_MASK 0x0002 /* AIF2TX2_ENA */ #define ARIZONA_AIF2TX2_ENA_SHIFT 1 /* AIF2TX2_ENA */ @@ -3754,6 +3859,22 @@ /* * R1370 (0x55A) - AIF2 Rx Enables */ +#define ARIZONA_AIF2RX6_ENA 0x0020 /* AIF2RX6_ENA */ +#define ARIZONA_AIF2RX6_ENA_MASK 0x0020 /* AIF2RX6_ENA */ +#define ARIZONA_AIF2RX6_ENA_SHIFT 5 /* AIF2RX6_ENA */ +#define ARIZONA_AIF2RX6_ENA_WIDTH 1 /* AIF2RX6_ENA */ +#define ARIZONA_AIF2RX5_ENA 0x0010 /* AIF2RX5_ENA */ +#define ARIZONA_AIF2RX5_ENA_MASK 0x0010 /* AIF2RX5_ENA */ +#define ARIZONA_AIF2RX5_ENA_SHIFT 4 /* AIF2RX5_ENA */ +#define ARIZONA_AIF2RX5_ENA_WIDTH 1 /* AIF2RX5_ENA */ +#define ARIZONA_AIF2RX4_ENA 0x0008 /* AIF2RX4_ENA */ +#define ARIZONA_AIF2RX4_ENA_MASK 0x0008 /* AIF2RX4_ENA */ +#define ARIZONA_AIF2RX4_ENA_SHIFT 3 /* AIF2RX4_ENA */ +#define ARIZONA_AIF2RX4_ENA_WIDTH 1 /* AIF2RX4_ENA */ +#define ARIZONA_AIF2RX3_ENA 0x0004 /* AIF2RX3_ENA */ +#define ARIZONA_AIF2RX3_ENA_MASK 0x0004 /* AIF2RX3_ENA */ +#define ARIZONA_AIF2RX3_ENA_SHIFT 2 /* AIF2RX3_ENA */ +#define ARIZONA_AIF2RX3_ENA_WIDTH 1 /* AIF2RX3_ENA */ #define ARIZONA_AIF2RX2_ENA 0x0002 /* AIF2RX2_ENA */ #define ARIZONA_AIF2RX2_ENA_MASK 0x0002 /* AIF2RX2_ENA */ #define ARIZONA_AIF2RX2_ENA_SHIFT 1 /* AIF2RX2_ENA */ diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 6f05b17d1965..6977bf9f19a8 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -292,6 +292,10 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "AIF1RX8", "AIF2RX1", "AIF2RX2", + "AIF2RX3", + "AIF2RX4", + "AIF2RX5", + "AIF2RX6", "AIF3RX1", "AIF3RX2", "SLIMRX1", @@ -395,6 +399,10 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { 0x27, 0x28, /* AIF2RX1 */ 0x29, + 0x2a, + 0x2b, + 0x2c, + 0x2d, 0x30, /* AIF3RX1 */ 0x31, 0x38, /* SLIMRX1 */ diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 9e81b6392692..1f96672c7c1e 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -81,7 +81,7 @@ struct arizona_priv { unsigned int spk_ena_pending:1; }; -#define ARIZONA_NUM_MIXER_INPUTS 99 +#define ARIZONA_NUM_MIXER_INPUTS 103 extern const unsigned int arizona_mixer_tlv[]; extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index bbd64384ca1c..181de7df2c87 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -302,6 +302,10 @@ ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), @@ -361,6 +365,10 @@ ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); @@ -561,11 +569,27 @@ SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, @@ -703,6 +727,10 @@ ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"), ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), +ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"), +ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"), +ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"), +ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"), ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), @@ -764,6 +792,10 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"), { name, "AIF1RX8", "AIF1RX8" }, \ { name, "AIF2RX1", "AIF2RX1" }, \ { name, "AIF2RX2", "AIF2RX2" }, \ + { name, "AIF2RX3", "AIF2RX3" }, \ + { name, "AIF2RX4", "AIF2RX4" }, \ + { name, "AIF2RX5", "AIF2RX5" }, \ + { name, "AIF2RX6", "AIF2RX6" }, \ { name, "AIF3RX1", "AIF3RX1" }, \ { name, "AIF3RX2", "AIF3RX2" }, \ { name, "SLIMRX1", "SLIMRX1" }, \ @@ -861,9 +893,17 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "AIF2 Capture", NULL, "AIF2TX1" }, { "AIF2 Capture", NULL, "AIF2TX2" }, + { "AIF2 Capture", NULL, "AIF2TX3" }, + { "AIF2 Capture", NULL, "AIF2TX4" }, + { "AIF2 Capture", NULL, "AIF2TX5" }, + { "AIF2 Capture", NULL, "AIF2TX6" }, { "AIF2RX1", NULL, "AIF2 Playback" }, { "AIF2RX2", NULL, "AIF2 Playback" }, + { "AIF2RX3", NULL, "AIF2 Playback" }, + { "AIF2RX4", NULL, "AIF2 Playback" }, + { "AIF2RX5", NULL, "AIF2 Playback" }, + { "AIF2RX6", NULL, "AIF2 Playback" }, { "AIF3 Capture", NULL, "AIF3TX1" }, { "AIF3 Capture", NULL, "AIF3TX2" }, @@ -947,6 +987,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), + ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"), + ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"), + ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"), + ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"), ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), @@ -1067,14 +1111,14 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .playback = { .stream_name = "AIF2 Playback", .channels_min = 1, - .channels_max = 2, + .channels_max = 6, .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, .capture = { .stream_name = "AIF2 Capture", .channels_min = 1, - .channels_max = 2, + .channels_max = 6, .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, -- cgit v1.2.3 From 254dc326dbfd23c2678fafad1b84fc0e42ac4374 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 19 Nov 2013 16:04:03 +0000 Subject: ASoC: wm5110: Expose input high pass filter controls Acked-by: Mark Brown Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm5110-tables.c | 4 ++++ include/linux/mfd/arizona/registers.h | 37 +++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.c | 10 ++++++++++ sound/soc/codecs/arizona.h | 1 + sound/soc/codecs/wm5110.c | 19 ++++++++++++++++++ 5 files changed, 71 insertions(+) (limited to 'include') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 4430404471c0..3b079f6b021e 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -518,6 +518,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000300, 0x0000 }, /* R768 - Input Enables */ { 0x00000308, 0x0000 }, /* R776 - Input Rate */ { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */ + { 0x0000030C, 0x0002 }, /* R780 - HPF Control */ { 0x00000310, 0x2080 }, /* R784 - IN1L Control */ { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */ { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */ @@ -539,6 +540,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000328, 0x2000 }, /* R808 - IN4L Control */ { 0x00000329, 0x0180 }, /* R809 - ADC Digital Volume 4L */ { 0x0000032A, 0x0000 }, /* R810 - DMIC4L Control */ + { 0x0000032C, 0x0000 }, /* R812 - IN4R Control */ { 0x0000032D, 0x0180 }, /* R813 - ADC Digital Volume 4R */ { 0x0000032E, 0x0000 }, /* R814 - DMIC4R Control */ { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ @@ -1512,6 +1514,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_INPUT_ENABLES_STATUS: case ARIZONA_INPUT_RATE: case ARIZONA_INPUT_VOLUME_RAMP: + case ARIZONA_HPF_CONTROL: case ARIZONA_IN1L_CONTROL: case ARIZONA_ADC_DIGITAL_VOLUME_1L: case ARIZONA_DMIC1L_CONTROL: @@ -1533,6 +1536,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_IN4L_CONTROL: case ARIZONA_ADC_DIGITAL_VOLUME_4L: case ARIZONA_DMIC4L_CONTROL: + case ARIZONA_IN4R_CONTROL: case ARIZONA_ADC_DIGITAL_VOLUME_4R: case ARIZONA_DMIC4R_CONTROL: case ARIZONA_OUTPUT_ENABLES_1: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 4706d3d46e56..cdf1f5acbe53 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -139,6 +139,7 @@ #define ARIZONA_INPUT_ENABLES_STATUS 0x301 #define ARIZONA_INPUT_RATE 0x308 #define ARIZONA_INPUT_VOLUME_RAMP 0x309 +#define ARIZONA_HPF_CONTROL 0x30C #define ARIZONA_IN1L_CONTROL 0x310 #define ARIZONA_ADC_DIGITAL_VOLUME_1L 0x311 #define ARIZONA_DMIC1L_CONTROL 0x312 @@ -160,6 +161,7 @@ #define ARIZONA_IN4L_CONTROL 0x328 #define ARIZONA_ADC_DIGITAL_VOLUME_4L 0x329 #define ARIZONA_DMIC4L_CONTROL 0x32A +#define ARIZONA_IN4R_CONTROL 0x32C #define ARIZONA_ADC_DIGITAL_VOLUME_4R 0x32D #define ARIZONA_DMIC4R_CONTROL 0x32E #define ARIZONA_OUTPUT_ENABLES_1 0x400 @@ -2292,9 +2294,19 @@ #define ARIZONA_IN_VI_RAMP_SHIFT 0 /* IN_VI_RAMP - [2:0] */ #define ARIZONA_IN_VI_RAMP_WIDTH 3 /* IN_VI_RAMP - [2:0] */ +/* + * R780 (0x30C) - HPF Control + */ +#define ARIZONA_IN_HPF_CUT_MASK 0x0007 /* IN_HPF_CUT [2:0] */ +#define ARIZONA_IN_HPF_CUT_SHIFT 0 /* IN_HPF_CUT [2:0] */ +#define ARIZONA_IN_HPF_CUT_WIDTH 3 /* IN_HPF_CUT [2:0] */ + /* * R784 (0x310) - IN1L Control */ +#define ARIZONA_IN1L_HPF_MASK 0x8000 /* IN1L_HPF - [15] */ +#define ARIZONA_IN1L_HPF_SHIFT 15 /* IN1L_HPF - [15] */ +#define ARIZONA_IN1L_HPF_WIDTH 1 /* IN1L_HPF - [15] */ #define ARIZONA_IN1_OSR_MASK 0x6000 /* IN1_OSR - [14:13] */ #define ARIZONA_IN1_OSR_SHIFT 13 /* IN1_OSR - [14:13] */ #define ARIZONA_IN1_OSR_WIDTH 2 /* IN1_OSR - [14:13] */ @@ -2333,6 +2345,9 @@ /* * R788 (0x314) - IN1R Control */ +#define ARIZONA_IN1R_HPF_MASK 0x8000 /* IN1R_HPF - [15] */ +#define ARIZONA_IN1R_HPF_SHIFT 15 /* IN1R_HPF - [15] */ +#define ARIZONA_IN1R_HPF_WIDTH 1 /* IN1R_HPF - [15] */ #define ARIZONA_IN1R_PGA_VOL_MASK 0x00FE /* IN1R_PGA_VOL - [7:1] */ #define ARIZONA_IN1R_PGA_VOL_SHIFT 1 /* IN1R_PGA_VOL - [7:1] */ #define ARIZONA_IN1R_PGA_VOL_WIDTH 7 /* IN1R_PGA_VOL - [7:1] */ @@ -2362,6 +2377,9 @@ /* * R792 (0x318) - IN2L Control */ +#define ARIZONA_IN2L_HPF_MASK 0x8000 /* IN2L_HPF - [15] */ +#define ARIZONA_IN2L_HPF_SHIFT 15 /* IN2L_HPF - [15] */ +#define ARIZONA_IN2L_HPF_WIDTH 1 /* IN2L_HPF - [15] */ #define ARIZONA_IN2_OSR_MASK 0x6000 /* IN2_OSR - [14:13] */ #define ARIZONA_IN2_OSR_SHIFT 13 /* IN2_OSR - [14:13] */ #define ARIZONA_IN2_OSR_WIDTH 2 /* IN2_OSR - [14:13] */ @@ -2400,6 +2418,9 @@ /* * R796 (0x31C) - IN2R Control */ +#define ARIZONA_IN2R_HPF_MASK 0x8000 /* IN2R_HPF - [15] */ +#define ARIZONA_IN2R_HPF_SHIFT 15 /* IN2R_HPF - [15] */ +#define ARIZONA_IN2R_HPF_WIDTH 1 /* IN2R_HPF - [15] */ #define ARIZONA_IN2R_PGA_VOL_MASK 0x00FE /* IN2R_PGA_VOL - [7:1] */ #define ARIZONA_IN2R_PGA_VOL_SHIFT 1 /* IN2R_PGA_VOL - [7:1] */ #define ARIZONA_IN2R_PGA_VOL_WIDTH 7 /* IN2R_PGA_VOL - [7:1] */ @@ -2429,6 +2450,9 @@ /* * R800 (0x320) - IN3L Control */ +#define ARIZONA_IN3L_HPF_MASK 0x8000 /* IN3L_HPF - [15] */ +#define ARIZONA_IN3L_HPF_SHIFT 15 /* IN3L_HPF - [15] */ +#define ARIZONA_IN3L_HPF_WIDTH 1 /* IN3L_HPF - [15] */ #define ARIZONA_IN3_OSR_MASK 0x6000 /* IN3_OSR - [14:13] */ #define ARIZONA_IN3_OSR_SHIFT 13 /* IN3_OSR - [14:13] */ #define ARIZONA_IN3_OSR_WIDTH 2 /* IN3_OSR - [14:13] */ @@ -2467,6 +2491,9 @@ /* * R804 (0x324) - IN3R Control */ +#define ARIZONA_IN3R_HPF_MASK 0x8000 /* IN3R_HPF - [15] */ +#define ARIZONA_IN3R_HPF_SHIFT 15 /* IN3R_HPF - [15] */ +#define ARIZONA_IN3R_HPF_WIDTH 1 /* IN3R_HPF - [15] */ #define ARIZONA_IN3R_PGA_VOL_MASK 0x00FE /* IN3R_PGA_VOL - [7:1] */ #define ARIZONA_IN3R_PGA_VOL_SHIFT 1 /* IN3R_PGA_VOL - [7:1] */ #define ARIZONA_IN3R_PGA_VOL_WIDTH 7 /* IN3R_PGA_VOL - [7:1] */ @@ -2496,6 +2523,9 @@ /* * R808 (0x328) - IN4 Control */ +#define ARIZONA_IN4L_HPF_MASK 0x8000 /* IN4L_HPF - [15] */ +#define ARIZONA_IN4L_HPF_SHIFT 15 /* IN4L_HPF - [15] */ +#define ARIZONA_IN4L_HPF_WIDTH 1 /* IN4L_HPF - [15] */ #define ARIZONA_IN4_OSR_MASK 0x6000 /* IN4_OSR - [14:13] */ #define ARIZONA_IN4_OSR_SHIFT 13 /* IN4_OSR - [14:13] */ #define ARIZONA_IN4_OSR_WIDTH 2 /* IN4_OSR - [14:13] */ @@ -2525,6 +2555,13 @@ #define ARIZONA_IN4L_DMIC_DLY_SHIFT 0 /* IN4L_DMIC_DLY - [5:0] */ #define ARIZONA_IN4L_DMIC_DLY_WIDTH 6 /* IN4L_DMIC_DLY - [5:0] */ +/* + * R812 (0x32C) - IN4R Control + */ +#define ARIZONA_IN4R_HPF_MASK 0x8000 /* IN4R_HPF - [15] */ +#define ARIZONA_IN4R_HPF_SHIFT 15 /* IN4R_HPF - [15] */ +#define ARIZONA_IN4R_HPF_WIDTH 1 /* IN4R_HPF - [15] */ + /* * R813 (0x32D) - ADC Digital Volume 4R */ diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 657808ba1418..708326265a37 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -560,6 +560,16 @@ const struct soc_enum arizona_ng_hold = 4, arizona_ng_hold_text); EXPORT_SYMBOL_GPL(arizona_ng_hold); +static const char * const arizona_in_hpf_cut_text[] = { + "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz" +}; + +const struct soc_enum arizona_in_hpf_cut_enum = + SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT, + ARRAY_SIZE(arizona_in_hpf_cut_text), + arizona_in_hpf_cut_text); +EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); + static const char * const arizona_in_dmic_osr_text[] = { "1.536MHz", "3.072MHz", "6.144MHz", }; diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 9e81b6392692..f8e63865a1c5 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -199,6 +199,7 @@ extern const struct soc_enum arizona_lhpf3_mode; extern const struct soc_enum arizona_lhpf4_mode; extern const struct soc_enum arizona_ng_hold; +extern const struct soc_enum arizona_in_hpf_cut_enum; extern const struct soc_enum arizona_in_dmic_osr[]; extern int arizona_in_ev(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index bbd64384ca1c..ea18e88e0a07 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -76,6 +76,25 @@ SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL, SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL, ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), +SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum), + +SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL, + ARIZONA_IN1L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL, + ARIZONA_IN1R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL, + ARIZONA_IN2L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL, + ARIZONA_IN2R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3L HPF Switch", ARIZONA_IN3L_CONTROL, + ARIZONA_IN3L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3R HPF Switch", ARIZONA_IN3R_CONTROL, + ARIZONA_IN3R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4L HPF Switch", ARIZONA_IN4L_CONTROL, + ARIZONA_IN4L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4R HPF Switch", ARIZONA_IN4R_CONTROL, + ARIZONA_IN4R_HPF_SHIFT, 1, 0), + SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, -- cgit v1.2.3 From 3635bf09a89cf92b80ac44198c5c8f0989624ea6 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 13 Nov 2013 18:56:24 +0800 Subject: ASoC: soc-pcm: add symmetry for channels and sample bits Some SoCs can only work in mono or stereo mode at one time. So if we let them capture a mono stream while playing a stereo stream, there might be a problem occur to one of these two streams: double paced or slowed down. In soc-pcm.c, we have soc_pcm_apply_symmetry() to apply the rate symmetry. But we don't have one for channels. Likewise, we can treat symmetric_rate as a solution for those SoCs or CODECs which can not handle asymmetrical LRCLK. But it's also impossible for them to handle asymmetrical BCLK. And accodring to BCLK = LRCLK * channel number * slot size(fixed or sample bits), sample bits might also be a problem if they are not using a fixed slot size. Thus, this patch applys symmetry for channels and sample bits. Meanwhile, there might be a race between two substreams if starting simultaneously. Previously, we only added warning to compalin but still using conservative way to let it carry on. However, this patch rejects the second stream with any unmatched parameter to make sure the first existing stream won't be broken. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 6 +++ include/sound/soc.h | 2 + sound/soc/soc-pcm.c | 130 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 115 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 800c101bb096..243d3b689699 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -220,6 +220,8 @@ struct snd_soc_dai_driver { struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream playback; unsigned int symmetric_rates:1; + unsigned int symmetric_channels:1; + unsigned int symmetric_samplebits:1; /* probe ordering - for components with runtime dependencies */ int probe_order; @@ -244,6 +246,8 @@ struct snd_soc_dai { unsigned int capture_active:1; /* stream is in use */ unsigned int playback_active:1; /* stream is in use */ unsigned int symmetric_rates:1; + unsigned int symmetric_channels:1; + unsigned int symmetric_samplebits:1; struct snd_pcm_runtime *runtime; unsigned int active; unsigned char probed:1; @@ -258,6 +262,8 @@ struct snd_soc_dai { /* Symmetry data - only valid if symmetry is being enforced */ unsigned int rate; + unsigned int channels; + unsigned int sample_bits; /* parent platform/codec */ struct snd_soc_platform *platform; diff --git a/include/sound/soc.h b/include/sound/soc.h index 1f741cb24f33..1cda7d343d16 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -879,6 +879,8 @@ struct snd_soc_dai_link { /* Symmetry requirements */ unsigned int symmetric_rates:1; + unsigned int symmetric_channels:1; + unsigned int symmetric_samplebits:1; /* Do not create a PCM for this DAI link (Backend link) */ unsigned int no_pcm:1; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 42782c01e413..ed1e077114a2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -84,30 +84,97 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; int ret; - if (!soc_dai->driver->symmetric_rates && - !rtd->dai_link->symmetric_rates) - return 0; + if (soc_dai->rate && (soc_dai->driver->symmetric_rates || + rtd->dai_link->symmetric_rates)) { + dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", + soc_dai->rate); + + ret = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + soc_dai->rate, soc_dai->rate); + if (ret < 0) { + dev_err(soc_dai->dev, + "ASoC: Unable to apply rate constraint: %d\n", + ret); + return ret; + } + } - /* This can happen if multiple streams are starting simultaneously - - * the second can need to get its constraints before the first has - * picked a rate. Complain and allow the application to carry on. - */ - if (!soc_dai->rate) { - dev_warn(soc_dai->dev, - "ASoC: Not enforcing symmetric_rates due to race\n"); - return 0; + if (soc_dai->channels && (soc_dai->driver->symmetric_channels || + rtd->dai_link->symmetric_channels)) { + dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n", + soc_dai->channels); + + ret = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + soc_dai->channels, + soc_dai->channels); + if (ret < 0) { + dev_err(soc_dai->dev, + "ASoC: Unable to apply channel symmetry constraint: %d\n", + ret); + return ret; + } } - dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate); + if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits || + rtd->dai_link->symmetric_samplebits)) { + dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n", + soc_dai->sample_bits); - ret = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - soc_dai->rate, soc_dai->rate); - if (ret < 0) { - dev_err(soc_dai->dev, - "ASoC: Unable to apply rate symmetry constraint: %d\n", - ret); - return ret; + ret = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + soc_dai->sample_bits, + soc_dai->sample_bits); + if (ret < 0) { + dev_err(soc_dai->dev, + "ASoC: Unable to apply sample bits symmetry constraint: %d\n", + ret); + return ret; + } + } + + return 0; +} + +static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + unsigned int rate, channels, sample_bits, symmetry; + + rate = params_rate(params); + channels = params_channels(params); + sample_bits = snd_pcm_format_physical_width(params_format(params)); + + /* reject unmatched parameters when applying symmetry */ + symmetry = cpu_dai->driver->symmetric_rates || + codec_dai->driver->symmetric_rates || + rtd->dai_link->symmetric_rates; + if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) { + dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", + cpu_dai->rate, rate); + return -EINVAL; + } + + symmetry = cpu_dai->driver->symmetric_channels || + codec_dai->driver->symmetric_channels || + rtd->dai_link->symmetric_channels; + if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) { + dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", + cpu_dai->channels, channels); + return -EINVAL; + } + + symmetry = cpu_dai->driver->symmetric_samplebits || + codec_dai->driver->symmetric_samplebits || + rtd->dai_link->symmetric_samplebits; + if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) { + dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", + cpu_dai->sample_bits, sample_bits); + return -EINVAL; } return 0; @@ -384,11 +451,17 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) codec->active--; /* clear the corresponding DAIs rate when inactive */ - if (!cpu_dai->active) + if (!cpu_dai->active) { cpu_dai->rate = 0; + cpu_dai->channels = 0; + cpu_dai->sample_bits = 0; + } - if (!codec_dai->active) + if (!codec_dai->active) { codec_dai->rate = 0; + codec_dai->channels = 0; + codec_dai->sample_bits = 0; + } /* Muting the DAC suppresses artifacts caused during digital * shutdown, for example from stopping clocks. @@ -525,6 +598,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + ret = soc_pcm_params_symmetry(substream, params); + if (ret) + goto out; + if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { @@ -561,9 +638,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - /* store the rate for each DAIs */ + /* store the parameters for each DAIs */ cpu_dai->rate = params_rate(params); + cpu_dai->channels = params_channels(params); + cpu_dai->sample_bits = + snd_pcm_format_physical_width(params_format(params)); + codec_dai->rate = params_rate(params); + codec_dai->channels = params_channels(params); + codec_dai->sample_bits = + snd_pcm_format_physical_width(params_format(params)); out: mutex_unlock(&rtd->pcm_mutex); -- cgit v1.2.3 From 8778ac6be25abf0496fc614a3e77ad2ff8300353 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Nov 2013 15:55:06 +0100 Subject: ASoC: Fix build without CONFIG_GPIOLIB snd_soc_jack_gpio stuff is currently enabled for CONFIG_GPIOLIB explicitly with ifdef, and this causes build errors on some drivers such as: sound/soc/omap/rx51.c:220:33: error: array type has incomplete element type Remove ifdef and provide dummy functions for CONFIG_GPIOLIB=n case instead. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/soc.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 1f741cb24f33..f7e1fac51bba 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -334,9 +334,7 @@ struct snd_soc_jack_pin; #include #include -#ifdef CONFIG_GPIOLIB struct snd_soc_jack_gpio; -#endif typedef int (*hw_write_t)(void *,const char* ,int); @@ -446,6 +444,17 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, struct snd_soc_jack_gpio *gpios); void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, struct snd_soc_jack_gpio *gpios); +#else +static inline int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, + struct snd_soc_jack_gpio *gpios) +{ + return 0; +} + +static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, + struct snd_soc_jack_gpio *gpios) +{ +} #endif /* codec register bit access */ @@ -580,7 +589,6 @@ struct snd_soc_jack_zone { * to provide more complex checks (eg, reading an * ADC). */ -#ifdef CONFIG_GPIOLIB struct snd_soc_jack_gpio { unsigned int gpio; const char *name; @@ -594,7 +602,6 @@ struct snd_soc_jack_gpio { int (*jack_status_check)(void); }; -#endif struct snd_soc_jack { struct mutex mutex; -- cgit v1.2.3 From a3d36bc2aba531328f7311ef57dec7687283ec57 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Wed, 13 Nov 2013 16:05:40 -0600 Subject: ASoC: cs42l52: Reorganize MICA/B Config and Select This patch reworks the MICA an MICB config for single-ended or differential and the selection of which MIC for the single config Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- include/sound/cs42l52.h | 6 ------ sound/soc/codecs/cs42l52.c | 25 ++++--------------------- 2 files changed, 4 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/include/sound/cs42l52.h b/include/sound/cs42l52.h index 7c2be4a51894..daa91f327e4f 100644 --- a/include/sound/cs42l52.h +++ b/include/sound/cs42l52.h @@ -22,12 +22,6 @@ struct cs42l52_platform_data { /* MICB mode selection 0=Single 1=Differential */ unsigned int micb_cfg; - /* MICA Select 0=MIC1A 1=MIC2A */ - unsigned int mica_sel; - - /* MICB Select 0=MIC2A 1=MIC2B */ - unsigned int micb_sel; - /* Charge Pump Freq. Check datasheet Pg73 */ unsigned int chgfreq; diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 19ee10b6d6ca..18010639d0c5 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -233,7 +233,7 @@ static const struct soc_enum mic_bias_level_enum = SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0, ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text); -static const char * const cs42l52_mic_text[] = { "Single", "Differential" }; +static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" }; static const struct soc_enum mica_enum = SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5, @@ -243,12 +243,6 @@ static const struct soc_enum micb_enum = SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5, ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); -static const struct snd_kcontrol_new mica_mux = - SOC_DAPM_ENUM("Left Mic Input Capture Mux", mica_enum); - -static const struct snd_kcontrol_new micb_mux = - SOC_DAPM_ENUM("Right Mic Input Capture Mux", micb_enum); - static const char * const digital_output_mux_text[] = {"ADC", "DSP"}; static const struct soc_enum digital_output_mux_enum = @@ -425,6 +419,9 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0), + SOC_ENUM("MICA Select", mica_enum), + SOC_ENUM("MICB Select", micb_enum), + SOC_DOUBLE_R_TLV("MIC Gain Volume", CS42L52_MICA_CTL, CS42L52_MICB_CTL, 0, 0x10, 0, mic_tlv), @@ -550,9 +547,6 @@ static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_MUX("MICA Mux", SND_SOC_NOPM, 0, 0, &mica_mux), - SND_SOC_DAPM_MUX("MICB Mux", SND_SOC_NOPM, 0, 0, &micb_mux), - SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1), SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1), SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0), @@ -1239,17 +1233,6 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, cs42l52->pdata.micb_cfg << CS42L52_MIC_CTL_TYPE_SHIFT); - if (cs42l52->pdata.mica_sel) - regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL, - CS42L52_MIC_CTL_MIC_SEL_MASK, - cs42l52->pdata.mica_sel << - CS42L52_MIC_CTL_MIC_SEL_SHIFT); - if (cs42l52->pdata.micb_sel) - regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL, - CS42L52_MIC_CTL_MIC_SEL_MASK, - cs42l52->pdata.micb_sel << - CS42L52_MIC_CTL_MIC_SEL_SHIFT); - if (cs42l52->pdata.chgfreq) regmap_update_bits(cs42l52->regmap, CS42L52_CHARGE_PUMP, CS42L52_CHARGE_PUMP_MASK, -- cgit v1.2.3 From 44b2ed54036ecec36ad27adf356f0274a72e5f05 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 14 Nov 2013 11:46:11 -0600 Subject: ASoC: cs42l52: Make MICA/B mixer dependent on mic config MICA/B Single-Ended input selection depends on mica/b config so lets make the mixer controls for them only show for selected mic's Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- include/sound/cs42l52.h | 8 ++++---- sound/soc/codecs/cs42l52.c | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/sound/cs42l52.h b/include/sound/cs42l52.h index daa91f327e4f..bbabf84bdb44 100644 --- a/include/sound/cs42l52.h +++ b/include/sound/cs42l52.h @@ -16,11 +16,11 @@ struct cs42l52_platform_data { /* MICBIAS Level. Check datasheet Pg48 */ unsigned int micbias_lvl; - /* MICA mode selection 0=Single 1=Differential */ - unsigned int mica_cfg; + /* MICA mode selection Differential or Single-ended */ + bool mica_diff_cfg; - /* MICB mode selection 0=Single 1=Differential */ - unsigned int micb_cfg; + /* MICB mode selection Differential or Single-ended */ + bool micb_diff_cfg; /* Charge Pump Freq. Check datasheet Pg73 */ unsigned int chgfreq; diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 18010639d0c5..78d2dd669e89 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -419,9 +419,6 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0), - SOC_ENUM("MICA Select", mica_enum), - SOC_ENUM("MICB Select", micb_enum), - SOC_DOUBLE_R_TLV("MIC Gain Volume", CS42L52_MICA_CTL, CS42L52_MICB_CTL, 0, 0x10, 0, mic_tlv), @@ -528,6 +525,30 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = { }; +static const struct snd_kcontrol_new cs42l52_mica_controls[] = { + SOC_ENUM("MICA Select", mica_enum), +}; + +static const struct snd_kcontrol_new cs42l52_micb_controls[] = { + SOC_ENUM("MICB Select", micb_enum), +}; + +static int cs42l52_add_mic_controls(struct snd_soc_codec *codec) +{ + struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec); + struct cs42l52_platform_data *pdata = &cs42l52->pdata; + + if (!pdata->mica_diff_cfg) + snd_soc_add_codec_controls(codec, cs42l52_mica_controls, + ARRAY_SIZE(cs42l52_mica_controls)); + + if (!pdata->micb_diff_cfg) + snd_soc_add_codec_controls(codec, cs42l52_micb_controls, + ARRAY_SIZE(cs42l52_micb_controls)); + + return 0; +} + static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = { SND_SOC_DAPM_INPUT("AIN1L"), @@ -1104,6 +1125,8 @@ static int cs42l52_probe(struct snd_soc_codec *codec) } regcache_cache_only(cs42l52->regmap, true); + cs42l52_add_mic_controls(codec); + cs42l52_init_beep(codec); cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1221,16 +1244,16 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, reg & 0xFF); /* Set Platform Data */ - if (cs42l52->pdata.mica_cfg) + if (cs42l52->pdata.mica_diff_cfg) regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL, CS42L52_MIC_CTL_TYPE_MASK, - cs42l52->pdata.mica_cfg << + cs42l52->pdata.mica_diff_cfg << CS42L52_MIC_CTL_TYPE_SHIFT); - if (cs42l52->pdata.micb_cfg) + if (cs42l52->pdata.micb_diff_cfg) regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL, CS42L52_MIC_CTL_TYPE_MASK, - cs42l52->pdata.micb_cfg << + cs42l52->pdata.micb_diff_cfg << CS42L52_MIC_CTL_TYPE_SHIFT); if (cs42l52->pdata.chgfreq) -- cgit v1.2.3 From 21585ee848078b12d0d1a513e93936bf96b444a0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 28 Nov 2013 08:50:32 +0100 Subject: ASoC: Add resource managed snd_dmaengine_pcm_register() For many drivers using the generic dmaengine PCM driver one of the few (or the only) things left to do in the drivers remove function is to unregister the PCM device. This patch adds a resource managed version of snd_dmaengine_pcm_register() which makes it possible to simplify the remove function as well as the error path in the probe function for those drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 4 ++++ sound/soc/soc-devres.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) (limited to 'include') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 15017311f2e9..4ef986cab182 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -140,6 +140,10 @@ int snd_dmaengine_pcm_register(struct device *dev, unsigned int flags); void snd_dmaengine_pcm_unregister(struct device *dev); +int devm_snd_dmaengine_pcm_register(struct device *dev, + const struct snd_dmaengine_pcm_config *config, + unsigned int flags); + int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c index b1d732255c02..999861942d28 100644 --- a/sound/soc/soc-devres.c +++ b/sound/soc/soc-devres.c @@ -12,6 +12,7 @@ #include #include #include +#include static void devm_component_release(struct device *dev, void *res) { @@ -84,3 +85,43 @@ int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) return ret; } EXPORT_SYMBOL_GPL(devm_snd_soc_register_card); + +#ifdef CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM + +static void devm_dmaengine_pcm_release(struct device *dev, void *res) +{ + snd_dmaengine_pcm_unregister(*(struct device **)res); +} + +/** + * devm_snd_dmaengine_pcm_register - resource managed dmaengine PCM registration + * @dev: The parent device for the PCM device + * @config: Platform specific PCM configuration + * @flags: Platform specific quirks + * + * Register a dmaengine based PCM device with automatic unregistration when the + * device is unregistered. + */ +int devm_snd_dmaengine_pcm_register(struct device *dev, + const struct snd_dmaengine_pcm_config *config, unsigned int flags) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_dmaengine_pcm_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_dmaengine_pcm_register(dev, config, flags); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_snd_dmaengine_pcm_register); + +#endif -- cgit v1.2.3 From ed326363d7a7844330325148efe06a994e4bc78f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 9 Dec 2013 14:28:36 +0100 Subject: ALSA: hda - Split verb definitions into sound/hda_verbs.h Since there are more HD-audio compatible codecs, move the definitions of HD-audio verbs into common header location, include/sound, so that it can be included cleanly from other drivers than HD-audio driver. Signed-off-by: Takashi Iwai --- include/sound/hda_verbs.h | 554 ++++++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_codec.h | 547 +-------------------------------------------- 2 files changed, 555 insertions(+), 546 deletions(-) create mode 100644 include/sound/hda_verbs.h (limited to 'include') diff --git a/include/sound/hda_verbs.h b/include/sound/hda_verbs.h new file mode 100644 index 000000000000..d0509db6d0ec --- /dev/null +++ b/include/sound/hda_verbs.h @@ -0,0 +1,554 @@ +/* + * HD-audio codec verbs + */ + +#ifndef __SOUND_HDA_VERBS_H +#define __SOUND_HDA_VERBS_H + +/* + * nodes + */ +#define AC_NODE_ROOT 0x00 + +/* + * function group types + */ +enum { + AC_GRP_AUDIO_FUNCTION = 0x01, + AC_GRP_MODEM_FUNCTION = 0x02, +}; + +/* + * widget types + */ +enum { + AC_WID_AUD_OUT, /* Audio Out */ + AC_WID_AUD_IN, /* Audio In */ + AC_WID_AUD_MIX, /* Audio Mixer */ + AC_WID_AUD_SEL, /* Audio Selector */ + AC_WID_PIN, /* Pin Complex */ + AC_WID_POWER, /* Power */ + AC_WID_VOL_KNB, /* Volume Knob */ + AC_WID_BEEP, /* Beep Generator */ + AC_WID_VENDOR = 0x0f /* Vendor specific */ +}; + +/* + * GET verbs + */ +#define AC_VERB_GET_STREAM_FORMAT 0x0a00 +#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00 +#define AC_VERB_GET_PROC_COEF 0x0c00 +#define AC_VERB_GET_COEF_INDEX 0x0d00 +#define AC_VERB_PARAMETERS 0x0f00 +#define AC_VERB_GET_CONNECT_SEL 0x0f01 +#define AC_VERB_GET_CONNECT_LIST 0x0f02 +#define AC_VERB_GET_PROC_STATE 0x0f03 +#define AC_VERB_GET_SDI_SELECT 0x0f04 +#define AC_VERB_GET_POWER_STATE 0x0f05 +#define AC_VERB_GET_CONV 0x0f06 +#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07 +#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08 +#define AC_VERB_GET_PIN_SENSE 0x0f09 +#define AC_VERB_GET_BEEP_CONTROL 0x0f0a +#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c +#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d +#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ +#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f +/* f10-f1a: GPIO */ +#define AC_VERB_GET_GPIO_DATA 0x0f15 +#define AC_VERB_GET_GPIO_MASK 0x0f16 +#define AC_VERB_GET_GPIO_DIRECTION 0x0f17 +#define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18 +#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19 +#define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a +#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c +/* f20: AFG/MFG */ +#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 +#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d +#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e +#define AC_VERB_GET_HDMI_ELDD 0x0f2f +#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30 +#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31 +#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 +#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 +#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 +#define AC_VERB_GET_DEVICE_SEL 0xf35 +#define AC_VERB_GET_DEVICE_LIST 0xf36 + +/* + * SET verbs + */ +#define AC_VERB_SET_STREAM_FORMAT 0x200 +#define AC_VERB_SET_AMP_GAIN_MUTE 0x300 +#define AC_VERB_SET_PROC_COEF 0x400 +#define AC_VERB_SET_COEF_INDEX 0x500 +#define AC_VERB_SET_CONNECT_SEL 0x701 +#define AC_VERB_SET_PROC_STATE 0x703 +#define AC_VERB_SET_SDI_SELECT 0x704 +#define AC_VERB_SET_POWER_STATE 0x705 +#define AC_VERB_SET_CHANNEL_STREAMID 0x706 +#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707 +#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708 +#define AC_VERB_SET_PIN_SENSE 0x709 +#define AC_VERB_SET_BEEP_CONTROL 0x70a +#define AC_VERB_SET_EAPD_BTLENABLE 0x70c +#define AC_VERB_SET_DIGI_CONVERT_1 0x70d +#define AC_VERB_SET_DIGI_CONVERT_2 0x70e +#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f +#define AC_VERB_SET_GPIO_DATA 0x715 +#define AC_VERB_SET_GPIO_MASK 0x716 +#define AC_VERB_SET_GPIO_DIRECTION 0x717 +#define AC_VERB_SET_GPIO_WAKE_MASK 0x718 +#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719 +#define AC_VERB_SET_GPIO_STICKY_MASK 0x71a +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f +#define AC_VERB_SET_EAPD 0x788 +#define AC_VERB_SET_CODEC_RESET 0x7ff +#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d +#define AC_VERB_SET_HDMI_DIP_INDEX 0x730 +#define AC_VERB_SET_HDMI_DIP_DATA 0x731 +#define AC_VERB_SET_HDMI_DIP_XMIT 0x732 +#define AC_VERB_SET_HDMI_CP_CTRL 0x733 +#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 +#define AC_VERB_SET_DEVICE_SEL 0x735 + +/* + * Parameter IDs + */ +#define AC_PAR_VENDOR_ID 0x00 +#define AC_PAR_SUBSYSTEM_ID 0x01 +#define AC_PAR_REV_ID 0x02 +#define AC_PAR_NODE_COUNT 0x04 +#define AC_PAR_FUNCTION_TYPE 0x05 +#define AC_PAR_AUDIO_FG_CAP 0x08 +#define AC_PAR_AUDIO_WIDGET_CAP 0x09 +#define AC_PAR_PCM 0x0a +#define AC_PAR_STREAM 0x0b +#define AC_PAR_PIN_CAP 0x0c +#define AC_PAR_AMP_IN_CAP 0x0d +#define AC_PAR_CONNLIST_LEN 0x0e +#define AC_PAR_POWER_STATE 0x0f +#define AC_PAR_PROC_CAP 0x10 +#define AC_PAR_GPIO_CAP 0x11 +#define AC_PAR_AMP_OUT_CAP 0x12 +#define AC_PAR_VOL_KNB_CAP 0x13 +#define AC_PAR_DEVLIST_LEN 0x15 +#define AC_PAR_HDMI_LPCM_CAP 0x20 + +/* + * AC_VERB_PARAMETERS results (32bit) + */ + +/* Function Group Type */ +#define AC_FGT_TYPE (0xff<<0) +#define AC_FGT_TYPE_SHIFT 0 +#define AC_FGT_UNSOL_CAP (1<<8) + +/* Audio Function Group Capabilities */ +#define AC_AFG_OUT_DELAY (0xf<<0) +#define AC_AFG_IN_DELAY (0xf<<8) +#define AC_AFG_BEEP_GEN (1<<16) + +/* Audio Widget Capabilities */ +#define AC_WCAP_STEREO (1<<0) /* stereo I/O */ +#define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */ +#define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */ +#define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */ +#define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */ +#define AC_WCAP_STRIPE (1<<5) /* stripe */ +#define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */ +#define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */ +#define AC_WCAP_CONN_LIST (1<<8) /* connection list */ +#define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ +#define AC_WCAP_POWER (1<<10) /* power control */ +#define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ +#define AC_WCAP_CP_CAPS (1<<12) /* content protection */ +#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */ +#define AC_WCAP_DELAY (0xf<<16) +#define AC_WCAP_DELAY_SHIFT 16 +#define AC_WCAP_TYPE (0xf<<20) +#define AC_WCAP_TYPE_SHIFT 20 + +/* supported PCM rates and bits */ +#define AC_SUPPCM_RATES (0xfff << 0) +#define AC_SUPPCM_BITS_8 (1<<16) +#define AC_SUPPCM_BITS_16 (1<<17) +#define AC_SUPPCM_BITS_20 (1<<18) +#define AC_SUPPCM_BITS_24 (1<<19) +#define AC_SUPPCM_BITS_32 (1<<20) + +/* supported PCM stream format */ +#define AC_SUPFMT_PCM (1<<0) +#define AC_SUPFMT_FLOAT32 (1<<1) +#define AC_SUPFMT_AC3 (1<<2) + +/* GP I/O count */ +#define AC_GPIO_IO_COUNT (0xff<<0) +#define AC_GPIO_O_COUNT (0xff<<8) +#define AC_GPIO_O_COUNT_SHIFT 8 +#define AC_GPIO_I_COUNT (0xff<<16) +#define AC_GPIO_I_COUNT_SHIFT 16 +#define AC_GPIO_UNSOLICITED (1<<30) +#define AC_GPIO_WAKE (1<<31) + +/* Converter stream, channel */ +#define AC_CONV_CHANNEL (0xf<<0) +#define AC_CONV_STREAM (0xf<<4) +#define AC_CONV_STREAM_SHIFT 4 + +/* Input converter SDI select */ +#define AC_SDI_SELECT (0xf<<0) + +/* stream format id */ +#define AC_FMT_CHAN_SHIFT 0 +#define AC_FMT_CHAN_MASK (0x0f << 0) +#define AC_FMT_BITS_SHIFT 4 +#define AC_FMT_BITS_MASK (7 << 4) +#define AC_FMT_BITS_8 (0 << 4) +#define AC_FMT_BITS_16 (1 << 4) +#define AC_FMT_BITS_20 (2 << 4) +#define AC_FMT_BITS_24 (3 << 4) +#define AC_FMT_BITS_32 (4 << 4) +#define AC_FMT_DIV_SHIFT 8 +#define AC_FMT_DIV_MASK (7 << 8) +#define AC_FMT_MULT_SHIFT 11 +#define AC_FMT_MULT_MASK (7 << 11) +#define AC_FMT_BASE_SHIFT 14 +#define AC_FMT_BASE_48K (0 << 14) +#define AC_FMT_BASE_44K (1 << 14) +#define AC_FMT_TYPE_SHIFT 15 +#define AC_FMT_TYPE_PCM (0 << 15) +#define AC_FMT_TYPE_NON_PCM (1 << 15) + +/* Unsolicited response control */ +#define AC_UNSOL_TAG (0x3f<<0) +#define AC_UNSOL_ENABLED (1<<7) +#define AC_USRSP_EN AC_UNSOL_ENABLED + +/* Unsolicited responses */ +#define AC_UNSOL_RES_TAG (0x3f<<26) +#define AC_UNSOL_RES_TAG_SHIFT 26 +#define AC_UNSOL_RES_SUBTAG (0x1f<<21) +#define AC_UNSOL_RES_SUBTAG_SHIFT 21 +#define AC_UNSOL_RES_DE (0x3f<<15) /* Device Entry + * (for DP1.2 MST) + */ +#define AC_UNSOL_RES_DE_SHIFT 15 +#define AC_UNSOL_RES_IA (1<<2) /* Inactive (for DP1.2 MST) */ +#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ +#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ +#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ +#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */ + +/* Pin widget capabilies */ +#define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ +#define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ +#define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */ +#define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */ +#define AC_PINCAP_OUT (1<<4) /* output capable */ +#define AC_PINCAP_IN (1<<5) /* input capable */ +#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ +/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, + * but is marked reserved in the Intel HDA specification. + */ +#define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ +/* Note: The same bit as LR_SWAP is newly defined as HDMI capability + * in HD-audio specification + */ +#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */ +#define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can + * coexist with AC_PINCAP_HDMI + */ +#define AC_PINCAP_VREF (0x37<<8) +#define AC_PINCAP_VREF_SHIFT 8 +#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ +#define AC_PINCAP_HBR (1<<27) /* High Bit Rate */ +/* Vref status (used in pin cap) */ +#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ +#define AC_PINCAP_VREF_50 (1<<1) /* 50% */ +#define AC_PINCAP_VREF_GRD (1<<2) /* ground */ +#define AC_PINCAP_VREF_80 (1<<4) /* 80% */ +#define AC_PINCAP_VREF_100 (1<<5) /* 100% */ + +/* Amplifier capabilities */ +#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ +#define AC_AMPCAP_OFFSET_SHIFT 0 +#define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ +#define AC_AMPCAP_NUM_STEPS_SHIFT 8 +#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB + * in 0.25dB + */ +#define AC_AMPCAP_STEP_SIZE_SHIFT 16 +#define AC_AMPCAP_MUTE (1<<31) /* mute capable */ +#define AC_AMPCAP_MUTE_SHIFT 31 + +/* driver-specific amp-caps: using bits 24-30 */ +#define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */ + +/* Connection list */ +#define AC_CLIST_LENGTH (0x7f<<0) +#define AC_CLIST_LONG (1<<7) + +/* Supported power status */ +#define AC_PWRST_D0SUP (1<<0) +#define AC_PWRST_D1SUP (1<<1) +#define AC_PWRST_D2SUP (1<<2) +#define AC_PWRST_D3SUP (1<<3) +#define AC_PWRST_D3COLDSUP (1<<4) +#define AC_PWRST_S3D3COLDSUP (1<<29) +#define AC_PWRST_CLKSTOP (1<<30) +#define AC_PWRST_EPSS (1U<<31) + +/* Power state values */ +#define AC_PWRST_SETTING (0xf<<0) +#define AC_PWRST_ACTUAL (0xf<<4) +#define AC_PWRST_ACTUAL_SHIFT 4 +#define AC_PWRST_D0 0x00 +#define AC_PWRST_D1 0x01 +#define AC_PWRST_D2 0x02 +#define AC_PWRST_D3 0x03 +#define AC_PWRST_ERROR (1<<8) +#define AC_PWRST_CLK_STOP_OK (1<<9) +#define AC_PWRST_SETTING_RESET (1<<10) + +/* Processing capabilies */ +#define AC_PCAP_BENIGN (1<<0) +#define AC_PCAP_NUM_COEF (0xff<<8) +#define AC_PCAP_NUM_COEF_SHIFT 8 + +/* Volume knobs capabilities */ +#define AC_KNBCAP_NUM_STEPS (0x7f<<0) +#define AC_KNBCAP_DELTA (1<<7) + +/* HDMI LPCM capabilities */ +#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */ +#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */ +#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */ +#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */ +#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */ +#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */ +#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */ +#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */ +#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */ +#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */ +#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */ +#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */ +#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ +#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ + +/* Display pin's device list length */ +#define AC_DEV_LIST_LEN_MASK 0x3f +#define AC_MAX_DEV_LIST_LEN 64 + +/* + * Control Parameters + */ + +/* Amp gain/mute */ +#define AC_AMP_MUTE (1<<7) +#define AC_AMP_GAIN (0x7f) +#define AC_AMP_GET_INDEX (0xf<<0) + +#define AC_AMP_GET_LEFT (1<<13) +#define AC_AMP_GET_RIGHT (0<<13) +#define AC_AMP_GET_OUTPUT (1<<15) +#define AC_AMP_GET_INPUT (0<<15) + +#define AC_AMP_SET_INDEX (0xf<<8) +#define AC_AMP_SET_INDEX_SHIFT 8 +#define AC_AMP_SET_RIGHT (1<<12) +#define AC_AMP_SET_LEFT (1<<13) +#define AC_AMP_SET_INPUT (1<<14) +#define AC_AMP_SET_OUTPUT (1<<15) + +/* DIGITAL1 bits */ +#define AC_DIG1_ENABLE (1<<0) +#define AC_DIG1_V (1<<1) +#define AC_DIG1_VCFG (1<<2) +#define AC_DIG1_EMPHASIS (1<<3) +#define AC_DIG1_COPYRIGHT (1<<4) +#define AC_DIG1_NONAUDIO (1<<5) +#define AC_DIG1_PROFESSIONAL (1<<6) +#define AC_DIG1_LEVEL (1<<7) + +/* DIGITAL2 bits */ +#define AC_DIG2_CC (0x7f<<0) + +/* DIGITAL3 bits */ +#define AC_DIG3_ICT (0xf<<0) +#define AC_DIG3_KAE (1<<7) + +/* Pin widget control - 8bit */ +#define AC_PINCTL_EPT (0x3<<0) +#define AC_PINCTL_EPT_NATIVE 0 +#define AC_PINCTL_EPT_HBR 3 +#define AC_PINCTL_VREFEN (0x7<<0) +#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ +#define AC_PINCTL_VREF_50 1 /* 50% */ +#define AC_PINCTL_VREF_GRD 2 /* ground */ +#define AC_PINCTL_VREF_80 4 /* 80% */ +#define AC_PINCTL_VREF_100 5 /* 100% */ +#define AC_PINCTL_IN_EN (1<<5) +#define AC_PINCTL_OUT_EN (1<<6) +#define AC_PINCTL_HP_EN (1<<7) + +/* Pin sense - 32bit */ +#define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) +#define AC_PINSENSE_PRESENCE (1<<31) +#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */ + +/* EAPD/BTL enable - 32bit */ +#define AC_EAPDBTL_BALANCED (1<<0) +#define AC_EAPDBTL_EAPD (1<<1) +#define AC_EAPDBTL_LR_SWAP (1<<2) + +/* HDMI ELD data */ +#define AC_ELDD_ELD_VALID (1<<31) +#define AC_ELDD_ELD_DATA 0xff + +/* HDMI DIP size */ +#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */ +#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */ + +/* HDMI DIP index */ +#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */ +#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */ + +/* HDMI DIP xmit (transmit) control */ +#define AC_DIPXMIT_MASK (0x3<<6) +#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */ +#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */ +#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */ + +/* HDMI content protection (CP) control */ +#define AC_CPCTRL_CES (1<<9) /* current encryption state */ +#define AC_CPCTRL_READY (1<<8) /* ready bit */ +#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */ +#define AC_CPCTRL_STATE (3<<0) /* current CP request state */ + +/* Converter channel <-> HDMI slot mapping */ +#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */ +#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */ + +/* configuration default - 32bit */ +#define AC_DEFCFG_SEQUENCE (0xf<<0) +#define AC_DEFCFG_DEF_ASSOC (0xf<<4) +#define AC_DEFCFG_ASSOC_SHIFT 4 +#define AC_DEFCFG_MISC (0xf<<8) +#define AC_DEFCFG_MISC_SHIFT 8 +#define AC_DEFCFG_MISC_NO_PRESENCE (1<<0) +#define AC_DEFCFG_COLOR (0xf<<12) +#define AC_DEFCFG_COLOR_SHIFT 12 +#define AC_DEFCFG_CONN_TYPE (0xf<<16) +#define AC_DEFCFG_CONN_TYPE_SHIFT 16 +#define AC_DEFCFG_DEVICE (0xf<<20) +#define AC_DEFCFG_DEVICE_SHIFT 20 +#define AC_DEFCFG_LOCATION (0x3f<<24) +#define AC_DEFCFG_LOCATION_SHIFT 24 +#define AC_DEFCFG_PORT_CONN (0x3<<30) +#define AC_DEFCFG_PORT_CONN_SHIFT 30 + +/* Display pin's device list entry */ +#define AC_DE_PD (1<<0) +#define AC_DE_ELDV (1<<1) +#define AC_DE_IA (1<<2) + +/* device device types (0x0-0xf) */ +enum { + AC_JACK_LINE_OUT, + AC_JACK_SPEAKER, + AC_JACK_HP_OUT, + AC_JACK_CD, + AC_JACK_SPDIF_OUT, + AC_JACK_DIG_OTHER_OUT, + AC_JACK_MODEM_LINE_SIDE, + AC_JACK_MODEM_HAND_SIDE, + AC_JACK_LINE_IN, + AC_JACK_AUX, + AC_JACK_MIC_IN, + AC_JACK_TELEPHONY, + AC_JACK_SPDIF_IN, + AC_JACK_DIG_OTHER_IN, + AC_JACK_OTHER = 0xf, +}; + +/* jack connection types (0x0-0xf) */ +enum { + AC_JACK_CONN_UNKNOWN, + AC_JACK_CONN_1_8, + AC_JACK_CONN_1_4, + AC_JACK_CONN_ATAPI, + AC_JACK_CONN_RCA, + AC_JACK_CONN_OPTICAL, + AC_JACK_CONN_OTHER_DIGITAL, + AC_JACK_CONN_OTHER_ANALOG, + AC_JACK_CONN_DIN, + AC_JACK_CONN_XLR, + AC_JACK_CONN_RJ11, + AC_JACK_CONN_COMB, + AC_JACK_CONN_OTHER = 0xf, +}; + +/* jack colors (0x0-0xf) */ +enum { + AC_JACK_COLOR_UNKNOWN, + AC_JACK_COLOR_BLACK, + AC_JACK_COLOR_GREY, + AC_JACK_COLOR_BLUE, + AC_JACK_COLOR_GREEN, + AC_JACK_COLOR_RED, + AC_JACK_COLOR_ORANGE, + AC_JACK_COLOR_YELLOW, + AC_JACK_COLOR_PURPLE, + AC_JACK_COLOR_PINK, + AC_JACK_COLOR_WHITE = 0xe, + AC_JACK_COLOR_OTHER, +}; + +/* Jack location (0x0-0x3f) */ +/* common case */ +enum { + AC_JACK_LOC_NONE, + AC_JACK_LOC_REAR, + AC_JACK_LOC_FRONT, + AC_JACK_LOC_LEFT, + AC_JACK_LOC_RIGHT, + AC_JACK_LOC_TOP, + AC_JACK_LOC_BOTTOM, +}; +/* bits 4-5 */ +enum { + AC_JACK_LOC_EXTERNAL = 0x00, + AC_JACK_LOC_INTERNAL = 0x10, + AC_JACK_LOC_SEPARATE = 0x20, + AC_JACK_LOC_OTHER = 0x30, +}; +enum { + /* external on primary chasis */ + AC_JACK_LOC_REAR_PANEL = 0x07, + AC_JACK_LOC_DRIVE_BAY, + /* internal */ + AC_JACK_LOC_RISER = 0x17, + AC_JACK_LOC_HDMI, + AC_JACK_LOC_ATAPI, + /* others */ + AC_JACK_LOC_MOBILE_IN = 0x37, + AC_JACK_LOC_MOBILE_OUT, +}; + +/* Port connectivity (0-3) */ +enum { + AC_JACK_PORT_COMPLEX, + AC_JACK_PORT_NONE, + AC_JACK_PORT_FIXED, + AC_JACK_PORT_BOTH, +}; + +/* max. codec address */ +#define HDA_MAX_CODEC_ADDRESS 0x0f + +#endif /* __SOUND_HDA_VERBS_H */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 260b190adf74..3c484c27048b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -25,552 +25,7 @@ #include #include #include - -/* - * nodes - */ -#define AC_NODE_ROOT 0x00 - -/* - * function group types - */ -enum { - AC_GRP_AUDIO_FUNCTION = 0x01, - AC_GRP_MODEM_FUNCTION = 0x02, -}; - -/* - * widget types - */ -enum { - AC_WID_AUD_OUT, /* Audio Out */ - AC_WID_AUD_IN, /* Audio In */ - AC_WID_AUD_MIX, /* Audio Mixer */ - AC_WID_AUD_SEL, /* Audio Selector */ - AC_WID_PIN, /* Pin Complex */ - AC_WID_POWER, /* Power */ - AC_WID_VOL_KNB, /* Volume Knob */ - AC_WID_BEEP, /* Beep Generator */ - AC_WID_VENDOR = 0x0f /* Vendor specific */ -}; - -/* - * GET verbs - */ -#define AC_VERB_GET_STREAM_FORMAT 0x0a00 -#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00 -#define AC_VERB_GET_PROC_COEF 0x0c00 -#define AC_VERB_GET_COEF_INDEX 0x0d00 -#define AC_VERB_PARAMETERS 0x0f00 -#define AC_VERB_GET_CONNECT_SEL 0x0f01 -#define AC_VERB_GET_CONNECT_LIST 0x0f02 -#define AC_VERB_GET_PROC_STATE 0x0f03 -#define AC_VERB_GET_SDI_SELECT 0x0f04 -#define AC_VERB_GET_POWER_STATE 0x0f05 -#define AC_VERB_GET_CONV 0x0f06 -#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07 -#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08 -#define AC_VERB_GET_PIN_SENSE 0x0f09 -#define AC_VERB_GET_BEEP_CONTROL 0x0f0a -#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c -#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d -#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ -#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f -/* f10-f1a: GPIO */ -#define AC_VERB_GET_GPIO_DATA 0x0f15 -#define AC_VERB_GET_GPIO_MASK 0x0f16 -#define AC_VERB_GET_GPIO_DIRECTION 0x0f17 -#define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18 -#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19 -#define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a -#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c -/* f20: AFG/MFG */ -#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 -#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d -#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e -#define AC_VERB_GET_HDMI_ELDD 0x0f2f -#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30 -#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31 -#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 -#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 -#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 -#define AC_VERB_GET_DEVICE_SEL 0xf35 -#define AC_VERB_GET_DEVICE_LIST 0xf36 - -/* - * SET verbs - */ -#define AC_VERB_SET_STREAM_FORMAT 0x200 -#define AC_VERB_SET_AMP_GAIN_MUTE 0x300 -#define AC_VERB_SET_PROC_COEF 0x400 -#define AC_VERB_SET_COEF_INDEX 0x500 -#define AC_VERB_SET_CONNECT_SEL 0x701 -#define AC_VERB_SET_PROC_STATE 0x703 -#define AC_VERB_SET_SDI_SELECT 0x704 -#define AC_VERB_SET_POWER_STATE 0x705 -#define AC_VERB_SET_CHANNEL_STREAMID 0x706 -#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707 -#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708 -#define AC_VERB_SET_PIN_SENSE 0x709 -#define AC_VERB_SET_BEEP_CONTROL 0x70a -#define AC_VERB_SET_EAPD_BTLENABLE 0x70c -#define AC_VERB_SET_DIGI_CONVERT_1 0x70d -#define AC_VERB_SET_DIGI_CONVERT_2 0x70e -#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f -#define AC_VERB_SET_GPIO_DATA 0x715 -#define AC_VERB_SET_GPIO_MASK 0x716 -#define AC_VERB_SET_GPIO_DIRECTION 0x717 -#define AC_VERB_SET_GPIO_WAKE_MASK 0x718 -#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719 -#define AC_VERB_SET_GPIO_STICKY_MASK 0x71a -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f -#define AC_VERB_SET_EAPD 0x788 -#define AC_VERB_SET_CODEC_RESET 0x7ff -#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d -#define AC_VERB_SET_HDMI_DIP_INDEX 0x730 -#define AC_VERB_SET_HDMI_DIP_DATA 0x731 -#define AC_VERB_SET_HDMI_DIP_XMIT 0x732 -#define AC_VERB_SET_HDMI_CP_CTRL 0x733 -#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 -#define AC_VERB_SET_DEVICE_SEL 0x735 - -/* - * Parameter IDs - */ -#define AC_PAR_VENDOR_ID 0x00 -#define AC_PAR_SUBSYSTEM_ID 0x01 -#define AC_PAR_REV_ID 0x02 -#define AC_PAR_NODE_COUNT 0x04 -#define AC_PAR_FUNCTION_TYPE 0x05 -#define AC_PAR_AUDIO_FG_CAP 0x08 -#define AC_PAR_AUDIO_WIDGET_CAP 0x09 -#define AC_PAR_PCM 0x0a -#define AC_PAR_STREAM 0x0b -#define AC_PAR_PIN_CAP 0x0c -#define AC_PAR_AMP_IN_CAP 0x0d -#define AC_PAR_CONNLIST_LEN 0x0e -#define AC_PAR_POWER_STATE 0x0f -#define AC_PAR_PROC_CAP 0x10 -#define AC_PAR_GPIO_CAP 0x11 -#define AC_PAR_AMP_OUT_CAP 0x12 -#define AC_PAR_VOL_KNB_CAP 0x13 -#define AC_PAR_DEVLIST_LEN 0x15 -#define AC_PAR_HDMI_LPCM_CAP 0x20 - -/* - * AC_VERB_PARAMETERS results (32bit) - */ - -/* Function Group Type */ -#define AC_FGT_TYPE (0xff<<0) -#define AC_FGT_TYPE_SHIFT 0 -#define AC_FGT_UNSOL_CAP (1<<8) - -/* Audio Function Group Capabilities */ -#define AC_AFG_OUT_DELAY (0xf<<0) -#define AC_AFG_IN_DELAY (0xf<<8) -#define AC_AFG_BEEP_GEN (1<<16) - -/* Audio Widget Capabilities */ -#define AC_WCAP_STEREO (1<<0) /* stereo I/O */ -#define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */ -#define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */ -#define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */ -#define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */ -#define AC_WCAP_STRIPE (1<<5) /* stripe */ -#define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */ -#define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */ -#define AC_WCAP_CONN_LIST (1<<8) /* connection list */ -#define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ -#define AC_WCAP_POWER (1<<10) /* power control */ -#define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ -#define AC_WCAP_CP_CAPS (1<<12) /* content protection */ -#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */ -#define AC_WCAP_DELAY (0xf<<16) -#define AC_WCAP_DELAY_SHIFT 16 -#define AC_WCAP_TYPE (0xf<<20) -#define AC_WCAP_TYPE_SHIFT 20 - -/* supported PCM rates and bits */ -#define AC_SUPPCM_RATES (0xfff << 0) -#define AC_SUPPCM_BITS_8 (1<<16) -#define AC_SUPPCM_BITS_16 (1<<17) -#define AC_SUPPCM_BITS_20 (1<<18) -#define AC_SUPPCM_BITS_24 (1<<19) -#define AC_SUPPCM_BITS_32 (1<<20) - -/* supported PCM stream format */ -#define AC_SUPFMT_PCM (1<<0) -#define AC_SUPFMT_FLOAT32 (1<<1) -#define AC_SUPFMT_AC3 (1<<2) - -/* GP I/O count */ -#define AC_GPIO_IO_COUNT (0xff<<0) -#define AC_GPIO_O_COUNT (0xff<<8) -#define AC_GPIO_O_COUNT_SHIFT 8 -#define AC_GPIO_I_COUNT (0xff<<16) -#define AC_GPIO_I_COUNT_SHIFT 16 -#define AC_GPIO_UNSOLICITED (1<<30) -#define AC_GPIO_WAKE (1<<31) - -/* Converter stream, channel */ -#define AC_CONV_CHANNEL (0xf<<0) -#define AC_CONV_STREAM (0xf<<4) -#define AC_CONV_STREAM_SHIFT 4 - -/* Input converter SDI select */ -#define AC_SDI_SELECT (0xf<<0) - -/* stream format id */ -#define AC_FMT_CHAN_SHIFT 0 -#define AC_FMT_CHAN_MASK (0x0f << 0) -#define AC_FMT_BITS_SHIFT 4 -#define AC_FMT_BITS_MASK (7 << 4) -#define AC_FMT_BITS_8 (0 << 4) -#define AC_FMT_BITS_16 (1 << 4) -#define AC_FMT_BITS_20 (2 << 4) -#define AC_FMT_BITS_24 (3 << 4) -#define AC_FMT_BITS_32 (4 << 4) -#define AC_FMT_DIV_SHIFT 8 -#define AC_FMT_DIV_MASK (7 << 8) -#define AC_FMT_MULT_SHIFT 11 -#define AC_FMT_MULT_MASK (7 << 11) -#define AC_FMT_BASE_SHIFT 14 -#define AC_FMT_BASE_48K (0 << 14) -#define AC_FMT_BASE_44K (1 << 14) -#define AC_FMT_TYPE_SHIFT 15 -#define AC_FMT_TYPE_PCM (0 << 15) -#define AC_FMT_TYPE_NON_PCM (1 << 15) - -/* Unsolicited response control */ -#define AC_UNSOL_TAG (0x3f<<0) -#define AC_UNSOL_ENABLED (1<<7) -#define AC_USRSP_EN AC_UNSOL_ENABLED - -/* Unsolicited responses */ -#define AC_UNSOL_RES_TAG (0x3f<<26) -#define AC_UNSOL_RES_TAG_SHIFT 26 -#define AC_UNSOL_RES_SUBTAG (0x1f<<21) -#define AC_UNSOL_RES_SUBTAG_SHIFT 21 -#define AC_UNSOL_RES_DE (0x3f<<15) /* Device Entry - * (for DP1.2 MST) - */ -#define AC_UNSOL_RES_DE_SHIFT 15 -#define AC_UNSOL_RES_IA (1<<2) /* Inactive (for DP1.2 MST) */ -#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ -#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ -#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ -#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */ - -/* Pin widget capabilies */ -#define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ -#define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ -#define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */ -#define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */ -#define AC_PINCAP_OUT (1<<4) /* output capable */ -#define AC_PINCAP_IN (1<<5) /* input capable */ -#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ -/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, - * but is marked reserved in the Intel HDA specification. - */ -#define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ -/* Note: The same bit as LR_SWAP is newly defined as HDMI capability - * in HD-audio specification - */ -#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */ -#define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can - * coexist with AC_PINCAP_HDMI - */ -#define AC_PINCAP_VREF (0x37<<8) -#define AC_PINCAP_VREF_SHIFT 8 -#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ -#define AC_PINCAP_HBR (1<<27) /* High Bit Rate */ -/* Vref status (used in pin cap) */ -#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ -#define AC_PINCAP_VREF_50 (1<<1) /* 50% */ -#define AC_PINCAP_VREF_GRD (1<<2) /* ground */ -#define AC_PINCAP_VREF_80 (1<<4) /* 80% */ -#define AC_PINCAP_VREF_100 (1<<5) /* 100% */ - -/* Amplifier capabilities */ -#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ -#define AC_AMPCAP_OFFSET_SHIFT 0 -#define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ -#define AC_AMPCAP_NUM_STEPS_SHIFT 8 -#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB - * in 0.25dB - */ -#define AC_AMPCAP_STEP_SIZE_SHIFT 16 -#define AC_AMPCAP_MUTE (1<<31) /* mute capable */ -#define AC_AMPCAP_MUTE_SHIFT 31 - -/* driver-specific amp-caps: using bits 24-30 */ -#define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */ - -/* Connection list */ -#define AC_CLIST_LENGTH (0x7f<<0) -#define AC_CLIST_LONG (1<<7) - -/* Supported power status */ -#define AC_PWRST_D0SUP (1<<0) -#define AC_PWRST_D1SUP (1<<1) -#define AC_PWRST_D2SUP (1<<2) -#define AC_PWRST_D3SUP (1<<3) -#define AC_PWRST_D3COLDSUP (1<<4) -#define AC_PWRST_S3D3COLDSUP (1<<29) -#define AC_PWRST_CLKSTOP (1<<30) -#define AC_PWRST_EPSS (1U<<31) - -/* Power state values */ -#define AC_PWRST_SETTING (0xf<<0) -#define AC_PWRST_ACTUAL (0xf<<4) -#define AC_PWRST_ACTUAL_SHIFT 4 -#define AC_PWRST_D0 0x00 -#define AC_PWRST_D1 0x01 -#define AC_PWRST_D2 0x02 -#define AC_PWRST_D3 0x03 -#define AC_PWRST_ERROR (1<<8) -#define AC_PWRST_CLK_STOP_OK (1<<9) -#define AC_PWRST_SETTING_RESET (1<<10) - -/* Processing capabilies */ -#define AC_PCAP_BENIGN (1<<0) -#define AC_PCAP_NUM_COEF (0xff<<8) -#define AC_PCAP_NUM_COEF_SHIFT 8 - -/* Volume knobs capabilities */ -#define AC_KNBCAP_NUM_STEPS (0x7f<<0) -#define AC_KNBCAP_DELTA (1<<7) - -/* HDMI LPCM capabilities */ -#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */ -#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */ -#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */ -#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */ -#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */ -#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */ -#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */ -#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */ -#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */ -#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */ -#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */ -#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */ -#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ -#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ - -/* Display pin's device list length */ -#define AC_DEV_LIST_LEN_MASK 0x3f -#define AC_MAX_DEV_LIST_LEN 64 - -/* - * Control Parameters - */ - -/* Amp gain/mute */ -#define AC_AMP_MUTE (1<<7) -#define AC_AMP_GAIN (0x7f) -#define AC_AMP_GET_INDEX (0xf<<0) - -#define AC_AMP_GET_LEFT (1<<13) -#define AC_AMP_GET_RIGHT (0<<13) -#define AC_AMP_GET_OUTPUT (1<<15) -#define AC_AMP_GET_INPUT (0<<15) - -#define AC_AMP_SET_INDEX (0xf<<8) -#define AC_AMP_SET_INDEX_SHIFT 8 -#define AC_AMP_SET_RIGHT (1<<12) -#define AC_AMP_SET_LEFT (1<<13) -#define AC_AMP_SET_INPUT (1<<14) -#define AC_AMP_SET_OUTPUT (1<<15) - -/* DIGITAL1 bits */ -#define AC_DIG1_ENABLE (1<<0) -#define AC_DIG1_V (1<<1) -#define AC_DIG1_VCFG (1<<2) -#define AC_DIG1_EMPHASIS (1<<3) -#define AC_DIG1_COPYRIGHT (1<<4) -#define AC_DIG1_NONAUDIO (1<<5) -#define AC_DIG1_PROFESSIONAL (1<<6) -#define AC_DIG1_LEVEL (1<<7) - -/* DIGITAL2 bits */ -#define AC_DIG2_CC (0x7f<<0) - -/* DIGITAL3 bits */ -#define AC_DIG3_ICT (0xf<<0) -#define AC_DIG3_KAE (1<<7) - -/* Pin widget control - 8bit */ -#define AC_PINCTL_EPT (0x3<<0) -#define AC_PINCTL_EPT_NATIVE 0 -#define AC_PINCTL_EPT_HBR 3 -#define AC_PINCTL_VREFEN (0x7<<0) -#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ -#define AC_PINCTL_VREF_50 1 /* 50% */ -#define AC_PINCTL_VREF_GRD 2 /* ground */ -#define AC_PINCTL_VREF_80 4 /* 80% */ -#define AC_PINCTL_VREF_100 5 /* 100% */ -#define AC_PINCTL_IN_EN (1<<5) -#define AC_PINCTL_OUT_EN (1<<6) -#define AC_PINCTL_HP_EN (1<<7) - -/* Pin sense - 32bit */ -#define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) -#define AC_PINSENSE_PRESENCE (1<<31) -#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */ - -/* EAPD/BTL enable - 32bit */ -#define AC_EAPDBTL_BALANCED (1<<0) -#define AC_EAPDBTL_EAPD (1<<1) -#define AC_EAPDBTL_LR_SWAP (1<<2) - -/* HDMI ELD data */ -#define AC_ELDD_ELD_VALID (1<<31) -#define AC_ELDD_ELD_DATA 0xff - -/* HDMI DIP size */ -#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */ -#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */ - -/* HDMI DIP index */ -#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */ -#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */ - -/* HDMI DIP xmit (transmit) control */ -#define AC_DIPXMIT_MASK (0x3<<6) -#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */ -#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */ -#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */ - -/* HDMI content protection (CP) control */ -#define AC_CPCTRL_CES (1<<9) /* current encryption state */ -#define AC_CPCTRL_READY (1<<8) /* ready bit */ -#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */ -#define AC_CPCTRL_STATE (3<<0) /* current CP request state */ - -/* Converter channel <-> HDMI slot mapping */ -#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */ -#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */ - -/* configuration default - 32bit */ -#define AC_DEFCFG_SEQUENCE (0xf<<0) -#define AC_DEFCFG_DEF_ASSOC (0xf<<4) -#define AC_DEFCFG_ASSOC_SHIFT 4 -#define AC_DEFCFG_MISC (0xf<<8) -#define AC_DEFCFG_MISC_SHIFT 8 -#define AC_DEFCFG_MISC_NO_PRESENCE (1<<0) -#define AC_DEFCFG_COLOR (0xf<<12) -#define AC_DEFCFG_COLOR_SHIFT 12 -#define AC_DEFCFG_CONN_TYPE (0xf<<16) -#define AC_DEFCFG_CONN_TYPE_SHIFT 16 -#define AC_DEFCFG_DEVICE (0xf<<20) -#define AC_DEFCFG_DEVICE_SHIFT 20 -#define AC_DEFCFG_LOCATION (0x3f<<24) -#define AC_DEFCFG_LOCATION_SHIFT 24 -#define AC_DEFCFG_PORT_CONN (0x3<<30) -#define AC_DEFCFG_PORT_CONN_SHIFT 30 - -/* Display pin's device list entry */ -#define AC_DE_PD (1<<0) -#define AC_DE_ELDV (1<<1) -#define AC_DE_IA (1<<2) - -/* device device types (0x0-0xf) */ -enum { - AC_JACK_LINE_OUT, - AC_JACK_SPEAKER, - AC_JACK_HP_OUT, - AC_JACK_CD, - AC_JACK_SPDIF_OUT, - AC_JACK_DIG_OTHER_OUT, - AC_JACK_MODEM_LINE_SIDE, - AC_JACK_MODEM_HAND_SIDE, - AC_JACK_LINE_IN, - AC_JACK_AUX, - AC_JACK_MIC_IN, - AC_JACK_TELEPHONY, - AC_JACK_SPDIF_IN, - AC_JACK_DIG_OTHER_IN, - AC_JACK_OTHER = 0xf, -}; - -/* jack connection types (0x0-0xf) */ -enum { - AC_JACK_CONN_UNKNOWN, - AC_JACK_CONN_1_8, - AC_JACK_CONN_1_4, - AC_JACK_CONN_ATAPI, - AC_JACK_CONN_RCA, - AC_JACK_CONN_OPTICAL, - AC_JACK_CONN_OTHER_DIGITAL, - AC_JACK_CONN_OTHER_ANALOG, - AC_JACK_CONN_DIN, - AC_JACK_CONN_XLR, - AC_JACK_CONN_RJ11, - AC_JACK_CONN_COMB, - AC_JACK_CONN_OTHER = 0xf, -}; - -/* jack colors (0x0-0xf) */ -enum { - AC_JACK_COLOR_UNKNOWN, - AC_JACK_COLOR_BLACK, - AC_JACK_COLOR_GREY, - AC_JACK_COLOR_BLUE, - AC_JACK_COLOR_GREEN, - AC_JACK_COLOR_RED, - AC_JACK_COLOR_ORANGE, - AC_JACK_COLOR_YELLOW, - AC_JACK_COLOR_PURPLE, - AC_JACK_COLOR_PINK, - AC_JACK_COLOR_WHITE = 0xe, - AC_JACK_COLOR_OTHER, -}; - -/* Jack location (0x0-0x3f) */ -/* common case */ -enum { - AC_JACK_LOC_NONE, - AC_JACK_LOC_REAR, - AC_JACK_LOC_FRONT, - AC_JACK_LOC_LEFT, - AC_JACK_LOC_RIGHT, - AC_JACK_LOC_TOP, - AC_JACK_LOC_BOTTOM, -}; -/* bits 4-5 */ -enum { - AC_JACK_LOC_EXTERNAL = 0x00, - AC_JACK_LOC_INTERNAL = 0x10, - AC_JACK_LOC_SEPARATE = 0x20, - AC_JACK_LOC_OTHER = 0x30, -}; -enum { - /* external on primary chasis */ - AC_JACK_LOC_REAR_PANEL = 0x07, - AC_JACK_LOC_DRIVE_BAY, - /* internal */ - AC_JACK_LOC_RISER = 0x17, - AC_JACK_LOC_HDMI, - AC_JACK_LOC_ATAPI, - /* others */ - AC_JACK_LOC_MOBILE_IN = 0x37, - AC_JACK_LOC_MOBILE_OUT, -}; - -/* Port connectivity (0-3) */ -enum { - AC_JACK_PORT_COMPLEX, - AC_JACK_PORT_NONE, - AC_JACK_PORT_FIXED, - AC_JACK_PORT_BOTH, -}; - -/* max. codec address */ -#define HDA_MAX_CODEC_ADDRESS 0x0f +#include /* * generic arrays -- cgit v1.2.3 From 194c7dea00c68c1b1f8ff26304fa937a006f66dd Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 3 Dec 2013 14:26:34 -0700 Subject: ASoC: dmaengine: add custom DMA config to snd_dmaengine_pcm_config Add fields to struct snd_dmaengine_pcm_config to allow custom: - DMA channel names. This is useful when the default "tx" and "rx" channel names don't apply, for example if a HW module supports multiple channels, each having different DMA channel names. This is the case with the FIFOs in Tegra's AHUB. This new facility can replace SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME. - DMA device This allows requesting DMA channels for a device other than the device which is registering the "PCM" driver. This is quite unusual, but is currently useful on Tegra. In much HW, and in Tegra20, each DAI HW module contains its own FIFOs which DMA writes to. However, in Tegra30, the DMA FIFOs were split out AHUB HW module, which then routes the data through a cross-bar, and into the DAI HW modules. However, the current ASoC driver structure does not expose this detail, and acts as if the FIFOs are still part of the DAI HW modules. Consequently, the "PCM" driver is registered with the DAI HW module, yet the DMA channels must be looked up in the AHUB HW module's device tree node. This new config field allows that to happen. Eventually, the Tegra drivers will be reworked to fully expose the AHUB, and this config field can be removed. Signed-off-by: Stephen Warren Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 6 ++++++ sound/soc/soc-generic-dmaengine-pcm.c | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 4ef986cab182..eb73a3a39ec2 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -114,6 +114,10 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * @compat_filter_fn: Will be used as the filter function when requesting a * channel for platforms which do not use devicetree. The filter parameter * will be the DAI's DMA data. + * @dma_dev: If set, request DMA channel on this device rather than the DAI + * device. + * @chan_names: If set, these custom DMA channel names will be requested at + * registration time. * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM. * @prealloc_buffer_size: Size of the preallocated audio buffer. * @@ -130,6 +134,8 @@ struct snd_dmaengine_pcm_config { struct snd_soc_pcm_runtime *rtd, struct snd_pcm_substream *substream); dma_filter_fn compat_filter_fn; + struct device *dma_dev; + const char *chan_names[SNDRV_PCM_STREAM_LAST + 1]; const struct snd_pcm_hardware *pcm_hardware; unsigned int prealloc_buffer_size; diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 1cb3494cf278..5b70c556fba3 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -288,7 +288,7 @@ static const char * const dmaengine_pcm_dma_channel_names[] = { }; static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, - struct device *dev) + struct device *dev, const struct snd_dmaengine_pcm_config *config) { unsigned int i; const char *name; @@ -298,12 +298,26 @@ static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, !dev->of_node) return; + if (config->dma_dev) { + /* + * If this warning is seen, it probably means that your Linux + * device structure does not match your HW device structure. + * It would be best to refactor the Linux device structure to + * correctly match the HW structure. + */ + dev_warn(dev, "DMA channels sourced from device %s", + dev_name(config->dma_dev)); + dev = config->dma_dev; + } + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) name = "rx-tx"; else name = dmaengine_pcm_dma_channel_names[i]; + if (config->chan_names[i]) + name = config->chan_names[i]; pcm->chan[i] = dma_request_slave_channel(dev, name); if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) break; @@ -346,7 +360,7 @@ int snd_dmaengine_pcm_register(struct device *dev, pcm->config = config; pcm->flags = flags; - dmaengine_pcm_request_chan_of(pcm, dev); + dmaengine_pcm_request_chan_of(pcm, dev, config); if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) ret = snd_soc_add_platform(dev, &pcm->platform, -- cgit v1.2.3 From 453c499028bf2ecf3b31ccb7c3657fe1b0b28943 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 14 Nov 2013 11:35:34 +0200 Subject: ASoC: davinci-mcasp: Support for McASP version found in DRA7xx The IP in DRA7xx is similar to the IP found in TI81xxAM3xxx/AM4xxx type of SoCs but it is is integrated with sDMA instead of eDMA. The suitable pcm driver for DRA7xx is the omap-pcm driver which is using dmaengine. In the driver we can configure both dma related structures used for eDMA and sDMA. The only thing we need to make sure that we set the correct dma_data at startup with snd_soc_dai_set_dma_data() Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../bindings/sound/davinci-mcasp-audio.txt | 1 + include/linux/platform_data/davinci_asp.h | 1 + sound/soc/davinci/davinci-mcasp.c | 52 +++++++++++++++++++--- 3 files changed, 47 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 1eed972d4719..990fa71ce804 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -5,6 +5,7 @@ Required properties: "ti,dm646x-mcasp-audio" : for DM646x platforms "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, AM43xx, TI81xx) + "ti,dra7-mcasp-audio" : for DRA7xx platforms - reg : Should contain reg specifiers for the entries in the reg-names property. - reg-names : Should contain: diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index 689a856b86f9..5245992b0367 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -92,6 +92,7 @@ enum { MCASP_VERSION_1 = 0, /* DM646x */ MCASP_VERSION_2, /* DA8xx/OMAPL1x */ MCASP_VERSION_3, /* TI81xx/AM33xx */ + MCASP_VERSION_4, /* DRA7xxx */ }; enum mcbsp_clk_input_pin { diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 93f2e294d649..fc8c13d2f31e 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -31,12 +31,14 @@ #include #include #include +#include #include "davinci-pcm.h" #include "davinci-mcasp.h" struct davinci_mcasp { struct davinci_pcm_dma_params dma_params[2]; + struct snd_dmaengine_dai_dma_data dma_data[2]; void __iomem *base; u32 fifo_base; struct device *dev; @@ -458,7 +460,9 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, u8 max_active_serializers = (channels + slots - 1) / slots; u32 reg; /* Default configuration */ - mcasp_set_bits(mcasp->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); + if (mcasp->version != MCASP_VERSION_4) + mcasp_set_bits(mcasp->base + DAVINCI_MCASP_PWREMUMGT_REG, + MCASP_SOFT); /* All PINS as McASP */ mcasp_set_reg(mcasp->base + DAVINCI_MCASP_PFUNC_REG, 0x00000000); @@ -605,6 +609,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[substream->stream]; + struct snd_dmaengine_dai_dma_data *dma_data = + &mcasp->dma_data[substream->stream]; int word_length; u8 fifo_level; u8 slots = mcasp->tdm_slots; @@ -666,6 +672,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, dma_params->acnt = dma_params->data_type; dma_params->fifo_level = fifo_level; + dma_data->maxburst = fifo_level; + davinci_config_channel_size(mcasp, word_length); return 0; @@ -711,7 +719,12 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); - snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params); + if (mcasp->version == MCASP_VERSION_4) + snd_soc_dai_set_dma_data(dai, substream, + &mcasp->dma_data[substream->stream]); + else + snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params); + return 0; } @@ -794,6 +807,13 @@ static struct snd_platform_data omap2_mcasp_pdata = { .version = MCASP_VERSION_3, }; +static struct snd_platform_data dra7_mcasp_pdata = { + .tx_dma_offset = 0x200, + .rx_dma_offset = 0x284, + .asp_chan_q = EVENTQ_0, + .version = MCASP_VERSION_4, +}; + static const struct of_device_id mcasp_dt_ids[] = { { .compatible = "ti,dm646x-mcasp-audio", @@ -807,6 +827,10 @@ static const struct of_device_id mcasp_dt_ids[] = { .compatible = "ti,am33xx-mcasp-audio", .data = &omap2_mcasp_pdata, }, + { + .compatible = "ti,dra7-mcasp-audio", + .data = &dra7_mcasp_pdata, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mcasp_dt_ids); @@ -999,6 +1023,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) else dma_data->dma_addr = mem->start + pdata->tx_dma_offset; + /* Unconditional dmaengine stuff */ + mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr; + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (res) dma_data->channel = res->start; @@ -1015,6 +1042,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) else dma_data->dma_addr = mem->start + pdata->rx_dma_offset; + /* Unconditional dmaengine stuff */ + mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr; + if (mcasp->version < MCASP_VERSION_3) { mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; /* dma_data->dma_addr is pointing to the data port address */ @@ -1029,6 +1059,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev) else dma_data->channel = pdata->rx_dma_channel; + /* Unconditional dmaengine stuff */ + mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx"; + mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx"; + dev_set_drvdata(&pdev->dev, mcasp); ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[pdata->op_mode], 1); @@ -1036,10 +1070,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret != 0) goto err_release_clk; - ret = davinci_soc_platform_register(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_component; + if (mcasp->version != MCASP_VERSION_4) { + ret = davinci_soc_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "register PCM failed: %d\n", ret); + goto err_unregister_component; + } } return 0; @@ -1054,9 +1090,11 @@ err_release_clk: static int davinci_mcasp_remove(struct platform_device *pdev) { + struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev); snd_soc_unregister_component(&pdev->dev); - davinci_soc_platform_unregister(&pdev->dev); + if (mcasp->version != MCASP_VERSION_4) + davinci_soc_platform_unregister(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From 0ad7c00057dc1640647c1dc81ccbd009de17a767 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 26 Nov 2013 10:04:22 -0700 Subject: dma: add channel request API that supports deferred probe dma_request_slave_channel() simply returns NULL whenever DMA channel lookup fails. Lookup could fail for two distinct reasons: a) No DMA specification exists for the channel name. This includes situations where no DMA specifications exist at all, or other general lookup problems. b) A DMA specification does exist, yet the driver for that channel is not yet registered. Case (b) should trigger deferred probe in client drivers. However, since they have no way to differentiate the two situations, it cannot. Implement new function dma_request_slave_channel_reason(), which performs identically to dma_request_slave_channel(), except that it returns an error-pointer rather than NULL, which allows callers to detect when deferred probe should occur. Eventually, all drivers should be converted to this new API, the old API removed, and the new API renamed to the more desirable name. This patch doesn't convert the existing API and all drivers in one go, since some drivers call dma_request_slave_channel() then dma_request_channel() if that fails. That would require either modifying dma_request_channel() in the same way, or adding extra error-handling code to all affected drivers, and there are close to 100 drivers using the other API, rather than just the 15-20 or so that use dma_request_slave_channel(), which might be tenable in a single patch. acpi_dma_request_slave_chan_by_name() doesn't currently implement deferred probe. It should, but this will be addressed later. Acked-by: Dan Williams Signed-off-by: Stephen Warren Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 35 +++++++++++++++++++++++++++++++---- drivers/dma/of-dma.c | 15 +++++++++------ include/linux/dmaengine.h | 8 ++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index ea806bdc12ef..e17e9b22d85e 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -540,6 +540,8 @@ EXPORT_SYMBOL_GPL(dma_get_slave_channel); * @mask: capabilities that the channel must satisfy * @fn: optional callback to disposition available channels * @fn_param: opaque parameter to pass to dma_filter_fn + * + * Returns pointer to appropriate DMA channel on success or NULL. */ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param) @@ -591,18 +593,43 @@ EXPORT_SYMBOL_GPL(__dma_request_channel); * dma_request_slave_channel - try to allocate an exclusive slave channel * @dev: pointer to client device structure * @name: slave channel name + * + * Returns pointer to appropriate DMA channel on success or an error pointer. */ -struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) +struct dma_chan *dma_request_slave_channel_reason(struct device *dev, + const char *name) { + struct dma_chan *chan; + /* If device-tree is present get slave info from here */ if (dev->of_node) return of_dma_request_slave_channel(dev->of_node, name); /* If device was enumerated by ACPI get slave info from here */ - if (ACPI_HANDLE(dev)) - return acpi_dma_request_slave_chan_by_name(dev, name); + if (ACPI_HANDLE(dev)) { + chan = acpi_dma_request_slave_chan_by_name(dev, name); + if (chan) + return chan; + } - return NULL; + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason); + +/** + * dma_request_slave_channel - try to allocate an exclusive slave channel + * @dev: pointer to client device structure + * @name: slave channel name + * + * Returns pointer to appropriate DMA channel on success or NULL. + */ +struct dma_chan *dma_request_slave_channel(struct device *dev, + const char *name) +{ + struct dma_chan *ch = dma_request_slave_channel_reason(dev, name); + if (IS_ERR(ch)) + return NULL; + return ch; } EXPORT_SYMBOL_GPL(dma_request_slave_channel); diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c index 0b88dd3d05f4..e8fe9dc455f4 100644 --- a/drivers/dma/of-dma.c +++ b/drivers/dma/of-dma.c @@ -143,7 +143,7 @@ static int of_dma_match_channel(struct device_node *np, const char *name, * @np: device node to get DMA request from * @name: name of desired channel * - * Returns pointer to appropriate dma channel on success or NULL on error. + * Returns pointer to appropriate DMA channel on success or an error pointer. */ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, const char *name) @@ -152,17 +152,18 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, struct of_dma *ofdma; struct dma_chan *chan; int count, i; + int ret_no_channel = -ENODEV; if (!np || !name) { pr_err("%s: not enough information provided\n", __func__); - return NULL; + return ERR_PTR(-ENODEV); } count = of_property_count_strings(np, "dma-names"); if (count < 0) { pr_err("%s: dma-names property of node '%s' missing or empty\n", __func__, np->full_name); - return NULL; + return ERR_PTR(-ENODEV); } for (i = 0; i < count; i++) { @@ -172,10 +173,12 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, mutex_lock(&of_dma_lock); ofdma = of_dma_find_controller(&dma_spec); - if (ofdma) + if (ofdma) { chan = ofdma->of_dma_xlate(&dma_spec, ofdma); - else + } else { + ret_no_channel = -EPROBE_DEFER; chan = NULL; + } mutex_unlock(&of_dma_lock); @@ -185,7 +188,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, return chan; } - return NULL; + return ERR_PTR(ret_no_channel); } /** diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 41cf0c399288..ed92b30a02fd 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -22,6 +22,7 @@ #define LINUX_DMAENGINE_H #include +#include #include #include #include @@ -1040,6 +1041,8 @@ enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx); void dma_issue_pending_all(void); struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param); +struct dma_chan *dma_request_slave_channel_reason(struct device *dev, + const char *name); struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name); void dma_release_channel(struct dma_chan *chan); #else @@ -1063,6 +1066,11 @@ static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, { return NULL; } +static inline struct dma_chan *dma_request_slave_channel_reason( + struct device *dev, const char *name) +{ + return ERR_PTR(-ENODEV); +} static inline struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) { -- cgit v1.2.3 From f0e9c08065dc31210fc4cf313c4ecaa088187dc5 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 16 Dec 2013 14:55:34 +0530 Subject: ALSA: compress: change the way sample rates are sent to kernel The usage of SNDRV_RATES is not effective as we can have rates like 12000 or some other ones used by decoders. This change the usage of this to use the raw Hz values to be sent to kernel Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/uapi/sound/compress_params.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 602dc6c45d1a..1114e380aecd 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -324,7 +324,7 @@ union snd_codec_options { /** struct snd_codec_desc - description of codec capabilities * @max_ch: Maximum number of audio channels - * @sample_rates: Sampling rates in Hz, use SNDRV_PCM_RATE_xxx for this + * @sample_rates: Sampling rates in Hz, use values like 48000 for this * @bit_rate: Indexed array containing supported bit rates * @num_bitrates: Number of valid values in bit_rate array * @rate_control: value is specified by SND_RATECONTROLMODE defines. -- cgit v1.2.3 From e1771bcf99b0dc91f4ba645c1740fd5031702f49 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 10 Dec 2013 12:35:25 -0700 Subject: ASoC: SPEAr: remove custom DMA alloc compat function spear_pcm_request_chan() is almost identical to dmaengine_pcm_compat_request_channel(), with the exception that the latter: a) Assumes that the DAI DMA data is a struct snd_dmaengine_dai_dma_data pointer rather than some custom type. b) dma_data->filter_data rather than dma_data should be passed to snd_dmaengine_pcm_request_channel() as the filter data. Make minor changes to the SPEAr DAI drivers so that those two conditions are met. This allows removal of the custom .compat_request_channel(). Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- include/sound/spear_dma.h | 1 - sound/soc/spear/spdif_in.c | 10 +++++++--- sound/soc/spear/spdif_out.c | 10 +++++++--- sound/soc/spear/spear_pcm.c | 21 +++++++-------------- sound/soc/spear/spear_pcm.h | 4 +++- 5 files changed, 24 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/sound/spear_dma.h b/include/sound/spear_dma.h index 1b365bfdfb37..65aca51fe255 100644 --- a/include/sound/spear_dma.h +++ b/include/sound/spear_dma.h @@ -29,7 +29,6 @@ struct spear_dma_data { dma_addr_t addr; u32 max_burst; enum dma_slave_buswidth addr_width; - bool (*filter)(struct dma_chan *chan, void *slave); }; #endif /* SPEAR_DMA_H */ diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index 4627110f3441..4ab442a63d7e 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ struct spdif_in_dev { struct device *dev; void (*reset_perip)(void); int irq; + struct snd_dmaengine_dai_dma_data dma_params_rx; + struct snd_dmaengine_pcm_config config; }; static void spdif_in_configure(struct spdif_in_dev *host) @@ -54,7 +57,8 @@ static int spdif_in_dai_probe(struct snd_soc_dai *dai) { struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai); - dai->capture_dma_data = &host->dma_params; + host->dma_params_rx.filter_data = &host->dma_params; + dai->capture_dma_data = &host->dma_params_rx; return 0; } @@ -245,7 +249,6 @@ static int spdif_in_probe(struct platform_device *pdev) host->dma_params.addr = res_fifo->start; host->dma_params.max_burst = 16; host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_params.filter = pdata->filter; host->reset_perip = pdata->reset_perip; host->dev = &pdev->dev; @@ -263,7 +266,8 @@ static int spdif_in_probe(struct platform_device *pdev) if (ret) return ret; - return devm_spear_pcm_platform_register(&pdev->dev); + return devm_spear_pcm_platform_register(&pdev->dev, &host->config, + pdata->filter); } static struct platform_driver spdif_in_driver = { diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c index 731a1e0cfeaa..fe99f461aff0 100644 --- a/sound/soc/spear/spdif_out.c +++ b/sound/soc/spear/spdif_out.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,8 @@ struct spdif_out_dev { struct spdif_out_params saved_params; u32 running; void __iomem *io_base; + struct snd_dmaengine_dai_dma_data dma_params_tx; + struct snd_dmaengine_pcm_config config; }; static void spdif_out_configure(struct spdif_out_dev *host) @@ -245,7 +248,8 @@ static int spdif_soc_dai_probe(struct snd_soc_dai *dai) { struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai); - dai->playback_dma_data = &host->dma_params; + host->dma_params_tx.filter_data = &host->dma_params; + dai->playback_dma_data = &host->dma_params_tx; return snd_soc_add_dai_controls(dai, spdif_out_controls, ARRAY_SIZE(spdif_out_controls)); @@ -304,7 +308,6 @@ static int spdif_out_probe(struct platform_device *pdev) host->dma_params.addr = res->start + SPDIF_OUT_FIFO_DATA; host->dma_params.max_burst = 16; host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_params.filter = pdata->filter; dev_set_drvdata(&pdev->dev, host); @@ -313,7 +316,8 @@ static int spdif_out_probe(struct platform_device *pdev) if (ret) return ret; - return devm_spear_pcm_platform_register(&pdev->dev); + return devm_spear_pcm_platform_register(&pdev->dev, &host->config, + pdata->filter); } #ifdef CONFIG_PM diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index f288724961da..0e5a8f35d0ad 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -32,26 +32,19 @@ static const struct snd_pcm_hardware spear_pcm_hardware = { .fifo_size = 0, /* fifo size in bytes */ }; -static struct dma_chan *spear_pcm_request_chan(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_substream *substream) -{ - struct spear_dma_data *dma_data; - - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - return snd_dmaengine_pcm_request_channel(dma_data->filter, dma_data); -} - static const struct snd_dmaengine_pcm_config spear_dmaengine_pcm_config = { .pcm_hardware = &spear_pcm_hardware, - .compat_request_channel = spear_pcm_request_chan, .prealloc_buffer_size = 16 * 1024, }; -int devm_spear_pcm_platform_register(struct device *dev) +int devm_spear_pcm_platform_register(struct device *dev, + struct snd_dmaengine_pcm_config *config, + bool (*filter)(struct dma_chan *chan, void *slave)) { - return devm_snd_dmaengine_pcm_register(dev, - &spear_dmaengine_pcm_config, + *config = spear_dmaengine_pcm_config; + config->compat_filter_fn = filter; + + return snd_dmaengine_pcm_register(dev, config, SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_COMPAT); } diff --git a/sound/soc/spear/spear_pcm.h b/sound/soc/spear/spear_pcm.h index 631e2aa1fb33..9b0ca62d6f02 100644 --- a/sound/soc/spear/spear_pcm.h +++ b/sound/soc/spear/spear_pcm.h @@ -17,6 +17,8 @@ #ifndef __SPEAR_PCM_H__ #define __SPEAR_PCM_H__ -int devm_spear_pcm_platform_register(struct device *dev); +int devm_spear_pcm_platform_register(struct device *dev, + struct snd_dmaengine_pcm_config *config, + bool (*filter)(struct dma_chan *chan, void *slave)); #endif -- cgit v1.2.3 From 792b62e705048f4da9a6f570c15093ab669839b6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 Dec 2013 09:11:01 +0000 Subject: mfd: wm5110: Expose DRE control registers Certain use-cases require the DRE to be disabled so expose registers necessary to control the DRE enables. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/mfd/wm5110-tables.c | 2 ++ include/linux/mfd/arizona/registers.h | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'include') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 338cfbe6727b..abd6713de7b0 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -601,6 +601,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x0000043D, 0x0180 }, /* R1085 - DAC Digital Volume 6R */ { 0x0000043E, 0x0080 }, /* R1086 - DAC Volume Limit 6R */ { 0x0000043F, 0x0800 }, /* R1087 - Noise Gate Select 6R */ + { 0x00000440, 0x8FFF }, /* R1088 - DRE Enable */ { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ { 0x00000458, 0x0000 }, /* R1112 - Noise Gate Control */ { 0x00000480, 0x0040 }, /* R1152 - Class W ANC Threshold 1 */ @@ -1631,6 +1632,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_DAC_DIGITAL_VOLUME_6R: case ARIZONA_DAC_VOLUME_LIMIT_6R: case ARIZONA_NOISE_GATE_SELECT_6R: + case ARIZONA_DRE_ENABLE: case ARIZONA_DAC_AEC_CONTROL_1: case ARIZONA_NOISE_GATE_CONTROL: case ARIZONA_PDM_SPK1_CTRL_1: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 89878149a43f..22916c0f1ca4 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -3207,6 +3207,10 @@ /* * R1088 (0x440) - DRE Enable */ +#define ARIZONA_DRE3R_ENA 0x0020 /* DRE3R_ENA */ +#define ARIZONA_DRE3R_ENA_MASK 0x0020 /* DRE3R_ENA */ +#define ARIZONA_DRE3R_ENA_SHIFT 5 /* DRE3R_ENA */ +#define ARIZONA_DRE3R_ENA_WIDTH 1 /* DRE3R_ENA */ #define ARIZONA_DRE3L_ENA 0x0010 /* DRE3L_ENA */ #define ARIZONA_DRE3L_ENA_MASK 0x0010 /* DRE3L_ENA */ #define ARIZONA_DRE3L_ENA_SHIFT 4 /* DRE3L_ENA */ -- cgit v1.2.3 From 8cb7a36eb3a80cd58353e351b7b4370d9a9f0c14 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Dec 2013 10:37:48 +0530 Subject: ASoC: mcbsp: Trivial cleanup in asoc-ti-mcbsp.h Commit 2203747c9771 ("ARM: omap: move platform_data definitions") moved the file to the current location but forgot to remove the pointer to its previous location. Clean it up. While at it also change the header file protection macros appropriately. Signed-off-by: Sachin Kamat Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- include/linux/platform_data/asoc-ti-mcbsp.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/platform_data/asoc-ti-mcbsp.h b/include/linux/platform_data/asoc-ti-mcbsp.h index c78d90b28b19..3c73c045f8da 100644 --- a/include/linux/platform_data/asoc-ti-mcbsp.h +++ b/include/linux/platform_data/asoc-ti-mcbsp.h @@ -1,6 +1,4 @@ /* - * arch/arm/plat-omap/include/mach/mcbsp.h - * * Defines for Multi-Channel Buffered Serial Port * * Copyright (C) 2002 RidgeRun, Inc. @@ -21,8 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#ifndef __ASM_ARCH_OMAP_MCBSP_H -#define __ASM_ARCH_OMAP_MCBSP_H +#ifndef __ASOC_TI_MCBSP_H +#define __ASOC_TI_MCBSP_H #include #include -- cgit v1.2.3 From 8c5178fca4ce5a57711ea14b807648e19b105d0e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 24 Dec 2013 12:24:28 +0000 Subject: ALSA: Add params_width() helpers Add helpers for obtaining the width of a format directly from params since this is expected to become a common operation in ASoC. Signed-off-by: Mark Brown Reviewed-by: Takashi Iwai --- include/sound/pcm_params.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include') diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 37ae12e0ab06..6b1c78f05fab 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -354,4 +354,16 @@ params_period_bytes(const struct snd_pcm_hw_params *p) params_channels(p)) / 8; } +static inline int +params_width(const struct snd_pcm_hw_params *p) +{ + return snd_pcm_format_width(params_format(p)); +} + +static inline int +params_physical_width(const struct snd_pcm_hw_params *p) +{ + return snd_pcm_format_physical_width(params_format(p)); +} + #endif /* __SOUND_PCM_PARAMS_H */ -- cgit v1.2.3 From ef749400434cefd14fe02fe3de9e9f0125b2256d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Dec 2013 19:28:51 -0800 Subject: ASoC: rsnd: add SRC (Sampling Rate Converter) support This patch adds SRC support to Renesas sound driver. SRC converts sampling rate between codec <-> cpu. It needs special codec chip, or very simple DA/AD converter to use it. This patch was tested via ak4554 codec, and supports Gen1 only at this point. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/rcar_snd.h | 1 + sound/soc/sh/rcar/adg.c | 73 +++++++++++++++++++++++ sound/soc/sh/rcar/gen.c | 10 ++++ sound/soc/sh/rcar/rsnd.h | 18 ++++++ sound/soc/sh/rcar/scu.c | 152 ++++++++++++++++++++++++++++++++++++++++++++--- sound/soc/sh/rcar/ssi.c | 2 +- 6 files changed, 248 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index a818ff76b138..e147498abe50 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -58,6 +58,7 @@ struct rsnd_ssi_platform_info { struct rsnd_scu_platform_info { u32 flags; + u32 convert_rate; /* sampling rate convert */ }; /* diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 2e71a7bda4c2..a53235c4d1b0 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -30,6 +30,79 @@ struct rsnd_adg { i++, (pos) = adg->clk[i]) #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) +static int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, + struct rsnd_mod *mod, + unsigned int src_rate, + unsigned int dst_rate) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + int idx, sel, div, shift; + u32 mask, val; + int id = rsnd_mod_id(mod); + unsigned int sel_rate [] = { + clk_get_rate(adg->clk[CLKA]), /* 000: CLKA */ + clk_get_rate(adg->clk[CLKB]), /* 001: CLKB */ + clk_get_rate(adg->clk[CLKC]), /* 010: CLKC */ + 0, /* 011: MLBCLK (not used) */ + adg->rbga_rate_for_441khz_div_6,/* 100: RBGA */ + adg->rbgb_rate_for_48khz_div_6, /* 101: RBGB */ + }; + + /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */ + for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { + for (div = 128, idx = 0; + div <= 2048; + div *= 2, idx++) { + if (src_rate == sel_rate[sel] / div) { + val = (idx << 4) | sel; + goto find_rate; + } + } + } + dev_err(dev, "can't find convert src clk\n"); + return -EINVAL; + +find_rate: + shift = (id % 4) * 8; + mask = 0xFF << shift; + val = val << shift; + + dev_dbg(dev, "adg convert src clk = %02x\n", val); + + switch (id / 4) { + case 0: + rsnd_mod_bset(mod, AUDIO_CLK_SEL3, mask, val); + break; + case 1: + rsnd_mod_bset(mod, AUDIO_CLK_SEL4, mask, val); + break; + case 2: + rsnd_mod_bset(mod, AUDIO_CLK_SEL5, mask, val); + break; + } + + /* + * Gen1 doesn't need dst_rate settings, + * since it uses SSI WS pin. + * see also rsnd_src_set_route_if_gen1() + */ + + return 0; +} + +int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, + struct rsnd_mod *mod, + unsigned int src_rate, + unsigned int dst_rate) +{ + if (rsnd_is_gen1(priv)) + return rsnd_adg_set_convert_clk_gen1(priv, mod, + src_rate, dst_rate); + + return -EINVAL; +} + static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val) { int id = rsnd_mod_id(mod); diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 862758d3ec06..add088bd4b2a 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -318,13 +318,23 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4), + RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), + RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), RSND_GEN1_M_REG(gen, SRU, SRC_ADINR, 0x214, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_IFSCR, 0x21c, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_IFSVR, 0x220, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_SRCCR, 0x224, 0x40), + RSND_GEN1_M_REG(gen, SRU, SRC_MNFSR, 0x228, 0x40), RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00), RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04), RSND_GEN1_S_REG(gen, ADG, SSICKR, 0x08), RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL3, 0x18), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL4, 0x1c), + RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL5, 0x20), RSND_GEN1_M_REG(gen, SSI, SSICR, 0x00, 0x40), RSND_GEN1_M_REG(gen, SSI, SSISR, 0x04, 0x40), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 3774dfcfaf0f..4ca66cd899c8 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -41,7 +41,14 @@ enum rsnd_reg { RSND_REG_SSI_MODE1, RSND_REG_BUSIF_MODE, RSND_REG_INT_ENABLE, /* for Gen2 */ + RSND_REG_SRC_ROUTE_MODE0, + RSND_REG_SRC_SWRSR, + RSND_REG_SRC_SRCIR, RSND_REG_SRC_ADINR, + RSND_REG_SRC_IFSCR, + RSND_REG_SRC_IFSVR, + RSND_REG_SRC_SRCCR, + RSND_REG_SRC_MNFSR, /* ADG */ RSND_REG_BRRA, @@ -50,6 +57,9 @@ enum rsnd_reg { RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL1, RSND_REG_AUDIO_CLK_SEL2, + RSND_REG_AUDIO_CLK_SEL3, /* for Gen1 */ + RSND_REG_AUDIO_CLK_SEL4, /* for Gen1 */ + RSND_REG_AUDIO_CLK_SEL5, /* for Gen1 */ /* SSI */ RSND_REG_SSICR, @@ -227,6 +237,10 @@ int rsnd_adg_probe(struct platform_device *pdev, struct rsnd_priv *priv); void rsnd_adg_remove(struct platform_device *pdev, struct rsnd_priv *priv); +int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, + struct rsnd_mod *mod, + unsigned int src_rate, + unsigned int dst_rate); /* * R-Car sound priv @@ -280,6 +294,10 @@ void rsnd_scu_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod); +unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, + struct rsnd_mod *ssi_mod, + struct snd_pcm_runtime *runtime); + #define rsnd_scu_nr(priv) ((priv)->scu_nr) /* diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c index 5f4f57206faf..1406dd8d9ed2 100644 --- a/sound/soc/sh/rcar/scu.c +++ b/sound/soc/sh/rcar/scu.c @@ -13,9 +13,13 @@ struct rsnd_scu { struct rsnd_scu_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; + struct clk *clk; }; #define rsnd_scu_mode_flags(p) ((p)->info->flags) +#define rsnd_scu_convert_rate(p) ((p)->info->convert_rate) + +#define RSND_SCU_NAME_SIZE 16 /* * ADINR @@ -26,6 +30,15 @@ struct rsnd_scu { #define OTBL_18 (6 << 16) #define OTBL_16 (8 << 16) +/* + * image of SRC (Sampling Rate Converter) + * + * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ + * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | + * 44.1kHz <-> +-----+ +-----+ +-------+ + * ... + * + */ #define rsnd_mod_to_scu(_mod) \ container_of((_mod), struct rsnd_scu, mod) @@ -56,7 +69,7 @@ static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, { 0x3, 28, }, /* 7 */ { 0x3, 30, }, /* 8 */ }; - + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); u32 mask; u32 val; int shift; @@ -86,9 +99,18 @@ static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, */ shift = (id % 4) * 8; mask = 0x1F << shift; - if (8 == id) /* SRU8 is very special */ + + /* + * ADG is used as source clock if SRC was used, + * then, SSI WS is used as destination clock. + * SSI WS is used as source clock if SRC is not used + * (when playback, source/destination become reverse when capture) + */ + if (rsnd_scu_convert_rate(scu)) /* use ADG */ + val = 0; + else if (8 == id) /* use SSI WS, but SRU8 is special */ val = id << shift; - else + else /* use SSI WS */ val = (id + 1) << shift; switch (id / 4) { @@ -106,14 +128,45 @@ static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, return 0; } -static int rsnd_scu_rate_ctrl(struct rsnd_priv *priv, +unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, + struct rsnd_mod *ssi_mod, + struct snd_pcm_runtime *runtime) +{ + struct rsnd_scu *scu; + unsigned int rate; + + /* this function is assuming SSI id = SCU id here */ + scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod))); + + /* + * return convert rate if SRC is used, + * otherwise, return runtime->rate as usual + */ + rate = rsnd_scu_convert_rate(scu); + if (!rate) + rate = runtime->rate; + + return rate; +} + +static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv, struct rsnd_mod *mod, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); + u32 convert_rate = rsnd_scu_convert_rate(scu); u32 adinr = runtime->channels; + /* set/clear soft reset */ + rsnd_mod_write(mod, SRC_SWRSR, 0); + rsnd_mod_write(mod, SRC_SWRSR, 1); + + /* Initialize the operation of the SRC internal circuits */ + rsnd_mod_write(mod, SRC_SRCIR, 1); + + /* Set channel number and output bit length */ switch (runtime->sample_bits) { case 16: adinr |= OTBL_16; @@ -124,9 +177,42 @@ static int rsnd_scu_rate_ctrl(struct rsnd_priv *priv, default: return -EIO; } - rsnd_mod_write(mod, SRC_ADINR, adinr); + if (convert_rate) { + u32 fsrate = 0x0400000 / convert_rate * runtime->rate; + int ret; + + /* Enable the initial value of IFS */ + rsnd_mod_write(mod, SRC_IFSCR, 1); + + /* Set initial value of IFS */ + rsnd_mod_write(mod, SRC_IFSVR, fsrate); + + /* Select SRC mode (fixed value) */ + rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); + + /* Set the restriction value of the FS ratio (98%) */ + rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98); + + if (rsnd_is_gen1(priv)) { + /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ + } + + /* set convert clock */ + ret = rsnd_adg_set_convert_clk(priv, mod, + runtime->rate, + convert_rate); + if (ret < 0) + return ret; + } + + /* Cancel the initialization and operate the SRC function */ + rsnd_mod_write(mod, SRC_SRCIR, 0); + + /* use DMA transfer */ + rsnd_mod_write(mod, BUSIF_MODE, 1); + return 0; } @@ -135,6 +221,7 @@ static int rsnd_scu_transfer_start(struct rsnd_priv *priv, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) { + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); int id = rsnd_mod_id(mod); u32 val; @@ -143,7 +230,28 @@ static int rsnd_scu_transfer_start(struct rsnd_priv *priv, rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val); } - rsnd_mod_write(mod, BUSIF_MODE, 1); + if (rsnd_scu_convert_rate(scu)) + rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); + + return 0; +} + +static int rsnd_scu_transfer_stop(struct rsnd_priv *priv, + struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct rsnd_dai_stream *io) +{ + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); + int id = rsnd_mod_id(mod); + u32 mask; + + if (rsnd_is_gen1(priv)) { + mask = (1 << id); + rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0); + } + + if (rsnd_scu_convert_rate(scu)) + rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0); return 0; } @@ -161,6 +269,7 @@ static int rsnd_scu_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); struct device *dev = rsnd_priv_to_dev(priv); int ret; @@ -175,13 +284,15 @@ static int rsnd_scu_start(struct rsnd_mod *mod, return 0; } + clk_enable(scu->clk); + /* it use DMA transter */ ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io); if (ret < 0) return ret; - ret = rsnd_scu_rate_ctrl(priv, mod, rdai, io); + ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io); if (ret < 0) return ret; @@ -194,9 +305,27 @@ static int rsnd_scu_start(struct rsnd_mod *mod, return 0; } +static int rsnd_scu_stop(struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct rsnd_dai_stream *io) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); + + if (!rsnd_scu_hpbif_is_enable(mod)) + return 0; + + rsnd_scu_transfer_stop(priv, mod, rdai, io); + + clk_disable(scu->clk); + + return 0; +} + static struct rsnd_mod_ops rsnd_scu_ops = { .name = "scu", .start = rsnd_scu_start, + .stop = rsnd_scu_stop, }; struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) @@ -212,6 +341,8 @@ int rsnd_scu_probe(struct platform_device *pdev, { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_scu *scu; + struct clk *clk; + char name[RSND_SCU_NAME_SIZE]; int i, nr; /* @@ -228,9 +359,16 @@ int rsnd_scu_probe(struct platform_device *pdev, priv->scu = scu; for_each_rsnd_scu(scu, priv, i) { + snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) + return PTR_ERR(clk); + rsnd_mod_init(priv, &scu->mod, &rsnd_scu_ops, i); scu->info = &info->scu_info[i]; + scu->clk = clk; dev_dbg(dev, "SCU%d probed\n", i); } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 2db9711549f5..b7cd06be9436 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -200,7 +200,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, 1, 2, 4, 8, 16, 6, 12, }; unsigned int main_rate; - unsigned int rate = runtime->rate; + unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime); /* * Find best clock, and try to start ADG -- cgit v1.2.3 From d9afee6904caa7cf3c7f417f02e765db89d2b5dc Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 4 Jan 2014 16:59:12 +0530 Subject: ALSA: compress: update comment for sample rate in snd_codec Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/uapi/sound/compress_params.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 1114e380aecd..8c23aebc82a5 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -364,7 +364,8 @@ struct snd_codec_desc { * @ch_out: Number of output channels. In case of contradiction between * this field and the channelMode field, the channelMode field * overrides. - * @sample_rate: Audio sample rate of input data + * @sample_rate: Audio sample rate of input data in Hz, use values like 48000 + * for this. * @bit_rate: Bitrate of encoded data. May be ignored by decoders * @rate_control: Encoding rate control. See SND_RATECONTROLMODE defines. * Encoders may rely on profiles for quality levels. -- cgit v1.2.3 From b8bab04829ab190f71921d4180bda438ba6124ae Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 4 Jan 2014 16:59:13 +0530 Subject: ALSA: compress: update struct snd_codec_desc for sample rate Now that we don't use SNDRV_PCM_RATE_xxx bit fields for sample rate, we need to change the description to an array for describing the sample rates supported by the sink/source Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/uapi/sound/compress_params.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 8c23aebc82a5..b62b24b7f834 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -57,6 +57,7 @@ #define MAX_NUM_CODECS 32 #define MAX_NUM_CODEC_DESCRIPTORS 32 #define MAX_NUM_BITRATES 32 +#define MAX_NUM_SAMPLE_RATES 32 /* Codecs are listed linearly to allow for extensibility */ #define SND_AUDIOCODEC_PCM ((__u32) 0x00000001) @@ -346,7 +347,7 @@ union snd_codec_options { struct snd_codec_desc { __u32 max_ch; - __u32 sample_rates; + __u32 sample_rates[MAX_NUM_SAMPLE_RATES]; __u32 bit_rate[MAX_NUM_BITRATES]; __u32 num_bitrates; __u32 rate_control; -- cgit v1.2.3 From 0475680b5c2ef4bbdc3af1f6cfd014ea08c8d981 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Dec 2013 15:54:58 +0000 Subject: ARM: ux500: Don't use enums for MSP IDs - for easy DT conversion Signed-off-by: Lee Jones Acked-by: Linus Walleij Signed-off-by: Mark Brown --- arch/arm/mach-ux500/board-mop500-audio.c | 8 ++++---- include/linux/platform_data/asoc-ux500-msp.h | 9 +-------- sound/soc/ux500/ux500_msp_i2s.h | 2 +- 3 files changed, 6 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-ux500/board-mop500-audio.c b/arch/arm/mach-ux500/board-mop500-audio.c index 154e15f59702..43d6cb8c381d 100644 --- a/arch/arm/mach-ux500/board-mop500-audio.c +++ b/arch/arm/mach-ux500/board-mop500-audio.c @@ -31,7 +31,7 @@ static struct stedma40_chan_cfg msp0_dma_tx = { }; struct msp_i2s_platform_data msp0_platform_data = { - .id = MSP_I2S_0, + .id = 0, .msp_i2s_dma_rx = &msp0_dma_rx, .msp_i2s_dma_tx = &msp0_dma_tx, }; @@ -49,7 +49,7 @@ static struct stedma40_chan_cfg msp1_dma_tx = { }; struct msp_i2s_platform_data msp1_platform_data = { - .id = MSP_I2S_1, + .id = 1, .msp_i2s_dma_rx = NULL, .msp_i2s_dma_tx = &msp1_dma_tx, }; @@ -69,13 +69,13 @@ static struct stedma40_chan_cfg msp2_dma_tx = { }; struct msp_i2s_platform_data msp2_platform_data = { - .id = MSP_I2S_2, + .id = 2, .msp_i2s_dma_rx = &msp2_dma_rx, .msp_i2s_dma_tx = &msp2_dma_tx, }; struct msp_i2s_platform_data msp3_platform_data = { - .id = MSP_I2S_3, + .id = 3, .msp_i2s_dma_rx = &msp1_dma_rx, .msp_i2s_dma_tx = NULL, }; diff --git a/include/linux/platform_data/asoc-ux500-msp.h b/include/linux/platform_data/asoc-ux500-msp.h index 9991aea3d577..2f34bb98fe2a 100644 --- a/include/linux/platform_data/asoc-ux500-msp.h +++ b/include/linux/platform_data/asoc-ux500-msp.h @@ -10,16 +10,9 @@ #include -enum msp_i2s_id { - MSP_I2S_0 = 0, - MSP_I2S_1, - MSP_I2S_2, - MSP_I2S_3, -}; - /* Platform data structure for a MSP I2S-device */ struct msp_i2s_platform_data { - enum msp_i2s_id id; + int id; struct stedma40_chan_cfg *msp_i2s_dma_rx; struct stedma40_chan_cfg *msp_i2s_dma_tx; }; diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index 258d0bcee0bd..875de0f68b85 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -475,7 +475,7 @@ struct ux500_msp_dma_params { }; struct ux500_msp { - enum msp_i2s_id id; + int id; void __iomem *registers; struct device *dev; struct ux500_msp_dma_params playback_dma_data; -- cgit v1.2.3 From 929559be6d2c494e25bb58b730da4a78c1459e7b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 7 Jan 2014 21:55:42 +0530 Subject: ALSA: compress: add num_sample_rates in snd_codec_desc this gives ability to convey the valid values of supported rates in sample_rates array Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/uapi/sound/compress_params.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index b62b24b7f834..165e7059de75 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -326,6 +326,7 @@ union snd_codec_options { /** struct snd_codec_desc - description of codec capabilities * @max_ch: Maximum number of audio channels * @sample_rates: Sampling rates in Hz, use values like 48000 for this + * @num_sample_rates: Number of valid values in sample_rates array * @bit_rate: Indexed array containing supported bit rates * @num_bitrates: Number of valid values in bit_rate array * @rate_control: value is specified by SND_RATECONTROLMODE defines. @@ -348,6 +349,7 @@ union snd_codec_options { struct snd_codec_desc { __u32 max_ch; __u32 sample_rates[MAX_NUM_SAMPLE_RATES]; + __u32 num_sample_rates; __u32 bit_rate[MAX_NUM_BITRATES]; __u32 num_bitrates; __u32 rate_control; -- cgit v1.2.3 From 1e9de42f4324b91ce2e9da0939cab8fc6ae93893 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 7 Jan 2014 17:51:42 +0000 Subject: ASoC: dpcm: Explicitly set BE DAI link supported stream directions Some BE DAIs can be "dummy" (when the DSP is controlling the DAI) and as such wont have set a minimum number of playback or capture channels required for BE DAI registration (to establish supported stream directions). Force machine drivers to explicitly set whether they support playback and capture stream directions for every BE DAIs. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++++ sound/soc/soc-pcm.c | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 1f741cb24f33..a5ef14f06124 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -886,6 +886,10 @@ struct snd_soc_dai_link { /* This DAI link can route to other DAI links at runtime (Frontend)*/ unsigned int dynamic:1; + /* DPCM capture and Playback support */ + unsigned int dpcm_capture:1; + unsigned int dpcm_playback:1; + /* pmdown_time is ignored at stop */ unsigned int ignore_pmdown_time:1; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 42782c01e413..141a302e4e77 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2026,10 +2026,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) int ret = 0, playback = 0, capture = 0; if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { - if (cpu_dai->driver->playback.channels_min) - playback = 1; - if (cpu_dai->driver->capture.channels_min) - capture = 1; + playback = rtd->dai_link->dpcm_playback; + capture = rtd->dai_link->dpcm_capture; } else { if (codec_dai->driver->playback.channels_min && cpu_dai->driver->playback.channels_min) -- cgit v1.2.3 From 3def927ea8c0a1983aa9f1499645efc53e005bb6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 3 Jan 2014 15:27:47 +0200 Subject: mfd: twl-core: API to set the regcache bypass for a given regmap in twl If the regcache is enabled on the regmap module drivers might need to access to HW register(s) in certain cases in cache bypass mode. As an example of this is the audio block's ANAMICL register. In normal operation the content can be cached but during initialization one bit from the register need to be monitored. With the twl_set_regcache_bypass() the client driver can switch regcache bypass on and off when it is needed so we can utilize the regcache for more registers. Signed-off-by: Peter Ujfalusi Acked-by: Mark Brown Signed-off-by: Lee Jones --- drivers/mfd/twl-core.c | 21 +++++++++++++++++++++ include/linux/i2c/twl.h | 3 +++ 2 files changed, 24 insertions(+) (limited to 'include') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index c91cb4367b9b..f0abca79ff34 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -383,6 +383,27 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) } EXPORT_SYMBOL(twl_i2c_read); +/** + * twl_regcache_bypass - Configure the regcache bypass for the regmap associated + * with the module + * @mod_no: module number + * @enable: Regcache bypass state + * + * Returns 0 else failure. + */ +int twl_set_regcache_bypass(u8 mod_no, bool enable) +{ + struct regmap *regmap = twl_get_regmap(mod_no); + + if (!regmap) + return -EPERM; + + regcache_cache_bypass(regmap, enable); + + return 0; +} +EXPORT_SYMBOL(twl_set_regcache_bypass); + /*----------------------------------------------------------------------*/ /** diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 673a3ce67f31..a09da0910339 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -175,6 +175,9 @@ static inline int twl_class_is_ ##class(void) \ TWL_CLASS_IS(4030, TWL4030_CLASS_ID) TWL_CLASS_IS(6030, TWL6030_CLASS_ID) +/* Set the regcache bypass for the regmap associated with the nodule */ +int twl_set_regcache_bypass(u8 mod_no, bool enable); + /* * Read and write several 8-bit registers at once. */ -- cgit v1.2.3 From bece9e957cbfb37f12488b24166364307e39f5b0 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 8 Jan 2014 10:40:18 +0000 Subject: ASoC: utils: Add internal call to determine if DAI is dummy. Provide a quick way to tell if a DAI is a dummy DAI or a regular DAI. This is for internal DAPM usage only and is used to determine whether to insert a DAI link connection into the DAPM graph. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 ++ sound/soc/soc-utils.c | 7 +++++++ 2 files changed, 9 insertions(+) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 800c101bb096..c42864b34581 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -123,6 +123,8 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, int direction); +int snd_soc_dai_is_dummy(struct snd_soc_dai *dai); + struct snd_soc_dai_ops { /* * DAI clocking configuration, all optional. diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 5e633659c1b3..d14bdb3c52df 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -123,6 +123,13 @@ static struct snd_soc_dai_driver dummy_dai = { }, }; +int snd_soc_dai_is_dummy(struct snd_soc_dai *dai) +{ + if (dai->driver == &dummy_dai) + return 1; + return 0; +} + static int snd_soc_dummy_probe(struct platform_device *pdev) { int ret; -- cgit v1.2.3 From b893ea5f1cd1adbbd7e0794d16d47bbb46f80733 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 8 Jan 2014 10:40:19 +0000 Subject: ASoC: sapm: Automatically connect DAI link widgets in DAPM graph. Connect the DAPM graph through each BE DAI link to the componnent(s) on the other side of the BE DAI link. This allows the graph to be walked on both sides of the link when graph changes are made. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 + sound/soc/soc-core.c | 1 + sound/soc/soc-dapm.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) (limited to 'include') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 2037c45adfe6..a5de124d2f9d 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -411,6 +411,7 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai); int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); +void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); int snd_soc_dapm_new_pcm(struct snd_soc_card *card, const struct snd_soc_pcm_stream *params, struct snd_soc_dapm_widget *source, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4e53d87e881d..7d9c0660ab24 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1728,6 +1728,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } snd_soc_dapm_link_dai_widgets(card); + snd_soc_dapm_connect_dai_link_widgets(card); if (card->controls) snd_soc_add_card_controls(card, card->controls, card->num_controls); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 67e63ab1f11e..51b4c192f41a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3634,6 +3634,55 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) return 0; } +void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd = card->rtd; + struct snd_soc_dai *cpu_dai, *codec_dai; + struct snd_soc_dapm_route r; + int i; + + memset(&r, 0, sizeof(r)); + + /* for each BE DAI link... */ + for (i = 0; i < card->num_rtd; i++) { + rtd = &card->rtd[i]; + cpu_dai = rtd->cpu_dai; + codec_dai = rtd->codec_dai; + + /* dynamic FE links have no fixed DAI mapping */ + if (rtd->dai_link->dynamic) + continue; + + /* there is no point in connecting BE DAI links with dummies */ + if (snd_soc_dai_is_dummy(codec_dai) || + snd_soc_dai_is_dummy(cpu_dai)) + continue; + + /* connect BE DAI playback if widgets are valid */ + if (codec_dai->playback_widget && cpu_dai->playback_widget) { + r.source = cpu_dai->playback_widget->name; + r.sink = codec_dai->playback_widget->name; + dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", + cpu_dai->codec->name, r.source, + codec_dai->platform->name, r.sink); + + snd_soc_dapm_add_route(&card->dapm, &r); + } + + /* connect BE DAI capture if widgets are valid */ + if (codec_dai->capture_widget && cpu_dai->capture_widget) { + r.source = codec_dai->capture_widget->name; + r.sink = cpu_dai->capture_widget->name; + dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", + codec_dai->codec->name, r.source, + cpu_dai->platform->name, r.sink); + + snd_soc_dapm_add_route(&card->dapm, &r); + } + + } +} + static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event) { -- cgit v1.2.3 From 7bfbdfea576e3ae109fa182519b6f004c6024952 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 3 Jan 2014 15:27:50 +0200 Subject: ASoC: twl4030: Remove check defaults functionality No need to keep the check defaults functionality anymore. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- include/linux/i2c/twl.h | 1 - sound/soc/codecs/twl4030.c | 23 ----------------------- 2 files changed, 24 deletions(-) (limited to 'include') diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index a09da0910339..2937a9472b94 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -670,7 +670,6 @@ struct twl4030_codec_data { unsigned int digimic_delay; /* in ms */ unsigned int ramp_delay_value; unsigned int offset_cncl_path; - unsigned int check_defaults:1; unsigned int reset_registers:1; unsigned int hs_extmute:1; int hs_extmute_gpio; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 419108ae31de..7b732ab70d2c 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -268,25 +268,6 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) udelay(10); } -static inline void twl4030_check_defaults(struct snd_soc_codec *codec) -{ - int i, difference = 0; - u8 val; - - dev_dbg(codec->dev, "Checking TWL audio default configuration\n"); - for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) { - twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i); - if (val != twl4030_reg[i]) { - difference++; - dev_dbg(codec->dev, - "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n", - i, val, twl4030_reg[i]); - } - } - dev_dbg(codec->dev, "Found %d non-matching registers. %s\n", - difference, difference ? "Not OK" : "OK"); -} - static inline void twl4030_reset_registers(struct snd_soc_codec *codec) { int i; @@ -378,10 +359,6 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } } - /* Check defaults, if instructed before anything else */ - if (pdata && pdata->check_defaults) - twl4030_check_defaults(codec); - /* Reset registers, if no setup data or if instructed to do so */ if (!pdata || (pdata && pdata->reset_registers)) twl4030_reset_registers(codec); -- cgit v1.2.3 From 0dc41562a44c9e1012bb810c2a84e81c425867b0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 3 Jan 2014 15:27:51 +0200 Subject: ASoC: twl4030: Remove reset registers functionality The register states now tracked by the regmap implementation in the core which makes the reset registers functionality 'redundant' since we know the state of the registers now all the time. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- include/linux/i2c/twl.h | 1 - sound/soc/codecs/twl4030.c | 17 ----------------- 2 files changed, 18 deletions(-) (limited to 'include') diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 2937a9472b94..ade1c06d4ceb 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -670,7 +670,6 @@ struct twl4030_codec_data { unsigned int digimic_delay; /* in ms */ unsigned int ramp_delay_value; unsigned int offset_cncl_path; - unsigned int reset_registers:1; unsigned int hs_extmute:1; int hs_extmute_gpio; }; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 7b732ab70d2c..ab2f22299db2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -268,17 +268,6 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) udelay(10); } -static inline void twl4030_reset_registers(struct snd_soc_codec *codec) -{ - int i; - - /* set all audio section registers to reasonable defaults */ - for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) - if (i != TWL4030_REG_APLL_CTL) - twl4030_write(codec, i, twl4030_reg[i]); - -} - static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata, struct device_node *node) { @@ -359,10 +348,6 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } } - /* Reset registers, if no setup data or if instructed to do so */ - if (!pdata || (pdata && pdata->reset_registers)) - twl4030_reset_registers(codec); - /* Refresh APLL_CTL register from HW */ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, TWL4030_REG_APLL_CTL); @@ -2293,8 +2278,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec) struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); struct twl4030_codec_data *pdata = twl4030->pdata; - /* Reset registers to their chip default before leaving */ - twl4030_reset_registers(codec); twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) -- cgit v1.2.3 From 47d98c026ef9a9888c36f3c4f26b81f548a0ca86 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jan 2014 16:12:25 +0100 Subject: ALSA: Remove memory reservation code from memalloc helper Nowadays we have CMA for obtaining the contiguous memory pages efficiently. Let's kill the old kludge for reserving the memory pages for large buffers. It was rarely useful (only for preserving pages among module reloading or a little help by an early boot scripting), used only by a couple of drivers, and yet it gives too much ugliness than its benefit. Signed-off-by: Takashi Iwai --- include/sound/memalloc.h | 7 -- include/sound/pcm.h | 1 - sound/core/memalloc.c | 264 -------------------------------------------- sound/core/pcm_memory.c | 19 +--- sound/pci/es1968.c | 28 +++-- sound/pci/rme9652/hdsp.c | 10 +- sound/pci/rme9652/rme9652.c | 10 +- 7 files changed, 18 insertions(+), 321 deletions(-) (limited to 'include') diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index 5f73785f5977..782d1df34208 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -149,13 +149,6 @@ int snd_dma_alloc_pages_fallback(int type, struct device *dev, size_t size, struct snd_dma_buffer *dmab); void snd_dma_free_pages(struct snd_dma_buffer *dmab); -/* buffer-preservation managements */ - -#define snd_dma_pci_buf_id(pci) (((unsigned int)(pci)->vendor << 16) | (pci)->device) - -size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id); -int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id); - /* basic memory allocation functions */ void *snd_malloc_pages(size_t size, gfp_t gfp_flags); void snd_free_pages(void *ptr, size_t size); diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 84b10f9a2832..fe6ca400b9ad 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -381,7 +381,6 @@ struct snd_pcm_substream { struct pm_qos_request latency_pm_qos_req; /* pm_qos request */ size_t buffer_bytes_max; /* limit ring buffer size */ struct snd_dma_buffer dma_buffer; - unsigned int dma_buf_id; size_t dma_max; /* -- hardware operations -- */ const struct snd_pcm_ops *ops; diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index bfaf4f04d91d..be1544ac4613 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -41,22 +41,6 @@ MODULE_DESCRIPTION("Memory allocator for ALSA system."); MODULE_LICENSE("GPL"); -/* - */ - -static DEFINE_MUTEX(list_mutex); -static LIST_HEAD(mem_list_head); - -/* buffer preservation list */ -struct snd_mem_list { - struct snd_dma_buffer buffer; - unsigned int id; - struct list_head list; -}; - -/* id for pre-allocated buffers */ -#define SNDRV_DMA_DEVICE_UNUSED (unsigned int)-1 - /* * * Generic memory allocators @@ -318,251 +302,6 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) } } - -/** - * snd_dma_get_reserved - get the reserved buffer for the given device - * @dmab: the buffer allocation record to store - * @id: the buffer id - * - * Looks for the reserved-buffer list and re-uses if the same buffer - * is found in the list. When the buffer is found, it's removed from the free list. - * - * Return: The size of buffer if the buffer is found, or zero if not found. - */ -size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) -{ - struct snd_mem_list *mem; - - if (WARN_ON(!dmab)) - return 0; - - mutex_lock(&list_mutex); - list_for_each_entry(mem, &mem_list_head, list) { - if (mem->id == id && - (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL || - ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) { - struct device *dev = dmab->dev.dev; - list_del(&mem->list); - *dmab = mem->buffer; - if (dmab->dev.dev == NULL) - dmab->dev.dev = dev; - kfree(mem); - mutex_unlock(&list_mutex); - return dmab->bytes; - } - } - mutex_unlock(&list_mutex); - return 0; -} - -/** - * snd_dma_reserve_buf - reserve the buffer - * @dmab: the buffer to reserve - * @id: the buffer id - * - * Reserves the given buffer as a reserved buffer. - * - * Return: Zero if successful, or a negative code on error. - */ -int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id) -{ - struct snd_mem_list *mem; - - if (WARN_ON(!dmab)) - return -EINVAL; - mem = kmalloc(sizeof(*mem), GFP_KERNEL); - if (! mem) - return -ENOMEM; - mutex_lock(&list_mutex); - mem->buffer = *dmab; - mem->id = id; - list_add_tail(&mem->list, &mem_list_head); - mutex_unlock(&list_mutex); - return 0; -} - -/* - * purge all reserved buffers - */ -static void free_all_reserved_pages(void) -{ - struct list_head *p; - struct snd_mem_list *mem; - - mutex_lock(&list_mutex); - while (! list_empty(&mem_list_head)) { - p = mem_list_head.next; - mem = list_entry(p, struct snd_mem_list, list); - list_del(p); - snd_dma_free_pages(&mem->buffer); - kfree(mem); - } - mutex_unlock(&list_mutex); -} - - -#ifdef CONFIG_PROC_FS -/* - * proc file interface - */ -#define SND_MEM_PROC_FILE "driver/snd-page-alloc" -static struct proc_dir_entry *snd_mem_proc; - -static int snd_mem_proc_read(struct seq_file *seq, void *offset) -{ - struct snd_mem_list *mem; - int devno; - static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" }; - - mutex_lock(&list_mutex); - devno = 0; - list_for_each_entry(mem, &mem_list_head, list) { - devno++; - seq_printf(seq, "buffer %d : ID %08x : type %s\n", - devno, mem->id, types[mem->buffer.dev.type]); - seq_printf(seq, " addr = 0x%lx, size = %d bytes\n", - (unsigned long)mem->buffer.addr, - (int)mem->buffer.bytes); - } - mutex_unlock(&list_mutex); - return 0; -} - -static int snd_mem_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, snd_mem_proc_read, NULL); -} - -/* FIXME: for pci only - other bus? */ -#ifdef CONFIG_PCI -#define gettoken(bufp) strsep(bufp, " \t\n") - -static ssize_t snd_mem_proc_write(struct file *file, const char __user * buffer, - size_t count, loff_t * ppos) -{ - char buf[128]; - char *token, *p; - - if (count > sizeof(buf) - 1) - return -EINVAL; - if (copy_from_user(buf, buffer, count)) - return -EFAULT; - buf[count] = '\0'; - - p = buf; - token = gettoken(&p); - if (! token || *token == '#') - return count; - if (strcmp(token, "add") == 0) { - char *endp; - int vendor, device, size, buffers; - long mask; - int i, alloced; - struct pci_dev *pci; - - if ((token = gettoken(&p)) == NULL || - (vendor = simple_strtol(token, NULL, 0)) <= 0 || - (token = gettoken(&p)) == NULL || - (device = simple_strtol(token, NULL, 0)) <= 0 || - (token = gettoken(&p)) == NULL || - (mask = simple_strtol(token, NULL, 0)) < 0 || - (token = gettoken(&p)) == NULL || - (size = memparse(token, &endp)) < 64*1024 || - size > 16*1024*1024 /* too big */ || - (token = gettoken(&p)) == NULL || - (buffers = simple_strtol(token, NULL, 0)) <= 0 || - buffers > 4) { - printk(KERN_ERR "snd-page-alloc: invalid proc write format\n"); - return count; - } - vendor &= 0xffff; - device &= 0xffff; - - alloced = 0; - pci = NULL; - while ((pci = pci_get_device(vendor, device, pci)) != NULL) { - if (mask > 0 && mask < 0xffffffff) { - if (pci_set_dma_mask(pci, mask) < 0 || - pci_set_consistent_dma_mask(pci, mask) < 0) { - printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); - pci_dev_put(pci); - return count; - } - } - for (i = 0; i < buffers; i++) { - struct snd_dma_buffer dmab; - memset(&dmab, 0, sizeof(dmab)); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - size, &dmab) < 0) { - printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); - pci_dev_put(pci); - return count; - } - snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); - } - alloced++; - } - if (! alloced) { - for (i = 0; i < buffers; i++) { - struct snd_dma_buffer dmab; - memset(&dmab, 0, sizeof(dmab)); - /* FIXME: We can allocate only in ZONE_DMA - * without a device pointer! - */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL, - size, &dmab) < 0) { - printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); - break; - } - snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device)); - } - } - } else if (strcmp(token, "erase") == 0) - /* FIXME: need for releasing each buffer chunk? */ - free_all_reserved_pages(); - else - printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n"); - return count; -} -#endif /* CONFIG_PCI */ - -static const struct file_operations snd_mem_proc_fops = { - .owner = THIS_MODULE, - .open = snd_mem_proc_open, - .read = seq_read, -#ifdef CONFIG_PCI - .write = snd_mem_proc_write, -#endif - .llseek = seq_lseek, - .release = single_release, -}; - -#endif /* CONFIG_PROC_FS */ - -/* - * module entry - */ - -static int __init snd_mem_init(void) -{ -#ifdef CONFIG_PROC_FS - snd_mem_proc = proc_create(SND_MEM_PROC_FILE, 0644, NULL, - &snd_mem_proc_fops); -#endif - return 0; -} - -static void __exit snd_mem_exit(void) -{ - remove_proc_entry(SND_MEM_PROC_FILE, NULL); - free_all_reserved_pages(); -} - - -module_init(snd_mem_init) -module_exit(snd_mem_exit) - - /* * exports */ @@ -570,8 +309,5 @@ EXPORT_SYMBOL(snd_dma_alloc_pages); EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); EXPORT_SYMBOL(snd_dma_free_pages); -EXPORT_SYMBOL(snd_dma_get_reserved_buf); -EXPORT_SYMBOL(snd_dma_reserve_buf); - EXPORT_SYMBOL(snd_malloc_pages); EXPORT_SYMBOL(snd_free_pages); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 0af622c34e19..01f8eafebda6 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -53,15 +53,6 @@ static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t siz struct snd_dma_buffer *dmab = &substream->dma_buffer; int err; - /* already reserved? */ - if (snd_dma_get_reserved_buf(dmab, substream->dma_buf_id) > 0) { - if (dmab->bytes >= size) - return 0; /* yes */ - /* no, free the reserved block */ - snd_dma_free_pages(dmab); - dmab->bytes = 0; - } - do { if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev, size, dmab)) < 0) { @@ -82,10 +73,7 @@ static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream { if (substream->dma_buffer.area == NULL) return; - if (substream->dma_buf_id) - snd_dma_reserve_buf(&substream->dma_buffer, substream->dma_buf_id); - else - snd_dma_free_pages(&substream->dma_buffer); + snd_dma_free_pages(&substream->dma_buffer); substream->dma_buffer.area = NULL; } @@ -260,11 +248,6 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, * * Do pre-allocation for the given DMA buffer type. * - * When substream->dma_buf_id is set, the function tries to look for - * the reserved buffer, and the buffer is not freed but reserved at - * destruction time. The dma_buf_id must be unique for all systems - * (in the same DMA buffer type) e.g. using snd_dma_pci_buf_id(). - * * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index b0e3d92c4656..772cc36f951d 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1422,7 +1422,7 @@ static void snd_es1968_free_dmabuf(struct es1968 *chip) if (! chip->dma.area) return; - snd_dma_reserve_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci)); + snd_dma_free_pages(&chip->dma); while ((p = chip->buf_list.next) != &chip->buf_list) { struct esm_memory *chunk = list_entry(p, struct esm_memory, list); list_del(p); @@ -1438,20 +1438,18 @@ snd_es1968_init_dmabuf(struct es1968 *chip) chip->dma.dev.type = SNDRV_DMA_TYPE_DEV; chip->dma.dev.dev = snd_dma_pci_data(chip->pci); - if (! snd_dma_get_reserved_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci))) { - err = snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - chip->total_bufsize, &chip->dma); - if (err < 0 || ! chip->dma.area) { - snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n", - chip->total_bufsize); - return -ENOMEM; - } - if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) { - snd_dma_free_pages(&chip->dma); - snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n"); - return -ENOMEM; - } + err = snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + chip->total_bufsize, &chip->dma); + if (err < 0 || ! chip->dma.area) { + snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n", + chip->total_bufsize); + return -ENOMEM; + } + if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) { + snd_dma_free_pages(&chip->dma); + snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n"); + return -ENOMEM; } INIT_LIST_HEAD(&chip->buf_list); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index f59a321a6d6a..bd90c80bb494 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -584,10 +584,6 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer { dmab->dev.type = SNDRV_DMA_TYPE_DEV; dmab->dev.dev = snd_dma_pci_data(pci); - if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { - if (dmab->bytes >= size) - return 0; - } if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), size, dmab) < 0) return -ENOMEM; @@ -596,10 +592,8 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) { - if (dmab->area) { - dmab->dev.dev = NULL; /* make it anonymous */ - snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); - } + if (dmab->area) + snd_dma_free_pages(dmab); } diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 3717f2dd30be..1503ee3585fd 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -294,10 +294,6 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer { dmab->dev.type = SNDRV_DMA_TYPE_DEV; dmab->dev.dev = snd_dma_pci_data(pci); - if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { - if (dmab->bytes >= size) - return 0; - } if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), size, dmab) < 0) return -ENOMEM; @@ -306,10 +302,8 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) { - if (dmab->area) { - dmab->dev.dev = NULL; /* make it anonymous */ - snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); - } + if (dmab->area) + snd_dma_free_pages(dmab); } -- cgit v1.2.3 From 08e2d592582e6b780bd925efcdb4971bf173f39a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 9 Jan 2014 14:29:24 +0000 Subject: mfd: wm5110: Add registers for headphone short circuit control Add the registers necessary to enable/disable the headphone short circuit protection. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/mfd/wm5110-tables.c | 6 ++++++ include/linux/mfd/arizona/registers.h | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'include') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index abd6713de7b0..4a4432eb499c 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -610,6 +610,9 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */ { 0x00000492, 0x0069 }, /* R1170 - PDM SPK2 CTRL 1 */ { 0x00000493, 0x0000 }, /* R1171 - PDM SPK2 CTRL 2 */ + { 0x000004A0, 0x3480 }, /* R1184 - HP1 Short Circuit Ctrl */ + { 0x000004A1, 0x3480 }, /* R1185 - HP2 Short Circuit Ctrl */ + { 0x000004A2, 0x3480 }, /* R1186 - HP3 Short Circuit Ctrl */ { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ { 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */ { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */ @@ -1639,6 +1642,9 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_PDM_SPK1_CTRL_2: case ARIZONA_PDM_SPK2_CTRL_1: case ARIZONA_PDM_SPK2_CTRL_2: + case ARIZONA_HP1_SHORT_CIRCUIT_CTRL: + case ARIZONA_HP2_SHORT_CIRCUIT_CTRL: + case ARIZONA_HP3_SHORT_CIRCUIT_CTRL: case ARIZONA_AIF1_BCLK_CTRL: case ARIZONA_AIF1_TX_PIN_CTRL: case ARIZONA_AIF1_RX_PIN_CTRL: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 22916c0f1ca4..19883aeb1ac8 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -226,6 +226,9 @@ #define ARIZONA_PDM_SPK1_CTRL_2 0x491 #define ARIZONA_PDM_SPK2_CTRL_1 0x492 #define ARIZONA_PDM_SPK2_CTRL_2 0x493 +#define ARIZONA_HP1_SHORT_CIRCUIT_CTRL 0x4A0 +#define ARIZONA_HP2_SHORT_CIRCUIT_CTRL 0x4A1 +#define ARIZONA_HP3_SHORT_CIRCUIT_CTRL 0x4A2 #define ARIZONA_SPK_CTRL_2 0x4B5 #define ARIZONA_SPK_CTRL_3 0x4B6 #define ARIZONA_DAC_COMP_1 0x4DC @@ -3332,6 +3335,30 @@ #define ARIZONA_SPK2_FMT_SHIFT 0 /* SPK2_FMT */ #define ARIZONA_SPK2_FMT_WIDTH 1 /* SPK2_FMT */ +/* + * R1184 (0x4A0) - HP1 Short Circuit Ctrl + */ +#define ARIZONA_HP1_SC_ENA 0x1000 /* HP1_SC_ENA */ +#define ARIZONA_HP1_SC_ENA_MASK 0x1000 /* HP1_SC_ENA */ +#define ARIZONA_HP1_SC_ENA_SHIFT 12 /* HP1_SC_ENA */ +#define ARIZONA_HP1_SC_ENA_WIDTH 1 /* HP1_SC_ENA */ + +/* + * R1185 (0x4A1) - HP2 Short Circuit Ctrl + */ +#define ARIZONA_HP2_SC_ENA 0x1000 /* HP2_SC_ENA */ +#define ARIZONA_HP2_SC_ENA_MASK 0x1000 /* HP2_SC_ENA */ +#define ARIZONA_HP2_SC_ENA_SHIFT 12 /* HP2_SC_ENA */ +#define ARIZONA_HP2_SC_ENA_WIDTH 1 /* HP2_SC_ENA */ + +/* + * R1186 (0x4A2) - HP3 Short Circuit Ctrl + */ +#define ARIZONA_HP3_SC_ENA 0x1000 /* HP3_SC_ENA */ +#define ARIZONA_HP3_SC_ENA_MASK 0x1000 /* HP3_SC_ENA */ +#define ARIZONA_HP3_SC_ENA_SHIFT 12 /* HP3_SC_ENA */ +#define ARIZONA_HP3_SC_ENA_WIDTH 1 /* HP3_SC_ENA */ + /* * R1244 (0x4DC) - DAC comp 1 */ -- cgit v1.2.3 From e3a9269f874067fcefc5eb8037466161fb0fe3f4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Jan 2014 10:24:43 +0100 Subject: ALSA: Add helper function for intersecting two rate masks A bit of special care is necessary when creating the intersection of two rate masks. This comes from the special meaning of the SNDRV_PCM_RATE_CONTINUOUS and SNDRV_PCM_RATE_KNOT bits, which needs special handling when intersecting two rate masks. SNDRV_PCM_RATE_CONTINUOUS means the hardware supports all rates in a specific interval. SNDRV_PCM_RATE_KNOT means the hardware supports a set of discrete rates specified by a list constraint. For all other cases the supported rates are specified directly in the rate mask. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/pcm.h | 2 ++ sound/core/pcm_misc.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'include') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 84b10f9a2832..d0170913374d 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -901,6 +901,8 @@ extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime); unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate); unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit); +unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a, + unsigned int rates_b); static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream, struct snd_dma_buffer *bufp) diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 43f24cce3dec..4560ca0e5651 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -514,3 +514,42 @@ unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit) return 0; } EXPORT_SYMBOL(snd_pcm_rate_bit_to_rate); + +static unsigned int snd_pcm_rate_mask_sanitize(unsigned int rates) +{ + if (rates & SNDRV_PCM_RATE_CONTINUOUS) + return SNDRV_PCM_RATE_CONTINUOUS; + else if (rates & SNDRV_PCM_RATE_KNOT) + return SNDRV_PCM_RATE_KNOT; + return rates; +} + +/** + * snd_pcm_rate_mask_intersect - computes the intersection between two rate masks + * @rates_a: The first rate mask + * @rates_b: The second rate mask + * + * This function computes the rates that are supported by both rate masks passed + * to the function. It will take care of the special handling of + * SNDRV_PCM_RATE_CONTINUOUS and SNDRV_PCM_RATE_KNOT. + * + * Return: A rate mask containing the rates that are supported by both rates_a + * and rates_b. + */ +unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a, + unsigned int rates_b) +{ + rates_a = snd_pcm_rate_mask_sanitize(rates_a); + rates_b = snd_pcm_rate_mask_sanitize(rates_b); + + if (rates_a & SNDRV_PCM_RATE_CONTINUOUS) + return rates_b; + else if (rates_b & SNDRV_PCM_RATE_CONTINUOUS) + return rates_a; + else if (rates_a & SNDRV_PCM_RATE_KNOT) + return rates_b; + else if (rates_b & SNDRV_PCM_RATE_KNOT) + return rates_a; + return rates_a & rates_b; +} +EXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect); -- cgit v1.2.3 From 507205632dd12636cfe4af4322dace263dca0c21 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Jan 2014 14:02:16 +0100 Subject: dma: Indicate residue granularity in dma_slave_caps This patch adds a new field to the dma_slave_caps struct which indicates the granularity with which the driver is able to update the residue field of the dma_tx_state struct. Making this information available to dmaengine users allows them to make better decisions on how to operate. E.g. for audio certain features like wakeup less operation or timer based scheduling only make sense and work correctly if the reported residue is fine-grained enough. Right now four different levels of granularity are supported: * DESCRIPTOR: The DMA channel is only able to tell whether a descriptor has been completed or not, which means residue reporting is not supported by this channel. The residue field of the dma_tx_state field will always be 0. * SEGMENT: The DMA channel updates the residue field after each successfully completed segment of the transfer (For cyclic transfers this is after each period). This is typically implemented by having the hardware generate an interrupt after each transferred segment and then the drivers updates the outstanding residue by the size of the segment. Another possibility is if the hardware supports SG and the segment descriptor has a field which gets set after the segment has been completed. The driver then counts the number of segments without the flag set to compute the residue. * BURST: The DMA channel updates the residue field after each transferred burst. This is typically only supported if the hardware has a progress register of some sort (E.g. a register with the current read/write address or a register with the amount of bursts/beats/bytes that have been transferred or still need to be transferred). Signed-off-by: Lars-Peter Clausen Acked-by: Vinod Koul Signed-off-by: Mark Brown --- include/linux/dmaengine.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index ed92b30a02fd..ba5f96db0754 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -364,6 +364,32 @@ struct dma_slave_config { unsigned int slave_id; }; +/** + * enum dma_residue_granularity - Granularity of the reported transfer residue + * @DMA_RESIDUE_GRANULARITY_DESCRIPTOR: Residue reporting is not support. The + * DMA channel is only able to tell whether a descriptor has been completed or + * not, which means residue reporting is not supported by this channel. The + * residue field of the dma_tx_state field will always be 0. + * @DMA_RESIDUE_GRANULARITY_SEGMENT: Residue is updated after each successfully + * completed segment of the transfer (For cyclic transfers this is after each + * period). This is typically implemented by having the hardware generate an + * interrupt after each transferred segment and then the drivers updates the + * outstanding residue by the size of the segment. Another possibility is if + * the hardware supports scatter-gather and the segment descriptor has a field + * which gets set after the segment has been completed. The driver then counts + * the number of segments without the flag set to compute the residue. + * @DMA_RESIDUE_GRANULARITY_BURST: Residue is updated after each transferred + * burst. This is typically only supported if the hardware has a progress + * register of some sort (E.g. a register with the current read/write address + * or a register with the amount of bursts/beats/bytes that have been + * transferred or still need to be transferred). + */ +enum dma_residue_granularity { + DMA_RESIDUE_GRANULARITY_DESCRIPTOR = 0, + DMA_RESIDUE_GRANULARITY_SEGMENT = 1, + DMA_RESIDUE_GRANULARITY_BURST = 2, +}; + /* struct dma_slave_caps - expose capabilities of a slave channel only * * @src_addr_widths: bit mask of src addr widths the channel supports @@ -374,6 +400,7 @@ struct dma_slave_config { * should be checked by controller as well * @cmd_pause: true, if pause and thereby resume is supported * @cmd_terminate: true, if terminate cmd is supported + * @residue_granularity: granularity of the reported transfer residue */ struct dma_slave_caps { u32 src_addr_widths; @@ -381,6 +408,7 @@ struct dma_slave_caps { u32 directions; bool cmd_pause; bool cmd_terminate; + enum dma_residue_granularity residue_granularity; }; static inline const char *dma_chan_name(struct dma_chan *chan) -- cgit v1.2.3 From 23607025303af6e84bc2cd4cabe89c21f6a22a3f Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 17 Jan 2014 17:03:55 +0000 Subject: ASoC: DPCM: make some DPCM API calls non static for compressed usage The ASoC compressed code needs to call the internal DPCM APIs in order to dynamically route compressed data to different DAIs. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 22 ++++++++++++++++++++++ sound/soc/soc-pcm.c | 29 ++++++++++++----------------- 2 files changed, 34 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index 047d657c331c..2883a7a6f9f3 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -11,6 +11,7 @@ #ifndef __LINUX_SND_SOC_DPCM_H #define __LINUX_SND_SOC_DPCM_H +#include #include #include @@ -135,4 +136,25 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute); int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd); int soc_dpcm_runtime_update(struct snd_soc_card *); +int dpcm_path_get(struct snd_soc_pcm_runtime *fe, + int stream, struct snd_soc_dapm_widget_list **list_); +int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, + int stream, struct snd_soc_dapm_widget_list **list, int new); +int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream); +int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream); +void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream); +void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream); +int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream); +int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int tream); +int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd); +int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream); +int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, + int event); + +static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list) +{ + kfree(*list); +} + + #endif diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 42782c01e413..64bf3f827aac 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -58,7 +58,7 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); /* DPCM stream event, send event to FE and all active BEs. */ -static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, +int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event) { struct snd_soc_dpcm *dpcm; @@ -773,7 +773,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, } /* disconnect a BE and FE */ -static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) +void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm, *d; @@ -869,7 +869,7 @@ static int widget_in_list(struct snd_soc_dapm_widget_list *list, return 0; } -static int dpcm_path_get(struct snd_soc_pcm_runtime *fe, +int dpcm_path_get(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dapm_widget_list **list_) { struct snd_soc_dai *cpu_dai = fe->cpu_dai; @@ -891,11 +891,6 @@ static int dpcm_path_get(struct snd_soc_pcm_runtime *fe, return paths; } -static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list) -{ - kfree(*list); -} - static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dapm_widget_list **list_) { @@ -965,7 +960,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, continue; /* don't connect if FE is not running */ - if (!fe->dpcm[stream].runtime) + if (!fe->dpcm[stream].runtime && !fe->fe_compr) continue; /* newly connected FE and BE */ @@ -990,7 +985,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, * Find the corresponding BE DAIs that source or sink audio to this * FE substream. */ -static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, +int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dapm_widget_list **list, int new) { if (new) @@ -999,7 +994,7 @@ static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, return dpcm_prune_paths(fe, stream, list); } -static void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) +void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; @@ -1037,7 +1032,7 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, } } -static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) +int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; int err, count = 0; @@ -1186,7 +1181,7 @@ be_err: return ret; } -static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) +int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; @@ -1247,7 +1242,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) return 0; } -static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) +int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; @@ -1312,7 +1307,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) return 0; } -static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) +int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; int ret; @@ -1442,7 +1437,7 @@ static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm, return ret; } -static int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, +int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd) { struct snd_soc_dpcm *dpcm; @@ -1610,7 +1605,7 @@ out: return ret; } -static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) +int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; int ret = 0; -- cgit v1.2.3 From 2a99ef0fdb35a0f8d6b56ccc5d9d821e9ff100c1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 17 Jan 2014 17:03:56 +0000 Subject: ASoC: compress: Add suport for DPCM into compressed audio Currently compressed audio streams are statically routed from the /dev to the DAI link. Some DSPs can route compressed data to multiple BE DAIs like they do for PCM data. Add support to allow dynamically routed compressed streams using the existing DPCM infrastructure. This patch adds special FE versions of the compressed ops that work out the runtime routing. Signed-off-by: Liam Girdwood Acked-by: Vinod Koul Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + sound/soc/soc-compress.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 301 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 1f741cb24f33..c0c67003a7b7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1029,6 +1029,7 @@ struct snd_soc_pcm_runtime { /* Dynamic PCM BE runtime data */ struct snd_soc_dpcm_runtime dpcm[2]; + int fe_compr; long pmdown_time; unsigned char pop_wait:1; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 53c9ecdd119f..5e9690c85d8f 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -24,6 +24,7 @@ #include #include #include +#include static int soc_compr_open(struct snd_compr_stream *cstream) { @@ -75,6 +76,98 @@ out: return ret; } +static int soc_compr_open_fe(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *fe = cstream->private_data; + struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; + struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; + struct snd_soc_dai *codec_dai = fe->codec_dai; + struct snd_soc_dpcm *dpcm; + struct snd_soc_dapm_widget_list *list; + int stream; + int ret = 0; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + stream = SNDRV_PCM_STREAM_PLAYBACK; + else + stream = SNDRV_PCM_STREAM_CAPTURE; + + mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + + if (platform->driver->compr_ops && platform->driver->compr_ops->open) { + ret = platform->driver->compr_ops->open(cstream); + if (ret < 0) { + pr_err("compress asoc: can't open platform %s\n", platform->name); + goto out; + } + } + + if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) { + ret = fe->dai_link->compr_ops->startup(cstream); + if (ret < 0) { + pr_err("compress asoc: %s startup failed\n", fe->dai_link->name); + goto machine_err; + } + } + + fe->dpcm[stream].runtime = fe_substream->runtime; + + if (dpcm_path_get(fe, stream, &list) <= 0) { + dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", + fe->dai_link->name, stream ? "capture" : "playback"); + } + + /* calculate valid and active FE <-> BE dpcms */ + dpcm_process_paths(fe, stream, &list, 1); + + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; + + ret = dpcm_be_dai_startup(fe, stream); + if (ret < 0) { + /* clean up all links */ + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; + + dpcm_be_disconnect(fe, stream); + fe->dpcm[stream].runtime = NULL; + goto fe_err; + } + + dpcm_clear_pending_state(fe, stream); + dpcm_path_put(&list); + + fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) { + cpu_dai->playback_active++; + codec_dai->playback_active++; + } else { + cpu_dai->capture_active++; + codec_dai->capture_active++; + } + + cpu_dai->active++; + codec_dai->active++; + fe->codec->active++; + + mutex_unlock(&fe->card->mutex); + + return 0; + +fe_err: + if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown) + fe->dai_link->compr_ops->shutdown(cstream); +machine_err: + if (platform->driver->compr_ops && platform->driver->compr_ops->free) + platform->driver->compr_ops->free(cstream); +out: + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; + mutex_unlock(&fe->card->mutex); + return ret; +} + /* * Power down the audio subsystem pmdown_time msecs after close is called. * This is to ensure there are no pops or clicks in between any music tracks @@ -164,6 +257,65 @@ static int soc_compr_free(struct snd_compr_stream *cstream) return 0; } +static int soc_compr_free_fe(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *fe = cstream->private_data; + struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; + struct snd_soc_dai *codec_dai = fe->codec_dai; + struct snd_soc_dpcm *dpcm; + int stream, ret; + + mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + + if (cstream->direction == SND_COMPRESS_PLAYBACK) { + stream = SNDRV_PCM_STREAM_PLAYBACK; + cpu_dai->playback_active--; + codec_dai->playback_active--; + } else { + stream = SNDRV_PCM_STREAM_CAPTURE; + cpu_dai->capture_active--; + codec_dai->capture_active--; + } + + cpu_dai->active--; + codec_dai->active--; + fe->codec->active--; + + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; + + ret = dpcm_be_dai_hw_free(fe, stream); + if (ret < 0) + dev_err(fe->dev, "compressed hw_free failed %d\n", ret); + + ret = dpcm_be_dai_shutdown(fe, stream); + + /* mark FE's links ready to prune */ + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); + else + dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); + + fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; + + dpcm_be_disconnect(fe, stream); + + fe->dpcm[stream].runtime = NULL; + + if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown) + fe->dai_link->compr_ops->shutdown(cstream); + + if (platform->driver->compr_ops && platform->driver->compr_ops->free) + platform->driver->compr_ops->free(cstream); + + mutex_unlock(&fe->card->mutex); + return 0; +} + static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) { @@ -194,6 +346,59 @@ out: return ret; } +static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) +{ + struct snd_soc_pcm_runtime *fe = cstream->private_data; + struct snd_soc_platform *platform = fe->platform; + int ret = 0, stream; + + if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || + cmd == SND_COMPR_TRIGGER_DRAIN) { + + if (platform->driver->compr_ops && + platform->driver->compr_ops->trigger) + return platform->driver->compr_ops->trigger(cstream, cmd); + } + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + stream = SNDRV_PCM_STREAM_PLAYBACK; + else + stream = SNDRV_PCM_STREAM_CAPTURE; + + + mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + + if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { + ret = platform->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + goto out; + } + + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; + + ret = dpcm_be_dai_trigger(fe, stream, cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; + break; + } + +out: + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; + mutex_unlock(&fe->card->mutex); + return ret; +} + static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_compr_params *params) { @@ -241,6 +446,64 @@ err: return ret; } +static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct snd_soc_pcm_runtime *fe = cstream->private_data; + struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; + struct snd_soc_platform *platform = fe->platform; + int ret = 0, stream; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) + stream = SNDRV_PCM_STREAM_PLAYBACK; + else + stream = SNDRV_PCM_STREAM_CAPTURE; + + mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + + if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { + ret = platform->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + goto out; + } + + if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { + ret = fe->dai_link->compr_ops->set_params(cstream); + if (ret < 0) + goto out; + } + + /* + * Create an empty hw_params for the BE as the machine driver must + * fix this up to match DSP decoder and ASRC configuration. + * I.e. machine driver fixup for compressed BE is mandatory. + */ + memset(&fe->dpcm[fe_substream->stream].hw_params, 0, + sizeof(struct snd_pcm_hw_params)); + + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; + + ret = dpcm_be_dai_hw_params(fe, stream); + if (ret < 0) + goto out; + + ret = dpcm_be_dai_prepare(fe, stream); + if (ret < 0) + goto out; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); + else + dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); + + fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; + +out: + fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; + mutex_unlock(&fe->card->mutex); + return ret; +} + static int soc_compr_get_params(struct snd_compr_stream *cstream, struct snd_codec *params) { @@ -360,6 +623,7 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, return ret; } + /* ASoC Compress operations */ static struct snd_compr_ops soc_compr_ops = { .open = soc_compr_open, @@ -375,6 +639,21 @@ static struct snd_compr_ops soc_compr_ops = { .get_codec_caps = soc_compr_get_codec_caps }; +/* ASoC Dynamic Compress operations */ +static struct snd_compr_ops soc_compr_dyn_ops = { + .open = soc_compr_open_fe, + .free = soc_compr_free_fe, + .set_params = soc_compr_set_params_fe, + .get_params = soc_compr_get_params, + .set_metadata = soc_compr_set_metadata, + .get_metadata = soc_compr_get_metadata, + .trigger = soc_compr_trigger_fe, + .pointer = soc_compr_pointer, + .ack = soc_compr_ack, + .get_caps = soc_compr_get_caps, + .get_codec_caps = soc_compr_get_codec_caps +}; + /* create a new compress */ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) { @@ -383,6 +662,7 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_compr *compr; + struct snd_pcm *be_pcm; char new_name[64]; int ret = 0, direction = 0; @@ -410,7 +690,26 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) ret = -ENOMEM; goto compr_err; } - memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); + + if (rtd->dai_link->dynamic) { + snprintf(new_name, sizeof(new_name), "(%s)", + rtd->dai_link->stream_name); + + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, + 1, 0, &be_pcm); + if (ret < 0) { + dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n", + rtd->dai_link->name); + goto compr_err; + } + + rtd->pcm = be_pcm; + rtd->fe_compr = 1; + be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; + be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; + memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops)); + } else + memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); /* Add copy callback for not memory mapped DSPs */ if (platform->driver->compr_ops && platform->driver->compr_ops->copy) -- cgit v1.2.3