Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
November 2013
- 132 participants
- 322 discussions
[alsa-devel] [PATCH 1/1] ASoC: arizona: Set FLL to free-run before disabling
by Richard Fitzgerald 20 Nov '13
by Richard Fitzgerald 20 Nov '13
20 Nov '13
Signed-off-by: Richard Fitzgerald <rf(a)opensource.wolfsonmicro.com>
---
sound/soc/codecs/arizona.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 6f05b17..fea9910 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -1529,6 +1529,8 @@ static void arizona_enable_fll(struct arizona_fll *fll,
try_wait_for_completion(&fll->ok);
regmap_update_bits(arizona->regmap, fll->base + 1,
+ ARIZONA_FLL1_FREERUN, 0);
+ regmap_update_bits(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
if (use_sync)
regmap_update_bits(arizona->regmap, fll->base + 0x11,
@@ -1546,6 +1548,8 @@ static void arizona_disable_fll(struct arizona_fll *fll)
struct arizona *arizona = fll->arizona;
bool change;
+ regmap_update_bits(arizona->regmap, fll->base + 1,
+ ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
regmap_update_bits_check(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, 0, &change);
regmap_update_bits(arizona->regmap, fll->base + 0x11,
--
1.7.2.5
2
3
20 Nov '13
Signed-off-by: D.J. Barrow <dbarrow(a)wolfsonmicro.com>
Signed-off-by: Richard Fitzgerald <rf(a)opensource.wolfsonmicro.com>
---
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(-)
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
index 4706d3d..8f4c9d7 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
@@ -3726,6 +3758,35 @@
#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
*/
#define ARIZONA_AIF2RX1_SLOT_MASK 0x003F /* AIF2RX1_SLOT - [5:0] */
@@ -3740,8 +3801,52 @@
#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 fea9910..6188b05 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 9e81b63..1f96672 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 f2d1094..1a73a02 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"),
@@ -1079,14 +1123,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,
},
--
1.7.2.5
2
1
[alsa-devel] [PATCH] ALSA: hda - Disable runtime PM on LynxPoint(-LP) controllers
by Takashi Iwai 20 Nov '13
by Takashi Iwai 20 Nov '13
20 Nov '13
We got bug reports of the stalled HD-audio, typically after S3 or S4,
and it turned out that they seemed triggered by runtime PM on Lynx
Point and Lynx Point-LP controllers. As there is no way to recover
properly from the stalled controller, it's safer to disable the
runtime PM support on these chips for now.
Further notes:
I actually could reproduce this on a few HP laptops here.
Go to S3 after runtime suspend, then the next playback fails,
resulting in either a codec stall or repeated sounds.
The problem seems lying in a deeper level. The complete stall could
be avoided by disabling the call of azx_stop_chip() in
azx_runtime_suspend(). More specifically, it's the disablement of
CORB/RIRB in azx_free_cmd_io(). After removing this call, the sound
is resumed.
However, even with that workaround, the first playback after resume
stalls due to the missing RIRB interrupts (so you get "switch to
polling mode" kernel warning). Interestingly, the codec communication
in the resume procedure does work. The system goes to runtime suspend
immediately after resume, then something gets broken at that point.
This missing interrupt problem happens even if you do nothing in
runtime suspend/resume callback with empty callbacks. This implies
that it's an issue in the underlying layer. So, the only feasible
"fix" in the sound driver side to suppress the runtime PM, so far.
Cc: <stable(a)vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai(a)suse.de>
---
Yet another note: the patch is based on v3.12, not on linux-next, so
that it can be backported cleanly for 3.12 and earlier kernels.
sound/pci/hda/hda_intel.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 6e61a019aa5e..27fc33e54a50 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -3973,7 +3973,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Wellsburg */
{ PCI_DEVICE(0x8086, 0x8d20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -3981,10 +3981,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c21),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
--
1.8.4.3
2
4
20 Nov '13
В Wed, 20 Nov 2013 13:29:18 +0100
Clemens Ladisch <clemens(a)ladisch.de> пишет:
> Roman Volkov wrote:
> > Clemens Ladisch <clemens(a)ladisch.de> пишет:
> >> Roman Volkov wrote:
> >>> + * 128kHz doesn't work for CS4361 (multichannel playback)
> >>
> >> Why do you expect 128 kHz to work?
> >
> > 128kHz will not work because ...
>
> ... the CMI8788 does not support 128 kHz in the first place.
>
> > And perhaps my anti-pop delay of 1 second is too long.
>
> The Windows driver uses 2.5 seconds.
>
> >> Is the reset pin actually connected? Does the Windows driver do
> >> this?
> >
> > Should be, otherwise this is bad design.
>
> This driver is not for a theoretical, optimally designed card; it is
> for the actual card that Asus builds. If the Windows driver does not
> touch the reset pin, we should not do this either (because it might be
> connected to the self-destruct trigger).
>
> > sometimes (rarely) I get completely distorted sound when I power up
> > the Windows machine.
>
> After a cold boot?
>
> This also happened for some other Xonar card when the Linux driver did
> things differently and did not reset these settings when shutting
> down.
>
> >> Use mdelay() only when sleeping is not possible; use msleep()
> >> instead.
> >
> > msleep() is not recommended for small delays (1ms-20ms).
>
> Only because it isn't very accurate. But using mdelay() is even worse
> because it busy-loops.
>
> >>> + case PLAYBACK_DST_20_CH:
> >>> + case PLAYBACK_DST_40_CH:
> >>> + case PLAYBACK_DST_51_CH:
> >>
> >> Why is it necessary to differentiate between those? There should
> >> be no mixer control; the driver can automatically detect what
> >> format is used. And this should not make any difference because
> >> the unused channels will be silent anyway.
> >
> > Just as in the windows driver.
>
> This is not necessarily a reason to implement the same in the Linux
> driver, especially if it's not required by the actual hardware, and
> reduces usability.
>
> > Should I change this to "HP\HP FP\Speakers"?
>
> Yes.
>
> >>> +/* Put the codec into low power mode, disable audio output, save
> >>> registers */
> >>
> >> Does the Windows driver implement this?
> >
> > I don't know. Linux docs says I should put my hardware into low
> > power mode and I do that.
>
> As far as I know, none of the Xonar cards have any real power-saving
> functionality; they rely on the entire PCI slot being powered down.
>
> For practical purposes, suspend/resume just means that you have to
> restore the registers.
>
> >>> - .function_flags = OXYGEN_FUNCTION_SPI,
> >>> + .function_flags = OXYGEN_FUNCTION_SPI |
> >>> OXYGEN_FUNCTION_ENABLE_SPI_4_5,
> >>
> >> Why?
> >
> > Because this just works and as in the Windows driver.
>
> If nothing is connected to those pins, it doesn't matter. This code
> in the Windows driver probably was just copy/pasted from the D2 code.
>
> >>> +++ linux-3.12-my/sound/pci/oxygen/xonar_dg.h
> >>
> >> This file was intended as the interface between xonar_dg.c and the
> >> generic oxygen.c driver.
> >>
> >> That you have to add so much stuff indicates that xonar_dg.c and
> >> xonar_dg_mixer.c are not very independent and maybe should have
> >> stayed a single file.
> >
> > But moving mixer to another file so simplifies things...
>
> Your choice. But it makes it hard to review changes when you move the
> code around in the same patch.
>
>
> Regards,
> Clemens
>
Okay, I won't argue. If the driver will work with the changes, I
don't care. How should I name the subject? Should I mark this with
"RESEND" or "UPDATE" or leave the subject named like "[PATCH 2/2]
snd-oxygen: Fixes for the Xonar DG card"?
--
Kind regards,
Roman Volkov,
v1ron(a)mail.ru
1
0
Hello, alsa maintainer:
Recently, i encounter aplay failed on arm 64 bits core. My test
environment is: Linux kernel use arm 64 bits, and alsa-lib/aplay is 32 bit
version. So the ioctl interface should use snd_pcm_ioctl_compat. but when i
use aplay to playback music, i encounter "aplay" segment fault. Do we need
some special configuration for alsa-lib/aplay to support 64 bit kernel? Any
suggestion will be appreciated. Thanks!
[\u@\h: \W]\#aplay windows.wav
[ 85.237519] 823 (aplay) snd_pcm_playback_open+++
[ 85.247876] 823 (aplay) snd_pcm_aio_write---
[ 85.254708] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.263597] 823 (aplay) ======snd_pcm_ioctl_compat3333
[ 85.271850] 823 (aplay) snd_pcm_playback_ioctl1+++
[ 85.279019] 823 (aplay) snd_pcm_common_ioctl1+++
[ 85.285318] 823 (aplay) snd_pcm_common_ioctl122
[ 85.292253] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.300186] 823 (aplay) ======snd_pcm_ioctl_compat3333
[ 85.307569] 823 (aplay) snd_pcm_playback_ioctl1+++
[ 85.314021] 823 (aplay) snd_pcm_common_ioctl1+++
[ 85.320697] 823 (aplay) snd_pcm_common_ioctl111
[ 85.328240] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.336255] 823 (aplay) ======snd_pcm_ioctl_compat3333
[ 85.343185] 823 (aplay) snd_pcm_playback_ioctl1+++
[ 85.350090] 823 (aplay) snd_pcm_common_ioctl1+++
[ 85.356800] 823 (aplay) snd_pcm_common_ioctl144
[ 85.366441] 823 (aplay) =====snd_pcm_mmap+++
[ 85.372840] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.380709] 823 (aplay) ======snd_pcm_ioctl_compat9999
[ 85.388074] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat++
[ 85.395184] 823 (aplay) state:0x0
[ 85.400355] 823 (aplay) hw_ptr:0x0
[ 85.405080] 823 (aplay) tstamp:0x0
[ 85.410326] 823 (aplay) suspend_stat:0x0
[ 85.416216] 823 (aplay) tstamp:0x0
[ 85.421039] 823 (aplay) appl_ptr:0x0
[ 85.426489] 823 (aplay) avail_min:0x1
[ 85.431579] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat--
[ 85.443771] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.451883] 823 (aplay) ======snd_pcm_ioctl_compat3333
[ 85.459321] 823 (aplay) snd_pcm_playback_ioctl1+++
[ 85.466280] 823 (aplay) snd_pcm_common_ioctl1+++
[ 85.472539] 823 (aplay) snd_pcm_common_ioctl122
Playing WAVE 'windows.wav' : Signed 16 bit Little Endian, Rate 22050 Hz,
Stereo
[ 85.500612] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.508756] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.519975] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.528101] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.536112] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.543496] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.552271] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.560207] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.594120] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.602221] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.639453] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.647597] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.656416] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.663826] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.693293] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.701231] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.730988] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.739043] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.748850] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.756855] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.765543] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.772949] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.802272] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.810266] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.839909] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.847899] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.857606] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.865619] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.873814] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.881784] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.891149] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.899062] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.911247] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.919318] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.928068] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.935994] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.945446] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.952828] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.962969] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.971003] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.980633] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 85.988651] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 85.997912] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.005880] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.019755] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.027851] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.037648] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.045668] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.055326] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.062700] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.071957] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.079852] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.093442] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.101428] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.110880] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.118767] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.128022] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.136031] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.145312] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.152642] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.166234] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.174252] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.185470] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.192864] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.202191] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.210222] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.219452] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.227353] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.241140] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.249167] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.258633] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.266583] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.275809] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.283209] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.292507] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.300462] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.312362] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.320295] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.329874] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.337825] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.347005] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.354979] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.364272] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.371671] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.386035] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.394010] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.404122] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.411491] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.420685] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.428587] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.437805] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.445723] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.458333] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.466412] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.476696] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.484743] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.494008] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.501393] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.510721] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.518682] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.528949] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.536991] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.546180] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.554122] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.563543] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.570903] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.583664] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.591141] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.600602] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.608548] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.617702] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.625703] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.634924] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.642317] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.653731] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.661075] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.670427] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.678383] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.687594] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.695585] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.709565] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.717652] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.734313] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.741774] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.755420] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.763633] 823 (aplay) ======snd_pcm_ioctl_compat5555
[ 86.773070] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.780448] 823 (aplay) ======snd_pcm_ioctl_compat66666
[ 86.789495] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.797508] 823 (aplay) ======snd_pcm_ioctl_compat9999
[ 86.804939] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat++
[ 86.812086] 823 (aplay) state:0x1
[ 86.817225] 823 (aplay) hw_ptr:0x0
[ 86.821974] 823 (aplay) tstamp:0x0
[ 86.827171] 823 (aplay) suspend_stat:0x0
[ 86.833049] 823 (aplay) tstamp:0x0
[ 86.837795] 823 (aplay) appl_ptr:0x0
[ 86.843255] 823 (aplay) avail_min:0x1
[ 86.848303] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat--
[ 86.857505] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.865637] 823 (aplay) ======snd_pcm_ioctl_compat77777
[ 86.874082] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.881454] 823 (aplay) ======snd_pcm_ioctl_compat1010
[ 86.889143] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.896981] 823 (aplay) ======snd_pcm_ioctl_compat1010
[ 86.904723] 823 (aplay) =====snd_pcm_mmap+++
[ 86.910536] 823 (aplay) =====snd_pcm_mmap33
[ 86.919994] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.928068] 823 (aplay) ======snd_pcm_ioctl_compat77777
[ 86.937550] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 86.945512] 823 (aplay) ======snd_pcm_ioctl_compat9999
[ 86.952892] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat++
[ 86.959975] 823 (aplay) state:0x1
[ 86.965065] 823 (aplay) hw_ptr:0x0
[ 86.969876] 823 (aplay) tstamp:0x0
[ 86.975111] 823 (aplay) suspend_stat:0x0
[ 86.980497] 823 (aplay) tstamp:0x0
[ 86.985722] 823 (aplay) appl_ptr:0x0
[ 86.990719] 823 (aplay) avail_min:0x300
[ 86.996397] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat--
[ 87.004605] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 87.012676] 823 (aplay) ======snd_pcm_ioctl_compat3333
[ 87.019501] 823 (aplay) snd_pcm_playback_ioctl1+++
[ 87.026451] 823 (aplay) snd_pcm_common_ioctl1+++
[ 87.033169] 823 (aplay) snd_pcm_common_ioctl11111
[ 87.048203] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 87.056227] 823 (aplay) ======snd_pcm_ioctl_compat9999
[ 87.063579] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat++
[ 87.070579] 823 (aplay) state:0x2
[ 87.075679] 823 (aplay) hw_ptr:0x0
[ 87.080477] 823 (aplay) tstamp:0x0
[ 87.085657] 823 (aplay) suspend_stat:0x0
[ 87.091028] 823 (aplay) tstamp:0x0
[ 87.096229] 823 (aplay) appl_ptr:0x0
[ 87.101165] 823 (aplay) avail_min:0x300
[ 87.106813] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat--
[ 87.116559] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 87.124489] 823 (aplay) ======snd_pcm_ioctl_compat77777
[ 87.134835] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 87.142950] 823 (aplay) ======snd_pcm_ioctl_compat9999
[ 87.149868] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat++
[ 87.157350] 823 (aplay) state:0x2
[ 87.162475] 823 (aplay) hw_ptr:0x0
[ 87.167254] 823 (aplay) tstamp:0x0
[ 87.172485] 823 (aplay) suspend_stat:0x0
[ 87.177886] 823 (aplay) tstamp:0x0
[ 87.183131] 823 (aplay) appl_ptr:0x0
[ 87.188110] 823 (aplay) avail_min:0x300
[ 87.193880] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat--
[ 87.202114] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 87.209559] 823 (aplay) ======snd_pcm_ioctl_compat9999
[ 87.217028] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat++
[ 87.224520] 823 (aplay) state:0x2
[ 87.229146] 823 (aplay) hw_ptr:0x0
[ 87.234352] 823 (aplay) tstamp:0x0
[ 87.239101] 823 (aplay) suspend_stat:0x0
[ 87.244924] 823 (aplay) tstamp:0x0
[ 87.249708] 823 (aplay) appl_ptr:0x0
[ 87.255147] 823 (aplay) avail_min:0x300
[ 87.260432] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat--
[ 87.268036] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 87.275875] 823 (aplay) ======snd_pcm_ioctl_compat9999
[ 87.283164] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat++
[ 87.290225] 823 (aplay) state:0x2
[ 87.295283] 823 (aplay) hw_ptr:0x0
[ 87.300041] 823 (aplay) tstamp:0x0
[ 87.305174] 823 (aplay) suspend_stat:0x0
[ 87.310583] 823 (aplay) tstamp:0x0
[ 87.315771] 823 (aplay) appl_ptr:0x0
[ 87.320771] 823 (aplay) avail_min:0x300
[ 87.326468] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat--
[ 87.335868] 823 (aplay) ======snd_pcm_ioctl_compat++++++++
[ 87.343945] 823 (aplay) ======snd_pcm_ioctl_compat9999
[ 87.350825] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat++
[ 87.358387] 823 (aplay) state:0x2
[ 87.363532] 823 (aplay) hw_ptr:0x0
[ 87.368252] 823 (aplay) tstamp:0x0
[ 87.373510] 823 (aplay) suspend_stat:0x0
[ 87.378904] 823 (aplay) tstamp:0x0
[ 87.384100] 823 (aplay) appl_ptr:0x0
[ 87.389050] 823 (aplay) avail_min:0x300
[ 87.394764] 823 (aplay) snd_pcm_ioctl_sync_ptr_compat--
[ 87.403146] 823 (aplay) Bad mode in Error handler detected, code
0xbf000000
[ 87.412595] 823 (aplay) CPU: 0 PID: 823 Comm: aplay Not tainted 3.10.0+
#35
[ 87.421956] 823 (aplay) task: ffffffc019add7c0 ti: ffffffc019a50000
task.ti: ffffffc019a50000
[ 87.433106] 823 (aplay) PC is at 0xf72fd970
[ 87.438849] 823 (aplay) LR is at 0x0
[ 87.443931] 823 (aplay) pc : [<00000000f72fd970>] lr :
[<0000000000000000>] pstate: 80000010
[ 87.454906] 823 (aplay) sp : ffffffc019a51ff0
[ 87.460837] x29: 0000000000000000 x28: 0000000000000000
[ 87.468175] x27: 0000000000000000 x26: 0000000000000000
[ 87.475415] x25: 0000000000000000 x24: 0000000000000000
[ 87.482645] x23: 0000000000000000 x22: 0000000000000000
[ 87.489961] x21: 0000000000000000 x20: 0000000000000000
[ 87.497217] x19: 0000000000000000 x18: 0000000000000000
[ 87.504365] x17: 0000000000000000 x16: 0000000000000000
[ 87.511611] x15: 0000000000000000 x14: 00000000f72fd9ec
[ 87.518832] x13: 00000000ffa0ee98 x12: 00000000ffa0ee98
[ 87.526061] x11: 00000000ffa0eeec x10: 000000000001e32c
[ 87.533332] x9 : 000000000001e31c x8 : 00000000ffa0f168
[ 87.540473] x7 : 00000000ffa0f168 x6 : 00000000ffa0f180
[ 87.547681] x5 : 00000000f738f000 x4 : 000000000000000f
[ 87.554817] x3 : 0000000000000300 x2 : 0000000000000001
[ 87.561998] x1 : 0000000000000000 x0 : 0000000000000000
[ 87.569196] 823 (aplay)
[ 87.573201] 823 (aplay) Bad mode in Synchronous Abort handler detected,
code 0x86000007
[ 87.583794] 823 (aplay) CPU: 0 PID: 823 Comm: aplay Not tainted 3.10.0+
#35
[ 87.593059] 823 (aplay) task: ffffffc019add7c0 ti: ffffffc019a50000
task.ti: ffffffc019a50000
[ 87.603993] 823 (aplay) PC is at 0x0
[ 87.608968] 823 (aplay) LR is at 0x0
[ 87.614003] 823 (aplay) pc : [<0000000000000000>] lr :
[<0000000000000000>] pstate: 800003c5
[ 87.624868] 823 (aplay) sp : ffffffc019a51ed0
[ 87.630832] x29: 0000000000000000 x28: 0000000000000000
[ 87.638120] x27: 0000000000000000 x26: 0000000000000000
[ 87.645395] x25: 0000000000000000 x24: 0000000000000000
[ 87.652731] x23: 0000000080000010 x22: 00000000f72fd970
[ 87.659999] x21: ffffffc019a51ff0 x20: 0000000000000000
[ 87.667198] x19: 0000000000000000 x18: 0000000000000000
[ 87.674377] x17: 0000000000000000 x16: 0000000000000000
[ 87.681570] x15: 0000000000000002 x14: 0000000000000082
[ 87.688706] x13: 0000000000000000 x12: 0000000000001db0
[ 87.695986] x11: ffffffc0012376f8 x10: 0000000000000050
[ 87.703184] x9 : ffffffc019a51c60 x8 : ffffffc000590228
[ 87.710415] x7 : 0000000000000003 x6 : 000000000000027d
[ 87.717643] x5 : ffffffc000081380 x4 : 0000000000000000
[ 87.724914] x3 : 0000000000000001 x2 : 0000000000000001
[ 87.732107] x1 : ffffffc019a51de0 x0 : 0000000000000000
[ 87.739282] 823 (aplay)
[ 87.743126] 823 (aplay) Internal error: Oops - bad mode: 0 [#1] PREEMPT
[ 87.752089] 823 (aplay) CPU: 0 PID: 823 Comm: aplay Not tainted 3.10.0+
#35
[ 87.761348] 823 (aplay) task: ffffffc019add7c0 ti: ffffffc019a50000
task.ti: ffffffc019a50000
[ 87.772375] 823 (aplay) PC is at 0x0
[ 87.777318] 823 (aplay) LR is at 0x0
[ 87.782386] 823 (aplay) pc : [<0000000000000000>] lr :
[<0000000000000000>] pstate: 800003c5
[ 87.793320] 823 (aplay) sp : ffffffc019a51ed0
[ 87.799289] x29: 0000000000000000 x28: 0000000000000000
[ 87.806491] x27: 0000000000000000 x26: 0000000000000000
[ 87.813665] x25: 0000000000000000 x24: 0000000000000000
[ 87.820915] x23: 0000000080000010 x22: 00000000f72fd970
[ 87.828152] x21: ffffffc019a51ff0 x20: 0000000000000000
[ 87.835382] x19: 0000000000000000 x18: 0000000000000000
[ 87.842585] x17: 0000000000000000 x16: 0000000000000000
[ 87.849845] x15: 0000000000000002 x14: 0000000000000082
[ 87.857020] x13: 0000000000000000 x12: 0000000000001db0
[ 87.864266] x11: ffffffc0012376f8 x10: 0000000000000050
[ 87.871505] x9 : ffffffc019a51c60 x8 : ffffffc000590228
[ 87.878720] x7 : 0000000000000003 x6 : 000000000000027d
[ 87.885914] x5 : ffffffc000081380 x4 : 0000000000000000
[ 87.893121] x3 : 0000000000000001 x2 : 0000000000000001
[ 87.900321] x1 : ffffffc019a51de0 x0 : 0000000000000000
[ 87.907443] 823 (aplay)
[ 87.911323] 823 (aplay) Process aplay (pid: 823, stack limit =
0xffffffc019a50058)
[ 87.921331] 823 (aplay) Stack: (0xffffffc019a51ed0 to 0xffffffc019a52000)
[ 87.930547] 823 (aplay) 1ec0: 00000000
00000000 00000000 00000000
[ 87.942875] 823 (aplay) 1ee0: 00000001 00000000 00000300 00000000
0000000f 00000000 f738f000 00000000
[ 87.955305] 823 (aplay) 1f00: ffa0f180 00000000 ffa0f168 00000000
ffa0f168 00000000 0001e31c 00000000
[ 87.967718] 823 (aplay) 1f20: 0001e32c 00000000 ffa0eeec 00000000
ffa0ee98 00000000 ffa0ee98 00000000
[ 87.979993] 823 (aplay) 1f40: f72fd9ec 00000000 00000000 00000000
00000000 00000000 00000000 00000000
[ 87.992343] 823 (aplay) 1f60: 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
[ 88.004660] 823 (aplay) 1f80: 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
[ 88.016989] 823 (aplay) 1fa0: 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
[ 88.029331] 823 (aplay) 1fc0: 00000000 00000000 19a51ff0 ffffffc0
f72fd970 00000000 80000010 00000000
[ 88.041739] 823 (aplay) 1fe0: 00000004 00000000 ffffffff ffffffff
00400080 a201ca14 00400020 200130de
[ 88.053478] 823 (aplay) Call trace:
[ 88.058456] 823 (aplay) Code: bad PC value
[ 88.065099] 823 (aplay) ---[ end trace c58f84f42ebfb68b ]---
[ 88.091636] 823 (aplay) snd_pcm_release++
[ 88.098134] 823 (aplay) snd_pcm_release--
Segmentation fault
[\u@\h: \W]\#
BR
cosmo
2
1
20 Nov '13
You're looking at a casual headset patch,
for a specific hardware it will match,
and suddenly, the headset jack will work,
so please apply this simple quirk!
BugLink: https://bugs.launchpad.net/bugs/1253038
Signed-off-by: David Henningsson <david.henningsson(a)canonical.com>
---
sound/pci/hda/patch_realtek.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 8593d4e..a90bfab 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4915,6 +4915,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP),
--
1.7.9.5
2
1
I found some problems on Maya44+ USB support in linux.
Using ubuntu 13.04 , Ubuntu 13.10 with alsa driver alsa-driver-1.0.25+dfsg
i found that this card isn't supported.
Only 2 of 4 channels work and they are mixed .
This card mounts TI TUSB3200AC chip.
This chip is also used in Re Loop devices and in Herlcues DJ Console.
To fix this problem i found on google a patch for Reloop device. I chanaged
VID and PID for MAYA44+ and now it works .
This patch involves in edititing ./sound/usb/quirks-table.h according to
attached patch
Also i provide an .asoundrc. With this .asoundrc you are able to use each
input and output channel
maya44+ patch
--- a/sound/usb/quirks-table.h 2013-11-12 12:43:24.380251603 +0100
+++ b/sound/usb/quirks-table.h 2013-11-06 12:28:20.000000000 +0100
@@ -320,6 +320,93 @@
#undef YAMAHA_DEVICE
#undef YAMAHA_INTERFACE
+
+/* Reloop Play */
+{
+ USB_DEVICE(0x200c, 0x100b),
+ .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = &(const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_STANDARD_MIXER,
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x01,
+ .ep_attr = USB_ENDPOINT_SYNC_ADAPTIVE,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .rate_min = 44100,
+ .rate_max = 48000,
+ .nr_rates = 2,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000
+ }
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+
+/* Maya44 USB+ Play */
+{
+ USB_DEVICE(0x2573, 0x0008),
+ .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = &(const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_STANDARD_MIXER,
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x01,
+ .ep_attr = USB_ENDPOINT_SYNC_ADAPTIVE,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .rate_min = 44100,
+ .rate_max = 48000,
+ .nr_rates = 2,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000
+ }
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+
+
+
+
+
/*
* Roland/RolandED/Edirol/BOSS devices
*/
.asoundrc example:
pcm.dshare {
type dmix
ipc_key 2048
slave {
pcm "hw:1"
rate 44100
period_time 0
period_size 1024
buffer_size 8192
channels 4
}
bindings {
0 0
1 1
2 2
3 3
}
}
pcm.dsnooped {
type dsnoop
ipc_key 2048
slave {
pcm "hw:1"
rate 48000
periods 0
period_time 0
period_size 1024
buffer_size 4096
channels 4
}
}
pcm.mayaAin1 {
type plug
slave {
pcm "dsnooped"
channels 4
}
ttable.0.0 1
}
pcm.mayaAin2 {
type plug
slave {
pcm "dsnooped"
channels 4
}
ttable.0.1 1
}
pcm.mayaAin3 {
type plug
slave {
pcm "dsnooped"
channels 4
}
ttable.0.2 1
}
pcm.mayaAin4 {
type plug
slave {
pcm "dsnooped"
channels 4
}
ttable.0.3 1
}
pcm.mayaAout1 {
type plug
slave {
pcm "dshare"
channels 4
}
ttable.0.0 1
}
pcm.mayaAout2 {
type plug
slave {
pcm "dshare"
channels 4
}
ttable.0.1 1
}
pcm.mayaAout3 {
type plug
slave {
pcm "dshare"
channels 4
}
ttable.0.2 1
}
pcm.mayaAout4 {
type plug
slave {
pcm "dshare"
channels 4
}
ttable.0.3 1
}
2
4
20 Nov '13
Fixes for the Xonar DG model of the Oxygen driver:
CS4245 CODEC now fully supported with the headphone amplifier.
Both front panel and rear jacks work.
Full support of capturing: from the microphone, line in, and aux input.
Multichannel playback routing corrected for 2.0/4.0/5.1 speakers
New mixer controls, hardware volume control supported for headphones only.
Signed-off-by: Roman I Volkov <v1ron(a)mail.ru>
---
Depends on: [PATCH 1/2] snd-oxygen: Changes for oxygen driver to fix the Xonar DG card
diff -uprN linux-3.12/sound/pci/oxygen/Makefile linux-3.12-my/sound/pci/oxygen/Makefile
--- linux-3.12/sound/pci/oxygen/Makefile 2013-11-04 03:41:51.000000000 +0400
+++ linux-3.12-my/sound/pci/oxygen/Makefile 2013-11-15 16:55:55.000000000 +0400
@@ -1,5 +1,5 @@
snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
-snd-oxygen-objs := oxygen.o xonar_dg.o
+snd-oxygen-objs := oxygen.o xonar_dg.o xonar_dg_mixer.o
snd-virtuoso-objs := virtuoso.o xonar_lib.o \
xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
diff -uprN linux-3.12/sound/pci/oxygen/xonar_dg.c linux-3.12-my/sound/pci/oxygen/xonar_dg.c
--- linux-3.12/sound/pci/oxygen/xonar_dg.c 2013-11-04 03:41:51.000000000 +0400
+++ linux-3.12-my/sound/pci/oxygen/xonar_dg.c 2013-11-19 01:01:07.000000000 +0400
@@ -2,7 +2,7 @@
* card driver for the Xonar DG/DGX
*
* Copyright (c) Clemens Ladisch <clemens(a)ladisch.de>
- *
+ * Copyright (c) Roman Volkov <v1ron(a)mail.ru>
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.
@@ -17,32 +17,48 @@
*/
/*
- * Xonar DG/DGX
+ * TODOs:
+ * DGX card: not tested.
+ * Suspend/resume: not tested
+ * SPDIF: not tested
+ * 128kHz doesn't work for CS4361 (multichannel playback)
+ *
* ------------
*
+ * Pecularities:
+ * CS4245/CS4361 both will mute outputs if MCLK\BCLK\LRCK rates are invalid.
+ * CS4245 mutes DAC even if ADC clocks are invalid.
+ * CS4245 Auxiliary Output is connected to the front panel headphones jack
+ * through amplifier.
+ *
* CMI8788:
*
* SPI 0 -> CS4245
*
+ * Playback:
* I²S 1 -> CS4245
* I²S 2 -> CS4361 (center/LFE)
* I²S 3 -> CS4361 (surround)
* I²S 4 -> CS4361 (front)
+ * Capture:
+ * I²S ADC 1 <- CS4245
*
- * GPIO 3 <- ?
+ * GPIO 3 <- unused (?)
* GPIO 4 <- headphone detect
- * GPIO 5 -> route input jack to line-in (0) or mic-in (1)
- * GPIO 6 -> route input jack to line-in (0) or mic-in (1)
- * GPIO 7 -> enable rear headphone amp
- * GPIO 8 -> enable output to speakers
+ * GPIO 5 -> ADC analog circuit power supply control for left channel (?)
+ * GPIO 6 -> ADC analog circuit power supply control for right channel (?)
+ * GPIO 7 -> switches green rear output jack between CS4245 / CS4361 first
+ * channel
+ * GPIO 8 -> DAC analog circuit power supply control (?)
*
* CS4245:
*
- * input 1 <- aux
- * input 2 <- front mic
- * input 4 <- line/mic
+ * input 0 <- Microphone
+ * input 1 <- Aux
+ * input 2 <- Front Panel Mic
+ * input 4 <- Line In
* DAC out -> headphones
- * aux out -> front panel headphones
+ * AUX out -> front panel headphones
*/
#include <linux/pci.h>
@@ -56,536 +72,263 @@
#include "xonar_dg.h"
#include "cs4245.h"
-#define GPIO_MAGIC 0x0008
-#define GPIO_HP_DETECT 0x0010
-#define GPIO_INPUT_ROUTE 0x0060
-#define GPIO_HP_REAR 0x0080
-#define GPIO_OUTPUT_ENABLE 0x0100
-
-struct dg {
- unsigned int output_sel;
- s8 input_vol[4][2];
- unsigned int input_sel;
- u8 hp_vol_att;
- u8 cs4245_regs[0x11];
-};
-
-static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
+int cs4245_write_spi(struct oxygen *chip, u8 reg)
{
struct dg *data = chip->model_data;
- oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
- OXYGEN_SPI_DATA_LENGTH_3 |
- OXYGEN_SPI_CLOCK_1280 |
- (0 << OXYGEN_SPI_CODEC_SHIFT) |
- OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
- CS4245_SPI_ADDRESS |
- CS4245_SPI_WRITE |
- (reg << 8) | value);
- data->cs4245_regs[reg] = value;
+ return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_3 | OXYGEN_SPI_CLOCK_1280 |
+ (0 << OXYGEN_SPI_CODEC_SHIFT) | OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+ (((u32)CS4245_SPI_ADDRESS) << 16) | (((u32)reg) << 8) |
+ ((u32)data->cs4245_shadow[reg]));
}
-static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
+int cs4245_read_spi(struct oxygen *chip, u8 reg)
{
struct dg *data = chip->model_data;
+ int ret;
- if (value != data->cs4245_regs[reg])
- cs4245_write(chip, reg, value);
-}
-
-static void cs4245_registers_init(struct oxygen *chip)
-{
- struct dg *data = chip->model_data;
+ ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_2 |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
+ OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
+ (CS4245_SPI_ADDRESS << 8) | reg);
+ if (ret < 0)
+ return ret;
- cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN);
- cs4245_write(chip, CS4245_DAC_CTRL_1,
- data->cs4245_regs[CS4245_DAC_CTRL_1]);
- cs4245_write(chip, CS4245_ADC_CTRL,
- data->cs4245_regs[CS4245_ADC_CTRL]);
- cs4245_write(chip, CS4245_SIGNAL_SEL,
- data->cs4245_regs[CS4245_SIGNAL_SEL]);
- cs4245_write(chip, CS4245_PGA_B_CTRL,
- data->cs4245_regs[CS4245_PGA_B_CTRL]);
- cs4245_write(chip, CS4245_PGA_A_CTRL,
- data->cs4245_regs[CS4245_PGA_A_CTRL]);
- cs4245_write(chip, CS4245_ANALOG_IN,
- data->cs4245_regs[CS4245_ANALOG_IN]);
- cs4245_write(chip, CS4245_DAC_A_CTRL,
- data->cs4245_regs[CS4245_DAC_A_CTRL]);
- cs4245_write(chip, CS4245_DAC_B_CTRL,
- data->cs4245_regs[CS4245_DAC_B_CTRL]);
- cs4245_write(chip, CS4245_DAC_CTRL_2,
- CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC);
- cs4245_write(chip, CS4245_INT_MASK, 0);
- cs4245_write(chip, CS4245_POWER_CTRL, 0);
-}
+ ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_2 |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
+ OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
+ (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8);
+ if (ret < 0)
+ return ret;
+ ret = oxygen_wait_spi(chip);
+ if (ret < 0)
+ return ret;
-static void cs4245_init(struct oxygen *chip)
-{
- struct dg *data = chip->model_data;
+ data->cs4245_shadow[reg] = oxygen_read8(chip, OXYGEN_SPI_DATA1);
- data->cs4245_regs[CS4245_DAC_CTRL_1] =
- CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
- data->cs4245_regs[CS4245_ADC_CTRL] =
- CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
- data->cs4245_regs[CS4245_SIGNAL_SEL] =
- CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
- data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
- data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
- data->cs4245_regs[CS4245_ANALOG_IN] =
- CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4;
- data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
- data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
- cs4245_registers_init(chip);
- snd_component_add(chip->card, "CS4245");
+ return 0;
}
-static void dg_output_enable(struct oxygen *chip)
+static int cs4245_dump_regs(struct oxygen *chip, bool bRead)
{
- msleep(2500);
- oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+ u8 address;
+
+ for (address = 0; address <= 0x10; address++) {
+ return bRead ? cs4245_read_spi(chip, address) :
+ cs4245_write_spi(chip, address);
+ }
+ return 0;
}
-static void dg_init(struct oxygen *chip)
+static void cs4245_init(struct oxygen *chip)
{
struct dg *data = chip->model_data;
- data->output_sel = 0;
- data->input_sel = 3;
- data->hp_vol_att = 2 * 16;
-
- cs4245_init(chip);
+ /* save the initial state */
+ cs4245_dump_regs(chip, true);
- oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_MAGIC | GPIO_HP_DETECT);
- oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE);
- oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
- GPIO_INPUT_ROUTE | GPIO_HP_REAR);
- dg_output_enable(chip);
-}
+ /*
+ * Power up the CODEC internals, enable soft ramp & zero cross, work
+ * in async. mode,
+ * Enable aux output from DAC. DAC output in the Windows driver is
+ * inverted.
+ */
+ data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] = CS4245_A_OUT_SEL_DAC |
+ CS4245_ASYNCH;
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] = 0;
+ data->cs4245_shadow[CS4245_DAC_CTRL_2] = CS4245_DAC_SOFT |
+ CS4245_DAC_ZERO | CS4245_INVERT_DAC;
+ data->cs4245_shadow[CS4245_ADC_CTRL] = 0;
+ data->cs4245_shadow[CS4245_ANALOG_IN] = CS4245_PGA_SOFT |
+ CS4245_PGA_ZERO;
+ data->cs4245_shadow[CS4245_MCLK_FREQ] = (CS4245_MCLK_1 <<
+ CS4245_MCLK1_SHIFT) | (CS4245_MCLK_1 << CS4245_MCLK2_SHIFT);
+
+ cs4245_write_spi(chip, CS4245_SIGNAL_SEL);
+ cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
+ cs4245_write_spi(chip, CS4245_DAC_CTRL_2);
+ cs4245_write_spi(chip, CS4245_ADC_CTRL);
+ cs4245_write_spi(chip, CS4245_ANALOG_IN);
+ cs4245_write_spi(chip, CS4245_MCLK_FREQ);
+ cs4245_write_spi(chip, CS4245_POWER_CTRL);
-static void dg_cleanup(struct oxygen *chip)
-{
- oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+ snd_component_add(chip->card, "CS4245");
}
-static void dg_suspend(struct oxygen *chip)
+static void dg_init(struct oxygen *chip)
{
- dg_cleanup(chip);
-}
+ /*
+ * Recommended sequence from the datasheet: reset the codec and then
+ * initialize it.
+ * The pin XGPIO1 as XGPIO1, gpios 8,7,6,5,1,0 as outputs.
+ */
+ oxygen_write8_masked(chip, OXYGEN_FUNCTION, 0,
+ OXYGEN_FUNCTION_RESET_CODEC);
+ mdelay(1);
+ oxygen_write8_masked(chip, OXYGEN_FUNCTION, 0xff,
+ OXYGEN_FUNCTION_RESET_CODEC);
+ mdelay(1);
-static void dg_resume(struct oxygen *chip)
-{
- cs4245_registers_init(chip);
- dg_output_enable(chip);
+ cs4245_init(chip);
+ oxygen_write16(chip, OXYGEN_GPIO_CONTROL, GPIO_OUTPUT_ENABLE |
+ GPIO_HP_REAR | GPIO_INPUT_ROUTE);
+ oxygen_write16(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR | GPIO_INPUT_ROUTE);
+ /* Anti-pop delay */
+ msleep_interruptible(1000);
+ oxygen_write16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE |
+ GPIO_HP_REAR | GPIO_INPUT_ROUTE);
}
static void set_cs4245_dac_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
struct dg *data = chip->model_data;
- u8 value;
+ unsigned char tmp;
+ unsigned char tmp2;
- value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
- if (params_rate(params) <= 50000)
- value |= CS4245_DAC_FM_SINGLE;
- else if (params_rate(params) <= 100000)
- value |= CS4245_DAC_FM_DOUBLE;
- else
- value |= CS4245_DAC_FM_QUAD;
- cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value);
+ tmp = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
+ tmp2 = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK;
+ if (params_rate(params) <= 50000) {
+ tmp |= CS4245_DAC_FM_SINGLE;
+ tmp2 |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
+ } else if (params_rate(params) <= 100000) {
+ tmp |= CS4245_DAC_FM_DOUBLE;
+ tmp2 |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
+ } else {
+ tmp |= CS4245_DAC_FM_QUAD;
+ tmp2 |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT;
+ }
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] = tmp;
+ data->cs4245_shadow[CS4245_MCLK_FREQ] = tmp2;
+ cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
+ cs4245_write_spi(chip, CS4245_MCLK_FREQ);
}
static void set_cs4245_adc_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
struct dg *data = chip->model_data;
- u8 value;
+ unsigned char tmp;
+ unsigned char tmp2;
- value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
- if (params_rate(params) <= 50000)
- value |= CS4245_ADC_FM_SINGLE;
- else if (params_rate(params) <= 100000)
- value |= CS4245_ADC_FM_DOUBLE;
- else
- value |= CS4245_ADC_FM_QUAD;
- cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
-}
-
-static inline unsigned int shift_bits(unsigned int value,
- unsigned int shift_from,
- unsigned int shift_to,
- unsigned int mask)
-{
- if (shift_from < shift_to)
- return (value << (shift_to - shift_from)) & mask;
- else
- return (value >> (shift_from - shift_to)) & mask;
+ tmp = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
+ tmp2 = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK;
+ if (params_rate(params) <= 50000) {
+ tmp |= CS4245_ADC_FM_SINGLE;
+ tmp2 |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
+ } else if (params_rate(params) <= 100000) {
+ tmp |= CS4245_ADC_FM_DOUBLE;
+ tmp2 |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
+ } else {
+ tmp |= CS4245_ADC_FM_QUAD;
+ tmp2 |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT;
+ }
+ data->cs4245_shadow[CS4245_ADC_CTRL] = tmp;
+ data->cs4245_shadow[CS4245_MCLK_FREQ] = tmp2;
+ cs4245_write_spi(chip, CS4245_ADC_CTRL);
+ cs4245_write_spi(chip, CS4245_MCLK_FREQ);
}
static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
unsigned int play_routing)
{
- return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
- shift_bits(play_routing,
- OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC1_SOURCE_MASK) |
- shift_bits(play_routing,
- OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC2_SOURCE_MASK) |
- shift_bits(play_routing,
- OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC3_SOURCE_MASK);
-}
-
-static int output_switch_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[3] = {
- "Speakers", "Headphones", "FP Headphones"
- };
-
- return snd_ctl_enum_info(info, 1, 3, names);
-}
-
-static int output_switch_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- mutex_lock(&chip->mutex);
- value->value.enumerated.item[0] = data->output_sel;
- mutex_unlock(&chip->mutex);
- return 0;
-}
-
-static int output_switch_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- u8 reg;
- int changed;
-
- if (value->value.enumerated.item[0] > 2)
- return -EINVAL;
-
- mutex_lock(&chip->mutex);
- changed = value->value.enumerated.item[0] != data->output_sel;
- if (changed) {
- data->output_sel = value->value.enumerated.item[0];
-
- reg = data->cs4245_regs[CS4245_SIGNAL_SEL] &
- ~CS4245_A_OUT_SEL_MASK;
- reg |= data->output_sel == 2 ?
- CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
- cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
-
- cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
- data->output_sel ? data->hp_vol_att : 0);
- cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
- data->output_sel ? data->hp_vol_att : 0);
-
- oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
- data->output_sel == 1 ? GPIO_HP_REAR : 0,
- GPIO_HP_REAR);
- }
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static int hp_volume_offset_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[3] = {
- "< 64 ohms", "64-150 ohms", "150-300 ohms"
- };
-
- return snd_ctl_enum_info(info, 1, 3, names);
-}
-
-static int hp_volume_offset_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- mutex_lock(&chip->mutex);
- if (data->hp_vol_att > 2 * 7)
- value->value.enumerated.item[0] = 0;
- else if (data->hp_vol_att > 0)
- value->value.enumerated.item[0] = 1;
- else
- value->value.enumerated.item[0] = 2;
- mutex_unlock(&chip->mutex);
- return 0;
-}
-
-static int hp_volume_offset_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
- struct oxygen *chip = ctl->private_data;
struct dg *data = chip->model_data;
- s8 att;
- int changed;
+ unsigned int routing = 0;
- if (value->value.enumerated.item[0] > 2)
- return -EINVAL;
- att = atts[value->value.enumerated.item[0]];
- mutex_lock(&chip->mutex);
- changed = att != data->hp_vol_att;
- if (changed) {
- data->hp_vol_att = att;
- if (data->output_sel) {
- cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
- cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
- }
+ switch (data->pcm_output) {
+ case PLAYBACK_DST_HP:
+ case PLAYBACK_DST_HP_FP:
+ oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+ OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 |
+ OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
+ break;
+ case PLAYBACK_DST_20_CH:
+ routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+ (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+ (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+ oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+ OXYGEN_PLAY_MUTE01 | OXYGEN_PLAY_MUTE23 |
+ OXYGEN_PLAY_MUTE45, OXYGEN_PLAY_MUTE_MASK);
+ break;
+ case PLAYBACK_DST_40_CH:
+ routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+ (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+ (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+ oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+ OXYGEN_PLAY_MUTE01 |
+ OXYGEN_PLAY_MUTE23, OXYGEN_PLAY_MUTE_MASK);
+ break;
+ case PLAYBACK_DST_51_CH:
+ routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+ (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+ (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+ oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+ OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
+ break;
}
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static int input_vol_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = 2;
- info->value.integer.min = 2 * -12;
- info->value.integer.max = 2 * 12;
- return 0;
-}
-
-static int input_vol_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- unsigned int idx = ctl->private_value;
-
- mutex_lock(&chip->mutex);
- value->value.integer.value[0] = data->input_vol[idx][0];
- value->value.integer.value[1] = data->input_vol[idx][1];
- mutex_unlock(&chip->mutex);
- return 0;
+ return routing;
}
-static int input_vol_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
+static void dump_cs4245_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
{
- struct oxygen *chip = ctl->private_data;
struct dg *data = chip->model_data;
- unsigned int idx = ctl->private_value;
- int changed = 0;
-
- if (value->value.integer.value[0] < 2 * -12 ||
- value->value.integer.value[0] > 2 * 12 ||
- value->value.integer.value[1] < 2 * -12 ||
- value->value.integer.value[1] > 2 * 12)
- return -EINVAL;
- mutex_lock(&chip->mutex);
- changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
- data->input_vol[idx][1] != value->value.integer.value[1];
- if (changed) {
- data->input_vol[idx][0] = value->value.integer.value[0];
- data->input_vol[idx][1] = value->value.integer.value[1];
- if (idx == data->input_sel) {
- cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
- data->input_vol[idx][0]);
- cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
- data->input_vol[idx][1]);
- }
- }
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
-
-static int input_sel_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[4] = {
- "Mic", "Aux", "Front Mic", "Line"
- };
+ unsigned int reg;
- return snd_ctl_enum_info(info, 1, 4, names);
+ snd_iprintf(buffer, "\nCS4245:");
+ cs4245_read_spi(chip, CS4245_INT_STATUS);
+ for (reg = 0; reg < ARRAY_SIZE(data->cs4245_shadow); ++reg)
+ snd_iprintf(buffer, " %02x", data->cs4245_shadow[reg]);
+ snd_iprintf(buffer, "\n");
}
-static int input_sel_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
+/* Put the codec into low power mode, disable audio output, save registers */
+static void dg_suspend(struct oxygen *chip)
{
- struct oxygen *chip = ctl->private_data;
struct dg *data = chip->model_data;
-
- mutex_lock(&chip->mutex);
- value->value.enumerated.item[0] = data->input_sel;
- mutex_unlock(&chip->mutex);
- return 0;
+ data->cs4245_shadow[CS4245_POWER_CTRL] = CS4245_PDN_MIC |
+ CS4245_PDN_ADC | CS4245_PDN_DAC | CS4245_PDN;
+ cs4245_write_spi(chip, CS4245_POWER_CTRL);
+ cs4245_dump_regs(chip, true);
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 0, GPIO_OUTPUT_ENABLE);
}
-static int input_sel_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
+static void dg_resume(struct oxygen *chip)
{
- static const u8 sel_values[4] = {
- CS4245_SEL_MIC,
- CS4245_SEL_INPUT_1,
- CS4245_SEL_INPUT_2,
- CS4245_SEL_INPUT_4
- };
- struct oxygen *chip = ctl->private_data;
struct dg *data = chip->model_data;
- int changed;
-
- if (value->value.enumerated.item[0] > 3)
- return -EINVAL;
-
- mutex_lock(&chip->mutex);
- changed = value->value.enumerated.item[0] != data->input_sel;
- if (changed) {
- data->input_sel = value->value.enumerated.item[0];
-
- cs4245_write(chip, CS4245_ANALOG_IN,
- (data->cs4245_regs[CS4245_ANALOG_IN] &
- ~CS4245_SEL_MASK) |
- sel_values[data->input_sel]);
-
- cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
- data->input_vol[data->input_sel][0]);
- cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
- data->input_vol[data->input_sel][1]);
-
- oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
- data->input_sel ? 0 : GPIO_INPUT_ROUTE,
- GPIO_INPUT_ROUTE);
- }
- mutex_unlock(&chip->mutex);
- return changed;
+ data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
+ cs4245_dump_regs(chip, false);
+ msleep_interruptible(1000);
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 0xffff,
+ GPIO_OUTPUT_ENABLE);
}
-static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
-{
- static const char *const names[2] = { "Active", "Frozen" };
-
- return snd_ctl_enum_info(info, 1, 2, names);
-}
-
-static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+static void dg_cleanup(struct oxygen *chip)
{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- value->value.enumerated.item[0] =
- !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
- return 0;
+ dg_suspend(chip);
}
-static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- u8 reg;
- int changed;
-
- mutex_lock(&chip->mutex);
- reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
- if (value->value.enumerated.item[0])
- reg |= CS4245_HPF_FREEZE;
- changed = reg != data->cs4245_regs[CS4245_ADC_CTRL];
- if (changed)
- cs4245_write(chip, CS4245_ADC_CTRL, reg);
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-#define INPUT_VOLUME(xname, index) { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .info = input_vol_info, \
- .get = input_vol_get, \
- .put = input_vol_put, \
- .tlv = { .p = cs4245_pga_db_scale }, \
- .private_value = index, \
-}
-static const struct snd_kcontrol_new dg_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Output Playback Enum",
- .info = output_switch_info,
- .get = output_switch_get,
- .put = output_switch_put,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Headphones Impedance Playback Enum",
- .info = hp_volume_offset_info,
- .get = hp_volume_offset_get,
- .put = hp_volume_offset_put,
- },
- INPUT_VOLUME("Mic Capture Volume", 0),
- INPUT_VOLUME("Aux Capture Volume", 1),
- INPUT_VOLUME("Front Mic Capture Volume", 2),
- INPUT_VOLUME("Line Capture Volume", 3),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .info = input_sel_info,
- .get = input_sel_get,
- .put = input_sel_put,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "ADC High-pass Filter Capture Enum",
- .info = hpf_info,
- .get = hpf_get,
- .put = hpf_put,
- },
-};
-
-static int dg_control_filter(struct snd_kcontrol_new *template)
+/* Disable built-in volume control, we have only headphone volume */
+static int xonar_control_filter(struct snd_kcontrol_new *template)
{
if (!strncmp(template->name, "Master Playback ", 16))
return 1;
return 0;
}
-static int dg_mixer_init(struct oxygen *chip)
-{
- unsigned int i;
- int err;
-
- for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&dg_controls[i], chip));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static void dump_cs4245_registers(struct oxygen *chip,
- struct snd_info_buffer *buffer)
-{
- struct dg *data = chip->model_data;
- unsigned int i;
-
- snd_iprintf(buffer, "\nCS4245:");
- for (i = 1; i <= 0x10; ++i)
- snd_iprintf(buffer, " %02x", data->cs4245_regs[i]);
- snd_iprintf(buffer, "\n");
-}
-
struct oxygen_model model_xonar_dg = {
.longname = "C-Media Oxygen HD Audio",
.chip = "CMI8786",
.init = dg_init,
- .control_filter = dg_control_filter,
- .mixer_init = dg_mixer_init,
+ .control_filter = xonar_control_filter,
+ .mixer_init = xonar_dg_mixer_init,
.cleanup = dg_cleanup,
.suspend = dg_suspend,
.resume = dg_resume,
@@ -596,11 +339,11 @@ struct oxygen_model model_xonar_dg = {
.model_data_size = sizeof(struct dg),
.device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_2 |
+ CAPTURE_0_FROM_I2S_1 |
CAPTURE_1_FROM_SPDIF,
.dac_channels_pcm = 6,
.dac_channels_mixer = 0,
- .function_flags = OXYGEN_FUNCTION_SPI,
+ .function_flags = OXYGEN_FUNCTION_SPI | OXYGEN_FUNCTION_ENABLE_SPI_4_5,
.dac_mclks = OXYGEN_MCLKS(256, 128, 128),
.adc_mclks = OXYGEN_MCLKS(256, 128, 128),
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
diff -uprN linux-3.12/sound/pci/oxygen/xonar_dg.h linux-3.12-my/sound/pci/oxygen/xonar_dg.h
--- linux-3.12/sound/pci/oxygen/xonar_dg.h 2013-11-04 03:41:51.000000000 +0400
+++ linux-3.12-my/sound/pci/oxygen/xonar_dg.h 2013-11-19 01:06:12.000000000 +0400
@@ -3,6 +3,48 @@
#include "oxygen.h"
+#define GPIO_MAGIC 0x0008
+#define GPIO_HP_DETECT 0x0010
+#define GPIO_INPUT_ROUTE 0x0060
+#define GPIO_HP_REAR 0x0080
+#define GPIO_OUTPUT_ENABLE 0x0100
+
+#define CAPTURE_SRC_MIC 0
+#define CAPTURE_SRC_FP_MIC 1
+#define CAPTURE_SRC_LINE 2
+#define CAPTURE_SRC_AUX 3
+
+#define PLAYBACK_DST_HP 0
+#define PLAYBACK_DST_HP_FP 1
+#define PLAYBACK_DST_20_CH 2
+#define PLAYBACK_DST_40_CH 3
+#define PLAYBACK_DST_51_CH 4
+
extern struct oxygen_model model_xonar_dg;
+/* Xonar DG Specific Data */
+struct dg {
+ unsigned char cs4245_shadow[16];
+ /* Output select: headphone/speakers */
+ unsigned char pcm_output;
+ /* Input select: MIC, Line, Aux */
+ unsigned char pga_source;
+ /* Independend capture volumes */
+ char mic_vol_l;
+ char mic_vol_r;
+ bool mic_m;
+ char line_vol_l;
+ char line_vol_r;
+ bool line_m;
+ char aux_vol_l;
+ char aux_vol_r;
+ bool aux_m;
+};
+
+/* Xonar DG SPI/I2C control routines */
+int cs4245_write_spi(struct oxygen *chip, u8 reg);
+
+/* Xonar DG Mixer */
+int xonar_dg_mixer_init(struct oxygen *chip);
+
#endif
diff -uprN linux-3.12/sound/pci/oxygen/xonar_dg_mixer.c linux-3.12-my/sound/pci/oxygen/xonar_dg_mixer.c
--- linux-3.12/sound/pci/oxygen/xonar_dg_mixer.c 1970-01-01 03:00:00.000000000 +0300
+++ linux-3.12-my/sound/pci/oxygen/xonar_dg_mixer.c 2013-11-19 01:04:16.000000000 +0400
@@ -0,0 +1,536 @@
+/*
+ * Mixer controls for the Xonar DG/DGX
+ *
+ * Copyright (c) Roman Volkov <v1ron(a)mail.ru>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * It is not good that we do not have software volume control
+ * as the Windows driver does. CS4361 cannot attenuate the volume.
+ * When we are switching from headphones to the speakers,
+ * which are controlled by the simple DAC CS4361, our headphones
+ * in the rear jack can stun us.
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "xonar_dg.h"
+#include "cs4245.h"
+
+/* CS4245 Headphone Channels A&B Volume Control */
+static int xonar_dg_dac_stereo_volume_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 2;
+ info->value.integer.min = 0;
+ info->value.integer.max = 255;
+ return 0;
+}
+
+static int xonar_dg_dac_stereo_volume_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ unsigned int tmp;
+
+ mutex_lock(&chip->mutex);
+ tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255;
+ val->value.integer.value[0] = tmp;
+ tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255;
+ val->value.integer.value[1] = tmp;
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int xonar_dg_dac_stereo_volume_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ if ((val->value.integer.value[0] > 255) ||
+ (val->value.integer.value[0] < 0) ||
+ (val->value.integer.value[1] > 255) ||
+ (val->value.integer.value[1] < 0)) {
+ return -EINVAL;
+ }
+ mutex_lock(&chip->mutex);
+ data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~val->value.integer.value[0];
+ data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~val->value.integer.value[1];
+ cs4245_write_spi(chip, CS4245_DAC_A_CTRL);
+ cs4245_write_spi(chip, CS4245_DAC_B_CTRL);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+/* CS4245 DAC Mute */
+static int xonar_dg_dac_mute_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ val->value.integer.value[0] = ((data->cs4245_shadow[CS4245_DAC_CTRL_1]
+ & CS4245_MUTE_DAC) == 0);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int xonar_dg_dac_mute_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ if (val->value.integer.value[0] > 1)
+ return -EINVAL;
+ mutex_lock(&chip->mutex);
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC;
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] |=
+ (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC;
+ cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+/* Xonar DG Output Select */
+static int xonar_dg_pcm_route_apply(struct oxygen *chip)
+{
+ struct dg *data = chip->model_data;
+
+ if (data->pcm_output == PLAYBACK_DST_HP) {
+ /* Mute FP (aux output) amplifier, switch rear jack to CS4245 */
+ oxygen_write8_masked(chip, OXYGEN_GPIO_DATA, 0xff,
+ GPIO_HP_REAR);
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] &=
+ ~CS4245_A_OUT_SEL_MASK;
+ } else if (data->pcm_output == PLAYBACK_DST_HP_FP) {
+ /*
+ * Unmute FP amplifier, switch rear jack to CS4361,
+ * I2S ports 2,3,4 should be inactive
+ */
+ oxygen_write8_masked(chip, OXYGEN_GPIO_DATA, 0x00, 0x80);
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] &=
+ ~CS4245_A_OUT_SEL_MASK;
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC;
+ } else {
+ /*
+ * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp.,
+ * and just change playback routing / DMA channels
+ */
+ oxygen_write8_masked(chip, OXYGEN_GPIO_DATA, 0x00, 0x80);
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] &=
+ ~CS4245_A_OUT_SEL_MASK;
+ }
+ cs4245_write_spi(chip, CS4245_SIGNAL_SEL);
+ return 0;
+}
+
+static int xonar_dg_pcm_route_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[5] = {
+ "Stereo Headphones",
+ "Stereo Headphones FP",
+ "Stereo Speakers",
+ "4 Speakers",
+ "5.1 Speakers",
+ };
+
+ return snd_ctl_enum_info(info, 1, 5, names);
+}
+
+static int xonar_dg_pcm_route_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ val->value.integer.value[0] = data->pcm_output;
+ mutex_unlock(&chip->mutex);
+
+ return 0;
+}
+
+static int xonar_dg_pcm_route_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ int ret;
+
+ mutex_lock(&chip->mutex);
+ data->pcm_output = val->value.integer.value[0];
+ ret = xonar_dg_pcm_route_apply(chip);
+ oxygen_update_dac_routing(chip);
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+/* CS4245 PGA Source */
+static int xonar_dg_pga_mute_reg_toggle(struct oxygen *chip, bool mute);
+static int xonar_dg_pga_volume_reg_write(struct oxygen *chip, char left,
+ char right);
+
+static int xonar_dg_pga_source_apply(struct oxygen *chip)
+{
+ struct dg *data = chip->model_data;
+
+ data->cs4245_shadow[CS4245_ANALOG_IN] &= ~CS4245_SEL_MASK;
+ if (data->pga_source == CAPTURE_SRC_FP_MIC)
+ data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_2;
+ else if (data->pga_source == CAPTURE_SRC_LINE)
+ data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_4;
+ else if (data->pga_source != CAPTURE_SRC_MIC)
+ data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_1;
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, 0xffff, GPIO_INPUT_ROUTE);
+ return cs4245_write_spi(chip, CS4245_ANALOG_IN);
+}
+
+static int xonar_dg_pga_source_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const ps_names[4] = {
+ "Microphone",
+ "Microphone FP",
+ "Line In",
+ "Aux"
+ };
+
+ return snd_ctl_enum_info(info, 1, 4, ps_names);
+}
+
+static int xonar_dg_pga_source_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ val->value.integer.value[0] = data->pga_source;
+ mutex_unlock(&chip->mutex);
+
+ return 0;
+}
+
+static int xonar_dg_pga_source_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ bool mute = false;
+ long route = val->value.integer.value[0];
+ char left = 0;
+ char right = 0;
+ int ret;
+
+ if (route > CAPTURE_SRC_AUX)
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ data->pga_source = route;
+ ret = xonar_dg_pga_source_apply(chip);
+ if (ret < 0)
+ goto err;
+ switch (route) {
+ case CAPTURE_SRC_MIC:
+ case CAPTURE_SRC_FP_MIC:
+ mute = data->mic_m;
+ left = data->mic_vol_l;
+ right = data->mic_vol_r;
+ break;
+ case CAPTURE_SRC_LINE:
+ mute = data->line_m;
+ left = data->line_vol_l;
+ right = data->line_vol_r;
+ break;
+ case CAPTURE_SRC_AUX:
+ mute = data->aux_m;
+ left = data->aux_vol_l;
+ right = data->aux_vol_r;
+ break;
+ }
+ ret = xonar_dg_pga_mute_reg_toggle(chip, mute);
+ if (ret < 0)
+ goto err;
+ ret = xonar_dg_pga_volume_reg_write(chip, left, right);
+ if (ret < 0)
+ goto err;
+err:
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+/* Common routines to access capture volume register - Mic, Line, Aux */
+static int xonar_dg_pga_volume_reg_write(struct oxygen *chip, char left,
+ char right)
+{
+ struct dg *data = chip->model_data;
+ int ret;
+
+ data->cs4245_shadow[CS4245_PGA_A_CTRL] = left;
+ data->cs4245_shadow[CS4245_PGA_B_CTRL] = right;
+ ret = cs4245_write_spi(chip, CS4245_PGA_A_CTRL);
+ if (ret < 0)
+ return ret;
+ return cs4245_write_spi(chip, CS4245_PGA_B_CTRL);
+}
+
+static int xonar_dg_pga_volume_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 2;
+ info->value.integer.min = -24;
+ info->value.integer.max = 24;
+ return 0;
+}
+
+static int xonar_dg_pga_volume_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ switch (ctl->private_value) {
+ case CAPTURE_SRC_MIC:
+ val->value.integer.value[0] = data->mic_vol_l;
+ val->value.integer.value[1] = data->mic_vol_r;
+ break;
+ case CAPTURE_SRC_LINE:
+ val->value.integer.value[0] = data->line_vol_l;
+ val->value.integer.value[1] = data->line_vol_r;
+ break;
+ case CAPTURE_SRC_AUX:
+ val->value.integer.value[0] = data->aux_vol_l;
+ val->value.integer.value[1] = data->aux_vol_r;
+ break;
+ }
+ mutex_unlock(&chip->mutex);
+
+ return 0;
+}
+
+static int xonar_dg_pga_volume_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ long left = val->value.integer.value[0];
+ long right = val->value.integer.value[1];
+ int ret = 0;
+
+ if ((left > 24) || (left < -24) || (right > 24) || (right < -24))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ switch (ctl->private_value) {
+ case CAPTURE_SRC_MIC:
+ data->mic_vol_l = left;
+ data->mic_vol_r = right;
+ break;
+ case CAPTURE_SRC_LINE:
+ data->line_vol_l = left;
+ data->line_vol_r = right;
+ break;
+ case CAPTURE_SRC_AUX:
+ data->aux_vol_l = left;
+ data->aux_vol_r = right;
+ break;
+ }
+ switch (data->pga_source) {
+ case CAPTURE_SRC_MIC:
+ case CAPTURE_SRC_FP_MIC:
+ ret = xonar_dg_pga_volume_reg_write(chip, data->mic_vol_l,
+ data->mic_vol_r);
+ break;
+ case CAPTURE_SRC_LINE:
+ ret = xonar_dg_pga_volume_reg_write(chip, data->line_vol_l,
+ data->line_vol_r);
+ break;
+ case CAPTURE_SRC_AUX:
+ ret = xonar_dg_pga_volume_reg_write(chip, data->aux_vol_l,
+ data->aux_vol_r);
+ break;
+ }
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+/* Common routines to access capture mute register - Mic, Line, Aux */
+static int xonar_dg_pga_mute_reg_toggle(struct oxygen *chip, bool mute)
+{
+ struct dg *data = chip->model_data;
+
+ data->cs4245_shadow[CS4245_ADC_CTRL] &= ~CS4245_MUTE_ADC;
+ data->cs4245_shadow[CS4245_ADC_CTRL] |= ((mute == 0) << 2) &
+ CS4245_MUTE_ADC;
+ return cs4245_write_spi(chip, CS4245_ADC_CTRL);
+}
+
+static int xonar_dg_pga_mute_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ switch (ctl->private_value) {
+ case CAPTURE_SRC_MIC:
+ val->value.integer.value[0] = data->mic_m != false ? 1 : 0;
+ break;
+ case CAPTURE_SRC_LINE:
+ val->value.integer.value[0] = data->mic_m != false ? 1 : 0;
+ break;
+ case CAPTURE_SRC_AUX:
+ val->value.integer.value[0] = data->mic_m != false ? 1 : 0;
+ break;
+ }
+ mutex_unlock(&chip->mutex);
+
+ return 0;
+}
+
+static int xonar_dg_pga_mute_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ long tmp = val->value.integer.value[0];
+ int ret = 0;
+
+ if ((tmp > 1) || (tmp < 0))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ switch (ctl->private_value) {
+ case CAPTURE_SRC_MIC:
+ data->mic_m = tmp != 0;
+ break;
+ case CAPTURE_SRC_LINE:
+ data->line_m = tmp != 0;
+ break;
+ case CAPTURE_SRC_AUX:
+ data->aux_m = tmp != 0;
+ break;
+ }
+ switch (data->pga_source) {
+ case CAPTURE_SRC_MIC:
+ case CAPTURE_SRC_FP_MIC:
+ ret = xonar_dg_pga_mute_reg_toggle(chip, data->mic_m);
+ break;
+ case CAPTURE_SRC_LINE:
+ ret = xonar_dg_pga_mute_reg_toggle(chip, data->line_m);
+ break;
+ case CAPTURE_SRC_AUX:
+ ret = xonar_dg_pga_mute_reg_toggle(chip, data->aux_m);
+ break;
+ }
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+#define CAPTURE_VOLUME(xname, private) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = xonar_dg_pga_volume_info, \
+ .get = xonar_dg_pga_volume_get, \
+ .put = xonar_dg_pga_volume_put, \
+ .tlv = { .p = xonar_dg_pga_db_scale, }, \
+ .private_value = private, \
+ }
+#define CAPTURE_SWITCH(xname, private) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .info = snd_ctl_boolean_mono_info, \
+ .get = xonar_dg_pga_mute_get, \
+ .put = xonar_dg_pga_mute_put, \
+ .private_value = private, \
+ }
+
+static const DECLARE_TLV_DB_MINMAX(xonar_dg_hp_db_scale, -12550, 0);
+static const DECLARE_TLV_DB_MINMAX(xonar_dg_pga_db_scale, -1200, 1200);
+static const struct snd_kcontrol_new xonar_dg_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = xonar_dg_dac_stereo_volume_info,
+ .get = xonar_dg_dac_stereo_volume_get,
+ .put = xonar_dg_dac_stereo_volume_put,
+ .tlv = { .p = xonar_dg_hp_db_scale, },
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Playback Switch",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_ctl_boolean_mono_info,
+ .get = xonar_dg_dac_mute_get,
+ .put = xonar_dg_dac_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Output Playback Enum",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = xonar_dg_pcm_route_info,
+ .get = xonar_dg_pcm_route_get,
+ .put = xonar_dg_pcm_route_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Capture Enum",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = xonar_dg_pga_source_info,
+ .get = xonar_dg_pga_source_get,
+ .put = xonar_dg_pga_source_put,
+ },
+ CAPTURE_VOLUME("Mic Capture Volume", CAPTURE_SRC_MIC),
+ CAPTURE_SWITCH("Mic Capture Switch", CAPTURE_SRC_MIC),
+ CAPTURE_VOLUME("Line Capture Volume", CAPTURE_SRC_LINE),
+ CAPTURE_SWITCH("Line Capture Switch", CAPTURE_SRC_LINE),
+ CAPTURE_VOLUME("Aux Capture Volume", CAPTURE_SRC_AUX),
+ CAPTURE_SWITCH("Aux Capture Switch", CAPTURE_SRC_AUX),
+};
+
+int xonar_dg_mixer_init(struct oxygen *chip)
+{
+ unsigned int i;
+ int ret;
+ for (i = 0; i < ARRAY_SIZE(xonar_dg_controls); i++) {
+ ret = snd_ctl_add(chip->card,
+ snd_ctl_new1(&xonar_dg_controls[i], chip));
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
2
2
20 Nov '13
Gen2 has SCU. SRU is for Gen1
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx(a)renesas.com>
---
include/sound/rcar_snd.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
index 12afab1..a818ff7 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
--
1.7.9.5
2
3
[alsa-devel] [PATCH 1/2] snd-oxygen: Changes for oxygen driver to fix the Xonar DG card
by Roman Volkov 20 Nov '13
by Roman Volkov 20 Nov '13
20 Nov '13
This patch does some preparation of existing Oxygen driver. Some constants added to the header files. To perform the SPI reading, there is a new function to wait when the SPI finishes a transaction. Channel routing must be updated when the user selects the audio output, and there are some extra symbols exported from the snd-oxygen-lib module.
Signed-off-by: Roman I Volkov <v1ron(a)mail.ru>
---
Should not affect other models of Oxygen driver, but who knows.
diff -uprN linux-3.12/sound/pci/oxygen/cs4245.h linux-3.12-my/sound/pci/oxygen/cs4245.h
--- linux-3.12/sound/pci/oxygen/cs4245.h 2013-11-04 03:41:51.000000000 +0400
+++ linux-3.12-my/sound/pci/oxygen/cs4245.h 2013-11-15 15:46:40.000000000 +0400
@@ -103,5 +103,6 @@
#define CS4245_ADC_UNDRFL 0x01
-#define CS4245_SPI_ADDRESS (0x9e << 16)
-#define CS4245_SPI_WRITE (0 << 16)
+#define CS4245_SPI_ADDRESS 0x9e
+#define CS4245_SPI_WRITE 0
+#define CS4245_SPI_READ 1
diff -uprN linux-3.12/sound/pci/oxygen/oxygen.h linux-3.12-my/sound/pci/oxygen/oxygen.h
--- linux-3.12/sound/pci/oxygen/oxygen.h 2013-11-04 03:41:51.000000000 +0400
+++ linux-3.12-my/sound/pci/oxygen/oxygen.h 2013-11-15 15:47:38.000000000 +0400
@@ -198,7 +198,8 @@ void oxygen_write_ac97(struct oxygen *ch
void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
unsigned int index, u16 data, u16 mask);
-void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
+int oxygen_wait_spi(struct oxygen *chip);
+int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
void oxygen_reset_uart(struct oxygen *chip);
diff -uprN linux-3.12/sound/pci/oxygen/oxygen_io.c linux-3.12-my/sound/pci/oxygen/oxygen_io.c
--- linux-3.12/sound/pci/oxygen/oxygen_io.c 2013-11-04 03:41:51.000000000 +0400
+++ linux-3.12-my/sound/pci/oxygen/oxygen_io.c 2013-11-19 00:56:12.000000000 +0400
@@ -105,8 +105,8 @@ static int oxygen_ac97_wait(struct oxyge
* Reading the status register also clears the bits, so we have to save
* the read bits in status.
*/
- wait_event_timeout(chip->ac97_waitqueue,
- ({ status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS);
+ wait_event_timeout(chip->ac97_waitqueue, ({ status |= oxygen_read8(chip,
+ OXYGEN_AC97_INTERRUPT_STATUS);
status & mask; }),
msecs_to_jiffies(1) + 1);
/*
@@ -194,23 +194,35 @@ void oxygen_write_ac97_masked(struct oxy
}
EXPORT_SYMBOL(oxygen_write_ac97_masked);
-void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
+int oxygen_wait_spi(struct oxygen *chip)
{
- unsigned int count;
+ /* Higher interval to be sure - 100 microseconds */
+ unsigned int count = 100;
- /* should not need more than 30.72 us (24 * 1.28 us) */
- count = 10;
- while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
- && count > 0) {
- udelay(4);
- --count;
+ for (;;) {
+ if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) &
+ OXYGEN_SPI_BUSY) == 0)
+ break;
+ if (count == 0) {
+ snd_printk(KERN_ERR "oxygen: spi wait timeout\n");
+ return -EIO;
+ }
+ udelay(1);
+ count--;
}
+ return 0;
+}
+EXPORT_SYMBOL(oxygen_wait_spi);
+int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
+{
oxygen_write8(chip, OXYGEN_SPI_DATA1, data);
oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8);
if (control & OXYGEN_SPI_DATA_LENGTH_3)
oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16);
oxygen_write8(chip, OXYGEN_SPI_CONTROL, control);
+
+ return oxygen_wait_spi(chip);
}
EXPORT_SYMBOL(oxygen_write_spi);
diff -uprN linux-3.12/sound/pci/oxygen/oxygen_mixer.c linux-3.12-my/sound/pci/oxygen/oxygen_mixer.c
--- linux-3.12/sound/pci/oxygen/oxygen_mixer.c 2013-11-04 03:41:51.000000000 +0400
+++ linux-3.12-my/sound/pci/oxygen/oxygen_mixer.c 2013-11-18 14:03:54.000000000 +0400
@@ -190,6 +190,7 @@ void oxygen_update_dac_routing(struct ox
if (chip->model.update_center_lfe_mix)
chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
}
+EXPORT_SYMBOL(oxygen_update_dac_routing);
static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
{
diff -uprN linux-3.12/sound/pci/oxygen/oxygen_regs.h linux-3.12-my/sound/pci/oxygen/oxygen_regs.h
--- linux-3.12/sound/pci/oxygen/oxygen_regs.h 2013-11-04 03:41:51.000000000 +0400
+++ linux-3.12-my/sound/pci/oxygen/oxygen_regs.h 2013-11-18 13:58:11.000000000 +0400
@@ -318,6 +318,7 @@
#define OXYGEN_PLAY_MUTE23 0x0002
#define OXYGEN_PLAY_MUTE45 0x0004
#define OXYGEN_PLAY_MUTE67 0x0008
+#define OXYGEN_PLAY_MUTE_MASK 0x000f
#define OXYGEN_PLAY_MULTICH_MASK 0x0010
#define OXYGEN_PLAY_MULTICH_I2S_DAC 0x0000
#define OXYGEN_PLAY_MULTICH_AC97 0x0010
2
2