* [PATCH v2 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec
@ 2021-03-04 19:02 ` Vitaly Rodionov
0 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai; +Cc: alsa-devel, patches, linux-kernel
Dell's laptops Inspiron 3500, Inspiron 3501, Inspiron 3505 are using
Cirrus Logic CS8409 HDA bridge with CS42L42 companion codec.
The CS8409 is a multichannel HD audio routing controller.
CS8409 includes support for four channels of digital
microphone data and two bidirectional ASPs for up to 32
channels of TDM data or 4 channels of I2S data. The CS8409 is
intended to be used with a remote companion codec that implements
high performance analog functions in close physical
proximity to the end-equipment audio port or speaker driver.
The CS42L42 is a low-power audio codec with integrated MIPI
SoundWire interface or I2C/I2S/TDM interfaces designed
for portable applications. It provides a high-dynamic range,
stereo DAC for audio playback and a mono high-dynamic-range
ADC for audio capture
Changes since version 1:
ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
* No change
ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42
companion codec.
* Removed redundant fields in fixup table
* Handle gpio via spec->gpio_dir, spec->gpio_data and spec->gpio_mask
* Moved cs8409_cs42l42_init() from patch 2, to handle resume correctly
ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42
companion codec.
* Run scripts/checkpatch.pl, fixed new warnings
ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
* Moved control values to cache to avoid i2c read at each time.
Stefan Binding (1):
ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
Vitaly Rodionov (3):
ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42
companion codec.
ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42
companion codec.
sound/pci/hda/hda_auto_parser.h | 2 +-
sound/pci/hda/hda_local.h | 2 +-
sound/pci/hda/patch_cirrus.c | 1068 +++++++++++++++++++++++++++++++
3 files changed, 1070 insertions(+), 2 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec
@ 2021-03-04 19:02 ` Vitaly Rodionov
0 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai; +Cc: patches, alsa-devel, linux-kernel
Dell's laptops Inspiron 3500, Inspiron 3501, Inspiron 3505 are using
Cirrus Logic CS8409 HDA bridge with CS42L42 companion codec.
The CS8409 is a multichannel HD audio routing controller.
CS8409 includes support for four channels of digital
microphone data and two bidirectional ASPs for up to 32
channels of TDM data or 4 channels of I2S data. The CS8409 is
intended to be used with a remote companion codec that implements
high performance analog functions in close physical
proximity to the end-equipment audio port or speaker driver.
The CS42L42 is a low-power audio codec with integrated MIPI
SoundWire interface or I2C/I2S/TDM interfaces designed
for portable applications. It provides a high-dynamic range,
stereo DAC for audio playback and a mono high-dynamic-range
ADC for audio capture
Changes since version 1:
ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
* No change
ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42
companion codec.
* Removed redundant fields in fixup table
* Handle gpio via spec->gpio_dir, spec->gpio_data and spec->gpio_mask
* Moved cs8409_cs42l42_init() from patch 2, to handle resume correctly
ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42
companion codec.
* Run scripts/checkpatch.pl, fixed new warnings
ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
* Moved control values to cache to avoid i2c read at each time.
Stefan Binding (1):
ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
Vitaly Rodionov (3):
ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42
companion codec.
ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42
companion codec.
sound/pci/hda/hda_auto_parser.h | 2 +-
sound/pci/hda/hda_local.h | 2 +-
sound/pci/hda/patch_cirrus.c | 1068 +++++++++++++++++++++++++++++++
3 files changed, 1070 insertions(+), 2 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 1/4] ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
2021-03-04 19:02 ` Vitaly Rodionov
@ 2021-03-04 19:02 ` Vitaly Rodionov
-1 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai; +Cc: alsa-devel, patches, linux-kernel
In preparation to support Cirrus Logic CS8409 HDA bridge on new Dell platforms
it is nessasary to increase AUTO_CFG_MAX_INS and AUTO_CFG_NUM_INPUTS values.
Currently AUTO_CFG_MAX_INS is limited to 8, but Cirrus Logic HDA bridge CS8409
has 18 input pins, 16 ASP receivers and 2 DMIC inputs. We have to increase this
value to 18, so generic code can handle this correctly.
Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
---
sound/pci/hda/hda_auto_parser.h | 2 +-
sound/pci/hda/hda_local.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h
index a22ca0e17a08..df63d66af1ab 100644
--- a/sound/pci/hda/hda_auto_parser.h
+++ b/sound/pci/hda/hda_auto_parser.h
@@ -27,7 +27,7 @@ enum {
};
#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
-#define AUTO_CFG_MAX_INS 8
+#define AUTO_CFG_MAX_INS 18
struct auto_pin_cfg_item {
hda_nid_t pin;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 5beb8aa44ecd..317245a5585d 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -180,7 +180,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
/*
* input MUX helper
*/
-#define HDA_MAX_NUM_INPUTS 16
+#define HDA_MAX_NUM_INPUTS 36
struct hda_input_mux_item {
char label[32];
unsigned int index;
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 1/4] ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
@ 2021-03-04 19:02 ` Vitaly Rodionov
0 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai; +Cc: patches, alsa-devel, linux-kernel
In preparation to support Cirrus Logic CS8409 HDA bridge on new Dell platforms
it is nessasary to increase AUTO_CFG_MAX_INS and AUTO_CFG_NUM_INPUTS values.
Currently AUTO_CFG_MAX_INS is limited to 8, but Cirrus Logic HDA bridge CS8409
has 18 input pins, 16 ASP receivers and 2 DMIC inputs. We have to increase this
value to 18, so generic code can handle this correctly.
Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
---
sound/pci/hda/hda_auto_parser.h | 2 +-
sound/pci/hda/hda_local.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h
index a22ca0e17a08..df63d66af1ab 100644
--- a/sound/pci/hda/hda_auto_parser.h
+++ b/sound/pci/hda/hda_auto_parser.h
@@ -27,7 +27,7 @@ enum {
};
#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
-#define AUTO_CFG_MAX_INS 8
+#define AUTO_CFG_MAX_INS 18
struct auto_pin_cfg_item {
hda_nid_t pin;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 5beb8aa44ecd..317245a5585d 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -180,7 +180,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
/*
* input MUX helper
*/
-#define HDA_MAX_NUM_INPUTS 16
+#define HDA_MAX_NUM_INPUTS 36
struct hda_input_mux_item {
char label[32];
unsigned int index;
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.
2021-03-04 19:02 ` Vitaly Rodionov
@ 2021-03-04 19:02 ` Vitaly Rodionov
-1 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai; +Cc: alsa-devel, patches, linux-kernel
Dell's laptops Inspiron 3500, Inspiron 3501, Inspiron 3505 are using Cirrus Logic
CS8409 HDA bridge with CS42L42 companion codec.
The CS8409 is a multichannel HD audio routing controller.
CS8409 includes support for four channels of digital
microphone data and two bidirectional ASPs for up to 32
channels of TDM data or 4 channels of I2S data. The CS8409 is
intended to be used with a remote companion codec that implements
high performance analog functions in close physical
proximity to the end-equipment audio port or speaker driver.
The CS42L42 is a low-power audio codec with integrated MIPI
SoundWire interface or I2C/I2S/TDM interfaces designed
for portable applications. It provides a high-dynamic range,
stereo DAC for audio playback and a mono high-dynamic-range
ADC for audio capture
CS42L42 is connected to CS8409 HDA bridge via I2C and I2S.
CS8409 CS42L42
------- --------
ASP1.A TX --> ASP_SDIN
ASP1.A RX <-- ASP_SDOUT
GPIO5 --> RST#
GPIO4 <-- INT#
GPIO3 <-- WAKE#
GPIO7 <-> I2C SDA
GPIO6 --> I2C CLK
Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3505
This patch will register CS8409 with sound card and create
input/output paths and two input devices, initialise CS42L42
companion codec and configure it for ASP TX/RX TDM mode,
24bit, 48kHz.
cat /proc/asound/pcm
00-00: CS8409 Analog : CS8409 Analog : playback 1 : capture 1
00-03: HDMI 0 : HDMI 0 : playback 1
dmesg
snd_hda_codec_cirrus hdaudioC0D0: autoconfig for CS8409: line_outs=1 (0x2c/0x0/0x0/0x0/0x0) type:speaker
snd_hda_codec_cirrus hdaudioC0D0: speaker_outs=0 (0x0/0x0/0x0/0x0/0x0)
snd_hda_codec_cirrus hdaudioC0D0: hp_outs=1 (0x24/0x0/0x0/0x0/0x0)
snd_hda_codec_cirrus hdaudioC0D0: mono: mono_out=0x0
snd_hda_codec_cirrus hdaudioC0D0: inputs:
snd_hda_codec_cirrus hdaudioC0D0: Internal Mic=0x44
snd_hda_codec_cirrus hdaudioC0D0: Mic=0x34
input: HDA Intel PCH Headphone as /devices/pci0000:00/0000:00:1f.3/sound/card0/input8
input: HDA Intel PCH Headset Mic as /devices/pci0000:00/0000:00:1f.3/sound/card0/input9
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
---
sound/pci/hda/patch_cirrus.c | 573 +++++++++++++++++++++++++++++++++++
1 file changed, 573 insertions(+)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index f46204ab0b90..c95588681d53 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
+#include <linux/pci.h>
#include <sound/tlv.h>
#include <sound/hda_codec.h>
#include "hda_local.h"
@@ -1219,6 +1220,577 @@ static int patch_cs4213(struct hda_codec *codec)
return err;
}
+/* Cirrus Logic CS8409 HDA bridge with
+ * companion codec CS42L42
+ */
+#define CS8409_VENDOR_NID 0x47
+
+#define CS8409_CS42L42_HP_PIN_NID 0x24
+#define CS8409_CS42L42_SPK_PIN_NID 0x2c
+#define CS8409_CS42L42_AMIC_PIN_NID 0x34
+#define CS8409_CS42L42_DMIC_PIN_NID 0x44
+
+#define GPIO3_INT (1 << 3)
+#define GPIO4_INT (1 << 4)
+#define GPIO5_INT (1 << 5)
+
+#define CS42L42_I2C_ADDR (0x48 << 1)
+
+#define CIR_I2C_ADDR 0x0059
+#define CIR_I2C_DATA 0x005A
+#define CIR_I2C_CTRL 0x005B
+#define CIR_I2C_STATUS 0x005C
+#define CIR_I2C_QWRITE 0x005D
+#define CIR_I2C_QREAD 0x005E
+
+struct cs8409_i2c_param {
+ unsigned int addr;
+ unsigned int reg;
+};
+
+struct cs8409_cir_param {
+ unsigned int nid;
+ unsigned int cir;
+ unsigned int coeff;
+};
+
+enum {
+ CS8409_BULLSEYE,
+ CS8409_WARLOCK,
+ CS8409_CYBORG,
+ CS8409_VERBS,
+};
+
+/* Dell Inspiron models with cs8409/cs42l42 */
+static const struct hda_model_fixup cs8409_models[] = {
+ { .id = CS8409_BULLSEYE, .name = "bullseye" },
+ { .id = CS8409_WARLOCK, .name = "warlock" },
+ { .id = CS8409_CYBORG, .name = "cyborg" },
+ {}
+};
+
+/* Dell Inspiron platforms
+ * with cs8409 bridge and cs42l42 codec
+ */
+static const struct snd_pci_quirk cs8409_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A24, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A25, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A29, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A2A, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A2B, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0AB0, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB2, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB1, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB3, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB4, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB5, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AD9, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0ADA, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0ADB, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A7A, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A7D, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A7E, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A7F, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A80, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0ADF, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AE0, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AE1, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AE2, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AE9, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEA, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEB, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEC, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AED, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEE, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEF, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AF0, "Cyborg", CS8409_CYBORG),
+ {} /* terminator */
+};
+
+static const struct hda_verb cs8409_cs42l42_init_verbs[] = {
+ { 0x01, AC_VERB_SET_GPIO_WAKE_MASK, 0x0018 }, /* WAKE from GPIO 3,4 */
+ { 0x47, AC_VERB_SET_PROC_STATE, 0x0001 }, /* Enable VPW processing */
+ { 0x47, AC_VERB_SET_COEF_INDEX, 0x0002 }, /* Configure GPIO 6,7 */
+ { 0x47, AC_VERB_SET_PROC_COEF, 0x0080 }, /* I2C mode */
+ { 0x47, AC_VERB_SET_COEF_INDEX, 0x005b }, /* Set I2C bus speed */
+ { 0x47, AC_VERB_SET_PROC_COEF, 0x0200 }, /* 100kHz I2C_STO = 2 */
+ {} /* terminator */
+};
+
+static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = {
+ { 0x24, 0x042120f0 }, /* ASP-1-TX */
+ { 0x34, 0x04a12050 }, /* ASP-1-RX */
+ { 0x2c, 0x901000f0 }, /* ASP-2-TX */
+ { 0x44, 0x90a00090 }, /* DMIC-1 */
+ {} /* terminator */
+};
+
+static const struct hda_verb cs8409_cs42l42_add_verbs[] = {
+ { 0x24, 0x71c, 0xF0 }, /* Widget node ASP-1-TX */
+ { 0x24, 0x71d, 0x20 },
+ { 0x24, 0x71e, 0x21 },
+ { 0x24, 0x71f, 0x04 },
+ { 0x34, 0x71c, 0x50 }, /* Widget node ASP-1-RX0 */
+ { 0x34, 0x71d, 0x20 },
+ { 0x34, 0x71e, 0xa1 },
+ { 0x34, 0x71f, 0x04 },
+ { 0x2C, 0x71c, 0xF0 }, /* Widget node ASP-2-TX */
+ { 0x2C, 0x71d, 0x00 },
+ { 0x2C, 0x71e, 0x10 },
+ { 0x2C, 0x71f, 0x90 },
+ { 0x44, 0x71c, 0x90 }, /* Widget node DMIC-1 */
+ { 0x44, 0x71d, 0x00 },
+ { 0x44, 0x71e, 0xA0 },
+ { 0x44, 0x71f, 0x90 },
+ {} /* terminator */
+};
+
+static const struct hda_fixup cs8409_fixups[] = {
+ [CS8409_BULLSEYE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cs8409_cs42l42_pincfgs,
+ .chained = true,
+ .chain_id = CS8409_VERBS,
+ },
+ [CS8409_WARLOCK] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cs8409_cs42l42_pincfgs,
+ .chained = true,
+ .chain_id = CS8409_VERBS,
+ },
+ [CS8409_CYBORG] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cs8409_cs42l42_pincfgs,
+ .chained = true,
+ .chain_id = CS8409_VERBS,
+ },
+ [CS8409_VERBS] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = cs8409_cs42l42_add_verbs,
+ },
+};
+
+/* Vendor specific HW configuration for CS42L42 */
+static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
+ { 0x1010, 0xB0 },
+ { 0x1D01, 0x00 },
+ { 0x1D02, 0x06 },
+ { 0x1D03, 0x00 },
+ { 0x1107, 0x01 },
+ { 0x1009, 0x02 },
+ { 0x1007, 0x03 },
+ { 0x1201, 0x00 },
+ { 0x1208, 0x13 },
+ { 0x1205, 0xFF },
+ { 0x1206, 0x00 },
+ { 0x1207, 0x20 },
+ { 0x1202, 0x0D },
+ { 0x2A02, 0x02 },
+ { 0x2A03, 0x00 },
+ { 0x2A04, 0x00 },
+ { 0x2A05, 0x02 },
+ { 0x2A06, 0x00 },
+ { 0x2A07, 0x20 },
+ { 0x2A08, 0x02 },
+ { 0x2A09, 0x00 },
+ { 0x2A0A, 0x80 },
+ { 0x2A0B, 0x02 },
+ { 0x2A0C, 0x00 },
+ { 0x2A0D, 0xA0 },
+ { 0x2A01, 0x0C },
+ { 0x2902, 0x01 },
+ { 0x2903, 0x02 },
+ { 0x2904, 0x00 },
+ { 0x2905, 0x00 },
+ { 0x2901, 0x01 },
+ { 0x1101, 0x0A },
+ { 0x1102, 0x84 },
+ { 0x2301, 0x00 },
+ { 0x2303, 0x00 },
+ { 0x2302, 0x3f },
+ { 0x2001, 0x03 },
+ { 0x1B75, 0xB6 },
+ { 0x1B73, 0xC2 },
+ { 0x1129, 0x01 },
+ { 0x1121, 0xF3 },
+ { 0x1103, 0x20 },
+ { 0x1105, 0x00 },
+ { 0x1112, 0xC0 },
+ { 0x1113, 0x80 },
+ { 0x1C03, 0xC0 },
+ { 0x1105, 0x00 },
+ { 0x1112, 0xC0 },
+ {} /* Terminator */
+};
+
+/* Vendor specific hw configuration for CS8409 */
+static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = {
+ { 0x47, 0x00, 0xb008 }, /* +PLL1/2_EN, +I2C_EN */
+ { 0x47, 0x01, 0x0002 }, /* ASP1/2_EN=0, ASP1_STP=1 */
+ { 0x47, 0x02, 0x0a80 }, /* ASP1/2_BUS_IDLE=10, +GPIO_I2C */
+ { 0x47, 0x19, 0x0800 }, /* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
+ { 0x47, 0x1a, 0x0820 }, /* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */
+ { 0x47, 0x29, 0x0800 }, /* ASP2.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
+ { 0x47, 0x2a, 0x2800 }, /* ASP2.A: TX.RAP=1, TX.RSZ=24 bits, TX.RCS=0 */
+ { 0x47, 0x39, 0x0800 }, /* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */
+ { 0x47, 0x3a, 0x0800 }, /* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */
+ { 0x47, 0x03, 0x8000 }, /* ASP1: LCHI = 00h */
+ { 0x47, 0x04, 0x28ff }, /* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */
+ { 0x47, 0x05, 0x0062 }, /* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */
+ { 0x47, 0x06, 0x801f }, /* ASP2: LCHI=1Fh */
+ { 0x47, 0x07, 0x283f }, /* ASP2: MC/SC_SRCSEL=PLL1, LCPR=3Fh */
+ { 0x47, 0x08, 0x805c }, /* ASP2: 5050=1, MCEN=0, FSD=010, SCPOL_IN/OUT=1, SCDIV=1:16 */
+ { 0x47, 0x09, 0x0023 }, /* DMIC1_MO=10b, DMIC1/2_SR=1 */
+ { 0x47, 0x0a, 0x0000 }, /* ASP1/2_BEEP=0 */
+ { 0x47, 0x01, 0x0062 }, /* ASP1/2_EN=1, ASP1_STP=1 */
+ { 0x47, 0x00, 0x9008 }, /* -PLL2_EN */
+ { 0x47, 0x68, 0x0000 }, /* TX2.A: pre-scale att.=0 dB */
+ { 0x47, 0x82, 0xfc03 }, /* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=1 */
+ { 0x47, 0xc0, 0x9999 }, /* test mode on */
+ { 0x47, 0xc5, 0x0000 }, /* GPIO hysteresis = 30 us */
+ { 0x47, 0xc0, 0x0000 }, /* test mode off */
+ {} /* Terminator */
+};
+
+/* Enable I2C clocks */
+static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int flag)
+{
+ unsigned int retval = 0;
+ unsigned int newval = 0;
+
+ retval = cs_vendor_coef_get(codec, 0x0);
+ newval = (flag) ? (retval | 0x8) : (retval & 0xfffffff7);
+ cs_vendor_coef_set(codec, 0x0, newval);
+}
+
+/* Wait I2C transaction */
+static int cs8409_i2c_wait_complete(struct hda_codec *codec)
+{
+ int repeat = 5;
+ unsigned int retval = 0;
+
+ do {
+ retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS);
+ if ((retval & 0x18) != 0x18) {
+ usleep_range(2000, 4000);
+ --repeat;
+ } else
+ break;
+
+ } while (repeat);
+
+ return repeat > 0 ? 0 : -1;
+}
+
+/* CS8409 slave i2cRead */
+static unsigned int cs8409_i2c_read(struct hda_codec *codec,
+ unsigned int i2c_address,
+ unsigned int i2c_reg,
+ unsigned int paged)
+{
+ unsigned int i2c_reg_data;
+ unsigned int retval;
+
+ cs8409_enable_i2c_clock(codec, 1);
+ cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
+
+ if (paged) {
+ cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
+ if (cs8409_i2c_wait_complete(codec) == -1) {
+ codec_err(codec,
+ "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
+ __func__, i2c_address, i2c_reg, retval);
+ }
+ }
+
+ i2c_reg_data = (i2c_reg << 8) & 0x0ffff;
+ cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data);
+ if (cs8409_i2c_wait_complete(codec) == -1) {
+ codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
+ __func__, i2c_address, i2c_reg, retval);
+ }
+
+ /* Register in bits 15-8 and the data in 7-0 */
+ retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
+ retval &= 0x0ff;
+
+ cs8409_enable_i2c_clock(codec, 0);
+
+ return retval;
+}
+
+/* CS8409 slave i2cWrite */
+static unsigned int cs8409_i2c_write(struct hda_codec *codec,
+ unsigned int i2c_address, unsigned int i2c_reg,
+ unsigned int i2c_data,
+ unsigned int paged)
+{
+ unsigned int retval = 0;
+ unsigned int i2c_reg_data = 0;
+
+ cs8409_enable_i2c_clock(codec, 1);
+ cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
+
+ if (paged) {
+ cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
+ if (cs8409_i2c_wait_complete(codec) == -1) {
+ codec_err(codec,
+ "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
+ __func__, i2c_address, i2c_reg, retval);
+ }
+ }
+
+ i2c_reg_data = ((i2c_reg << 8) & 0x0ff00) | (i2c_data & 0x0ff);
+ cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg_data);
+
+ if (cs8409_i2c_wait_complete(codec) == -1) {
+ codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
+ __func__, i2c_address, i2c_reg, retval);
+ }
+
+ cs8409_enable_i2c_clock(codec, 0);
+
+ return retval;
+}
+
+/* Assert/release RTS# line to CS42L42 */
+static void cs8409_cs42l42_reset(struct hda_codec *codec)
+{
+ /* Assert RTS# line */
+ snd_hda_codec_write(codec,
+ codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0);
+ /* wait ~10ms */
+ usleep_range(10000, 15000);
+ /* Release RTS# line */
+ snd_hda_codec_write(codec,
+ codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, GPIO5_INT);
+ /* wait ~10ms */
+ usleep_range(10000, 15000);
+
+ /* Clear interrupts status */
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1);
+
+}
+
+static void cs8409_cs42l42_reg_setup(struct hda_codec *codec)
+{
+ const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq;
+
+ for (; seq->addr; seq++)
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1);
+
+}
+
+static int cs8409_cs42l42_build_controls(struct hda_codec *codec)
+{
+ int err;
+
+ err = snd_hda_gen_build_controls(codec);
+ if (err < 0)
+ return err;
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/* Manage PDREF, when transition to D3hot */
+static int cs8409_suspend(struct hda_codec *codec)
+{
+ snd_hda_shutup_pins(codec);
+ return 0;
+}
+#endif
+
+/* Vendor specific HW configuration
+ * PLL, ASP, I2C, SPI, GPIOs, DMIC etc...
+ */
+static int cs8409_cs42l42_hw_init(struct hda_codec *codec)
+{
+ const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg;
+
+ for (; seq->nid; seq++)
+ cs_vendor_coef_set(codec, seq->cir, seq->coeff);
+
+ /* Reset CS42L42 */
+ cs8409_cs42l42_reset(codec);
+
+ /* Initialise CS42L42 companion codec */
+ cs8409_cs42l42_reg_setup(codec);
+
+ if (codec->fixup_id == CS8409_WARLOCK ||
+ codec->fixup_id == CS8409_CYBORG) {
+ /* FULL_SCALE_VOL = 0 for Warlock / Cyborg */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01, 1);
+ /* DMIC1_MO=00b, DMIC1/2_SR=1 */
+ cs_vendor_coef_set(codec, 0x09, 0x0003);
+ }
+
+ return 1;
+}
+
+static int cs8409_cs42l42_init(struct hda_codec *codec)
+{
+ int ret = 0;
+ struct cs_spec *spec = codec->spec;
+
+ ret = snd_hda_gen_init(codec);
+
+ if (spec->gpio_mask) {
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+ spec->gpio_mask);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+ spec->gpio_dir);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_data);
+ }
+
+ if (!ret) {
+ /* On Dell platforms with suspend D3 mode support we
+ * have to re-initialise cs8409 bridge and companion
+ * cs42l42 codec
+ */
+ snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs);
+ snd_hda_sequence_write(codec, cs8409_cs42l42_add_verbs);
+
+ cs8409_cs42l42_hw_init(codec);
+
+ }
+
+ return ret;
+}
+
+static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
+ .build_controls = cs8409_cs42l42_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = cs8409_cs42l42_init,
+ .free = cs_free,
+ .unsol_event = snd_hda_jack_unsol_event,
+#ifdef CONFIG_PM
+ .suspend = cs8409_suspend,
+#endif
+};
+
+static int cs8409_cs42l42_fixup(struct hda_codec *codec)
+{
+ int err = 0;
+ struct cs_spec *spec = codec->spec;
+ unsigned int pincap = 0;
+
+ /* Basic initial sequence for specific hw configuration */
+ snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs);
+
+ /* CS8409 is simple HDA bridge and intended to be used with a remote
+ * companion codec. Most of input/output PIN(s) have only basic
+ * capabilities. NID(s) 0x24 and 0x34 have only OUTC and INC
+ * capabilities and no presence detect capable (PDC) and call to
+ * snd_hda_gen_build_controls() will mark them as non detectable
+ * phantom jacks. However, in this configuration companion codec
+ * CS42L42 is connected to these pins and it has jack detect
+ * capabilities. We have to override pin capabilities,
+ * otherwise they will not be created as input devices.
+ */
+ _snd_hdac_read_parm(&codec->core,
+ CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, &pincap);
+
+ snd_hdac_override_parm(&codec->core,
+ CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP,
+ (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT)));
+
+ _snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID,
+ AC_PAR_PIN_CAP, &pincap);
+
+ snd_hdac_override_parm(&codec->core,
+ CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP,
+ (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT)));
+
+ snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID,
+ (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP));
+
+ snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID,
+ (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP));
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, 0, 0);
+ if (err < 0)
+ return err;
+
+ err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+ if (err < 0)
+ return err;
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return err;
+}
+
+static int patch_cs8409(struct hda_codec *codec)
+{
+ struct cs_spec *spec;
+ int err = -EINVAL;
+
+ spec = cs_alloc_spec(codec, CS8409_VENDOR_NID);
+ if (!spec)
+ return -ENOMEM;
+
+ snd_hda_pick_fixup(codec,
+ cs8409_models, cs8409_fixup_tbl, cs8409_fixups);
+
+ codec_dbg(codec, "Picked ID=%d, VID=%08x, DEV=%08x\n",
+ codec->fixup_id,
+ codec->bus->pci->subsystem_vendor,
+ codec->bus->pci->subsystem_device);
+
+ switch (codec->fixup_id) {
+ /* Dell platforms with CS42L42 companion codec */
+ case CS8409_BULLSEYE:
+ case CS8409_WARLOCK:
+ case CS8409_CYBORG:
+
+ snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs);
+
+ codec->patch_ops = cs8409_cs42l42_patch_ops;
+
+ spec->gen.suppress_auto_mute = 1;
+ spec->gen.no_primary_hp = 1;
+ /* GPIO 5 out, 3,4 in */
+ spec->gpio_dir = GPIO5_INT;
+ spec->gpio_data = 0;
+ spec->gpio_mask = 0x03f;
+
+ err = cs8409_cs42l42_fixup(codec);
+
+ if (err > 0)
+ err = cs8409_cs42l42_hw_init(codec);
+ break;
+
+ default:
+ codec_err(codec, "VID=%08x, DEV=%08x not supported\n",
+ codec->bus->pci->subsystem_vendor,
+ codec->bus->pci->subsystem_device);
+ break;
+ }
+ if (err < 0)
+ cs_free(codec);
+ else
+ snd_hda_codec_set_name(codec, "CS8409/CS42L42");
+
+ return err;
+}
/*
* patch entries
@@ -1229,6 +1801,7 @@ static const struct hda_device_id snd_hda_id_cirrus[] = {
HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208),
HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210),
HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213),
+ HDA_CODEC_ENTRY(0x10138409, "CS8409", patch_cs8409),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus);
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.
@ 2021-03-04 19:02 ` Vitaly Rodionov
0 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai; +Cc: patches, alsa-devel, linux-kernel
Dell's laptops Inspiron 3500, Inspiron 3501, Inspiron 3505 are using Cirrus Logic
CS8409 HDA bridge with CS42L42 companion codec.
The CS8409 is a multichannel HD audio routing controller.
CS8409 includes support for four channels of digital
microphone data and two bidirectional ASPs for up to 32
channels of TDM data or 4 channels of I2S data. The CS8409 is
intended to be used with a remote companion codec that implements
high performance analog functions in close physical
proximity to the end-equipment audio port or speaker driver.
The CS42L42 is a low-power audio codec with integrated MIPI
SoundWire interface or I2C/I2S/TDM interfaces designed
for portable applications. It provides a high-dynamic range,
stereo DAC for audio playback and a mono high-dynamic-range
ADC for audio capture
CS42L42 is connected to CS8409 HDA bridge via I2C and I2S.
CS8409 CS42L42
------- --------
ASP1.A TX --> ASP_SDIN
ASP1.A RX <-- ASP_SDOUT
GPIO5 --> RST#
GPIO4 <-- INT#
GPIO3 <-- WAKE#
GPIO7 <-> I2C SDA
GPIO6 --> I2C CLK
Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3505
This patch will register CS8409 with sound card and create
input/output paths and two input devices, initialise CS42L42
companion codec and configure it for ASP TX/RX TDM mode,
24bit, 48kHz.
cat /proc/asound/pcm
00-00: CS8409 Analog : CS8409 Analog : playback 1 : capture 1
00-03: HDMI 0 : HDMI 0 : playback 1
dmesg
snd_hda_codec_cirrus hdaudioC0D0: autoconfig for CS8409: line_outs=1 (0x2c/0x0/0x0/0x0/0x0) type:speaker
snd_hda_codec_cirrus hdaudioC0D0: speaker_outs=0 (0x0/0x0/0x0/0x0/0x0)
snd_hda_codec_cirrus hdaudioC0D0: hp_outs=1 (0x24/0x0/0x0/0x0/0x0)
snd_hda_codec_cirrus hdaudioC0D0: mono: mono_out=0x0
snd_hda_codec_cirrus hdaudioC0D0: inputs:
snd_hda_codec_cirrus hdaudioC0D0: Internal Mic=0x44
snd_hda_codec_cirrus hdaudioC0D0: Mic=0x34
input: HDA Intel PCH Headphone as /devices/pci0000:00/0000:00:1f.3/sound/card0/input8
input: HDA Intel PCH Headset Mic as /devices/pci0000:00/0000:00:1f.3/sound/card0/input9
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
---
sound/pci/hda/patch_cirrus.c | 573 +++++++++++++++++++++++++++++++++++
1 file changed, 573 insertions(+)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index f46204ab0b90..c95588681d53 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
+#include <linux/pci.h>
#include <sound/tlv.h>
#include <sound/hda_codec.h>
#include "hda_local.h"
@@ -1219,6 +1220,577 @@ static int patch_cs4213(struct hda_codec *codec)
return err;
}
+/* Cirrus Logic CS8409 HDA bridge with
+ * companion codec CS42L42
+ */
+#define CS8409_VENDOR_NID 0x47
+
+#define CS8409_CS42L42_HP_PIN_NID 0x24
+#define CS8409_CS42L42_SPK_PIN_NID 0x2c
+#define CS8409_CS42L42_AMIC_PIN_NID 0x34
+#define CS8409_CS42L42_DMIC_PIN_NID 0x44
+
+#define GPIO3_INT (1 << 3)
+#define GPIO4_INT (1 << 4)
+#define GPIO5_INT (1 << 5)
+
+#define CS42L42_I2C_ADDR (0x48 << 1)
+
+#define CIR_I2C_ADDR 0x0059
+#define CIR_I2C_DATA 0x005A
+#define CIR_I2C_CTRL 0x005B
+#define CIR_I2C_STATUS 0x005C
+#define CIR_I2C_QWRITE 0x005D
+#define CIR_I2C_QREAD 0x005E
+
+struct cs8409_i2c_param {
+ unsigned int addr;
+ unsigned int reg;
+};
+
+struct cs8409_cir_param {
+ unsigned int nid;
+ unsigned int cir;
+ unsigned int coeff;
+};
+
+enum {
+ CS8409_BULLSEYE,
+ CS8409_WARLOCK,
+ CS8409_CYBORG,
+ CS8409_VERBS,
+};
+
+/* Dell Inspiron models with cs8409/cs42l42 */
+static const struct hda_model_fixup cs8409_models[] = {
+ { .id = CS8409_BULLSEYE, .name = "bullseye" },
+ { .id = CS8409_WARLOCK, .name = "warlock" },
+ { .id = CS8409_CYBORG, .name = "cyborg" },
+ {}
+};
+
+/* Dell Inspiron platforms
+ * with cs8409 bridge and cs42l42 codec
+ */
+static const struct snd_pci_quirk cs8409_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A24, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A25, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A29, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A2A, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0A2B, "Bullseye", CS8409_BULLSEYE),
+ SND_PCI_QUIRK(0x1028, 0x0AB0, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB2, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB1, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB3, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB4, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AB5, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AD9, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0ADA, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0ADB, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK),
+ SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A7A, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A7D, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A7E, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A7F, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0A80, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0ADF, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AE0, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AE1, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AE2, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AE9, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEA, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEB, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEC, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AED, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEE, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AEF, "Cyborg", CS8409_CYBORG),
+ SND_PCI_QUIRK(0x1028, 0x0AF0, "Cyborg", CS8409_CYBORG),
+ {} /* terminator */
+};
+
+static const struct hda_verb cs8409_cs42l42_init_verbs[] = {
+ { 0x01, AC_VERB_SET_GPIO_WAKE_MASK, 0x0018 }, /* WAKE from GPIO 3,4 */
+ { 0x47, AC_VERB_SET_PROC_STATE, 0x0001 }, /* Enable VPW processing */
+ { 0x47, AC_VERB_SET_COEF_INDEX, 0x0002 }, /* Configure GPIO 6,7 */
+ { 0x47, AC_VERB_SET_PROC_COEF, 0x0080 }, /* I2C mode */
+ { 0x47, AC_VERB_SET_COEF_INDEX, 0x005b }, /* Set I2C bus speed */
+ { 0x47, AC_VERB_SET_PROC_COEF, 0x0200 }, /* 100kHz I2C_STO = 2 */
+ {} /* terminator */
+};
+
+static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = {
+ { 0x24, 0x042120f0 }, /* ASP-1-TX */
+ { 0x34, 0x04a12050 }, /* ASP-1-RX */
+ { 0x2c, 0x901000f0 }, /* ASP-2-TX */
+ { 0x44, 0x90a00090 }, /* DMIC-1 */
+ {} /* terminator */
+};
+
+static const struct hda_verb cs8409_cs42l42_add_verbs[] = {
+ { 0x24, 0x71c, 0xF0 }, /* Widget node ASP-1-TX */
+ { 0x24, 0x71d, 0x20 },
+ { 0x24, 0x71e, 0x21 },
+ { 0x24, 0x71f, 0x04 },
+ { 0x34, 0x71c, 0x50 }, /* Widget node ASP-1-RX0 */
+ { 0x34, 0x71d, 0x20 },
+ { 0x34, 0x71e, 0xa1 },
+ { 0x34, 0x71f, 0x04 },
+ { 0x2C, 0x71c, 0xF0 }, /* Widget node ASP-2-TX */
+ { 0x2C, 0x71d, 0x00 },
+ { 0x2C, 0x71e, 0x10 },
+ { 0x2C, 0x71f, 0x90 },
+ { 0x44, 0x71c, 0x90 }, /* Widget node DMIC-1 */
+ { 0x44, 0x71d, 0x00 },
+ { 0x44, 0x71e, 0xA0 },
+ { 0x44, 0x71f, 0x90 },
+ {} /* terminator */
+};
+
+static const struct hda_fixup cs8409_fixups[] = {
+ [CS8409_BULLSEYE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cs8409_cs42l42_pincfgs,
+ .chained = true,
+ .chain_id = CS8409_VERBS,
+ },
+ [CS8409_WARLOCK] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cs8409_cs42l42_pincfgs,
+ .chained = true,
+ .chain_id = CS8409_VERBS,
+ },
+ [CS8409_CYBORG] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cs8409_cs42l42_pincfgs,
+ .chained = true,
+ .chain_id = CS8409_VERBS,
+ },
+ [CS8409_VERBS] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = cs8409_cs42l42_add_verbs,
+ },
+};
+
+/* Vendor specific HW configuration for CS42L42 */
+static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
+ { 0x1010, 0xB0 },
+ { 0x1D01, 0x00 },
+ { 0x1D02, 0x06 },
+ { 0x1D03, 0x00 },
+ { 0x1107, 0x01 },
+ { 0x1009, 0x02 },
+ { 0x1007, 0x03 },
+ { 0x1201, 0x00 },
+ { 0x1208, 0x13 },
+ { 0x1205, 0xFF },
+ { 0x1206, 0x00 },
+ { 0x1207, 0x20 },
+ { 0x1202, 0x0D },
+ { 0x2A02, 0x02 },
+ { 0x2A03, 0x00 },
+ { 0x2A04, 0x00 },
+ { 0x2A05, 0x02 },
+ { 0x2A06, 0x00 },
+ { 0x2A07, 0x20 },
+ { 0x2A08, 0x02 },
+ { 0x2A09, 0x00 },
+ { 0x2A0A, 0x80 },
+ { 0x2A0B, 0x02 },
+ { 0x2A0C, 0x00 },
+ { 0x2A0D, 0xA0 },
+ { 0x2A01, 0x0C },
+ { 0x2902, 0x01 },
+ { 0x2903, 0x02 },
+ { 0x2904, 0x00 },
+ { 0x2905, 0x00 },
+ { 0x2901, 0x01 },
+ { 0x1101, 0x0A },
+ { 0x1102, 0x84 },
+ { 0x2301, 0x00 },
+ { 0x2303, 0x00 },
+ { 0x2302, 0x3f },
+ { 0x2001, 0x03 },
+ { 0x1B75, 0xB6 },
+ { 0x1B73, 0xC2 },
+ { 0x1129, 0x01 },
+ { 0x1121, 0xF3 },
+ { 0x1103, 0x20 },
+ { 0x1105, 0x00 },
+ { 0x1112, 0xC0 },
+ { 0x1113, 0x80 },
+ { 0x1C03, 0xC0 },
+ { 0x1105, 0x00 },
+ { 0x1112, 0xC0 },
+ {} /* Terminator */
+};
+
+/* Vendor specific hw configuration for CS8409 */
+static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = {
+ { 0x47, 0x00, 0xb008 }, /* +PLL1/2_EN, +I2C_EN */
+ { 0x47, 0x01, 0x0002 }, /* ASP1/2_EN=0, ASP1_STP=1 */
+ { 0x47, 0x02, 0x0a80 }, /* ASP1/2_BUS_IDLE=10, +GPIO_I2C */
+ { 0x47, 0x19, 0x0800 }, /* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
+ { 0x47, 0x1a, 0x0820 }, /* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */
+ { 0x47, 0x29, 0x0800 }, /* ASP2.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
+ { 0x47, 0x2a, 0x2800 }, /* ASP2.A: TX.RAP=1, TX.RSZ=24 bits, TX.RCS=0 */
+ { 0x47, 0x39, 0x0800 }, /* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */
+ { 0x47, 0x3a, 0x0800 }, /* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */
+ { 0x47, 0x03, 0x8000 }, /* ASP1: LCHI = 00h */
+ { 0x47, 0x04, 0x28ff }, /* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */
+ { 0x47, 0x05, 0x0062 }, /* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */
+ { 0x47, 0x06, 0x801f }, /* ASP2: LCHI=1Fh */
+ { 0x47, 0x07, 0x283f }, /* ASP2: MC/SC_SRCSEL=PLL1, LCPR=3Fh */
+ { 0x47, 0x08, 0x805c }, /* ASP2: 5050=1, MCEN=0, FSD=010, SCPOL_IN/OUT=1, SCDIV=1:16 */
+ { 0x47, 0x09, 0x0023 }, /* DMIC1_MO=10b, DMIC1/2_SR=1 */
+ { 0x47, 0x0a, 0x0000 }, /* ASP1/2_BEEP=0 */
+ { 0x47, 0x01, 0x0062 }, /* ASP1/2_EN=1, ASP1_STP=1 */
+ { 0x47, 0x00, 0x9008 }, /* -PLL2_EN */
+ { 0x47, 0x68, 0x0000 }, /* TX2.A: pre-scale att.=0 dB */
+ { 0x47, 0x82, 0xfc03 }, /* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=1 */
+ { 0x47, 0xc0, 0x9999 }, /* test mode on */
+ { 0x47, 0xc5, 0x0000 }, /* GPIO hysteresis = 30 us */
+ { 0x47, 0xc0, 0x0000 }, /* test mode off */
+ {} /* Terminator */
+};
+
+/* Enable I2C clocks */
+static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int flag)
+{
+ unsigned int retval = 0;
+ unsigned int newval = 0;
+
+ retval = cs_vendor_coef_get(codec, 0x0);
+ newval = (flag) ? (retval | 0x8) : (retval & 0xfffffff7);
+ cs_vendor_coef_set(codec, 0x0, newval);
+}
+
+/* Wait I2C transaction */
+static int cs8409_i2c_wait_complete(struct hda_codec *codec)
+{
+ int repeat = 5;
+ unsigned int retval = 0;
+
+ do {
+ retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS);
+ if ((retval & 0x18) != 0x18) {
+ usleep_range(2000, 4000);
+ --repeat;
+ } else
+ break;
+
+ } while (repeat);
+
+ return repeat > 0 ? 0 : -1;
+}
+
+/* CS8409 slave i2cRead */
+static unsigned int cs8409_i2c_read(struct hda_codec *codec,
+ unsigned int i2c_address,
+ unsigned int i2c_reg,
+ unsigned int paged)
+{
+ unsigned int i2c_reg_data;
+ unsigned int retval;
+
+ cs8409_enable_i2c_clock(codec, 1);
+ cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
+
+ if (paged) {
+ cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
+ if (cs8409_i2c_wait_complete(codec) == -1) {
+ codec_err(codec,
+ "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
+ __func__, i2c_address, i2c_reg, retval);
+ }
+ }
+
+ i2c_reg_data = (i2c_reg << 8) & 0x0ffff;
+ cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data);
+ if (cs8409_i2c_wait_complete(codec) == -1) {
+ codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
+ __func__, i2c_address, i2c_reg, retval);
+ }
+
+ /* Register in bits 15-8 and the data in 7-0 */
+ retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
+ retval &= 0x0ff;
+
+ cs8409_enable_i2c_clock(codec, 0);
+
+ return retval;
+}
+
+/* CS8409 slave i2cWrite */
+static unsigned int cs8409_i2c_write(struct hda_codec *codec,
+ unsigned int i2c_address, unsigned int i2c_reg,
+ unsigned int i2c_data,
+ unsigned int paged)
+{
+ unsigned int retval = 0;
+ unsigned int i2c_reg_data = 0;
+
+ cs8409_enable_i2c_clock(codec, 1);
+ cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
+
+ if (paged) {
+ cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
+ if (cs8409_i2c_wait_complete(codec) == -1) {
+ codec_err(codec,
+ "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
+ __func__, i2c_address, i2c_reg, retval);
+ }
+ }
+
+ i2c_reg_data = ((i2c_reg << 8) & 0x0ff00) | (i2c_data & 0x0ff);
+ cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg_data);
+
+ if (cs8409_i2c_wait_complete(codec) == -1) {
+ codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
+ __func__, i2c_address, i2c_reg, retval);
+ }
+
+ cs8409_enable_i2c_clock(codec, 0);
+
+ return retval;
+}
+
+/* Assert/release RTS# line to CS42L42 */
+static void cs8409_cs42l42_reset(struct hda_codec *codec)
+{
+ /* Assert RTS# line */
+ snd_hda_codec_write(codec,
+ codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0);
+ /* wait ~10ms */
+ usleep_range(10000, 15000);
+ /* Release RTS# line */
+ snd_hda_codec_write(codec,
+ codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, GPIO5_INT);
+ /* wait ~10ms */
+ usleep_range(10000, 15000);
+
+ /* Clear interrupts status */
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1);
+
+}
+
+static void cs8409_cs42l42_reg_setup(struct hda_codec *codec)
+{
+ const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq;
+
+ for (; seq->addr; seq++)
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1);
+
+}
+
+static int cs8409_cs42l42_build_controls(struct hda_codec *codec)
+{
+ int err;
+
+ err = snd_hda_gen_build_controls(codec);
+ if (err < 0)
+ return err;
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/* Manage PDREF, when transition to D3hot */
+static int cs8409_suspend(struct hda_codec *codec)
+{
+ snd_hda_shutup_pins(codec);
+ return 0;
+}
+#endif
+
+/* Vendor specific HW configuration
+ * PLL, ASP, I2C, SPI, GPIOs, DMIC etc...
+ */
+static int cs8409_cs42l42_hw_init(struct hda_codec *codec)
+{
+ const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg;
+
+ for (; seq->nid; seq++)
+ cs_vendor_coef_set(codec, seq->cir, seq->coeff);
+
+ /* Reset CS42L42 */
+ cs8409_cs42l42_reset(codec);
+
+ /* Initialise CS42L42 companion codec */
+ cs8409_cs42l42_reg_setup(codec);
+
+ if (codec->fixup_id == CS8409_WARLOCK ||
+ codec->fixup_id == CS8409_CYBORG) {
+ /* FULL_SCALE_VOL = 0 for Warlock / Cyborg */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01, 1);
+ /* DMIC1_MO=00b, DMIC1/2_SR=1 */
+ cs_vendor_coef_set(codec, 0x09, 0x0003);
+ }
+
+ return 1;
+}
+
+static int cs8409_cs42l42_init(struct hda_codec *codec)
+{
+ int ret = 0;
+ struct cs_spec *spec = codec->spec;
+
+ ret = snd_hda_gen_init(codec);
+
+ if (spec->gpio_mask) {
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+ spec->gpio_mask);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+ spec->gpio_dir);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_data);
+ }
+
+ if (!ret) {
+ /* On Dell platforms with suspend D3 mode support we
+ * have to re-initialise cs8409 bridge and companion
+ * cs42l42 codec
+ */
+ snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs);
+ snd_hda_sequence_write(codec, cs8409_cs42l42_add_verbs);
+
+ cs8409_cs42l42_hw_init(codec);
+
+ }
+
+ return ret;
+}
+
+static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
+ .build_controls = cs8409_cs42l42_build_controls,
+ .build_pcms = snd_hda_gen_build_pcms,
+ .init = cs8409_cs42l42_init,
+ .free = cs_free,
+ .unsol_event = snd_hda_jack_unsol_event,
+#ifdef CONFIG_PM
+ .suspend = cs8409_suspend,
+#endif
+};
+
+static int cs8409_cs42l42_fixup(struct hda_codec *codec)
+{
+ int err = 0;
+ struct cs_spec *spec = codec->spec;
+ unsigned int pincap = 0;
+
+ /* Basic initial sequence for specific hw configuration */
+ snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs);
+
+ /* CS8409 is simple HDA bridge and intended to be used with a remote
+ * companion codec. Most of input/output PIN(s) have only basic
+ * capabilities. NID(s) 0x24 and 0x34 have only OUTC and INC
+ * capabilities and no presence detect capable (PDC) and call to
+ * snd_hda_gen_build_controls() will mark them as non detectable
+ * phantom jacks. However, in this configuration companion codec
+ * CS42L42 is connected to these pins and it has jack detect
+ * capabilities. We have to override pin capabilities,
+ * otherwise they will not be created as input devices.
+ */
+ _snd_hdac_read_parm(&codec->core,
+ CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, &pincap);
+
+ snd_hdac_override_parm(&codec->core,
+ CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP,
+ (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT)));
+
+ _snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID,
+ AC_PAR_PIN_CAP, &pincap);
+
+ snd_hdac_override_parm(&codec->core,
+ CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP,
+ (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT)));
+
+ snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID,
+ (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP));
+
+ snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID,
+ (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP));
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, 0, 0);
+ if (err < 0)
+ return err;
+
+ err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+ if (err < 0)
+ return err;
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return err;
+}
+
+static int patch_cs8409(struct hda_codec *codec)
+{
+ struct cs_spec *spec;
+ int err = -EINVAL;
+
+ spec = cs_alloc_spec(codec, CS8409_VENDOR_NID);
+ if (!spec)
+ return -ENOMEM;
+
+ snd_hda_pick_fixup(codec,
+ cs8409_models, cs8409_fixup_tbl, cs8409_fixups);
+
+ codec_dbg(codec, "Picked ID=%d, VID=%08x, DEV=%08x\n",
+ codec->fixup_id,
+ codec->bus->pci->subsystem_vendor,
+ codec->bus->pci->subsystem_device);
+
+ switch (codec->fixup_id) {
+ /* Dell platforms with CS42L42 companion codec */
+ case CS8409_BULLSEYE:
+ case CS8409_WARLOCK:
+ case CS8409_CYBORG:
+
+ snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs);
+
+ codec->patch_ops = cs8409_cs42l42_patch_ops;
+
+ spec->gen.suppress_auto_mute = 1;
+ spec->gen.no_primary_hp = 1;
+ /* GPIO 5 out, 3,4 in */
+ spec->gpio_dir = GPIO5_INT;
+ spec->gpio_data = 0;
+ spec->gpio_mask = 0x03f;
+
+ err = cs8409_cs42l42_fixup(codec);
+
+ if (err > 0)
+ err = cs8409_cs42l42_hw_init(codec);
+ break;
+
+ default:
+ codec_err(codec, "VID=%08x, DEV=%08x not supported\n",
+ codec->bus->pci->subsystem_vendor,
+ codec->bus->pci->subsystem_device);
+ break;
+ }
+ if (err < 0)
+ cs_free(codec);
+ else
+ snd_hda_codec_set_name(codec, "CS8409/CS42L42");
+
+ return err;
+}
/*
* patch entries
@@ -1229,6 +1801,7 @@ static const struct hda_device_id snd_hda_id_cirrus[] = {
HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208),
HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210),
HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213),
+ HDA_CODEC_ENTRY(0x10138409, "CS8409", patch_cs8409),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus);
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.
2021-03-04 19:02 ` Vitaly Rodionov
@ 2021-03-04 19:02 ` Vitaly Rodionov
-1 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai; +Cc: alsa-devel, patches, linux-kernel
In the case of CS8409 we do not have unsol events from NID's 0x24 and 0x34
where hs mic and hp are connected. Companion codec CS42L42 will generate
interrupt via gpio 4 to notify jack events. We have to overwrite standard
snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers and
then notify status via generic snd_hda_jack_unsol_event() call.
Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3505.
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
---
sound/pci/hda/patch_cirrus.c | 304 ++++++++++++++++++++++++++++++++++-
1 file changed, 302 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index c95588681d53..0b8980240176 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <sound/tlv.h>
#include <sound/hda_codec.h>
@@ -38,6 +39,15 @@ struct cs_spec {
/* for MBP SPDIF control */
int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+
+ unsigned int cs42l42_hp_jack_in:1;
+ unsigned int cs42l42_mic_jack_in:1;
+
+ struct mutex cs8409_i2c_mux;
+
+ /* verb exec op override */
+ int (*exec_verb)(struct hdac_device *dev, unsigned int cmd,
+ unsigned int flags, unsigned int *res);
};
/* available models with CS420x */
@@ -1229,6 +1239,13 @@ static int patch_cs4213(struct hda_codec *codec)
#define CS8409_CS42L42_SPK_PIN_NID 0x2c
#define CS8409_CS42L42_AMIC_PIN_NID 0x34
#define CS8409_CS42L42_DMIC_PIN_NID 0x44
+#define CS8409_CS42L42_DMIC_ADC_PIN_NID 0x22
+
+#define CS42L42_HSDET_AUTO_DONE 0x02
+#define CS42L42_HSTYPE_MASK 0x03
+
+#define CS42L42_JACK_INSERTED 0x0C
+#define CS42L42_JACK_REMOVED 0x00
#define GPIO3_INT (1 << 3)
#define GPIO4_INT (1 << 4)
@@ -1429,6 +1446,7 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
{ 0x1C03, 0xC0 },
{ 0x1105, 0x00 },
{ 0x1112, 0xC0 },
+ { 0x1101, 0x02 },
{} /* Terminator */
};
@@ -1565,6 +1583,8 @@ static unsigned int cs8409_i2c_write(struct hda_codec *codec,
/* Assert/release RTS# line to CS42L42 */
static void cs8409_cs42l42_reset(struct hda_codec *codec)
{
+ struct cs_spec *spec = codec->spec;
+
/* Assert RTS# line */
snd_hda_codec_write(codec,
codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0);
@@ -1576,21 +1596,184 @@ static void cs8409_cs42l42_reset(struct hda_codec *codec)
/* wait ~10ms */
usleep_range(10000, 15000);
- /* Clear interrupts status */
+ mutex_lock(&spec->cs8409_i2c_mux);
+
+ /* Clear interrupts, by reading interrupt status registers */
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1);
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1);
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1);
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
+}
+
+/* Configure CS42L42 slave codec for jack autodetect */
+static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+
+ /* Set TIP_SENSE_EN for analog front-end of tip sense. */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x0020, 1);
+ /* Clear WAKE# */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0001, 1);
+ /* Wait ~2.5ms */
+ usleep_range(2500, 3000);
+ /* Set mode WAKE# output follows the combination logic directly */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0020, 1);
+ /* Clear interrupts status */
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
+ /* Enable interrupt */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0x03, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b79, 0x00, 1);
+
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
+ return 0;
+}
+
+/* Enable and run CS42L42 slave codec jack auto detect */
+static void cs8409_cs42l42_run_jack_detect(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+
+ /* Clear interrupts */
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b77, 1);
+
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1102, 0x87, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1f06, 0x86, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b74, 0x07, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0x01, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0x80, 1);
+ /* Wait ~110ms*/
+ usleep_range(110000, 200000);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0, 1);
+ /* Wait ~10ms */
+ usleep_range(10000, 25000);
+
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
}
static void cs8409_cs42l42_reg_setup(struct hda_codec *codec)
{
const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq;
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
for (; seq->addr; seq++)
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1);
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
+}
+
+/*
+ * In the case of CS8409 we do not have unsolicited events from NID's 0x24
+ * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will
+ * generate interrupt via gpio 4 to notify jack events. We have to overwrite
+ * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
+ * and then notify status via generic snd_hda_jack_unsol_event() call.
+ */
+void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ struct cs_spec *spec = codec->spec;
+ int status_changed = 0;
+ unsigned int reg_cdc_status = 0;
+ unsigned int reg_hs_status = 0;
+ unsigned int reg_ts_status = 0;
+ int type = 0;
+ struct hda_jack_tbl *jk;
+
+ /* jack_unsol_event() will be called every time gpio line changing state.
+ * In this case gpio4 line goes up as a result of reading interrupt status
+ * registers in previous cs8409_jack_unsol_event() call.
+ * We don't need to handle this event, ignoring...
+ */
+ if ((res & (1 << 4)))
+ return;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+
+ /* Read jack detect status registers */
+ reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
+ reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1);
+ reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
+
+ /* Clear interrupts */
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
+
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
+ /* HSDET_AUTO_DONE */
+ if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) {
+
+ type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
+ /* CS42L42 reports optical jack as type 4
+ * We don't handle optical jack
+ */
+ if (type != 4) {
+ if (!spec->cs42l42_hp_jack_in) {
+ status_changed = 1;
+ spec->cs42l42_hp_jack_in = 1;
+ }
+ /* type = 3 has no mic */
+ if ((!spec->cs42l42_mic_jack_in) && (type != 3)) {
+ status_changed = 1;
+ spec->cs42l42_mic_jack_in = 1;
+ }
+ }
+
+ } else {
+ /* TIP_SENSE INSERT/REMOVE */
+ switch (reg_ts_status) {
+ case CS42L42_JACK_INSERTED:
+ cs8409_cs42l42_run_jack_detect(codec);
+ break;
+
+ case CS42L42_JACK_REMOVED:
+ if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) {
+ status_changed = 1;
+ spec->cs42l42_hp_jack_in = 0;
+ spec->cs42l42_mic_jack_in = 0;
+ }
+ break;
+
+ default:
+ /* jack in transition */
+ status_changed = 0;
+ break;
+ }
+ }
+
+ if (status_changed) {
+
+ snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
+ (spec->cs42l42_hp_jack_in)?0 : PIN_OUT);
+
+ /* Report jack*/
+ jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
+ if (jk) {
+ snd_hda_jack_unsol_event(codec,
+ (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
+ }
+ /* Report jack*/
+ jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0);
+ if (jk) {
+ snd_hda_jack_unsol_event(codec,
+ (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
+ }
+ }
}
static int cs8409_cs42l42_build_controls(struct hda_codec *codec)
@@ -1603,6 +1786,13 @@ static int cs8409_cs42l42_build_controls(struct hda_codec *codec)
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+ /* Run jack auto detect first time on boot
+ * after controls have been added, to check if jack has
+ * been already plugged in
+ */
+ cs8409_cs42l42_run_jack_detect(codec);
+ usleep_range(100000, 150000);
+
return 0;
}
@@ -1610,21 +1800,72 @@ static int cs8409_cs42l42_build_controls(struct hda_codec *codec)
/* Manage PDREF, when transition to D3hot */
static int cs8409_suspend(struct hda_codec *codec)
{
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+ /* Power down CS42L42 ASP/EQ/MIX/HP */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1101, 0xfe, 1);
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
snd_hda_shutup_pins(codec);
+
return 0;
}
#endif
+static void cs8409_cs42l42_cap_sync_hook(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs_spec *spec = codec->spec;
+ unsigned int curval, expval;
+ /* CS8409 DMIC Pin only allows the setting of the Stream Parameters in
+ * Power State D0. When a headset is unplugged, and the path is switched to
+ * the DMIC, the Stream is restarted with the new ADC, but this is done in
+ * Power State D3. Restart the Stream now DMIC is in D0.
+ */
+ if (spec->gen.cur_adc == CS8409_CS42L42_DMIC_ADC_PIN_NID) {
+ curval = snd_hda_codec_read(codec, spec->gen.cur_adc,
+ 0, AC_VERB_GET_CONV, 0);
+ expval = (spec->gen.cur_adc_stream_tag << 4) | 0;
+ if (curval != expval) {
+ codec_dbg(codec, "%s Restarting Stream after DMIC switch\n", __func__);
+ __snd_hda_codec_cleanup_stream(codec, spec->gen.cur_adc, 1);
+ snd_hda_codec_setup_stream(codec, spec->gen.cur_adc,
+ spec->gen.cur_adc_stream_tag, 0,
+ spec->gen.cur_adc_format);
+ }
+ }
+}
+
+/* Enable/Disable Unsolicited Response for gpio(s) 3,4 */
+static void cs8409_enable_ur(struct hda_codec *codec, int flag)
+{
+ /* GPIO4 INT# and GPIO3 WAKE# */
+ snd_hda_codec_write(codec, codec->core.afg,
+ 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK,
+ flag?(GPIO3_INT | GPIO4_INT) : 0);
+
+ snd_hda_codec_write(codec, codec->core.afg,
+ 0, AC_VERB_SET_UNSOLICITED_ENABLE,
+ flag?AC_UNSOL_ENABLED : 0);
+
+}
+
/* Vendor specific HW configuration
* PLL, ASP, I2C, SPI, GPIOs, DMIC etc...
*/
static int cs8409_cs42l42_hw_init(struct hda_codec *codec)
{
const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg;
+ struct cs_spec *spec = codec->spec;
for (; seq->nid; seq++)
cs_vendor_coef_set(codec, seq->cir, seq->coeff);
+ /* Disable Unsolicited Response during boot */
+ cs8409_enable_ur(codec, 0);
+
/* Reset CS42L42 */
cs8409_cs42l42_reset(codec);
@@ -1634,11 +1875,18 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec)
if (codec->fixup_id == CS8409_WARLOCK ||
codec->fixup_id == CS8409_CYBORG) {
/* FULL_SCALE_VOL = 0 for Warlock / Cyborg */
+ mutex_lock(&spec->cs8409_i2c_mux);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01, 1);
+ mutex_unlock(&spec->cs8409_i2c_mux);
/* DMIC1_MO=00b, DMIC1/2_SR=1 */
cs_vendor_coef_set(codec, 0x09, 0x0003);
}
+ cs8409_cs42l42_enable_jack_detect(codec);
+
+ /* Enable Unsolicited Response */
+ cs8409_enable_ur(codec, 1);
+
return 1;
}
@@ -1668,6 +1916,8 @@ static int cs8409_cs42l42_init(struct hda_codec *codec)
cs8409_cs42l42_hw_init(codec);
+ cs8409_cs42l42_run_jack_detect(codec);
+ usleep_range(100000, 150000);
}
return ret;
@@ -1678,7 +1928,7 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
.build_pcms = snd_hda_gen_build_pcms,
.init = cs8409_cs42l42_init,
.free = cs_free,
- .unsol_event = snd_hda_jack_unsol_event,
+ .unsol_event = cs8409_jack_unsol_event,
#ifdef CONFIG_PM
.suspend = cs8409_suspend,
#endif
@@ -1738,6 +1988,45 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec)
return err;
}
+static int cs8409_cs42l42_exec_verb(struct hdac_device *dev,
+ unsigned int cmd, unsigned int flags, unsigned int *res)
+{
+ struct hda_codec *codec = container_of(dev, struct hda_codec, core);
+ struct cs_spec *spec = codec->spec;
+
+ unsigned int nid = 0;
+ unsigned int verb = 0;
+
+ nid = ((cmd >> 20) & 0x07f);
+ verb = ((cmd >> 8) & 0x0fff);
+
+ /* CS8409 pins have no AC_PINSENSE_PRESENCE
+ * capabilities. We have to intercept 2 calls for pins 0x24 and 0x34
+ * and return correct pin sense values for read_pin_sense() call from
+ * hda_jack based on CS42L42 jack detect status.
+ */
+ switch (nid) {
+ case CS8409_CS42L42_HP_PIN_NID:
+ if (verb == AC_VERB_GET_PIN_SENSE) {
+ *res = (spec->cs42l42_hp_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+ return 0;
+ }
+ break;
+
+ case CS8409_CS42L42_AMIC_PIN_NID:
+ if (verb == AC_VERB_GET_PIN_SENSE) {
+ *res = (spec->cs42l42_mic_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+ return 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return spec->exec_verb(dev, cmd, flags, res);
+}
+
static int patch_cs8409(struct hda_codec *codec)
{
struct cs_spec *spec;
@@ -1763,8 +2052,16 @@ static int patch_cs8409(struct hda_codec *codec)
snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs);
+ /* verb exec op override */
+ spec->exec_verb = codec->core.exec_verb;
+ codec->core.exec_verb = cs8409_cs42l42_exec_verb;
+
+ mutex_init(&spec->cs8409_i2c_mux);
+
codec->patch_ops = cs8409_cs42l42_patch_ops;
+ spec->gen.cap_sync_hook = cs8409_cs42l42_cap_sync_hook;
+
spec->gen.suppress_auto_mute = 1;
spec->gen.no_primary_hp = 1;
/* GPIO 5 out, 3,4 in */
@@ -1772,6 +2069,9 @@ static int patch_cs8409(struct hda_codec *codec)
spec->gpio_data = 0;
spec->gpio_mask = 0x03f;
+ spec->cs42l42_hp_jack_in = 0;
+ spec->cs42l42_mic_jack_in = 0;
+
err = cs8409_cs42l42_fixup(codec);
if (err > 0)
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.
@ 2021-03-04 19:02 ` Vitaly Rodionov
0 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai; +Cc: patches, alsa-devel, linux-kernel
In the case of CS8409 we do not have unsol events from NID's 0x24 and 0x34
where hs mic and hp are connected. Companion codec CS42L42 will generate
interrupt via gpio 4 to notify jack events. We have to overwrite standard
snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers and
then notify status via generic snd_hda_jack_unsol_event() call.
Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3505.
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
---
sound/pci/hda/patch_cirrus.c | 304 ++++++++++++++++++++++++++++++++++-
1 file changed, 302 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index c95588681d53..0b8980240176 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <sound/tlv.h>
#include <sound/hda_codec.h>
@@ -38,6 +39,15 @@ struct cs_spec {
/* for MBP SPDIF control */
int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+
+ unsigned int cs42l42_hp_jack_in:1;
+ unsigned int cs42l42_mic_jack_in:1;
+
+ struct mutex cs8409_i2c_mux;
+
+ /* verb exec op override */
+ int (*exec_verb)(struct hdac_device *dev, unsigned int cmd,
+ unsigned int flags, unsigned int *res);
};
/* available models with CS420x */
@@ -1229,6 +1239,13 @@ static int patch_cs4213(struct hda_codec *codec)
#define CS8409_CS42L42_SPK_PIN_NID 0x2c
#define CS8409_CS42L42_AMIC_PIN_NID 0x34
#define CS8409_CS42L42_DMIC_PIN_NID 0x44
+#define CS8409_CS42L42_DMIC_ADC_PIN_NID 0x22
+
+#define CS42L42_HSDET_AUTO_DONE 0x02
+#define CS42L42_HSTYPE_MASK 0x03
+
+#define CS42L42_JACK_INSERTED 0x0C
+#define CS42L42_JACK_REMOVED 0x00
#define GPIO3_INT (1 << 3)
#define GPIO4_INT (1 << 4)
@@ -1429,6 +1446,7 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
{ 0x1C03, 0xC0 },
{ 0x1105, 0x00 },
{ 0x1112, 0xC0 },
+ { 0x1101, 0x02 },
{} /* Terminator */
};
@@ -1565,6 +1583,8 @@ static unsigned int cs8409_i2c_write(struct hda_codec *codec,
/* Assert/release RTS# line to CS42L42 */
static void cs8409_cs42l42_reset(struct hda_codec *codec)
{
+ struct cs_spec *spec = codec->spec;
+
/* Assert RTS# line */
snd_hda_codec_write(codec,
codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0);
@@ -1576,21 +1596,184 @@ static void cs8409_cs42l42_reset(struct hda_codec *codec)
/* wait ~10ms */
usleep_range(10000, 15000);
- /* Clear interrupts status */
+ mutex_lock(&spec->cs8409_i2c_mux);
+
+ /* Clear interrupts, by reading interrupt status registers */
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1);
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1);
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1);
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
+}
+
+/* Configure CS42L42 slave codec for jack autodetect */
+static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+
+ /* Set TIP_SENSE_EN for analog front-end of tip sense. */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x0020, 1);
+ /* Clear WAKE# */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0001, 1);
+ /* Wait ~2.5ms */
+ usleep_range(2500, 3000);
+ /* Set mode WAKE# output follows the combination logic directly */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0020, 1);
+ /* Clear interrupts status */
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
+ /* Enable interrupt */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0x03, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b79, 0x00, 1);
+
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
+ return 0;
+}
+
+/* Enable and run CS42L42 slave codec jack auto detect */
+static void cs8409_cs42l42_run_jack_detect(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+
+ /* Clear interrupts */
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b77, 1);
+
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1102, 0x87, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1f06, 0x86, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b74, 0x07, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0x01, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0x80, 1);
+ /* Wait ~110ms*/
+ usleep_range(110000, 200000);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77, 1);
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0, 1);
+ /* Wait ~10ms */
+ usleep_range(10000, 25000);
+
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
}
static void cs8409_cs42l42_reg_setup(struct hda_codec *codec)
{
const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq;
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
for (; seq->addr; seq++)
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1);
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
+}
+
+/*
+ * In the case of CS8409 we do not have unsolicited events from NID's 0x24
+ * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will
+ * generate interrupt via gpio 4 to notify jack events. We have to overwrite
+ * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
+ * and then notify status via generic snd_hda_jack_unsol_event() call.
+ */
+void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ struct cs_spec *spec = codec->spec;
+ int status_changed = 0;
+ unsigned int reg_cdc_status = 0;
+ unsigned int reg_hs_status = 0;
+ unsigned int reg_ts_status = 0;
+ int type = 0;
+ struct hda_jack_tbl *jk;
+
+ /* jack_unsol_event() will be called every time gpio line changing state.
+ * In this case gpio4 line goes up as a result of reading interrupt status
+ * registers in previous cs8409_jack_unsol_event() call.
+ * We don't need to handle this event, ignoring...
+ */
+ if ((res & (1 << 4)))
+ return;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+
+ /* Read jack detect status registers */
+ reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
+ reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1);
+ reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
+
+ /* Clear interrupts */
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
+ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
+
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
+ /* HSDET_AUTO_DONE */
+ if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) {
+
+ type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
+ /* CS42L42 reports optical jack as type 4
+ * We don't handle optical jack
+ */
+ if (type != 4) {
+ if (!spec->cs42l42_hp_jack_in) {
+ status_changed = 1;
+ spec->cs42l42_hp_jack_in = 1;
+ }
+ /* type = 3 has no mic */
+ if ((!spec->cs42l42_mic_jack_in) && (type != 3)) {
+ status_changed = 1;
+ spec->cs42l42_mic_jack_in = 1;
+ }
+ }
+
+ } else {
+ /* TIP_SENSE INSERT/REMOVE */
+ switch (reg_ts_status) {
+ case CS42L42_JACK_INSERTED:
+ cs8409_cs42l42_run_jack_detect(codec);
+ break;
+
+ case CS42L42_JACK_REMOVED:
+ if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) {
+ status_changed = 1;
+ spec->cs42l42_hp_jack_in = 0;
+ spec->cs42l42_mic_jack_in = 0;
+ }
+ break;
+
+ default:
+ /* jack in transition */
+ status_changed = 0;
+ break;
+ }
+ }
+
+ if (status_changed) {
+
+ snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
+ (spec->cs42l42_hp_jack_in)?0 : PIN_OUT);
+
+ /* Report jack*/
+ jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
+ if (jk) {
+ snd_hda_jack_unsol_event(codec,
+ (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
+ }
+ /* Report jack*/
+ jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0);
+ if (jk) {
+ snd_hda_jack_unsol_event(codec,
+ (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
+ }
+ }
}
static int cs8409_cs42l42_build_controls(struct hda_codec *codec)
@@ -1603,6 +1786,13 @@ static int cs8409_cs42l42_build_controls(struct hda_codec *codec)
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+ /* Run jack auto detect first time on boot
+ * after controls have been added, to check if jack has
+ * been already plugged in
+ */
+ cs8409_cs42l42_run_jack_detect(codec);
+ usleep_range(100000, 150000);
+
return 0;
}
@@ -1610,21 +1800,72 @@ static int cs8409_cs42l42_build_controls(struct hda_codec *codec)
/* Manage PDREF, when transition to D3hot */
static int cs8409_suspend(struct hda_codec *codec)
{
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+ /* Power down CS42L42 ASP/EQ/MIX/HP */
+ cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1101, 0xfe, 1);
+ mutex_unlock(&spec->cs8409_i2c_mux);
+
snd_hda_shutup_pins(codec);
+
return 0;
}
#endif
+static void cs8409_cs42l42_cap_sync_hook(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cs_spec *spec = codec->spec;
+ unsigned int curval, expval;
+ /* CS8409 DMIC Pin only allows the setting of the Stream Parameters in
+ * Power State D0. When a headset is unplugged, and the path is switched to
+ * the DMIC, the Stream is restarted with the new ADC, but this is done in
+ * Power State D3. Restart the Stream now DMIC is in D0.
+ */
+ if (spec->gen.cur_adc == CS8409_CS42L42_DMIC_ADC_PIN_NID) {
+ curval = snd_hda_codec_read(codec, spec->gen.cur_adc,
+ 0, AC_VERB_GET_CONV, 0);
+ expval = (spec->gen.cur_adc_stream_tag << 4) | 0;
+ if (curval != expval) {
+ codec_dbg(codec, "%s Restarting Stream after DMIC switch\n", __func__);
+ __snd_hda_codec_cleanup_stream(codec, spec->gen.cur_adc, 1);
+ snd_hda_codec_setup_stream(codec, spec->gen.cur_adc,
+ spec->gen.cur_adc_stream_tag, 0,
+ spec->gen.cur_adc_format);
+ }
+ }
+}
+
+/* Enable/Disable Unsolicited Response for gpio(s) 3,4 */
+static void cs8409_enable_ur(struct hda_codec *codec, int flag)
+{
+ /* GPIO4 INT# and GPIO3 WAKE# */
+ snd_hda_codec_write(codec, codec->core.afg,
+ 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK,
+ flag?(GPIO3_INT | GPIO4_INT) : 0);
+
+ snd_hda_codec_write(codec, codec->core.afg,
+ 0, AC_VERB_SET_UNSOLICITED_ENABLE,
+ flag?AC_UNSOL_ENABLED : 0);
+
+}
+
/* Vendor specific HW configuration
* PLL, ASP, I2C, SPI, GPIOs, DMIC etc...
*/
static int cs8409_cs42l42_hw_init(struct hda_codec *codec)
{
const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg;
+ struct cs_spec *spec = codec->spec;
for (; seq->nid; seq++)
cs_vendor_coef_set(codec, seq->cir, seq->coeff);
+ /* Disable Unsolicited Response during boot */
+ cs8409_enable_ur(codec, 0);
+
/* Reset CS42L42 */
cs8409_cs42l42_reset(codec);
@@ -1634,11 +1875,18 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec)
if (codec->fixup_id == CS8409_WARLOCK ||
codec->fixup_id == CS8409_CYBORG) {
/* FULL_SCALE_VOL = 0 for Warlock / Cyborg */
+ mutex_lock(&spec->cs8409_i2c_mux);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01, 1);
+ mutex_unlock(&spec->cs8409_i2c_mux);
/* DMIC1_MO=00b, DMIC1/2_SR=1 */
cs_vendor_coef_set(codec, 0x09, 0x0003);
}
+ cs8409_cs42l42_enable_jack_detect(codec);
+
+ /* Enable Unsolicited Response */
+ cs8409_enable_ur(codec, 1);
+
return 1;
}
@@ -1668,6 +1916,8 @@ static int cs8409_cs42l42_init(struct hda_codec *codec)
cs8409_cs42l42_hw_init(codec);
+ cs8409_cs42l42_run_jack_detect(codec);
+ usleep_range(100000, 150000);
}
return ret;
@@ -1678,7 +1928,7 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
.build_pcms = snd_hda_gen_build_pcms,
.init = cs8409_cs42l42_init,
.free = cs_free,
- .unsol_event = snd_hda_jack_unsol_event,
+ .unsol_event = cs8409_jack_unsol_event,
#ifdef CONFIG_PM
.suspend = cs8409_suspend,
#endif
@@ -1738,6 +1988,45 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec)
return err;
}
+static int cs8409_cs42l42_exec_verb(struct hdac_device *dev,
+ unsigned int cmd, unsigned int flags, unsigned int *res)
+{
+ struct hda_codec *codec = container_of(dev, struct hda_codec, core);
+ struct cs_spec *spec = codec->spec;
+
+ unsigned int nid = 0;
+ unsigned int verb = 0;
+
+ nid = ((cmd >> 20) & 0x07f);
+ verb = ((cmd >> 8) & 0x0fff);
+
+ /* CS8409 pins have no AC_PINSENSE_PRESENCE
+ * capabilities. We have to intercept 2 calls for pins 0x24 and 0x34
+ * and return correct pin sense values for read_pin_sense() call from
+ * hda_jack based on CS42L42 jack detect status.
+ */
+ switch (nid) {
+ case CS8409_CS42L42_HP_PIN_NID:
+ if (verb == AC_VERB_GET_PIN_SENSE) {
+ *res = (spec->cs42l42_hp_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+ return 0;
+ }
+ break;
+
+ case CS8409_CS42L42_AMIC_PIN_NID:
+ if (verb == AC_VERB_GET_PIN_SENSE) {
+ *res = (spec->cs42l42_mic_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+ return 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return spec->exec_verb(dev, cmd, flags, res);
+}
+
static int patch_cs8409(struct hda_codec *codec)
{
struct cs_spec *spec;
@@ -1763,8 +2052,16 @@ static int patch_cs8409(struct hda_codec *codec)
snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs);
+ /* verb exec op override */
+ spec->exec_verb = codec->core.exec_verb;
+ codec->core.exec_verb = cs8409_cs42l42_exec_verb;
+
+ mutex_init(&spec->cs8409_i2c_mux);
+
codec->patch_ops = cs8409_cs42l42_patch_ops;
+ spec->gen.cap_sync_hook = cs8409_cs42l42_cap_sync_hook;
+
spec->gen.suppress_auto_mute = 1;
spec->gen.no_primary_hp = 1;
/* GPIO 5 out, 3,4 in */
@@ -1772,6 +2069,9 @@ static int patch_cs8409(struct hda_codec *codec)
spec->gpio_data = 0;
spec->gpio_mask = 0x03f;
+ spec->cs42l42_hp_jack_in = 0;
+ spec->cs42l42_mic_jack_in = 0;
+
err = cs8409_cs42l42_fixup(codec);
if (err > 0)
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 4/4] ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
2021-03-04 19:02 ` Vitaly Rodionov
@ 2021-03-04 19:02 ` Vitaly Rodionov
-1 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: alsa-devel, patches, linux-kernel, Stefan Binding
From: Stefan Binding <sbinding@opensource.cirrus.com>
CS8409 does not support Volume Control for NIDs 0x24 (the Headphones),
or 0x34 (The Headset Mic).
However, CS42L42 codec does support gain control for both.
We can add support for Volume Controls, by writing the the CS42L42
regmap via i2c commands, using custom info, get and put volume
functions, saved in the control.
Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3500
Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
---
sound/pci/hda/patch_cirrus.c | 201 ++++++++++++++++++++++++++++++++++-
1 file changed, 198 insertions(+), 3 deletions(-)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 0b8980240176..082420545ab7 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -21,6 +21,9 @@
/*
*/
+#define CS42L42_HP_CH (2U)
+#define CS42L42_HS_MIC_CH (1U)
+
struct cs_spec {
struct hda_gen_spec gen;
@@ -42,6 +45,9 @@ struct cs_spec {
unsigned int cs42l42_hp_jack_in:1;
unsigned int cs42l42_mic_jack_in:1;
+ unsigned int cs42l42_volume_init:1;
+ char cs42l42_hp_volume[CS42L42_HP_CH];
+ char cs42l42_hs_mic_volume[CS42L42_HS_MIC_CH];
struct mutex cs8409_i2c_mux;
@@ -1260,6 +1266,14 @@ static int patch_cs4213(struct hda_codec *codec)
#define CIR_I2C_QWRITE 0x005D
#define CIR_I2C_QREAD 0x005E
+#define CS8409_CS42L42_HP_VOL_REAL_MIN (-63)
+#define CS8409_CS42L42_HP_VOL_REAL_MAX (0)
+#define CS8409_CS42L42_AMIC_VOL_REAL_MIN (-97)
+#define CS8409_CS42L42_AMIC_VOL_REAL_MAX (12)
+#define CS8409_CS42L42_REG_HS_VOLUME_CHA (0x2301)
+#define CS8409_CS42L42_REG_HS_VOLUME_CHB (0x2303)
+#define CS8409_CS42L42_REG_AMIC_VOLUME (0x1D03)
+
struct cs8409_i2c_param {
unsigned int addr;
unsigned int reg;
@@ -1401,7 +1415,6 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
{ 0x1010, 0xB0 },
{ 0x1D01, 0x00 },
{ 0x1D02, 0x06 },
- { 0x1D03, 0x00 },
{ 0x1107, 0x01 },
{ 0x1009, 0x02 },
{ 0x1007, 0x03 },
@@ -1431,8 +1444,6 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
{ 0x2901, 0x01 },
{ 0x1101, 0x0A },
{ 0x1102, 0x84 },
- { 0x2301, 0x00 },
- { 0x2303, 0x00 },
{ 0x2302, 0x3f },
{ 0x2001, 0x03 },
{ 0x1B75, 0xB6 },
@@ -1580,6 +1591,179 @@ static unsigned int cs8409_i2c_write(struct hda_codec *codec,
return retval;
}
+static int cs8409_cs42l42_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ u16 nid = get_amp_nid(kcontrol);
+ u8 chs = get_amp_channels(kcontrol);
+
+ codec_dbg(codec, "%s() nid: %d\n", __func__, nid);
+ switch (nid) {
+ case CS8409_CS42L42_HP_PIN_NID:
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = chs == 3 ? 2 : 1;
+ uinfo->value.integer.min = CS8409_CS42L42_HP_VOL_REAL_MIN;
+ uinfo->value.integer.max = CS8409_CS42L42_HP_VOL_REAL_MAX;
+ break;
+ case CS8409_CS42L42_AMIC_PIN_NID:
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = chs == 3 ? 2 : 1;
+ uinfo->value.integer.min = CS8409_CS42L42_AMIC_VOL_REAL_MIN;
+ uinfo->value.integer.max = CS8409_CS42L42_AMIC_VOL_REAL_MAX;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void cs8409_cs42l42_update_volume(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+ spec->cs42l42_hp_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_HS_VOLUME_CHA, 1));
+ spec->cs42l42_hp_volume[1] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_HS_VOLUME_CHB, 1));
+ spec->cs42l42_hs_mic_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_AMIC_VOLUME, 1));
+ codec_dbg(codec, "%s() HP Volume: %d/%d, HS Mic Volume: %d\n", __func__,
+ spec->cs42l42_hp_volume[0], spec->cs42l42_hp_volume[1],
+ spec->cs42l42_hs_mic_volume[0]);
+ mutex_unlock(&spec->cs8409_i2c_mux);
+ spec->cs42l42_volume_init = 1;
+}
+
+static int cs8409_cs42l42_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+ hda_nid_t nid = get_amp_nid(kcontrol);
+ int chs = get_amp_channels(kcontrol);
+ long *valp = ucontrol->value.integer.value;
+
+ codec_dbg(codec, "%s() nid: %d\n", __func__, nid);
+ if (!spec->cs42l42_volume_init) {
+ snd_hda_power_up(codec);
+ cs8409_cs42l42_update_volume(codec);
+ snd_hda_power_down(codec);
+ }
+ switch (nid) {
+ case CS8409_CS42L42_HP_PIN_NID:
+ if (chs & 1) {
+ *valp++ = spec->cs42l42_hp_volume[0];
+ codec_dbg(codec, "%s() vol(a) = %d\n", __func__, spec->cs42l42_hp_volume[0]);
+ }
+ if (chs & 2) {
+ *valp++ = spec->cs42l42_hp_volume[1];
+ codec_dbg(codec, "%s() vol(b) = %d\n", __func__, spec->cs42l42_hp_volume[1]);
+ }
+ break;
+ case CS8409_CS42L42_AMIC_PIN_NID:
+ if (chs & 1) {
+ *valp++ = spec->cs42l42_hs_mic_volume[0];
+ codec_dbg(codec, "%s() vol() = %d\n", __func__, spec->cs42l42_hs_mic_volume[0]);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int cs8409_cs42l42_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+ hda_nid_t nid = get_amp_nid(kcontrol);
+ int chs = get_amp_channels(kcontrol);
+ long *valp = ucontrol->value.integer.value;
+ int change = 0;
+ char vol = 0;
+
+ codec_dbg(codec, "%s() nid: %d\n", __func__, nid);
+ snd_hda_power_up(codec);
+ switch (nid) {
+ case CS8409_CS42L42_HP_PIN_NID:
+ mutex_lock(&spec->cs8409_i2c_mux);
+ if (chs & 1) {
+ vol = -(*valp);
+ codec_dbg(codec, "%s() vol(a) = %d\n", __func__, vol);
+ change = cs8409_i2c_write(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_HS_VOLUME_CHA, vol, 1);
+ valp++;
+ }
+ if (chs & 2) {
+ vol = -(*valp);
+ codec_dbg(codec, "%s() vol(b) = %d\n", __func__, vol);
+ change |= cs8409_i2c_write(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_HS_VOLUME_CHB, vol, 1);
+ }
+ mutex_unlock(&spec->cs8409_i2c_mux);
+ break;
+ case CS8409_CS42L42_AMIC_PIN_NID:
+ mutex_lock(&spec->cs8409_i2c_mux);
+ if (chs & 1) {
+ codec_dbg(codec, "%s() vol() = %d\n", __func__, (char)*valp);
+ change = cs8409_i2c_write(
+ codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_AMIC_VOLUME, (char)*valp, 1);
+ valp++;
+ }
+ mutex_unlock(&spec->cs8409_i2c_mux);
+ break;
+ default:
+ break;
+ }
+ cs8409_cs42l42_update_volume(codec);
+ snd_hda_power_down(codec);
+ return change;
+}
+
+static const DECLARE_TLV_DB_SCALE(
+ cs8409_cs42l42_hp_db_scale,
+ CS8409_CS42L42_HP_VOL_REAL_MIN * 100, 100, 1);
+
+static const DECLARE_TLV_DB_SCALE(
+ cs8409_cs42l42_amic_db_scale,
+ CS8409_CS42L42_AMIC_VOL_REAL_MIN * 100, 100, 1);
+
+static const struct snd_kcontrol_new cs8409_cs42l42_hp_volume_mixer = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .name = "Headphone Playback Volume",
+ .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE
+ | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .info = cs8409_cs42l42_volume_info,
+ .get = cs8409_cs42l42_volume_get,
+ .put = cs8409_cs42l42_volume_put,
+ .tlv = { .p = cs8409_cs42l42_hp_db_scale },
+ .private_value = HDA_COMPOSE_AMP_VAL(
+ CS8409_CS42L42_HP_PIN_NID, 3, 0, HDA_OUTPUT)
+ | HDA_AMP_VAL_MIN_MUTE
+};
+
+static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .name = "Headset Mic Capture Volume",
+ .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE
+ | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .info = cs8409_cs42l42_volume_info,
+ .get = cs8409_cs42l42_volume_get,
+ .put = cs8409_cs42l42_volume_put,
+ .tlv = { .p = cs8409_cs42l42_amic_db_scale },
+ .private_value = HDA_COMPOSE_AMP_VAL(
+ CS8409_CS42L42_AMIC_PIN_NID, 1, 0, HDA_INPUT)
+ | HDA_AMP_VAL_MIN_MUTE
+};
+
/* Assert/release RTS# line to CS42L42 */
static void cs8409_cs42l42_reset(struct hda_codec *codec)
{
@@ -1882,6 +2066,8 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec)
cs_vendor_coef_set(codec, 0x09, 0x0003);
}
+ cs8409_cs42l42_update_volume(codec);
+
cs8409_cs42l42_enable_jack_detect(codec);
/* Enable Unsolicited Response */
@@ -1983,6 +2169,14 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec)
if (err < 0)
return err;
+ if (!snd_hda_gen_add_kctl(
+ &spec->gen, NULL, &cs8409_cs42l42_hp_volume_mixer))
+ return -1;
+
+ if (!snd_hda_gen_add_kctl(
+ &spec->gen, NULL, &cs8409_cs42l42_amic_volume_mixer))
+ return -1;
+
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return err;
@@ -2064,6 +2258,7 @@ static int patch_cs8409(struct hda_codec *codec)
spec->gen.suppress_auto_mute = 1;
spec->gen.no_primary_hp = 1;
+ spec->gen.suppress_vmaster = 1;
/* GPIO 5 out, 3,4 in */
spec->gpio_dir = GPIO5_INT;
spec->gpio_data = 0;
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 4/4] ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
@ 2021-03-04 19:02 ` Vitaly Rodionov
0 siblings, 0 replies; 19+ messages in thread
From: Vitaly Rodionov @ 2021-03-04 19:02 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: patches, alsa-devel, linux-kernel, Stefan Binding
From: Stefan Binding <sbinding@opensource.cirrus.com>
CS8409 does not support Volume Control for NIDs 0x24 (the Headphones),
or 0x34 (The Headset Mic).
However, CS42L42 codec does support gain control for both.
We can add support for Volume Controls, by writing the the CS42L42
regmap via i2c commands, using custom info, get and put volume
functions, saved in the control.
Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3500
Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
Signed-off-by: Vitaly Rodionov <vitalyr@opensource.cirrus.com>
---
sound/pci/hda/patch_cirrus.c | 201 ++++++++++++++++++++++++++++++++++-
1 file changed, 198 insertions(+), 3 deletions(-)
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 0b8980240176..082420545ab7 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -21,6 +21,9 @@
/*
*/
+#define CS42L42_HP_CH (2U)
+#define CS42L42_HS_MIC_CH (1U)
+
struct cs_spec {
struct hda_gen_spec gen;
@@ -42,6 +45,9 @@ struct cs_spec {
unsigned int cs42l42_hp_jack_in:1;
unsigned int cs42l42_mic_jack_in:1;
+ unsigned int cs42l42_volume_init:1;
+ char cs42l42_hp_volume[CS42L42_HP_CH];
+ char cs42l42_hs_mic_volume[CS42L42_HS_MIC_CH];
struct mutex cs8409_i2c_mux;
@@ -1260,6 +1266,14 @@ static int patch_cs4213(struct hda_codec *codec)
#define CIR_I2C_QWRITE 0x005D
#define CIR_I2C_QREAD 0x005E
+#define CS8409_CS42L42_HP_VOL_REAL_MIN (-63)
+#define CS8409_CS42L42_HP_VOL_REAL_MAX (0)
+#define CS8409_CS42L42_AMIC_VOL_REAL_MIN (-97)
+#define CS8409_CS42L42_AMIC_VOL_REAL_MAX (12)
+#define CS8409_CS42L42_REG_HS_VOLUME_CHA (0x2301)
+#define CS8409_CS42L42_REG_HS_VOLUME_CHB (0x2303)
+#define CS8409_CS42L42_REG_AMIC_VOLUME (0x1D03)
+
struct cs8409_i2c_param {
unsigned int addr;
unsigned int reg;
@@ -1401,7 +1415,6 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
{ 0x1010, 0xB0 },
{ 0x1D01, 0x00 },
{ 0x1D02, 0x06 },
- { 0x1D03, 0x00 },
{ 0x1107, 0x01 },
{ 0x1009, 0x02 },
{ 0x1007, 0x03 },
@@ -1431,8 +1444,6 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
{ 0x2901, 0x01 },
{ 0x1101, 0x0A },
{ 0x1102, 0x84 },
- { 0x2301, 0x00 },
- { 0x2303, 0x00 },
{ 0x2302, 0x3f },
{ 0x2001, 0x03 },
{ 0x1B75, 0xB6 },
@@ -1580,6 +1591,179 @@ static unsigned int cs8409_i2c_write(struct hda_codec *codec,
return retval;
}
+static int cs8409_cs42l42_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ u16 nid = get_amp_nid(kcontrol);
+ u8 chs = get_amp_channels(kcontrol);
+
+ codec_dbg(codec, "%s() nid: %d\n", __func__, nid);
+ switch (nid) {
+ case CS8409_CS42L42_HP_PIN_NID:
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = chs == 3 ? 2 : 1;
+ uinfo->value.integer.min = CS8409_CS42L42_HP_VOL_REAL_MIN;
+ uinfo->value.integer.max = CS8409_CS42L42_HP_VOL_REAL_MAX;
+ break;
+ case CS8409_CS42L42_AMIC_PIN_NID:
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = chs == 3 ? 2 : 1;
+ uinfo->value.integer.min = CS8409_CS42L42_AMIC_VOL_REAL_MIN;
+ uinfo->value.integer.max = CS8409_CS42L42_AMIC_VOL_REAL_MAX;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void cs8409_cs42l42_update_volume(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ mutex_lock(&spec->cs8409_i2c_mux);
+ spec->cs42l42_hp_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_HS_VOLUME_CHA, 1));
+ spec->cs42l42_hp_volume[1] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_HS_VOLUME_CHB, 1));
+ spec->cs42l42_hs_mic_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_AMIC_VOLUME, 1));
+ codec_dbg(codec, "%s() HP Volume: %d/%d, HS Mic Volume: %d\n", __func__,
+ spec->cs42l42_hp_volume[0], spec->cs42l42_hp_volume[1],
+ spec->cs42l42_hs_mic_volume[0]);
+ mutex_unlock(&spec->cs8409_i2c_mux);
+ spec->cs42l42_volume_init = 1;
+}
+
+static int cs8409_cs42l42_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+ hda_nid_t nid = get_amp_nid(kcontrol);
+ int chs = get_amp_channels(kcontrol);
+ long *valp = ucontrol->value.integer.value;
+
+ codec_dbg(codec, "%s() nid: %d\n", __func__, nid);
+ if (!spec->cs42l42_volume_init) {
+ snd_hda_power_up(codec);
+ cs8409_cs42l42_update_volume(codec);
+ snd_hda_power_down(codec);
+ }
+ switch (nid) {
+ case CS8409_CS42L42_HP_PIN_NID:
+ if (chs & 1) {
+ *valp++ = spec->cs42l42_hp_volume[0];
+ codec_dbg(codec, "%s() vol(a) = %d\n", __func__, spec->cs42l42_hp_volume[0]);
+ }
+ if (chs & 2) {
+ *valp++ = spec->cs42l42_hp_volume[1];
+ codec_dbg(codec, "%s() vol(b) = %d\n", __func__, spec->cs42l42_hp_volume[1]);
+ }
+ break;
+ case CS8409_CS42L42_AMIC_PIN_NID:
+ if (chs & 1) {
+ *valp++ = spec->cs42l42_hs_mic_volume[0];
+ codec_dbg(codec, "%s() vol() = %d\n", __func__, spec->cs42l42_hs_mic_volume[0]);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int cs8409_cs42l42_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+ hda_nid_t nid = get_amp_nid(kcontrol);
+ int chs = get_amp_channels(kcontrol);
+ long *valp = ucontrol->value.integer.value;
+ int change = 0;
+ char vol = 0;
+
+ codec_dbg(codec, "%s() nid: %d\n", __func__, nid);
+ snd_hda_power_up(codec);
+ switch (nid) {
+ case CS8409_CS42L42_HP_PIN_NID:
+ mutex_lock(&spec->cs8409_i2c_mux);
+ if (chs & 1) {
+ vol = -(*valp);
+ codec_dbg(codec, "%s() vol(a) = %d\n", __func__, vol);
+ change = cs8409_i2c_write(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_HS_VOLUME_CHA, vol, 1);
+ valp++;
+ }
+ if (chs & 2) {
+ vol = -(*valp);
+ codec_dbg(codec, "%s() vol(b) = %d\n", __func__, vol);
+ change |= cs8409_i2c_write(codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_HS_VOLUME_CHB, vol, 1);
+ }
+ mutex_unlock(&spec->cs8409_i2c_mux);
+ break;
+ case CS8409_CS42L42_AMIC_PIN_NID:
+ mutex_lock(&spec->cs8409_i2c_mux);
+ if (chs & 1) {
+ codec_dbg(codec, "%s() vol() = %d\n", __func__, (char)*valp);
+ change = cs8409_i2c_write(
+ codec, CS42L42_I2C_ADDR,
+ CS8409_CS42L42_REG_AMIC_VOLUME, (char)*valp, 1);
+ valp++;
+ }
+ mutex_unlock(&spec->cs8409_i2c_mux);
+ break;
+ default:
+ break;
+ }
+ cs8409_cs42l42_update_volume(codec);
+ snd_hda_power_down(codec);
+ return change;
+}
+
+static const DECLARE_TLV_DB_SCALE(
+ cs8409_cs42l42_hp_db_scale,
+ CS8409_CS42L42_HP_VOL_REAL_MIN * 100, 100, 1);
+
+static const DECLARE_TLV_DB_SCALE(
+ cs8409_cs42l42_amic_db_scale,
+ CS8409_CS42L42_AMIC_VOL_REAL_MIN * 100, 100, 1);
+
+static const struct snd_kcontrol_new cs8409_cs42l42_hp_volume_mixer = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .name = "Headphone Playback Volume",
+ .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE
+ | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .info = cs8409_cs42l42_volume_info,
+ .get = cs8409_cs42l42_volume_get,
+ .put = cs8409_cs42l42_volume_put,
+ .tlv = { .p = cs8409_cs42l42_hp_db_scale },
+ .private_value = HDA_COMPOSE_AMP_VAL(
+ CS8409_CS42L42_HP_PIN_NID, 3, 0, HDA_OUTPUT)
+ | HDA_AMP_VAL_MIN_MUTE
+};
+
+static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .index = 0,
+ .name = "Headset Mic Capture Volume",
+ .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE
+ | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .info = cs8409_cs42l42_volume_info,
+ .get = cs8409_cs42l42_volume_get,
+ .put = cs8409_cs42l42_volume_put,
+ .tlv = { .p = cs8409_cs42l42_amic_db_scale },
+ .private_value = HDA_COMPOSE_AMP_VAL(
+ CS8409_CS42L42_AMIC_PIN_NID, 1, 0, HDA_INPUT)
+ | HDA_AMP_VAL_MIN_MUTE
+};
+
/* Assert/release RTS# line to CS42L42 */
static void cs8409_cs42l42_reset(struct hda_codec *codec)
{
@@ -1882,6 +2066,8 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec)
cs_vendor_coef_set(codec, 0x09, 0x0003);
}
+ cs8409_cs42l42_update_volume(codec);
+
cs8409_cs42l42_enable_jack_detect(codec);
/* Enable Unsolicited Response */
@@ -1983,6 +2169,14 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec)
if (err < 0)
return err;
+ if (!snd_hda_gen_add_kctl(
+ &spec->gen, NULL, &cs8409_cs42l42_hp_volume_mixer))
+ return -1;
+
+ if (!snd_hda_gen_add_kctl(
+ &spec->gen, NULL, &cs8409_cs42l42_amic_volume_mixer))
+ return -1;
+
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
return err;
@@ -2064,6 +2258,7 @@ static int patch_cs8409(struct hda_codec *codec)
spec->gen.suppress_auto_mute = 1;
spec->gen.no_primary_hp = 1;
+ spec->gen.suppress_vmaster = 1;
/* GPIO 5 out, 3,4 in */
spec->gpio_dir = GPIO5_INT;
spec->gpio_data = 0;
--
2.25.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.
2021-03-04 19:02 ` Vitaly Rodionov
@ 2021-03-04 22:31 ` kernel test robot
-1 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-03-04 22:31 UTC (permalink / raw)
To: Vitaly Rodionov, Jaroslav Kysela, Takashi Iwai
Cc: clang-built-linux, alsa-devel, patches, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 4007 bytes --]
Hi Vitaly,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on sound/for-next]
[also build test WARNING on v5.12-rc1 next-20210304]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
base: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next
config: riscv-randconfig-r025-20210304 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project eec7f8f7b1226be422a76542cb403d02538f453a)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install riscv cross compiling tool for clang build
# apt-get install binutils-riscv64-linux-gnu
# https://github.com/0day-ci/linux/commit/c4eca3e1e50f15e73efe5c3c605ce4e584ace51d
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
git checkout c4eca3e1e50f15e73efe5c3c605ce4e584ace51d
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> sound/pci/hda/patch_cirrus.c:1511:37: warning: variable 'retval' is uninitialized when used here [-Wuninitialized]
__func__, i2c_address, i2c_reg, retval);
^~~~~~
sound/pci/hda/hda_local.h:723:39: note: expanded from macro 'codec_err'
dev_err(hda_codec_dev(codec), fmt, ##args)
^~~~
include/linux/dev_printk.h:112:32: note: expanded from macro 'dev_err'
_dev_err(dev, dev_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~~
sound/pci/hda/patch_cirrus.c:1501:21: note: initialize the variable 'retval' to silence this warning
unsigned int retval;
^
= 0
1 warning generated.
vim +/retval +1511 sound/pci/hda/patch_cirrus.c
1493
1494 /* CS8409 slave i2cRead */
1495 static unsigned int cs8409_i2c_read(struct hda_codec *codec,
1496 unsigned int i2c_address,
1497 unsigned int i2c_reg,
1498 unsigned int paged)
1499 {
1500 unsigned int i2c_reg_data;
1501 unsigned int retval;
1502
1503 cs8409_enable_i2c_clock(codec, 1);
1504 cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
1505
1506 if (paged) {
1507 cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
1508 if (cs8409_i2c_wait_complete(codec) == -1) {
1509 codec_err(codec,
1510 "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
> 1511 __func__, i2c_address, i2c_reg, retval);
1512 }
1513 }
1514
1515 i2c_reg_data = (i2c_reg << 8) & 0x0ffff;
1516 cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data);
1517 if (cs8409_i2c_wait_complete(codec) == -1) {
1518 codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1519 __func__, i2c_address, i2c_reg, retval);
1520 }
1521
1522 /* Register in bits 15-8 and the data in 7-0 */
1523 retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
1524 retval &= 0x0ff;
1525
1526 cs8409_enable_i2c_clock(codec, 0);
1527
1528 return retval;
1529 }
1530
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26193 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.
@ 2021-03-04 22:31 ` kernel test robot
0 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-03-04 22:31 UTC (permalink / raw)
To: Vitaly Rodionov, Jaroslav Kysela, Takashi Iwai
Cc: clang-built-linux, alsa-devel, linux-kernel, patches
[-- Attachment #1: Type: text/plain, Size: 4007 bytes --]
Hi Vitaly,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on sound/for-next]
[also build test WARNING on v5.12-rc1 next-20210304]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
base: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next
config: riscv-randconfig-r025-20210304 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project eec7f8f7b1226be422a76542cb403d02538f453a)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install riscv cross compiling tool for clang build
# apt-get install binutils-riscv64-linux-gnu
# https://github.com/0day-ci/linux/commit/c4eca3e1e50f15e73efe5c3c605ce4e584ace51d
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
git checkout c4eca3e1e50f15e73efe5c3c605ce4e584ace51d
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> sound/pci/hda/patch_cirrus.c:1511:37: warning: variable 'retval' is uninitialized when used here [-Wuninitialized]
__func__, i2c_address, i2c_reg, retval);
^~~~~~
sound/pci/hda/hda_local.h:723:39: note: expanded from macro 'codec_err'
dev_err(hda_codec_dev(codec), fmt, ##args)
^~~~
include/linux/dev_printk.h:112:32: note: expanded from macro 'dev_err'
_dev_err(dev, dev_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~~
sound/pci/hda/patch_cirrus.c:1501:21: note: initialize the variable 'retval' to silence this warning
unsigned int retval;
^
= 0
1 warning generated.
vim +/retval +1511 sound/pci/hda/patch_cirrus.c
1493
1494 /* CS8409 slave i2cRead */
1495 static unsigned int cs8409_i2c_read(struct hda_codec *codec,
1496 unsigned int i2c_address,
1497 unsigned int i2c_reg,
1498 unsigned int paged)
1499 {
1500 unsigned int i2c_reg_data;
1501 unsigned int retval;
1502
1503 cs8409_enable_i2c_clock(codec, 1);
1504 cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
1505
1506 if (paged) {
1507 cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
1508 if (cs8409_i2c_wait_complete(codec) == -1) {
1509 codec_err(codec,
1510 "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
> 1511 __func__, i2c_address, i2c_reg, retval);
1512 }
1513 }
1514
1515 i2c_reg_data = (i2c_reg << 8) & 0x0ffff;
1516 cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data);
1517 if (cs8409_i2c_wait_complete(codec) == -1) {
1518 codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1519 __func__, i2c_address, i2c_reg, retval);
1520 }
1521
1522 /* Register in bits 15-8 and the data in 7-0 */
1523 retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
1524 retval &= 0x0ff;
1525
1526 cs8409_enable_i2c_clock(codec, 0);
1527
1528 return retval;
1529 }
1530
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26193 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.
2021-03-04 19:02 ` Vitaly Rodionov
@ 2021-03-04 23:13 ` kernel test robot
-1 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-03-04 23:13 UTC (permalink / raw)
To: Vitaly Rodionov, Jaroslav Kysela, Takashi Iwai
Cc: clang-built-linux, patches, alsa-devel, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 12929 bytes --]
Hi Vitaly,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on sound/for-next]
[also build test WARNING on v5.12-rc1 next-20210304]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
base: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next
config: riscv-randconfig-r025-20210304 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project eec7f8f7b1226be422a76542cb403d02538f453a)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install riscv cross compiling tool for clang build
# apt-get install binutils-riscv64-linux-gnu
# https://github.com/0day-ci/linux/commit/9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
git checkout 9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
sound/pci/hda/patch_cirrus.c:1529:37: warning: variable 'retval' is uninitialized when used here [-Wuninitialized]
__func__, i2c_address, i2c_reg, retval);
^~~~~~
sound/pci/hda/hda_local.h:723:39: note: expanded from macro 'codec_err'
dev_err(hda_codec_dev(codec), fmt, ##args)
^~~~
include/linux/dev_printk.h:112:32: note: expanded from macro 'dev_err'
_dev_err(dev, dev_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~~
sound/pci/hda/patch_cirrus.c:1519:21: note: initialize the variable 'retval' to silence this warning
unsigned int retval;
^
= 0
>> sound/pci/hda/patch_cirrus.c:1686:6: warning: no previous prototype for function 'cs8409_jack_unsol_event' [-Wmissing-prototypes]
void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
^
sound/pci/hda/patch_cirrus.c:1686:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
^
static
2 warnings generated.
vim +/cs8409_jack_unsol_event +1686 sound/pci/hda/patch_cirrus.c
1511
1512 /* CS8409 slave i2cRead */
1513 static unsigned int cs8409_i2c_read(struct hda_codec *codec,
1514 unsigned int i2c_address,
1515 unsigned int i2c_reg,
1516 unsigned int paged)
1517 {
1518 unsigned int i2c_reg_data;
> 1519 unsigned int retval;
1520
1521 cs8409_enable_i2c_clock(codec, 1);
1522 cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
1523
1524 if (paged) {
1525 cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
1526 if (cs8409_i2c_wait_complete(codec) == -1) {
1527 codec_err(codec,
1528 "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1529 __func__, i2c_address, i2c_reg, retval);
1530 }
1531 }
1532
1533 i2c_reg_data = (i2c_reg << 8) & 0x0ffff;
1534 cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data);
1535 if (cs8409_i2c_wait_complete(codec) == -1) {
1536 codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1537 __func__, i2c_address, i2c_reg, retval);
1538 }
1539
1540 /* Register in bits 15-8 and the data in 7-0 */
1541 retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
1542 retval &= 0x0ff;
1543
1544 cs8409_enable_i2c_clock(codec, 0);
1545
1546 return retval;
1547 }
1548
1549 /* CS8409 slave i2cWrite */
1550 static unsigned int cs8409_i2c_write(struct hda_codec *codec,
1551 unsigned int i2c_address, unsigned int i2c_reg,
1552 unsigned int i2c_data,
1553 unsigned int paged)
1554 {
1555 unsigned int retval = 0;
1556 unsigned int i2c_reg_data = 0;
1557
1558 cs8409_enable_i2c_clock(codec, 1);
1559 cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
1560
1561 if (paged) {
1562 cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
1563 if (cs8409_i2c_wait_complete(codec) == -1) {
1564 codec_err(codec,
1565 "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1566 __func__, i2c_address, i2c_reg, retval);
1567 }
1568 }
1569
1570 i2c_reg_data = ((i2c_reg << 8) & 0x0ff00) | (i2c_data & 0x0ff);
1571 cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg_data);
1572
1573 if (cs8409_i2c_wait_complete(codec) == -1) {
1574 codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1575 __func__, i2c_address, i2c_reg, retval);
1576 }
1577
1578 cs8409_enable_i2c_clock(codec, 0);
1579
1580 return retval;
1581 }
1582
1583 /* Assert/release RTS# line to CS42L42 */
1584 static void cs8409_cs42l42_reset(struct hda_codec *codec)
1585 {
1586 struct cs_spec *spec = codec->spec;
1587
1588 /* Assert RTS# line */
1589 snd_hda_codec_write(codec,
1590 codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0);
1591 /* wait ~10ms */
1592 usleep_range(10000, 15000);
1593 /* Release RTS# line */
1594 snd_hda_codec_write(codec,
1595 codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, GPIO5_INT);
1596 /* wait ~10ms */
1597 usleep_range(10000, 15000);
1598
1599 mutex_lock(&spec->cs8409_i2c_mux);
1600
1601 /* Clear interrupts, by reading interrupt status registers */
1602 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1603 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1);
1604 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1);
1605 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1);
1606
1607 mutex_unlock(&spec->cs8409_i2c_mux);
1608
1609 }
1610
1611 /* Configure CS42L42 slave codec for jack autodetect */
1612 static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec)
1613 {
1614 struct cs_spec *spec = codec->spec;
1615
1616 mutex_lock(&spec->cs8409_i2c_mux);
1617
1618 /* Set TIP_SENSE_EN for analog front-end of tip sense. */
1619 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x0020, 1);
1620 /* Clear WAKE# */
1621 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0001, 1);
1622 /* Wait ~2.5ms */
1623 usleep_range(2500, 3000);
1624 /* Set mode WAKE# output follows the combination logic directly */
1625 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0020, 1);
1626 /* Clear interrupts status */
1627 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1628 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
1629 /* Enable interrupt */
1630 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0x03, 1);
1631 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b79, 0x00, 1);
1632
1633 mutex_unlock(&spec->cs8409_i2c_mux);
1634
1635 return 0;
1636 }
1637
1638 /* Enable and run CS42L42 slave codec jack auto detect */
1639 static void cs8409_cs42l42_run_jack_detect(struct hda_codec *codec)
1640 {
1641 struct cs_spec *spec = codec->spec;
1642
1643 mutex_lock(&spec->cs8409_i2c_mux);
1644
1645 /* Clear interrupts */
1646 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1647 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b77, 1);
1648
1649 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1102, 0x87, 1);
1650 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1f06, 0x86, 1);
1651 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b74, 0x07, 1);
1652 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0x01, 1);
1653 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0x80, 1);
1654 /* Wait ~110ms*/
1655 usleep_range(110000, 200000);
1656 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77, 1);
1657 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0, 1);
1658 /* Wait ~10ms */
1659 usleep_range(10000, 25000);
1660
1661 mutex_unlock(&spec->cs8409_i2c_mux);
1662
1663 }
1664
1665 static void cs8409_cs42l42_reg_setup(struct hda_codec *codec)
1666 {
1667 const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq;
1668 struct cs_spec *spec = codec->spec;
1669
1670 mutex_lock(&spec->cs8409_i2c_mux);
1671
1672 for (; seq->addr; seq++)
1673 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1);
1674
1675 mutex_unlock(&spec->cs8409_i2c_mux);
1676
1677 }
1678
1679 /*
1680 * In the case of CS8409 we do not have unsolicited events from NID's 0x24
1681 * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will
1682 * generate interrupt via gpio 4 to notify jack events. We have to overwrite
1683 * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
1684 * and then notify status via generic snd_hda_jack_unsol_event() call.
1685 */
> 1686 void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
1687 {
1688 struct cs_spec *spec = codec->spec;
1689 int status_changed = 0;
1690 unsigned int reg_cdc_status = 0;
1691 unsigned int reg_hs_status = 0;
1692 unsigned int reg_ts_status = 0;
1693 int type = 0;
1694 struct hda_jack_tbl *jk;
1695
1696 /* jack_unsol_event() will be called every time gpio line changing state.
1697 * In this case gpio4 line goes up as a result of reading interrupt status
1698 * registers in previous cs8409_jack_unsol_event() call.
1699 * We don't need to handle this event, ignoring...
1700 */
1701 if ((res & (1 << 4)))
1702 return;
1703
1704 mutex_lock(&spec->cs8409_i2c_mux);
1705
1706 /* Read jack detect status registers */
1707 reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1708 reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1);
1709 reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1710
1711 /* Clear interrupts */
1712 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
1713 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1714 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1715
1716 mutex_unlock(&spec->cs8409_i2c_mux);
1717
1718 /* HSDET_AUTO_DONE */
1719 if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) {
1720
1721 type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
1722 /* CS42L42 reports optical jack as type 4
1723 * We don't handle optical jack
1724 */
1725 if (type != 4) {
1726 if (!spec->cs42l42_hp_jack_in) {
1727 status_changed = 1;
1728 spec->cs42l42_hp_jack_in = 1;
1729 }
1730 /* type = 3 has no mic */
1731 if ((!spec->cs42l42_mic_jack_in) && (type != 3)) {
1732 status_changed = 1;
1733 spec->cs42l42_mic_jack_in = 1;
1734 }
1735 }
1736
1737 } else {
1738 /* TIP_SENSE INSERT/REMOVE */
1739 switch (reg_ts_status) {
1740 case CS42L42_JACK_INSERTED:
1741 cs8409_cs42l42_run_jack_detect(codec);
1742 break;
1743
1744 case CS42L42_JACK_REMOVED:
1745 if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) {
1746 status_changed = 1;
1747 spec->cs42l42_hp_jack_in = 0;
1748 spec->cs42l42_mic_jack_in = 0;
1749 }
1750 break;
1751
1752 default:
1753 /* jack in transition */
1754 status_changed = 0;
1755 break;
1756 }
1757 }
1758
1759 if (status_changed) {
1760
1761 snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
1762 (spec->cs42l42_hp_jack_in)?0 : PIN_OUT);
1763
1764 /* Report jack*/
1765 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
1766 if (jk) {
1767 snd_hda_jack_unsol_event(codec,
1768 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1769 }
1770 /* Report jack*/
1771 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0);
1772 if (jk) {
1773 snd_hda_jack_unsol_event(codec,
1774 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1775 }
1776 }
1777 }
1778
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26193 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.
@ 2021-03-04 23:13 ` kernel test robot
0 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-03-04 23:13 UTC (permalink / raw)
To: Vitaly Rodionov, Jaroslav Kysela, Takashi Iwai
Cc: clang-built-linux, alsa-devel, linux-kernel, patches
[-- Attachment #1: Type: text/plain, Size: 12929 bytes --]
Hi Vitaly,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on sound/for-next]
[also build test WARNING on v5.12-rc1 next-20210304]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
base: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next
config: riscv-randconfig-r025-20210304 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project eec7f8f7b1226be422a76542cb403d02538f453a)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install riscv cross compiling tool for clang build
# apt-get install binutils-riscv64-linux-gnu
# https://github.com/0day-ci/linux/commit/9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
git checkout 9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
sound/pci/hda/patch_cirrus.c:1529:37: warning: variable 'retval' is uninitialized when used here [-Wuninitialized]
__func__, i2c_address, i2c_reg, retval);
^~~~~~
sound/pci/hda/hda_local.h:723:39: note: expanded from macro 'codec_err'
dev_err(hda_codec_dev(codec), fmt, ##args)
^~~~
include/linux/dev_printk.h:112:32: note: expanded from macro 'dev_err'
_dev_err(dev, dev_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~~
sound/pci/hda/patch_cirrus.c:1519:21: note: initialize the variable 'retval' to silence this warning
unsigned int retval;
^
= 0
>> sound/pci/hda/patch_cirrus.c:1686:6: warning: no previous prototype for function 'cs8409_jack_unsol_event' [-Wmissing-prototypes]
void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
^
sound/pci/hda/patch_cirrus.c:1686:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
^
static
2 warnings generated.
vim +/cs8409_jack_unsol_event +1686 sound/pci/hda/patch_cirrus.c
1511
1512 /* CS8409 slave i2cRead */
1513 static unsigned int cs8409_i2c_read(struct hda_codec *codec,
1514 unsigned int i2c_address,
1515 unsigned int i2c_reg,
1516 unsigned int paged)
1517 {
1518 unsigned int i2c_reg_data;
> 1519 unsigned int retval;
1520
1521 cs8409_enable_i2c_clock(codec, 1);
1522 cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
1523
1524 if (paged) {
1525 cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
1526 if (cs8409_i2c_wait_complete(codec) == -1) {
1527 codec_err(codec,
1528 "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1529 __func__, i2c_address, i2c_reg, retval);
1530 }
1531 }
1532
1533 i2c_reg_data = (i2c_reg << 8) & 0x0ffff;
1534 cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data);
1535 if (cs8409_i2c_wait_complete(codec) == -1) {
1536 codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1537 __func__, i2c_address, i2c_reg, retval);
1538 }
1539
1540 /* Register in bits 15-8 and the data in 7-0 */
1541 retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
1542 retval &= 0x0ff;
1543
1544 cs8409_enable_i2c_clock(codec, 0);
1545
1546 return retval;
1547 }
1548
1549 /* CS8409 slave i2cWrite */
1550 static unsigned int cs8409_i2c_write(struct hda_codec *codec,
1551 unsigned int i2c_address, unsigned int i2c_reg,
1552 unsigned int i2c_data,
1553 unsigned int paged)
1554 {
1555 unsigned int retval = 0;
1556 unsigned int i2c_reg_data = 0;
1557
1558 cs8409_enable_i2c_clock(codec, 1);
1559 cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address);
1560
1561 if (paged) {
1562 cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8);
1563 if (cs8409_i2c_wait_complete(codec) == -1) {
1564 codec_err(codec,
1565 "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1566 __func__, i2c_address, i2c_reg, retval);
1567 }
1568 }
1569
1570 i2c_reg_data = ((i2c_reg << 8) & 0x0ff00) | (i2c_data & 0x0ff);
1571 cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg_data);
1572
1573 if (cs8409_i2c_wait_complete(codec) == -1) {
1574 codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n",
1575 __func__, i2c_address, i2c_reg, retval);
1576 }
1577
1578 cs8409_enable_i2c_clock(codec, 0);
1579
1580 return retval;
1581 }
1582
1583 /* Assert/release RTS# line to CS42L42 */
1584 static void cs8409_cs42l42_reset(struct hda_codec *codec)
1585 {
1586 struct cs_spec *spec = codec->spec;
1587
1588 /* Assert RTS# line */
1589 snd_hda_codec_write(codec,
1590 codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0);
1591 /* wait ~10ms */
1592 usleep_range(10000, 15000);
1593 /* Release RTS# line */
1594 snd_hda_codec_write(codec,
1595 codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, GPIO5_INT);
1596 /* wait ~10ms */
1597 usleep_range(10000, 15000);
1598
1599 mutex_lock(&spec->cs8409_i2c_mux);
1600
1601 /* Clear interrupts, by reading interrupt status registers */
1602 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1603 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1);
1604 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1);
1605 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1);
1606
1607 mutex_unlock(&spec->cs8409_i2c_mux);
1608
1609 }
1610
1611 /* Configure CS42L42 slave codec for jack autodetect */
1612 static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec)
1613 {
1614 struct cs_spec *spec = codec->spec;
1615
1616 mutex_lock(&spec->cs8409_i2c_mux);
1617
1618 /* Set TIP_SENSE_EN for analog front-end of tip sense. */
1619 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x0020, 1);
1620 /* Clear WAKE# */
1621 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0001, 1);
1622 /* Wait ~2.5ms */
1623 usleep_range(2500, 3000);
1624 /* Set mode WAKE# output follows the combination logic directly */
1625 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0020, 1);
1626 /* Clear interrupts status */
1627 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1628 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
1629 /* Enable interrupt */
1630 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0x03, 1);
1631 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b79, 0x00, 1);
1632
1633 mutex_unlock(&spec->cs8409_i2c_mux);
1634
1635 return 0;
1636 }
1637
1638 /* Enable and run CS42L42 slave codec jack auto detect */
1639 static void cs8409_cs42l42_run_jack_detect(struct hda_codec *codec)
1640 {
1641 struct cs_spec *spec = codec->spec;
1642
1643 mutex_lock(&spec->cs8409_i2c_mux);
1644
1645 /* Clear interrupts */
1646 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1647 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b77, 1);
1648
1649 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1102, 0x87, 1);
1650 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1f06, 0x86, 1);
1651 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b74, 0x07, 1);
1652 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0x01, 1);
1653 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0x80, 1);
1654 /* Wait ~110ms*/
1655 usleep_range(110000, 200000);
1656 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77, 1);
1657 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0, 1);
1658 /* Wait ~10ms */
1659 usleep_range(10000, 25000);
1660
1661 mutex_unlock(&spec->cs8409_i2c_mux);
1662
1663 }
1664
1665 static void cs8409_cs42l42_reg_setup(struct hda_codec *codec)
1666 {
1667 const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq;
1668 struct cs_spec *spec = codec->spec;
1669
1670 mutex_lock(&spec->cs8409_i2c_mux);
1671
1672 for (; seq->addr; seq++)
1673 cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1);
1674
1675 mutex_unlock(&spec->cs8409_i2c_mux);
1676
1677 }
1678
1679 /*
1680 * In the case of CS8409 we do not have unsolicited events from NID's 0x24
1681 * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will
1682 * generate interrupt via gpio 4 to notify jack events. We have to overwrite
1683 * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
1684 * and then notify status via generic snd_hda_jack_unsol_event() call.
1685 */
> 1686 void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
1687 {
1688 struct cs_spec *spec = codec->spec;
1689 int status_changed = 0;
1690 unsigned int reg_cdc_status = 0;
1691 unsigned int reg_hs_status = 0;
1692 unsigned int reg_ts_status = 0;
1693 int type = 0;
1694 struct hda_jack_tbl *jk;
1695
1696 /* jack_unsol_event() will be called every time gpio line changing state.
1697 * In this case gpio4 line goes up as a result of reading interrupt status
1698 * registers in previous cs8409_jack_unsol_event() call.
1699 * We don't need to handle this event, ignoring...
1700 */
1701 if ((res & (1 << 4)))
1702 return;
1703
1704 mutex_lock(&spec->cs8409_i2c_mux);
1705
1706 /* Read jack detect status registers */
1707 reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1708 reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1);
1709 reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1710
1711 /* Clear interrupts */
1712 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
1713 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1714 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1715
1716 mutex_unlock(&spec->cs8409_i2c_mux);
1717
1718 /* HSDET_AUTO_DONE */
1719 if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) {
1720
1721 type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
1722 /* CS42L42 reports optical jack as type 4
1723 * We don't handle optical jack
1724 */
1725 if (type != 4) {
1726 if (!spec->cs42l42_hp_jack_in) {
1727 status_changed = 1;
1728 spec->cs42l42_hp_jack_in = 1;
1729 }
1730 /* type = 3 has no mic */
1731 if ((!spec->cs42l42_mic_jack_in) && (type != 3)) {
1732 status_changed = 1;
1733 spec->cs42l42_mic_jack_in = 1;
1734 }
1735 }
1736
1737 } else {
1738 /* TIP_SENSE INSERT/REMOVE */
1739 switch (reg_ts_status) {
1740 case CS42L42_JACK_INSERTED:
1741 cs8409_cs42l42_run_jack_detect(codec);
1742 break;
1743
1744 case CS42L42_JACK_REMOVED:
1745 if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) {
1746 status_changed = 1;
1747 spec->cs42l42_hp_jack_in = 0;
1748 spec->cs42l42_mic_jack_in = 0;
1749 }
1750 break;
1751
1752 default:
1753 /* jack in transition */
1754 status_changed = 0;
1755 break;
1756 }
1757 }
1758
1759 if (status_changed) {
1760
1761 snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
1762 (spec->cs42l42_hp_jack_in)?0 : PIN_OUT);
1763
1764 /* Report jack*/
1765 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
1766 if (jk) {
1767 snd_hda_jack_unsol_event(codec,
1768 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1769 }
1770 /* Report jack*/
1771 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0);
1772 if (jk) {
1773 snd_hda_jack_unsol_event(codec,
1774 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1775 }
1776 }
1777 }
1778
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26193 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.
2021-03-04 19:02 ` Vitaly Rodionov
(?)
@ 2021-03-05 3:43 ` kernel test robot
-1 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-03-05 3:43 UTC (permalink / raw)
To: Vitaly Rodionov, Jaroslav Kysela, Takashi Iwai
Cc: kbuild-all, patches, alsa-devel, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 5598 bytes --]
Hi Vitaly,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on sound/for-next]
[also build test WARNING on v5.12-rc1 next-20210304]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
base: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next
config: alpha-randconfig-r035-20210305 (attached as .config)
compiler: alpha-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
git checkout 9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=alpha
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> sound/pci/hda/patch_cirrus.c:1686:6: warning: no previous prototype for 'cs8409_jack_unsol_event' [-Wmissing-prototypes]
1686 | void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
| ^~~~~~~~~~~~~~~~~~~~~~~
vim +/cs8409_jack_unsol_event +1686 sound/pci/hda/patch_cirrus.c
1678
1679 /*
1680 * In the case of CS8409 we do not have unsolicited events from NID's 0x24
1681 * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will
1682 * generate interrupt via gpio 4 to notify jack events. We have to overwrite
1683 * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
1684 * and then notify status via generic snd_hda_jack_unsol_event() call.
1685 */
> 1686 void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
1687 {
1688 struct cs_spec *spec = codec->spec;
1689 int status_changed = 0;
1690 unsigned int reg_cdc_status = 0;
1691 unsigned int reg_hs_status = 0;
1692 unsigned int reg_ts_status = 0;
1693 int type = 0;
1694 struct hda_jack_tbl *jk;
1695
1696 /* jack_unsol_event() will be called every time gpio line changing state.
1697 * In this case gpio4 line goes up as a result of reading interrupt status
1698 * registers in previous cs8409_jack_unsol_event() call.
1699 * We don't need to handle this event, ignoring...
1700 */
1701 if ((res & (1 << 4)))
1702 return;
1703
1704 mutex_lock(&spec->cs8409_i2c_mux);
1705
1706 /* Read jack detect status registers */
1707 reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1708 reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1);
1709 reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1710
1711 /* Clear interrupts */
1712 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
1713 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1714 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1715
1716 mutex_unlock(&spec->cs8409_i2c_mux);
1717
1718 /* HSDET_AUTO_DONE */
1719 if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) {
1720
1721 type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
1722 /* CS42L42 reports optical jack as type 4
1723 * We don't handle optical jack
1724 */
1725 if (type != 4) {
1726 if (!spec->cs42l42_hp_jack_in) {
1727 status_changed = 1;
1728 spec->cs42l42_hp_jack_in = 1;
1729 }
1730 /* type = 3 has no mic */
1731 if ((!spec->cs42l42_mic_jack_in) && (type != 3)) {
1732 status_changed = 1;
1733 spec->cs42l42_mic_jack_in = 1;
1734 }
1735 }
1736
1737 } else {
1738 /* TIP_SENSE INSERT/REMOVE */
1739 switch (reg_ts_status) {
1740 case CS42L42_JACK_INSERTED:
1741 cs8409_cs42l42_run_jack_detect(codec);
1742 break;
1743
1744 case CS42L42_JACK_REMOVED:
1745 if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) {
1746 status_changed = 1;
1747 spec->cs42l42_hp_jack_in = 0;
1748 spec->cs42l42_mic_jack_in = 0;
1749 }
1750 break;
1751
1752 default:
1753 /* jack in transition */
1754 status_changed = 0;
1755 break;
1756 }
1757 }
1758
1759 if (status_changed) {
1760
1761 snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
1762 (spec->cs42l42_hp_jack_in)?0 : PIN_OUT);
1763
1764 /* Report jack*/
1765 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
1766 if (jk) {
1767 snd_hda_jack_unsol_event(codec,
1768 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1769 }
1770 /* Report jack*/
1771 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0);
1772 if (jk) {
1773 snd_hda_jack_unsol_event(codec,
1774 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1775 }
1776 }
1777 }
1778
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 36161 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.
@ 2021-03-05 3:43 ` kernel test robot
0 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-03-05 3:43 UTC (permalink / raw)
To: Vitaly Rodionov, Jaroslav Kysela, Takashi Iwai
Cc: patches, alsa-devel, kbuild-all, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 5598 bytes --]
Hi Vitaly,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on sound/for-next]
[also build test WARNING on v5.12-rc1 next-20210304]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
base: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next
config: alpha-randconfig-r035-20210305 (attached as .config)
compiler: alpha-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
git checkout 9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=alpha
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> sound/pci/hda/patch_cirrus.c:1686:6: warning: no previous prototype for 'cs8409_jack_unsol_event' [-Wmissing-prototypes]
1686 | void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
| ^~~~~~~~~~~~~~~~~~~~~~~
vim +/cs8409_jack_unsol_event +1686 sound/pci/hda/patch_cirrus.c
1678
1679 /*
1680 * In the case of CS8409 we do not have unsolicited events from NID's 0x24
1681 * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will
1682 * generate interrupt via gpio 4 to notify jack events. We have to overwrite
1683 * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
1684 * and then notify status via generic snd_hda_jack_unsol_event() call.
1685 */
> 1686 void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
1687 {
1688 struct cs_spec *spec = codec->spec;
1689 int status_changed = 0;
1690 unsigned int reg_cdc_status = 0;
1691 unsigned int reg_hs_status = 0;
1692 unsigned int reg_ts_status = 0;
1693 int type = 0;
1694 struct hda_jack_tbl *jk;
1695
1696 /* jack_unsol_event() will be called every time gpio line changing state.
1697 * In this case gpio4 line goes up as a result of reading interrupt status
1698 * registers in previous cs8409_jack_unsol_event() call.
1699 * We don't need to handle this event, ignoring...
1700 */
1701 if ((res & (1 << 4)))
1702 return;
1703
1704 mutex_lock(&spec->cs8409_i2c_mux);
1705
1706 /* Read jack detect status registers */
1707 reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1708 reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1);
1709 reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1710
1711 /* Clear interrupts */
1712 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
1713 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1714 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1715
1716 mutex_unlock(&spec->cs8409_i2c_mux);
1717
1718 /* HSDET_AUTO_DONE */
1719 if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) {
1720
1721 type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
1722 /* CS42L42 reports optical jack as type 4
1723 * We don't handle optical jack
1724 */
1725 if (type != 4) {
1726 if (!spec->cs42l42_hp_jack_in) {
1727 status_changed = 1;
1728 spec->cs42l42_hp_jack_in = 1;
1729 }
1730 /* type = 3 has no mic */
1731 if ((!spec->cs42l42_mic_jack_in) && (type != 3)) {
1732 status_changed = 1;
1733 spec->cs42l42_mic_jack_in = 1;
1734 }
1735 }
1736
1737 } else {
1738 /* TIP_SENSE INSERT/REMOVE */
1739 switch (reg_ts_status) {
1740 case CS42L42_JACK_INSERTED:
1741 cs8409_cs42l42_run_jack_detect(codec);
1742 break;
1743
1744 case CS42L42_JACK_REMOVED:
1745 if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) {
1746 status_changed = 1;
1747 spec->cs42l42_hp_jack_in = 0;
1748 spec->cs42l42_mic_jack_in = 0;
1749 }
1750 break;
1751
1752 default:
1753 /* jack in transition */
1754 status_changed = 0;
1755 break;
1756 }
1757 }
1758
1759 if (status_changed) {
1760
1761 snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
1762 (spec->cs42l42_hp_jack_in)?0 : PIN_OUT);
1763
1764 /* Report jack*/
1765 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
1766 if (jk) {
1767 snd_hda_jack_unsol_event(codec,
1768 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1769 }
1770 /* Report jack*/
1771 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0);
1772 if (jk) {
1773 snd_hda_jack_unsol_event(codec,
1774 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1775 }
1776 }
1777 }
1778
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 36161 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.
@ 2021-03-05 3:43 ` kernel test robot
0 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2021-03-05 3:43 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 5739 bytes --]
Hi Vitaly,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on sound/for-next]
[also build test WARNING on v5.12-rc1 next-20210304]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
base: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next
config: alpha-randconfig-r035-20210305 (attached as .config)
compiler: alpha-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Vitaly-Rodionov/ALSA-hda-cirrus-Add-support-for-CS8409-HDA-bridge-and-CS42L42-companion-codec/20210305-030714
git checkout 9d4c2aa0fd6872aa8b866929c1537ce2905a6dba
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=alpha
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> sound/pci/hda/patch_cirrus.c:1686:6: warning: no previous prototype for 'cs8409_jack_unsol_event' [-Wmissing-prototypes]
1686 | void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
| ^~~~~~~~~~~~~~~~~~~~~~~
vim +/cs8409_jack_unsol_event +1686 sound/pci/hda/patch_cirrus.c
1678
1679 /*
1680 * In the case of CS8409 we do not have unsolicited events from NID's 0x24
1681 * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will
1682 * generate interrupt via gpio 4 to notify jack events. We have to overwrite
1683 * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
1684 * and then notify status via generic snd_hda_jack_unsol_event() call.
1685 */
> 1686 void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
1687 {
1688 struct cs_spec *spec = codec->spec;
1689 int status_changed = 0;
1690 unsigned int reg_cdc_status = 0;
1691 unsigned int reg_hs_status = 0;
1692 unsigned int reg_ts_status = 0;
1693 int type = 0;
1694 struct hda_jack_tbl *jk;
1695
1696 /* jack_unsol_event() will be called every time gpio line changing state.
1697 * In this case gpio4 line goes up as a result of reading interrupt status
1698 * registers in previous cs8409_jack_unsol_event() call.
1699 * We don't need to handle this event, ignoring...
1700 */
1701 if ((res & (1 << 4)))
1702 return;
1703
1704 mutex_lock(&spec->cs8409_i2c_mux);
1705
1706 /* Read jack detect status registers */
1707 reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1708 reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1);
1709 reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1710
1711 /* Clear interrupts */
1712 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1);
1713 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
1714 cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
1715
1716 mutex_unlock(&spec->cs8409_i2c_mux);
1717
1718 /* HSDET_AUTO_DONE */
1719 if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) {
1720
1721 type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
1722 /* CS42L42 reports optical jack as type 4
1723 * We don't handle optical jack
1724 */
1725 if (type != 4) {
1726 if (!spec->cs42l42_hp_jack_in) {
1727 status_changed = 1;
1728 spec->cs42l42_hp_jack_in = 1;
1729 }
1730 /* type = 3 has no mic */
1731 if ((!spec->cs42l42_mic_jack_in) && (type != 3)) {
1732 status_changed = 1;
1733 spec->cs42l42_mic_jack_in = 1;
1734 }
1735 }
1736
1737 } else {
1738 /* TIP_SENSE INSERT/REMOVE */
1739 switch (reg_ts_status) {
1740 case CS42L42_JACK_INSERTED:
1741 cs8409_cs42l42_run_jack_detect(codec);
1742 break;
1743
1744 case CS42L42_JACK_REMOVED:
1745 if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) {
1746 status_changed = 1;
1747 spec->cs42l42_hp_jack_in = 0;
1748 spec->cs42l42_mic_jack_in = 0;
1749 }
1750 break;
1751
1752 default:
1753 /* jack in transition */
1754 status_changed = 0;
1755 break;
1756 }
1757 }
1758
1759 if (status_changed) {
1760
1761 snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
1762 (spec->cs42l42_hp_jack_in)?0 : PIN_OUT);
1763
1764 /* Report jack*/
1765 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
1766 if (jk) {
1767 snd_hda_jack_unsol_event(codec,
1768 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1769 }
1770 /* Report jack*/
1771 jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0);
1772 if (jk) {
1773 snd_hda_jack_unsol_event(codec,
1774 (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG);
1775 }
1776 }
1777 }
1778
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 36161 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec
2021-03-04 19:02 ` Vitaly Rodionov
@ 2021-03-05 9:12 ` Takashi Iwai
-1 siblings, 0 replies; 19+ messages in thread
From: Takashi Iwai @ 2021-03-05 9:12 UTC (permalink / raw)
To: Vitaly Rodionov
Cc: Jaroslav Kysela, Takashi Iwai, alsa-devel, patches, linux-kernel
On Thu, 04 Mar 2021 20:02:37 +0100,
Vitaly Rodionov wrote:
>
> Dell's laptops Inspiron 3500, Inspiron 3501, Inspiron 3505 are using
> Cirrus Logic CS8409 HDA bridge with CS42L42 companion codec.
>
> The CS8409 is a multichannel HD audio routing controller.
> CS8409 includes support for four channels of digital
> microphone data and two bidirectional ASPs for up to 32
> channels of TDM data or 4 channels of I2S data. The CS8409 is
> intended to be used with a remote companion codec that implements
> high performance analog functions in close physical
> proximity to the end-equipment audio port or speaker driver.
>
> The CS42L42 is a low-power audio codec with integrated MIPI
> SoundWire interface or I2C/I2S/TDM interfaces designed
> for portable applications. It provides a high-dynamic range,
> stereo DAC for audio playback and a mono high-dynamic-range
> ADC for audio capture
>
> Changes since version 1:
>
> ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
> * No change
>
> ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42
> companion codec.
> * Removed redundant fields in fixup table
> * Handle gpio via spec->gpio_dir, spec->gpio_data and spec->gpio_mask
> * Moved cs8409_cs42l42_init() from patch 2, to handle resume correctly
>
> ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42
> companion codec.
> * Run scripts/checkpatch.pl, fixed new warnings
>
> ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
> * Moved control values to cache to avoid i2c read at each time.
>
> Stefan Binding (1):
> ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
>
> Vitaly Rodionov (3):
> ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
> ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42
> companion codec.
> ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42
> companion codec.
It seems that 0-day bot caught a few issues. I'll wait for the next
respin :)
thanks,
Takashi
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec
@ 2021-03-05 9:12 ` Takashi Iwai
0 siblings, 0 replies; 19+ messages in thread
From: Takashi Iwai @ 2021-03-05 9:12 UTC (permalink / raw)
To: Vitaly Rodionov; +Cc: patches, alsa-devel, Takashi Iwai, linux-kernel
On Thu, 04 Mar 2021 20:02:37 +0100,
Vitaly Rodionov wrote:
>
> Dell's laptops Inspiron 3500, Inspiron 3501, Inspiron 3505 are using
> Cirrus Logic CS8409 HDA bridge with CS42L42 companion codec.
>
> The CS8409 is a multichannel HD audio routing controller.
> CS8409 includes support for four channels of digital
> microphone data and two bidirectional ASPs for up to 32
> channels of TDM data or 4 channels of I2S data. The CS8409 is
> intended to be used with a remote companion codec that implements
> high performance analog functions in close physical
> proximity to the end-equipment audio port or speaker driver.
>
> The CS42L42 is a low-power audio codec with integrated MIPI
> SoundWire interface or I2C/I2S/TDM interfaces designed
> for portable applications. It provides a high-dynamic range,
> stereo DAC for audio playback and a mono high-dynamic-range
> ADC for audio capture
>
> Changes since version 1:
>
> ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
> * No change
>
> ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42
> companion codec.
> * Removed redundant fields in fixup table
> * Handle gpio via spec->gpio_dir, spec->gpio_data and spec->gpio_mask
> * Moved cs8409_cs42l42_init() from patch 2, to handle resume correctly
>
> ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42
> companion codec.
> * Run scripts/checkpatch.pl, fixed new warnings
>
> ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
> * Moved control values to cache to avoid i2c read at each time.
>
> Stefan Binding (1):
> ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control
>
> Vitaly Rodionov (3):
> ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18
> ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42
> companion codec.
> ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42
> companion codec.
It seems that 0-day bot caught a few issues. I'll wait for the next
respin :)
thanks,
Takashi
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2021-03-05 9:13 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-04 19:02 [PATCH v2 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec Vitaly Rodionov
2021-03-04 19:02 ` Vitaly Rodionov
2021-03-04 19:02 ` [PATCH v2 1/4] ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18 Vitaly Rodionov
2021-03-04 19:02 ` Vitaly Rodionov
2021-03-04 19:02 ` [PATCH v2 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec Vitaly Rodionov
2021-03-04 19:02 ` Vitaly Rodionov
2021-03-04 22:31 ` kernel test robot
2021-03-04 22:31 ` kernel test robot
2021-03-04 19:02 ` [PATCH v2 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from " Vitaly Rodionov
2021-03-04 19:02 ` Vitaly Rodionov
2021-03-04 23:13 ` kernel test robot
2021-03-04 23:13 ` kernel test robot
2021-03-05 3:43 ` kernel test robot
2021-03-05 3:43 ` kernel test robot
2021-03-05 3:43 ` kernel test robot
2021-03-04 19:02 ` [PATCH v2 4/4] ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control Vitaly Rodionov
2021-03-04 19:02 ` Vitaly Rodionov
2021-03-05 9:12 ` [PATCH v2 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec Takashi Iwai
2021-03-05 9:12 ` Takashi Iwai
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.