[PATCH v3 2/4] ALSA: hda/cirrus: Cleanup patch_cirrus.c code.

2021-03-15 Thread Vitaly Rodionov
From: Stefan Binding 

Minor changes, clean up code, remove unnecessary
initialization of variables, reduced number of
warnings from ./scripts/checkpatch.pl from 19 to 0

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 

Changes in v1:
- Fixed warning (Reported-by: kernel test robot )

Changes in v2:
- No Changes

Chsnges in v3:
- No Changes

---
 sound/pci/hda/patch_cirrus.c | 147 +--
 1 file changed, 72 insertions(+), 75 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index d95478ea2fb2..275bba02cc05 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -127,7 +127,7 @@ enum {
  * 1 DAC => HP(sense) / Speakers,
  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
-*/
+ */
 #define CS4210_DAC_NID 0x02
 #define CS4210_ADC_NID 0x03
 #define CS4210_VENDOR_NID  0x0B
@@ -146,6 +146,7 @@ enum {
 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
 {
struct cs_spec *spec = codec->spec;
+
snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
return snd_hda_codec_read(codec, spec->vendor_nid, 0,
@@ -156,6 +157,7 @@ static inline void cs_vendor_coef_set(struct hda_codec 
*codec, unsigned int idx,
  unsigned int coef)
 {
struct cs_spec *spec = codec->spec;
+
snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
@@ -192,6 +194,7 @@ static void cs_automute(struct hda_codec *codec)
 static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
 {
unsigned int val;
+
val = snd_hda_codec_get_pincfg(codec, nid);
return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
 }
@@ -210,7 +213,7 @@ static void init_input_coef(struct hda_codec *codec)
coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
 * No effect if SPDIF_OUT2 is
 * selected in IDX_SPDIF_CTL.
-   */
+*/
 
cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
}
@@ -284,13 +287,6 @@ static const struct hda_verb cs_errata_init_verbs[] = {
{0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
{0x11, AC_VERB_SET_PROC_COEF, 0x0008},
{0x11, AC_VERB_SET_PROC_STATE, 0x00},
-
-#if 0 /* Don't to set to D3 as we are in power-up sequence */
-   {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */
-   {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */
-   /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already 
handled */
-#endif
-
{} /* terminator */
 };
 
@@ -378,8 +374,10 @@ static int cs_parse_auto_config(struct hda_codec *codec)
/* keep the ADCs powered up when it's dynamically switchable */
if (spec->gen.dyn_adc_switch) {
unsigned int done = 0;
+
for (i = 0; i < spec->gen.input_mux.num_items; i++) {
int idx = spec->gen.dyn_adc_idx[i];
+
if (done & (1 << idx))
continue;
snd_hda_gen_fix_pin_power(codec,
@@ -513,6 +511,7 @@ static void cs420x_fixup_gpio_13(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
spec->gpio_mask = spec->gpio_dir =
@@ -525,6 +524,7 @@ static void cs420x_fixup_gpio_23(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
spec->gpio_mask = spec->gpio_dir =
@@ -669,6 +669,7 @@ static void cs4208_fixup_gpio0(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 0;
spec->gpio_eapd_speaker = 1;
spec->gpio_mask = spec->gpio_dir =
@@ -823,7 +824,7 @@ static int patch_cs4208(struct hda_codec *codec)
  * 1 DAC => HP(sense) / Speakers,
  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
-*/
+ */
 
 /* CS4210 board names */
 static const struct hda_model_fixup cs421x_models[] = {
@@ -866,6 +867,7 @@ static void cs

[PATCH v3 4/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

2021-03-15 Thread Vitaly Rodionov
From: Stefan Binding 

CS8409/CS42L42 Driver currently does most of the platform specific
setup inside the main body of the code, however, this setup can be
moved into fixup functions, to make the driver more generic.

Making the driver more generic, allows the driver to use the
cs_parse_auto_config function in the patch function. This function
forces all of the ADCs to be permanently powered, which means the
cap_sync_hook function is no longer needed to restart the stream, when
the jack has been ejected.

Since the codec is re-initialized on every init/resume, there is no
need to add specific verbs to be run on init, and instead these can
be combined with the initialization verbs, which are run on init.

In addition, the extra fixup verbs are no longer required, since this
is taken care of elsewhere.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 

Changes in v1:
- No changes

Changes in v2:
- Removed redundant fields in cs8409_cs42l42_init_verbs table.

Changes in v3:
- No changes

---
 sound/pci/hda/patch_cirrus.c | 280 ---
 1 file changed, 98 insertions(+), 182 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index c99ec5e485af..9180b806 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1292,9 +1292,14 @@ enum {
CS8409_BULLSEYE,
CS8409_WARLOCK,
CS8409_CYBORG,
-   CS8409_VERBS,
+   CS8409_FIXUPS,
 };
 
+static void cs8409_cs42l42_fixups(struct hda_codec *codec,
+   const struct hda_fixup *fix, int action);
+static int cs8409_cs42l42_exec_verb(struct hdac_device *dev,
+   unsigned int cmd, unsigned int flags, unsigned int *res);
+
 /* Dell Inspiron models with cs8409/cs42l42 */
 static const struct hda_model_fixup cs8409_models[] = {
{ .id = CS8409_BULLSEYE, .name = "bullseye" },
@@ -1368,48 +1373,28 @@ static const struct hda_pintbl cs8409_cs42l42_pincfgs[] 
= {
{} /* 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,
+   .chain_id = CS8409_FIXUPS,
},
[CS8409_WARLOCK] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
-   .chain_id = CS8409_VERBS,
+   .chain_id = CS8409_FIXUPS,
},
[CS8409_CYBORG] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
-   .chain_id = CS8409_VERBS,
+   .chain_id = CS8409_FIXUPS,
},
-   [CS8409_VERBS] = {
-   .type = HDA_FIXUP_VERBS,
-   .v.verbs = cs8409_cs42l42_add_verbs,
+   [CS8409_FIXUPS] = {
+   .type = HDA_FIXUP_FUNC,
+   .v.func = cs8409_cs42l42_fixups,
},
 };
 
@@ -2004,26 +1989,6 @@ static void cs8409_jack_unsol_event(struct hda_codec 
*codec, unsigned int res)
}
 }
 
-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);
-
-   /* 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(10, 15);
-
-   return 0;
-}
-
 #ifdef CONFIG_PM
 /* Manage PDREF, when transition to D3hot */
 static int cs8409_suspend(struct hda_codec *codec)
@@ -2044,31 +2009,6 @@ static int cs8409_suspend(struct hda_codec *codec)
 }
 #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 in

[PATCH v3 0/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups

2021-03-15 Thread Vitaly Rodionov
This series of patches will address comments by Pierre-Louis Bossart,
cleans up patch_cirrus.c source, reducing checkpatch.pl warnings from 19 to 0,
fixing an issue reported by Canonical: BugLink: 
https://bugs.launchpad.net/bugs/1918378,
and makes the CS8409 patch more generic by using fixups.

Stefan Binding (4):
  ALSA: hda/cirrus: Add error handling into CS8409 I2C functions
  ALSA: hda/cirrus: Cleanup patch_cirrus.c code.
  ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name
  ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

 sound/pci/hda/patch_cirrus.c | 525 ---
 1 file changed, 242 insertions(+), 283 deletions(-)

-- 
2.25.1



[PATCH v3 1/4] ALSA: hda/cirrus: Add error handling into CS8409 I2C functions

2021-03-15 Thread Vitaly Rodionov
From: Stefan Binding 

Also removing 2 redundant cs8409_i2c_read() calls, as we already did read
them in a code above.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 

Changes in v1:
- No changes

Changes in v2:
- Chanaged commit message to describe removal of 2 cs8409_i2c_read()s.
- Added comments for i2c_read/write functions
- Removed redundant parentheses

Changes in v3:
- Fixed warnings Reported-by: kernel test robot 

---
 sound/pci/hda/patch_cirrus.c | 136 +++
 1 file changed, 91 insertions(+), 45 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 6a9e5c803977..d95478ea2fb2 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1493,22 +1493,34 @@ static const struct cs8409_cir_param 
cs8409_cs42l42_hw_cfg[] = {
{} /* Terminator */
 };
 
-/* Enable I2C clocks */
-static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int flag)
+/**
+ * cs8409_enable_i2c_clock - Enable I2C clocks
+ * @codec: the codec instance
+ * @enable: Enable or disable I2C clocks
+ *
+ * Enable or Disable I2C clocks.
+ */
+static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int 
enable)
 {
unsigned int retval = 0;
unsigned int newval = 0;
 
retval = cs_vendor_coef_get(codec, 0x0);
-   newval = (flag) ? (retval | 0x8) : (retval & 0xfff7);
+   newval = (enable) ? (retval | 0x8) : (retval & 0xfff7);
cs_vendor_coef_set(codec, 0x0, newval);
 }
 
-/* Wait I2C transaction  */
+/**
+ * cs8409_i2c_wait_complete - Wait for I2C transaction
+ * @codec: the codec instance
+ *
+ * Wait for I2C transaction to complete.
+ * Return -1 if transaction wait times out.
+ */
 static int cs8409_i2c_wait_complete(struct hda_codec *codec)
 {
int repeat = 5;
-   unsigned int retval = 0;
+   unsigned int retval;
 
do {
retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS);
@@ -1516,82 +1528,103 @@ static int cs8409_i2c_wait_complete(struct hda_codec 
*codec)
usleep_range(2000, 4000);
--repeat;
} else
-   break;
+   return 0;
 
} while (repeat);
 
-   return repeat > 0 ? 0 : -1;
+   return -1;
 }
 
-/* CS8409 slave i2cRead */
-static unsigned int cs8409_i2c_read(struct hda_codec *codec,
+/**
+ * cs8409_i2c_read - CS8409 I2C Read.
+ * @codec: the codec instance
+ * @i2c_address: I2C Address
+ * @i2c_reg: Register to read
+ * @paged: Is a paged transaction
+ *
+ * CS8409 I2C Read.
+ * Returns negative on error, otherwise returns read value in bits 0-7.
+ */
+static 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 = 0;
+   unsigned int read_data;
 
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) {
+   if (cs8409_i2c_wait_complete(codec) < 0) {
codec_err(codec,
-   "%s() Paged Transaction Failed 0x%02x : 0x%04x 
= 0x%02x\n",
-   __func__, i2c_address, i2c_reg, retval);
+   "%s() Paged Transaction Failed 0x%02x : 
0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
}
 
i2c_reg_data = (i2c_reg << 8) & 0x0;
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);
+   if (cs8409_i2c_wait_complete(codec) < 0) {
+   codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
 
/* Register in bits 15-8 and the data in 7-0 */
-   retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
-   retval &= 0x0ff;
+   read_data = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
 
cs8409_enable_i2c_clock(codec, 0);
 
-   return retval;
+   return read_data & 0x0ff;
 }
 
-/* CS8409 slave i2cWrite */
-static unsigned int cs8409_i2c_write(struct hda_codec *codec,
+/**
+ * cs8409_i2c_write - CS8409 I2C Write.
+ * @codec: the codec instance
+ * @i2c_address: I2C Address
+ * @i2c_reg: Register to write to
+ * @i2c_data: Data to write

[PATCH v3 3/4] ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name

2021-03-15 Thread Vitaly Rodionov
From: Stefan Binding 

Existing name "Headset Mic Volume Control" causes multiple Microphone
entries to appear in UI. Using name "Mic Volume Control" ensures only a
single Microphone entry exists when the Headset is connected.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 
BugLink: https://bugs.launchpad.net/bugs/1918378
Reported-and-tested-by: You-Sheng Yang 

Changes in v1:
- No changes

Changes in v2:
- No changes

Changes in v3:
- No changes

---
 sound/pci/hda/patch_cirrus.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 275bba02cc05..c99ec5e485af 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1789,7 +1789,7 @@ static const struct snd_kcontrol_new 
cs8409_cs42l42_hp_volume_mixer = {
 static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.index = 0,
-   .name = "Headset Mic Capture Volume",
+   .name = "Mic Capture Volume",
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE
 | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-- 
2.25.1



[PATCH v2 1/4] ALSA: hda/cirrus: Add error handling into CS8409 I2C functions

2021-03-15 Thread Vitaly Rodionov
From: Stefan Binding 

Also removing 2 redundant cs8409_i2c_read() calls, as we already did read
them in a code above.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 

Changes in v1:
- No changes

Changes in v2:
- Chanaged commit message to describe removal of 2 cs8409_i2c_read()s.
- Added comments for i2c_read/write functions
- Removed redundant parentheses

---
 sound/pci/hda/patch_cirrus.c | 136 +++
 1 file changed, 91 insertions(+), 45 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 6a9e5c803977..6c062c7ab76a 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1493,22 +1493,34 @@ static const struct cs8409_cir_param 
cs8409_cs42l42_hw_cfg[] = {
{} /* Terminator */
 };
 
-/* Enable I2C clocks */
-static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int flag)
+/**
+ * cs8409_enable_i2c_clock - Enable I2C clocks
+ * @codec: the codec instance
+ * @enable: Enable or disable I2C clocks
+ *
+ * Enable or Disable I2C clocks.
+ */
+static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int 
enable)
 {
unsigned int retval = 0;
unsigned int newval = 0;
 
retval = cs_vendor_coef_get(codec, 0x0);
-   newval = (flag) ? (retval | 0x8) : (retval & 0xfff7);
+   newval = (enable) ? (retval | 0x8) : (retval & 0xfff7);
cs_vendor_coef_set(codec, 0x0, newval);
 }
 
-/* Wait I2C transaction  */
+/**
+ * cs8409_i2c_wait_complete - Wait for I2C transaction
+ * @codec: the codec instance
+ *
+ * Wait for I2C transaction to complete.
+ * Return -1 if transaction wait times out.
+ */
 static int cs8409_i2c_wait_complete(struct hda_codec *codec)
 {
int repeat = 5;
-   unsigned int retval = 0;
+   unsigned int retval;
 
do {
retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS);
@@ -1516,82 +1528,103 @@ static int cs8409_i2c_wait_complete(struct hda_codec 
*codec)
usleep_range(2000, 4000);
--repeat;
} else
-   break;
+   return 0;
 
} while (repeat);
 
-   return repeat > 0 ? 0 : -1;
+   return -1;
 }
 
-/* CS8409 slave i2cRead */
-static unsigned int cs8409_i2c_read(struct hda_codec *codec,
+/**
+ * cs8409_i2c_read - CS8409 I2C Read.
+ * @codec: the codec instance
+ * @i2c_address: I2C Address
+ * @i2c_reg: Register to read
+ * @paged: Is a paged transaction
+ *
+ * CS8409 I2C Read.
+ * Returns negative on error, otherwise returns read value in bits 0-7.
+ */
+static 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 = 0;
+   unsigned int read_data;
 
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) {
+   if (cs8409_i2c_wait_complete(codec) < 0) {
codec_err(codec,
-   "%s() Paged Transaction Failed 0x%02x : 0x%04x 
= 0x%02x\n",
-   __func__, i2c_address, i2c_reg, retval);
+   "%s() Paged Transaction Failed 0x%02x : 
0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
}
 
i2c_reg_data = (i2c_reg << 8) & 0x0;
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);
+   if (cs8409_i2c_wait_complete(codec) < 0) {
+   codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
 
/* Register in bits 15-8 and the data in 7-0 */
-   retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
-   retval &= 0x0ff;
+   read_data = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
 
cs8409_enable_i2c_clock(codec, 0);
 
-   return retval;
+   return read_data & 0x0ff;
 }
 
-/* CS8409 slave i2cWrite */
-static unsigned int cs8409_i2c_write(struct hda_codec *codec,
+/**
+ * cs8409_i2c_read - CS8409 I2C Write.
+ * @codec: the codec instance
+ * @i2c_address: I2C Address
+ * @i2c_reg: Register to write to
+ * @i2c_data: Data to write
+ * @paged: Is a paged transaction
+ *
+ * CS8409 I2C Write.
+ * 

[PATCH v2 3/4] ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name

2021-03-15 Thread Vitaly Rodionov
From: Stefan Binding 

Existing name "Headset Mic Volume Control" causes multiple Microphone
entries to appear in UI. Using name "Mic Volume Control" ensures only a
single Microphone entry exists when the Headset is connected.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 
BugLink: https://bugs.launchpad.net/bugs/1918378
Reported-and-tested-by: You-Sheng Yang 

Changes in v1:
- No changes

Changes in v2:
- No changes
---
 sound/pci/hda/patch_cirrus.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 7dd48f0ff000..b64c11e8c8a1 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1789,7 +1789,7 @@ static const struct snd_kcontrol_new 
cs8409_cs42l42_hp_volume_mixer = {
 static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.index = 0,
-   .name = "Headset Mic Capture Volume",
+   .name = "Mic Capture Volume",
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE
 | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-- 
2.25.1



[PATCH v2 2/4] ALSA: hda/cirrus: Cleanup patch_cirrus.c code.

2021-03-15 Thread Vitaly Rodionov
From: Stefan Binding 

Minor changes, clean up code, remove unnecessary
initialization of variables, reduced number of
warnings from ./scripts/checkpatch.pl from 19 to 0

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 

Changes in v1:
- Fixed warning (Reported-by: kernel test robot )

Changes in v2:
- No Changes
---
 sound/pci/hda/patch_cirrus.c | 147 +--
 1 file changed, 72 insertions(+), 75 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 6c062c7ab76a..7dd48f0ff000 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -127,7 +127,7 @@ enum {
  * 1 DAC => HP(sense) / Speakers,
  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
-*/
+ */
 #define CS4210_DAC_NID 0x02
 #define CS4210_ADC_NID 0x03
 #define CS4210_VENDOR_NID  0x0B
@@ -146,6 +146,7 @@ enum {
 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
 {
struct cs_spec *spec = codec->spec;
+
snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
return snd_hda_codec_read(codec, spec->vendor_nid, 0,
@@ -156,6 +157,7 @@ static inline void cs_vendor_coef_set(struct hda_codec 
*codec, unsigned int idx,
  unsigned int coef)
 {
struct cs_spec *spec = codec->spec;
+
snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
@@ -192,6 +194,7 @@ static void cs_automute(struct hda_codec *codec)
 static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
 {
unsigned int val;
+
val = snd_hda_codec_get_pincfg(codec, nid);
return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
 }
@@ -210,7 +213,7 @@ static void init_input_coef(struct hda_codec *codec)
coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
 * No effect if SPDIF_OUT2 is
 * selected in IDX_SPDIF_CTL.
-   */
+*/
 
cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
}
@@ -284,13 +287,6 @@ static const struct hda_verb cs_errata_init_verbs[] = {
{0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
{0x11, AC_VERB_SET_PROC_COEF, 0x0008},
{0x11, AC_VERB_SET_PROC_STATE, 0x00},
-
-#if 0 /* Don't to set to D3 as we are in power-up sequence */
-   {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */
-   {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */
-   /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already 
handled */
-#endif
-
{} /* terminator */
 };
 
@@ -378,8 +374,10 @@ static int cs_parse_auto_config(struct hda_codec *codec)
/* keep the ADCs powered up when it's dynamically switchable */
if (spec->gen.dyn_adc_switch) {
unsigned int done = 0;
+
for (i = 0; i < spec->gen.input_mux.num_items; i++) {
int idx = spec->gen.dyn_adc_idx[i];
+
if (done & (1 << idx))
continue;
snd_hda_gen_fix_pin_power(codec,
@@ -513,6 +511,7 @@ static void cs420x_fixup_gpio_13(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
spec->gpio_mask = spec->gpio_dir =
@@ -525,6 +524,7 @@ static void cs420x_fixup_gpio_23(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
spec->gpio_mask = spec->gpio_dir =
@@ -669,6 +669,7 @@ static void cs4208_fixup_gpio0(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 0;
spec->gpio_eapd_speaker = 1;
spec->gpio_mask = spec->gpio_dir =
@@ -823,7 +824,7 @@ static int patch_cs4208(struct hda_codec *codec)
  * 1 DAC => HP(sense) / Speakers,
  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
-*/
+ */
 
 /* CS4210 board names */
 static const struct hda_model_fixup cs421x_models[] = {
@@ -866,6 +867,7 @@ static void cs421x_fixup_sense_b(struct hda_code

[PATCH v2 4/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

2021-03-15 Thread Vitaly Rodionov
From: Stefan Binding 

CS8409/CS42L42 Driver currently does most of the platform specific
setup inside the main body of the code, however, this setup can be
moved into fixup functions, to make the driver more generic.

Making the driver more generic, allows the driver to use the
cs_parse_auto_config function in the patch function. This function
forces all of the ADCs to be permanently powered, which means the
cap_sync_hook function is no longer needed to restart the stream, when
the jack has been ejected.

Since the codec is re-initialized on every init/resume, there is no
need to add specific verbs to be run on init, and instead these can
be combined with the initialization verbs, which are run on init.

In addition, the extra fixup verbs are no longer required, since this
is taken care of elsewhere.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 
---
 sound/pci/hda/patch_cirrus.c | 280 ---
 1 file changed, 98 insertions(+), 182 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index b64c11e8c8a1..965e4357f030 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1292,9 +1292,14 @@ enum {
CS8409_BULLSEYE,
CS8409_WARLOCK,
CS8409_CYBORG,
-   CS8409_VERBS,
+   CS8409_FIXUPS,
 };
 
+static void cs8409_cs42l42_fixups(struct hda_codec *codec,
+   const struct hda_fixup *fix, int action);
+static int cs8409_cs42l42_exec_verb(struct hdac_device *dev,
+   unsigned int cmd, unsigned int flags, unsigned int *res);
+
 /* Dell Inspiron models with cs8409/cs42l42 */
 static const struct hda_model_fixup cs8409_models[] = {
{ .id = CS8409_BULLSEYE, .name = "bullseye" },
@@ -1368,48 +1373,28 @@ static const struct hda_pintbl cs8409_cs42l42_pincfgs[] 
= {
{} /* 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,
+   .chain_id = CS8409_FIXUPS,
},
[CS8409_WARLOCK] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
-   .chain_id = CS8409_VERBS,
+   .chain_id = CS8409_FIXUPS,
},
[CS8409_CYBORG] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
-   .chain_id = CS8409_VERBS,
+   .chain_id = CS8409_FIXUPS,
},
-   [CS8409_VERBS] = {
-   .type = HDA_FIXUP_VERBS,
-   .v.verbs = cs8409_cs42l42_add_verbs,
+   [CS8409_FIXUPS] = {
+   .type = HDA_FIXUP_FUNC,
+   .v.func = cs8409_cs42l42_fixups,
},
 };
 
@@ -2004,26 +1989,6 @@ static void cs8409_jack_unsol_event(struct hda_codec 
*codec, unsigned int res)
}
 }
 
-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);
-
-   /* 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(10, 15);
-
-   return 0;
-}
-
 #ifdef CONFIG_PM
 /* Manage PDREF, when transition to D3hot */
 static int cs8409_suspend(struct hda_codec *codec)
@@ -2044,31 +2009,6 @@ static int cs8409_suspend(struct hda_codec *codec)
 }
 #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 head

[PATCH v2 0/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups

2021-03-15 Thread Vitaly Rodionov
This series of patches will address comments by Pierre-Louis Bossart,
cleans up patch_cirrus.c source, reducing checkpatch.pl warnings from 19 to 0,
fixing an issue reported by Canonical: BugLink: 
https://bugs.launchpad.net/bugs/1918378,
and makes the CS8409 patch more generic by using fixups.

Stefan Binding (4):
  ALSA: hda/cirrus: Add error handling into CS8409 I2C functions
  ALSA: hda/cirrus: Cleanup patch_cirrus.c code.
  ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name
  ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

 sound/pci/hda/patch_cirrus.c | 525 ---
 1 file changed, 242 insertions(+), 283 deletions(-)

-- 
2.25.1



Re: [PATCH v1 4/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

2021-03-15 Thread Vitaly Rodionov

On 15/03/2021 7:49 am, Takashi Iwai wrote:

On Sat, 13 Mar 2021 12:34:10 +0100,
Vitaly Rodionov wrote:

@@ -1357,6 +1362,22 @@ static const struct hda_verb cs8409_cs42l42_init_verbs[] 
= {
{ 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 */
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0xF0 }, /* Widget node 
ASP-1-TX */
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x20 },
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x21 },
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x04 },
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0x50 }, /* Widget node 
ASP-1-RX0 */
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x20 },
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0xa1 },
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x04 },
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0xF0 }, /* Widget node 
ASP-2-TX */
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x00 },
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x10 },
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x90 },
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0x90 }, /* Widget node 
DMIC-1 */
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x00 },
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0xA0 },
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x90 },

Those widgets are all pin widgets, right?  If so, setting via the
pincfg table would be more suitable, as it's cached and exposed via
sysfs for debugging.


Yes, you are right, actually we already have these widgets in pincfg 
table, so this code is redundant.


Will fix in next version.




thanks,

Takashi





Re: [PATCH v1 1/4] ALSA: hda/cirrus: Add error handling into CS8409 I2C functions

2021-03-15 Thread Vitaly Rodionov

On 15/03/2021 7:45 am, Takashi Iwai wrote:

Hi Takashi,
Thanks a lot for your comments.


On Sat, 13 Mar 2021 12:34:07 +0100,
Vitaly Rodionov wrote:

@@ -1508,7 +1508,7 @@ static void cs8409_enable_i2c_clock(struct hda_codec 
*codec, unsigned int flag)
  static int cs8409_i2c_wait_complete(struct hda_codec *codec)
  {
int repeat = 5;
-   unsigned int retval = 0;
+   unsigned int retval;
  
  	do {

retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS);
@@ -1520,78 +1520,82 @@ static int cs8409_i2c_wait_complete(struct hda_codec 
*codec)
  
  	} while (repeat);
  
-	return repeat > 0 ? 0 : -1;

+   return !!repeat;
  }

If the return value of the function has changed, it's nicer to
comment, e.g. a brief function description would be helpful.
Also now this looks rather like a bool?

Yes, agreed , we will add comments to describe parameters and return values




@@ -1881,13 +1896,15 @@ static void cs8409_jack_unsol_event(struct hda_codec 
*codec, unsigned int res)
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 */

+   /* Clear interrupts, by reading interrupt status registers */
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);

Why those two calls are removed?
This 2 call are redundant as we already did read these 2 registers in a 
code few lines above.



mutex_unlock(>cs8409_i2c_mux);
  
+	/* If status values are < 0, read error has occurred. */

+   if ((reg_cdc_status < 0) || (reg_hs_status < 0) || (reg_ts_status < 0))
+   return;

Parentheses around the comparison are superfluous, you can remove
them.

Will fix.


thanks,

Takashi





Re: [PATCH v1 0/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups

2021-03-14 Thread Vitaly Rodionov

On 14/03/2021 8:36 am, Takashi Iwai wrote:

On Sat, 13 Mar 2021 12:34:06 +0100,
Vitaly Rodionov wrote:

This series of patches will address comments by Pierre-Louis Bossart,
cleans up patch_cirrus.c source, reducing checkpatch.pl warnings from 19 to 0,
fixing an issue reported by Canonical: BugLink: 
https://bugs.launchpad.net/bugs/1918378,
and makes the CS8409 patch more generic by using fixups.

Stefan Binding (4):
   ALSA: hda/cirrus: Add error handling into CS8409 I2C functions
   ALSA: hda/cirrus: Cleanup patch_cirrus.c code.
   ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name
   ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

Is this the same content as the series you've already submitted in
20210312184452.3288-1-vita...@opensource.cirrus.com ?


Hi Takashi,

Yes, this is second version of same series, where we have fixed warnings 
from 0-day bot.


Thanks,

Vitaly




thanks,

Takashi





[PATCH v1 3/4] ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name

2021-03-13 Thread Vitaly Rodionov
From: Stefan Binding 

Existing name "Headset Mic Volume Control" causes multiple Microphone
entries to appear in UI. Using name "Mic Volume Control" ensures only a
single Microphone entry exists when the Headset is connected.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 
BugLink: https://bugs.launchpad.net/bugs/1918378
Reported-and-tested-by: You-Sheng Yang 

Changes in v1:
- No changes

---
 sound/pci/hda/patch_cirrus.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 650457bf0d77..74ac758aa4d5 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1760,7 +1760,7 @@ static const struct snd_kcontrol_new 
cs8409_cs42l42_hp_volume_mixer = {
 static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.index = 0,
-   .name = "Headset Mic Capture Volume",
+   .name = "Mic Capture Volume",
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE
 | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-- 
2.25.1



[PATCH v1 0/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups

2021-03-13 Thread Vitaly Rodionov
This series of patches will address comments by Pierre-Louis Bossart,
cleans up patch_cirrus.c source, reducing checkpatch.pl warnings from 19 to 0,
fixing an issue reported by Canonical: BugLink: 
https://bugs.launchpad.net/bugs/1918378,
and makes the CS8409 patch more generic by using fixups.

Stefan Binding (4):
  ALSA: hda/cirrus: Add error handling into CS8409 I2C functions
  ALSA: hda/cirrus: Cleanup patch_cirrus.c code.
  ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name
  ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

 sound/pci/hda/patch_cirrus.c | 506 ---
 1 file changed, 228 insertions(+), 278 deletions(-)

-- 
2.25.1



[PATCH v1 2/4] ALSA: hda/cirrus: Cleanup patch_cirrus.c code.

2021-03-13 Thread Vitaly Rodionov
From: Stefan Binding 

Minor changes, clean up code, remove unnecessary
initialization of variables, reduced number of
warnings from ./scripts/checkpatch.pl from 19 to 0

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 

Changes in v1:
- Fixed warning (Reported-by: kernel test robot )

---
 sound/pci/hda/patch_cirrus.c | 155 ++-
 1 file changed, 78 insertions(+), 77 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index ca8b522b1d6d..650457bf0d77 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -127,7 +127,7 @@ enum {
  * 1 DAC => HP(sense) / Speakers,
  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
-*/
+ */
 #define CS4210_DAC_NID 0x02
 #define CS4210_ADC_NID 0x03
 #define CS4210_VENDOR_NID  0x0B
@@ -146,6 +146,7 @@ enum {
 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
 {
struct cs_spec *spec = codec->spec;
+
snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
return snd_hda_codec_read(codec, spec->vendor_nid, 0,
@@ -156,6 +157,7 @@ static inline void cs_vendor_coef_set(struct hda_codec 
*codec, unsigned int idx,
  unsigned int coef)
 {
struct cs_spec *spec = codec->spec;
+
snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
@@ -192,6 +194,7 @@ static void cs_automute(struct hda_codec *codec)
 static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
 {
unsigned int val;
+
val = snd_hda_codec_get_pincfg(codec, nid);
return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
 }
@@ -210,7 +213,7 @@ static void init_input_coef(struct hda_codec *codec)
coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
 * No effect if SPDIF_OUT2 is
 * selected in IDX_SPDIF_CTL.
-   */
+*/
 
cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
}
@@ -284,13 +287,6 @@ static const struct hda_verb cs_errata_init_verbs[] = {
{0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
{0x11, AC_VERB_SET_PROC_COEF, 0x0008},
{0x11, AC_VERB_SET_PROC_STATE, 0x00},
-
-#if 0 /* Don't to set to D3 as we are in power-up sequence */
-   {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */
-   {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */
-   /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already 
handled */
-#endif
-
{} /* terminator */
 };
 
@@ -378,8 +374,10 @@ static int cs_parse_auto_config(struct hda_codec *codec)
/* keep the ADCs powered up when it's dynamically switchable */
if (spec->gen.dyn_adc_switch) {
unsigned int done = 0;
+
for (i = 0; i < spec->gen.input_mux.num_items; i++) {
int idx = spec->gen.dyn_adc_idx[i];
+
if (done & (1 << idx))
continue;
snd_hda_gen_fix_pin_power(codec,
@@ -513,6 +511,7 @@ static void cs420x_fixup_gpio_13(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
spec->gpio_mask = spec->gpio_dir =
@@ -525,6 +524,7 @@ static void cs420x_fixup_gpio_23(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
spec->gpio_mask = spec->gpio_dir =
@@ -669,6 +669,7 @@ static void cs4208_fixup_gpio0(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 0;
spec->gpio_eapd_speaker = 1;
spec->gpio_mask = spec->gpio_dir =
@@ -823,7 +824,7 @@ static int patch_cs4208(struct hda_codec *codec)
  * 1 DAC => HP(sense) / Speakers,
  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
-*/
+ */
 
 /* CS4210 board names */
 static const struct hda_model_fixup cs421x_models[] = {
@@ -866,6 +867,7 @@ static void cs421x_fixup_sense_b(struct hda_codec *codec,
  

[PATCH v1 1/4] ALSA: hda/cirrus: Add error handling into CS8409 I2C functions

2021-03-13 Thread Vitaly Rodionov
From: Stefan Binding 

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 

Changes in v1:
- No changes

---
 sound/pci/hda/patch_cirrus.c | 95 +---
 1 file changed, 56 insertions(+), 39 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 6a9e5c803977..ca8b522b1d6d 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1508,7 +1508,7 @@ static void cs8409_enable_i2c_clock(struct hda_codec 
*codec, unsigned int flag)
 static int cs8409_i2c_wait_complete(struct hda_codec *codec)
 {
int repeat = 5;
-   unsigned int retval = 0;
+   unsigned int retval;
 
do {
retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS);
@@ -1520,78 +1520,82 @@ static int cs8409_i2c_wait_complete(struct hda_codec 
*codec)
 
} while (repeat);
 
-   return repeat > 0 ? 0 : -1;
+   return !!repeat;
 }
 
-/* CS8409 slave i2cRead */
-static unsigned int cs8409_i2c_read(struct hda_codec *codec,
+/* CS8409 slave i2cRead.
+ * Returns negative on error, otherwise returns read value in bits 0-7.
+ */
+static 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 = 0;
+   unsigned int read_data;
 
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) {
+   if (!cs8409_i2c_wait_complete(codec)) {
codec_err(codec,
-   "%s() Paged Transaction Failed 0x%02x : 0x%04x 
= 0x%02x\n",
-   __func__, i2c_address, i2c_reg, retval);
+   "%s() Paged Transaction Failed 0x%02x : 
0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
}
 
i2c_reg_data = (i2c_reg << 8) & 0x0;
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);
+   if (!cs8409_i2c_wait_complete(codec)) {
+   codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
 
/* Register in bits 15-8 and the data in 7-0 */
-   retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
-   retval &= 0x0ff;
+   read_data = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
 
cs8409_enable_i2c_clock(codec, 0);
 
-   return retval;
+   return read_data & 0x0ff;
 }
 
 /* CS8409 slave i2cWrite */
-static unsigned int cs8409_i2c_write(struct hda_codec *codec,
+static 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;
+   unsigned int i2c_reg_data;
 
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) {
+   if (!cs8409_i2c_wait_complete(codec)) {
codec_err(codec,
-   "%s() Paged Transaction Failed 0x%02x : 0x%04x 
= 0x%02x\n",
-   __func__, i2c_address, i2c_reg, retval);
+   "%s() Paged Transaction Failed 0x%02x : 
0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
}
 
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);
+   if (!cs8409_i2c_wait_complete(codec)) {
+   codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
 
cs8409_enable_i2c_clock(codec, 0);
 
-   return retval;

[PATCH v1 4/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

2021-03-13 Thread Vitaly Rodionov
From: Stefan Binding 

CS8409/CS42L42 Driver currently does most of the platform specific
setup inside the main body of the code, however, this setup can be
moved into fixup functions, to make the driver more generic.

Making the driver more generic, allows the driver to use the
cs_parse_auto_config function in the patch function. This function
forces all of the ADCs to be permanently powered, which means the
cap_sync_hook function is no longer needed to restart the stream, when
the jack has been ejected.

Since the codec is re-initialized on every init/resume, there is no
need to add specific verbs to be run on init, and instead these can
be combined with the initialization verbs, which are run on init.

In addition, the extra fixup verbs are no longer required, since this
is taken care of elsewhere.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 

Changes in v1:
- No changes

---
 sound/pci/hda/patch_cirrus.c | 304 ++-
 1 file changed, 118 insertions(+), 186 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 74ac758aa4d5..d0a3c3189d26 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1292,9 +1292,14 @@ enum {
CS8409_BULLSEYE,
CS8409_WARLOCK,
CS8409_CYBORG,
-   CS8409_VERBS,
+   CS8409_FIXUPS,
 };
 
+static void cs8409_cs42l42_fixups(struct hda_codec *codec,
+   const struct hda_fixup *fix, int action);
+static int cs8409_cs42l42_exec_verb(struct hdac_device *dev,
+   unsigned int cmd, unsigned int flags, unsigned int *res);
+
 /* Dell Inspiron models with cs8409/cs42l42 */
 static const struct hda_model_fixup cs8409_models[] = {
{ .id = CS8409_BULLSEYE, .name = "bullseye" },
@@ -1357,6 +1362,22 @@ static const struct hda_verb cs8409_cs42l42_init_verbs[] 
= {
{ 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 */
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0xF0 }, /* Widget node 
ASP-1-TX */
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x20 },
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x21 },
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x04 },
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0x50 }, /* Widget node 
ASP-1-RX0 */
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x20 },
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0xa1 },
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x04 },
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0xF0 }, /* Widget node 
ASP-2-TX */
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x00 },
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x10 },
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x90 },
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0x90 }, /* Widget node 
DMIC-1 */
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x00 },
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0xA0 },
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x90 },
{} /* terminator */
 };
 
@@ -1368,48 +1389,28 @@ static const struct hda_pintbl cs8409_cs42l42_pincfgs[] 
= {
{} /* 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,
+   .chain_id = CS8409_FIXUPS,
},
[CS8409_WARLOCK] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
-   .chain_id = CS8409_VERBS,
+   .chain_id = CS8409_FIXUPS,
},
[CS8409_CYBORG] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
-   .chain_id = CS8409_VERBS,
+   .chain_id = CS8409_FIXUPS,
},
-   [CS8409_VERBS] = {
-   .type = HDA_F

[PATCH 4/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

2021-03-12 Thread Vitaly Rodionov
From: Stefan Binding 

CS8409/CS42L42 Driver currently does most of the platform specific
setup inside the main body of the code, however, this setup can be
moved into fixup functions, to make the driver more generic.

Making the driver more generic, allows the driver to use the
cs_parse_auto_config function in the patch function. This function
forces all of the ADCs to be permanently powered, which means the
cap_sync_hook function is no longer needed to restart the stream, when
the jack has been ejected.

Since the codec is re-initialized on every init/resume, there is no
need to add specific verbs to be run on init, and instead these can
be combined with the initialization verbs, which are run on init.

In addition, the extra fixup verbs are no longer required, since this
is taken care of elsewhere.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 
---
 sound/pci/hda/patch_cirrus.c | 304 ++-
 1 file changed, 118 insertions(+), 186 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 6495da523ea3..8cb91ca1720a 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1292,9 +1292,14 @@ enum {
CS8409_BULLSEYE,
CS8409_WARLOCK,
CS8409_CYBORG,
-   CS8409_VERBS,
+   CS8409_FIXUPS,
 };
 
+static void cs8409_cs42l42_fixups(struct hda_codec *codec,
+   const struct hda_fixup *fix, int action);
+static int cs8409_cs42l42_exec_verb(struct hdac_device *dev,
+   unsigned int cmd, unsigned int flags, unsigned int *res);
+
 /* Dell Inspiron models with cs8409/cs42l42 */
 static const struct hda_model_fixup cs8409_models[] = {
{ .id = CS8409_BULLSEYE, .name = "bullseye" },
@@ -1357,6 +1362,22 @@ static const struct hda_verb cs8409_cs42l42_init_verbs[] 
= {
{ 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 */
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0xF0 }, /* Widget node 
ASP-1-TX */
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x20 },
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x21 },
+   { 0x24, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x04 },
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0x50 }, /* Widget node 
ASP-1-RX0 */
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x20 },
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0xa1 },
+   { 0x34, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x04 },
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0xF0 }, /* Widget node 
ASP-2-TX */
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x00 },
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x10 },
+   { 0x2C, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x90 },
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, 0x90 }, /* Widget node 
DMIC-1 */
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0x00 },
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0xA0 },
+   { 0x44, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x90 },
{} /* terminator */
 };
 
@@ -1368,48 +1389,28 @@ static const struct hda_pintbl cs8409_cs42l42_pincfgs[] 
= {
{} /* 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,
+   .chain_id = CS8409_FIXUPS,
},
[CS8409_WARLOCK] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
-   .chain_id = CS8409_VERBS,
+   .chain_id = CS8409_FIXUPS,
},
[CS8409_CYBORG] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
-   .chain_id = CS8409_VERBS,
+   .chain_id = CS8409_FIXUPS,
},
-   [CS8409_VERBS] = {
-   .type = HDA_FIXUP_VERBS,
-   .v.verbs = cs8409_cs42l42

[PATCH 3/4] ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name

2021-03-12 Thread Vitaly Rodionov
From: Stefan Binding 

Existing name "Headset Mic Volume Control" causes multiple Microphone
entries to appear in UI. Using name "Mic Volume Control" ensures only a
single Microphone entry exists when the Headset is connected.

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 
BugLink: https://bugs.launchpad.net/bugs/1918378
Reported-and-tested-by: You-Sheng Yang 
---
 sound/pci/hda/patch_cirrus.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 20e2cc433c6e..6495da523ea3 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1760,7 +1760,7 @@ static const struct snd_kcontrol_new 
cs8409_cs42l42_hp_volume_mixer = {
 static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.index = 0,
-   .name = "Headset Mic Capture Volume",
+   .name = "Mic Capture Volume",
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE
 | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-- 
2.25.1



[PATCH 2/4] ALSA: hda/cirrus: Cleanup patch_cirrus.c code.

2021-03-12 Thread Vitaly Rodionov
From: Stefan Binding 

Minor changes, clean up code, remove unnecessary
initialization of variables, reduced number of
warnings from ./scripts/checkpatch.pl from 19 to 0

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 
---
 sound/pci/hda/patch_cirrus.c | 155 ++-
 1 file changed, 78 insertions(+), 77 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index ca8b522b1d6d..20e2cc433c6e 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -127,7 +127,7 @@ enum {
  * 1 DAC => HP(sense) / Speakers,
  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
-*/
+ */
 #define CS4210_DAC_NID 0x02
 #define CS4210_ADC_NID 0x03
 #define CS4210_VENDOR_NID  0x0B
@@ -146,6 +146,7 @@ enum {
 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
 {
struct cs_spec *spec = codec->spec;
+
snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
return snd_hda_codec_read(codec, spec->vendor_nid, 0,
@@ -156,6 +157,7 @@ static inline void cs_vendor_coef_set(struct hda_codec 
*codec, unsigned int idx,
  unsigned int coef)
 {
struct cs_spec *spec = codec->spec;
+
snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
@@ -192,6 +194,7 @@ static void cs_automute(struct hda_codec *codec)
 static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
 {
unsigned int val;
+
val = snd_hda_codec_get_pincfg(codec, nid);
return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
 }
@@ -210,7 +213,7 @@ static void init_input_coef(struct hda_codec *codec)
coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
 * No effect if SPDIF_OUT2 is
 * selected in IDX_SPDIF_CTL.
-   */
+*/
 
cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
}
@@ -284,13 +287,6 @@ static const struct hda_verb cs_errata_init_verbs[] = {
{0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
{0x11, AC_VERB_SET_PROC_COEF, 0x0008},
{0x11, AC_VERB_SET_PROC_STATE, 0x00},
-
-#if 0 /* Don't to set to D3 as we are in power-up sequence */
-   {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */
-   {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */
-   /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already 
handled */
-#endif
-
{} /* terminator */
 };
 
@@ -378,8 +374,10 @@ static int cs_parse_auto_config(struct hda_codec *codec)
/* keep the ADCs powered up when it's dynamically switchable */
if (spec->gen.dyn_adc_switch) {
unsigned int done = 0;
+
for (i = 0; i < spec->gen.input_mux.num_items; i++) {
int idx = spec->gen.dyn_adc_idx[i];
+
if (done & (1 << idx))
continue;
snd_hda_gen_fix_pin_power(codec,
@@ -513,6 +511,7 @@ static void cs420x_fixup_gpio_13(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
spec->gpio_mask = spec->gpio_dir =
@@ -525,6 +524,7 @@ static void cs420x_fixup_gpio_23(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
spec->gpio_mask = spec->gpio_dir =
@@ -669,6 +669,7 @@ static void cs4208_fixup_gpio0(struct hda_codec *codec,
 {
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct cs_spec *spec = codec->spec;
+
spec->gpio_eapd_hp = 0;
spec->gpio_eapd_speaker = 1;
spec->gpio_mask = spec->gpio_dir =
@@ -823,7 +824,7 @@ static int patch_cs4208(struct hda_codec *codec)
  * 1 DAC => HP(sense) / Speakers,
  * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
  * 1 SPDIF OUT => SPDIF Trasmitter(sense)
-*/
+ */
 
 /* CS4210 board names */
 static const struct hda_model_fixup cs421x_models[] = {
@@ -866,6 +867,7 @@ static void cs421x_fixup_sense_b(struct hda_codec *codec,
 const struct hda_fixup *fix, int action)
 {

[PATCH 1/4] ALSA: hda/cirrus: Add error handling into CS8409 I2C functions

2021-03-12 Thread Vitaly Rodionov
From: Stefan Binding 

Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500

Signed-off-by: Stefan Binding 
Signed-off-by: Vitaly Rodionov 
---
 sound/pci/hda/patch_cirrus.c | 95 +---
 1 file changed, 56 insertions(+), 39 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 6a9e5c803977..ca8b522b1d6d 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1508,7 +1508,7 @@ static void cs8409_enable_i2c_clock(struct hda_codec 
*codec, unsigned int flag)
 static int cs8409_i2c_wait_complete(struct hda_codec *codec)
 {
int repeat = 5;
-   unsigned int retval = 0;
+   unsigned int retval;
 
do {
retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS);
@@ -1520,78 +1520,82 @@ static int cs8409_i2c_wait_complete(struct hda_codec 
*codec)
 
} while (repeat);
 
-   return repeat > 0 ? 0 : -1;
+   return !!repeat;
 }
 
-/* CS8409 slave i2cRead */
-static unsigned int cs8409_i2c_read(struct hda_codec *codec,
+/* CS8409 slave i2cRead.
+ * Returns negative on error, otherwise returns read value in bits 0-7.
+ */
+static 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 = 0;
+   unsigned int read_data;
 
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) {
+   if (!cs8409_i2c_wait_complete(codec)) {
codec_err(codec,
-   "%s() Paged Transaction Failed 0x%02x : 0x%04x 
= 0x%02x\n",
-   __func__, i2c_address, i2c_reg, retval);
+   "%s() Paged Transaction Failed 0x%02x : 
0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
}
 
i2c_reg_data = (i2c_reg << 8) & 0x0;
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);
+   if (!cs8409_i2c_wait_complete(codec)) {
+   codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
 
/* Register in bits 15-8 and the data in 7-0 */
-   retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
-   retval &= 0x0ff;
+   read_data = cs_vendor_coef_get(codec, CIR_I2C_QREAD);
 
cs8409_enable_i2c_clock(codec, 0);
 
-   return retval;
+   return read_data & 0x0ff;
 }
 
 /* CS8409 slave i2cWrite */
-static unsigned int cs8409_i2c_write(struct hda_codec *codec,
+static 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;
+   unsigned int i2c_reg_data;
 
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) {
+   if (!cs8409_i2c_wait_complete(codec)) {
codec_err(codec,
-   "%s() Paged Transaction Failed 0x%02x : 0x%04x 
= 0x%02x\n",
-   __func__, i2c_address, i2c_reg, retval);
+   "%s() Paged Transaction Failed 0x%02x : 
0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
}
 
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);
+   if (!cs8409_i2c_wait_complete(codec)) {
+   codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n",
+   __func__, i2c_address, i2c_reg);
+   return -EIO;
}
 
cs8409_enable_i2c_clock(codec, 0);
 
-   return retval;
+   return 0;
 }
 
 static int

[PATCH 0/4] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups

2021-03-12 Thread Vitaly Rodionov
This series of patches will address comments by Pierre-Louis Bossart,
cleans up patch_cirrus.c source, reducing checkpatch.pl warnings from 19 to 0,
fixing an issue reported by Canonical: BugLink: 
https://bugs.launchpad.net/bugs/1918378,
and makes the CS8409 patch more generic by using fixups.

Stefan Binding (4):
  ALSA: hda/cirrus: Add error handling into CS8409 I2C functions
  ALSA: hda/cirrus: Cleanup patch_cirrus.c code.
  ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name
  ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups.

 sound/pci/hda/patch_cirrus.c | 506 ---
 1 file changed, 228 insertions(+), 278 deletions(-)

-- 
2.25.1



Re: [PATCH v3 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.

2021-03-09 Thread Vitaly Rodionov

On 08/03/2021 3:35 pm, Pierre-Louis Bossart wrote:





@@ -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;


what does this protect? there isn't any comment or explanations in the 
commit message.




we are protecting sequences of i2c transactions.

for example,  when we are writing sequence to activate jack detect, as a 
result of interrupt via gpio4


unsolicited response can be called by framework at the same time. we 
want to finish first sequence.




Re: [PATCH v3 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.

2021-03-09 Thread Vitaly Rodionov

On 08/03/2021 3:33 pm, Pierre-Louis Bossart wrote:

Hi Pierre-Louis

Thanks a lot for your comments. Since this patch set has been merged we 
will address

your comments in a next fix patch.



+/* Enable I2C clocks */
+static void cs8409_enable_i2c_clock(struct hda_codec *codec, 
unsigned int flag)

+{
+    unsigned int retval = 0;
+    unsigned int newval = 0;


initializations not needed

Will fix that.



+    retval = cs_vendor_coef_get(codec, 0x0);
+    newval = (flag) ? (retval | 0x8) : (retval & 0xfff7);
+    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;


initialization not needed.

Will fix that.



+
+    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;


can we simplify by returning !!repeat ?

Yes, we can simplify this code as well.



+}
+
+/* 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 = 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);


return an error?
Yes, you are right there is no reason to continue if we hit an error 
here. Will be fixed.



+    }
+    }
+
+    i2c_reg_data = (i2c_reg << 8) & 0x0;
+    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);


return and error?

Same as above



+    }
+
+    /* 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);


return error?

Same as above



+    }
+    }
+
+    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);


return error?

Same as above



+    }
+
+    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(1, 15000);
+    /* Release RTS# line */
+    snd_hda_codec_write(codec,
+    codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, GPIO5_INT);
+    /* wait ~10ms */
+    usleep_range(1, 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);


clear on read?
This is how CS42L42 works, to clear interrupts we have to read 
interrupts status registers.




+static int cs8409_cs42l42_fixup(struct hda_codec *codec)
+{
+    int err = 0;


useless init

Will fix.



+    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
+ 

[PATCH v3 1/4] ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18

2021-03-06 Thread Vitaly Rodionov
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 
---

Changes in v3:
- No changes

 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



[PATCH v3 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.

2021-03-06 Thread Vitaly Rodionov
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 
---

Changes in v3:
- Fixed missing static function declaration warning (Reported-by: kernel test 
robot )
- Improved unsolicited events handling for headset type 4

 sound/pci/hda/patch_cirrus.c | 309 ++-
 1 file changed, 307 insertions(+), 2 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index d664eed5c3cf..1d2f6a1224e6 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -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_NID0x34
 #define CS8409_CS42L42_DMIC_PIN_NID0x44
+#define CS8409_CS42L42_DMIC_ADC_PIN_NID0x22
+
+#define CS42L42_HSDET_AUTO_DONE0x02
+#define CS42L42_HSTYPE_MASK0x03
+
+#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,190 @@ static void cs8409_cs42l42_reset(struct hda_codec 
*codec)
/* wait ~10ms */
usleep_range(1, 15000);
 
-   /* Clear interrupts status */
+   mutex_lock(>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(>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(>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(>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(>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_writ

[PATCH v3 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec

2021-03-06 Thread Vitaly Rodionov
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| 1081 +++
 3 files changed, 1083 insertions(+), 2 deletions(-)

-- 
2.25.1



[PATCH v3 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.

2021-03-06 Thread Vitaly Rodionov
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/pci:00/:00:1f.3/sound/card0/input8
input: HDA Intel PCH Headset Mic as 
/devices/pci:00/:00:1f.3/sound/card0/input9

Signed-off-by: Vitaly Rodionov 
---

Changes in v3:
- Fixed uninitialized variable warning (Reported-by: kernel test robot 
)
- Moved gpio setup into s8409_cs42l42_hw_init()
- Improved susped() implementation

 sound/pci/hda/patch_cirrus.c | 576 +++
 1 file changed, 576 insertions(+)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index f46204ab0b90..d664eed5c3cf 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include "hda_local.h"
@@ -1219,6 +1220,580 @@ 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_NID0x34
+#define CS8409_CS42L42_DMIC_PIN_NID0x44
+
+#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_

[PATCH v3 4/4] ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control

2021-03-06 Thread Vitaly Rodionov
From: Stefan Binding 

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 
Signed-off-by: Vitaly Rodionov 
---

Changes in v3:
- Added restore volumes after resume
- Removed redundant debug logging after testing


 sound/pci/hda/patch_cirrus.c | 200 +++
 1 file changed, 200 insertions(+)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 1d2f6a1224e6..6a9e5c803977 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;
@@ -1580,6 +1594,165 @@ 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(>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));
+   mutex_unlock(>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;
+
+   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];
+   if (chs & 2)
+   *valp++ = spec->cs42l42_hp_volume[1];
+   break;
+   case CS8409_CS42L42_AMIC_PIN_NID:
+   if (chs & 1)
+   *valp++ = spec->cs42l42_hs_mic_volume[0];
+   break;
+   default:
+   break;
+   }
+   return 0;
+}
+
+static int cs8409_cs42

[PATCH v2 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.

2021-03-04 Thread Vitaly Rodionov
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 
---
 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 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -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_NID0x34
 #define CS8409_CS42L42_DMIC_PIN_NID0x44
+#define CS8409_CS42L42_DMIC_ADC_PIN_NID0x22
+
+#define CS42L42_HSDET_AUTO_DONE0x02
+#define CS42L42_HSTYPE_MASK0x03
+
+#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(1, 15000);
 
-   /* Clear interrupts status */
+   mutex_lock(>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(>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(>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(>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(>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(11, 20);
+   cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1

[PATCH v2 1/4] ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18

2021-03-04 Thread Vitaly Rodionov
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 
---
 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



[PATCH v2 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec

2021-03-04 Thread Vitaly Rodionov
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



[PATCH v2 4/4] ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control

2021-03-04 Thread Vitaly Rodionov
From: Stefan Binding 

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 
Signed-off-by: Vitaly Rodionov 
---
 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(>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(>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

[PATCH v2 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.

2021-03-04 Thread Vitaly Rodionov
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/pci:00/:00:1f.3/sound/card0/input8
input: HDA Intel PCH Headset Mic as 
/devices/pci:00/:00:1f.3/sound/card0/input9

Signed-off-by: Vitaly Rodionov 
---
 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 
 #include 
 #include 
+#include 
 #include 
 #include 
 #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_NID0x34
+#define CS8409_CS42L42_DMIC_PIN_NID0x44
+
+#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(0x10

Re: [PATCH 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.

2021-03-04 Thread Vitaly Rodionov

On 04/03/2021 1:45 pm, Takashi Iwai wrote:

On Wed, 03 Mar 2021 19:29:58 +0100,
Vitaly Rodionov wrote:

@@ -1243,6 +1258,8 @@ static int patch_cs4213(struct hda_codec *codec)
  #define CIR_I2C_QWRITE0x005D
  #define CIR_I2C_QREAD 0x005E
  
+static struct mutex cs8409_i2c_mux;

Any reason that this must be the global mutex?  I suppose it can fit
in own spec->i2c_mutex instead?

No,  there is no reason to have global mutex, will move it out to spec.




+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);

Hrm, this looks a big scary.  We may need to reconsider how to handle
this better later, but it's OK as long as you've tested with this
code...


We have been thinking about this code, and we have some ideas , it was 
tested by us, DELL and Canonical and works.


But we would like to change it a bit later, and handle it in a more 
generic way.





+static int cs8409_cs42l42_init(struct hda_codec *codec)
+{
+   int ret = 0;
+
+   ret = snd_hda_gen_init(codec);
+
+   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);

Ah... the init stuff at resume appears finally here.  This part should
be in the second patch instead.

Yes, moving this into second patch.



+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;

The blank line above should be removed.


+   case CS8409_CS42L42_HP_PIN_NID:
+   if (verb == AC_VERB_GET_PIN_SENSE) {
+   *res = 
(spec->cs42l42_hp_jack_in)?AC_PINSENSE_PRESENCE:0;

The spaces are needed around operators.
Similar coding-style issues are seen other places.  Please try to run
scripts/checkpatch.pl.


Fixed, and checked with scripts/checkpatch.pl. Base has 19 warnings. 
This patch will not introduce any new.





thanks,

Takashi


Thanks,

Vitaly




Re: [PATCH 4/4] ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control

2021-03-04 Thread Vitaly Rodionov

On 04/03/2021 1:49 pm, Takashi Iwai wrote:

On Wed, 03 Mar 2021 19:29:59 +0100,
Vitaly Rodionov wrote:

+static int cs8409_cs42l42_volume_get(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+   hda_nid_t nid = get_amp_nid(kcontrol);
+   int chs = get_amp_channels(kcontrol);
+   long *valp = ucontrol->value.integer.value;
+   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(_i2c_mux);
+   if (chs & 1) {
+   vol = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+   CS8409_CS42L42_REG_HS_VOLUME_CHA, 1));

Better to cache the values instead of i2c read at each time?
Then the unnecessary power up/down sequence can be avoided, too.

Yes, agree. Will be fixed in next version of patch.



thanks,

Takashi


Thank you,

Vitaly



Re: [PATCH 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.

2021-03-04 Thread Vitaly Rodionov

On 04/03/2021 1:39 pm, Takashi Iwai wrote:
Thank you very much for quick response!

On Wed, 03 Mar 2021 19:29:57 +0100,
Vitaly Rodionov wrote:

+static const struct hda_verb cs8409_cs42l42_init_verbs[] = {
+   { 0x01, AC_VERB_SET_POWER_STATE, 0x },/* AFG: D0 */

I guess this power state change is superfluous.  The AFG node is
already powered up when the codec probe or init is called.

Yes, This should be removed



+   { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0020 }, /* GPIO 5 out, 3,4 in */
+   { 0x01, AC_VERB_SET_GPIO_DATA, 0x },  /* GPIO  data 0 */
+   { 0x01, AC_VERB_SET_GPIO_MASK, 0x003f },  /* Enable GPIO */

Those are handled in spec->gpio_dir, gpio->data and gpio->mask
fields.

Will handle via spec fields.



+   { 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 */

Those remaining verbs are good in the init verbs.  But I suppose they
have to be applied at the resume as well?  But...
This was added in the next patch, but you are right we should handle it 
here.



+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);

... it seems applied only at the fixup call at parsing?

Ditto about cs8409_cs42l42_hw_init(codec).

Yes, needs to be fixed. I will make v2 patch set.



thanks,

Takashi





[PATCH 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.

2021-03-03 Thread Vitaly Rodionov
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 
---
 sound/pci/hda/patch_cirrus.c | 335 +--
 1 file changed, 324 insertions(+), 11 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 9d664982544f..fa417f7adc7d 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -38,6 +39,13 @@ 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;
+
+   /* 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 +1237,13 @@ static int patch_cs4213(struct hda_codec *codec)
 #define CS8409_CS42L42_SPK_PIN_NID 0x2c
 #define CS8409_CS42L42_AMIC_PIN_NID0x34
 #define CS8409_CS42L42_DMIC_PIN_NID0x44
+#define CS8409_CS42L42_DMIC_ADC_PIN_NID0x22
+
+#define CS42L42_HSDET_AUTO_DONE0x02
+#define CS42L42_HSTYPE_MASK0x03
+
+#define CS42L42_JACK_INSERTED  0x0C
+#define CS42L42_JACK_REMOVED   0x00
 
 #define GPIO3_INT (1 << 3)
 #define GPIO4_INT (1 << 4)
@@ -1243,6 +1258,8 @@ static int patch_cs4213(struct hda_codec *codec)
 #define CIR_I2C_QWRITE 0x005D
 #define CIR_I2C_QREAD  0x005E
 
+static struct mutex cs8409_i2c_mux;
+
 struct cs8409_i2c_param {
unsigned int addr;
unsigned int reg;
@@ -1433,6 +1450,7 @@ static const struct cs8409_i2c_param 
cs42l42_init_reg_seq[] = {
{ 0x1C03, 0xC0 },
{ 0x1105, 0x00 },
{ 0x1112, 0xC0 },
+   { 0x1101, 0x02 },
{} /* Terminator */
 };
 
@@ -1580,21 +1598,180 @@ static void cs8409_cs42l42_reset(struct hda_codec 
*codec)
/* wait ~10ms */
usleep_range(1, 15000);
 
-   /* Clear interrupts status */
+   mutex_lock(_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(_i2c_mux);
+
+}
+
+/* Configure CS42L42 slave codec for jack autodetect */
+static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec)
+{
+   mutex_lock(_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(_i2c_mux);
+
+   return 0;
+}
+
+/* Enable and run CS42L42 slave codec jack auto detect */
+static void cs8409_cs42l42_run_jack_detect(struct hda_codec *codec)
+{
+   mutex_lock(_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(11, 20);
+   cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77, 1);
+   cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0, 1);
+   /* Wait ~10ms */
+   usleep_range(1, 25000);
+
+   mutex_unlock(_i2c_mux);
+
 }
 
 static void cs8409_cs42l42_reg_setup(struct hda_codec *codec)
 {
const struct cs8409_i2c_param *seq = cs42l42_

[PATCH 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.

2021-03-03 Thread Vitaly Rodionov
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/pci:00/:00:1f.3/sound/card0/input8
input: HDA Intel PCH Headset Mic as 
/devices/pci:00/:00:1f.3/sound/card0/input9

Signed-off-by: Vitaly Rodionov 
---
 sound/pci/hda/patch_cirrus.c | 543 +++
 1 file changed, 543 insertions(+)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index f46204ab0b90..9d664982544f 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include "hda_local.h"
@@ -1219,6 +1220,547 @@ 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_NID0x34
+#define CS8409_CS42L42_DMIC_PIN_NID0x44
+
+#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(0x10

[PATCH 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.

2021-03-03 Thread Vitaly Rodionov
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

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| 1033 +++
 3 files changed, 1035 insertions(+), 2 deletions(-)

-- 
2.25.1



[PATCH 1/4] ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18

2021-03-03 Thread Vitaly Rodionov
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 
---
 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



[PATCH 4/4] ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control

2021-03-03 Thread Vitaly Rodionov
From: Stefan Binding 

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 
Signed-off-by: Vitaly Rodionov 
---
 sound/pci/hda/patch_cirrus.c | 177 +++
 1 file changed, 177 insertions(+)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index fa417f7adc7d..caad844fd047 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1258,6 +1258,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)
+
 static struct mutex cs8409_i2c_mux;
 
 struct cs8409_i2c_param {
@@ -1584,6 +1592,166 @@ 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 int cs8409_cs42l42_volume_get(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+   hda_nid_t nid = get_amp_nid(kcontrol);
+   int chs = get_amp_channels(kcontrol);
+   long *valp = ucontrol->value.integer.value;
+   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(_i2c_mux);
+   if (chs & 1) {
+   vol = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+   CS8409_CS42L42_REG_HS_VOLUME_CHA, 1));
+   codec_dbg(codec, "%s() vol(a) = %d\n", __func__, vol);
+   *valp++ = vol;
+   }
+   if (chs & 2) {
+   vol = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+   CS8409_CS42L42_REG_HS_VOLUME_CHB, 1));
+   codec_dbg(codec, "%s() vol(b) = %d\n", __func__, vol);
+   *valp++ = vol;
+   }
+   mutex_unlock(_i2c_mux);
+   break;
+   case CS8409_CS42L42_AMIC_PIN_NID:
+   mutex_lock(_i2c_mux);
+   if (chs & 1) {
+   vol = cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+   CS8409_CS42L42_REG_AMIC_VOLUME, 1);
+   codec_dbg(codec, "%s() vol() = %d\n", __func__, vol);
+   *valp++ = vol;
+   }
+   mutex_unlock(_i2c_mux);
+   break;
+   default:
+   break;
+   }
+   snd_hda_power_down(codec);
+   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);
+   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:
+   

[PATCH 4/4] ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control

2021-03-03 Thread Vitaly Rodionov
From: Stefan Binding 

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 
Signed-off-by: Vitaly Rodionov 
---
 sound/pci/hda/patch_cirrus.c | 177 +++
 1 file changed, 177 insertions(+)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index fa417f7adc7d..caad844fd047 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1258,6 +1258,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)
+
 static struct mutex cs8409_i2c_mux;
 
 struct cs8409_i2c_param {
@@ -1584,6 +1592,166 @@ 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 int cs8409_cs42l42_volume_get(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+   struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+   hda_nid_t nid = get_amp_nid(kcontrol);
+   int chs = get_amp_channels(kcontrol);
+   long *valp = ucontrol->value.integer.value;
+   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(_i2c_mux);
+   if (chs & 1) {
+   vol = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+   CS8409_CS42L42_REG_HS_VOLUME_CHA, 1));
+   codec_dbg(codec, "%s() vol(a) = %d\n", __func__, vol);
+   *valp++ = vol;
+   }
+   if (chs & 2) {
+   vol = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+   CS8409_CS42L42_REG_HS_VOLUME_CHB, 1));
+   codec_dbg(codec, "%s() vol(b) = %d\n", __func__, vol);
+   *valp++ = vol;
+   }
+   mutex_unlock(_i2c_mux);
+   break;
+   case CS8409_CS42L42_AMIC_PIN_NID:
+   mutex_lock(_i2c_mux);
+   if (chs & 1) {
+   vol = cs8409_i2c_read(codec, CS42L42_I2C_ADDR,
+   CS8409_CS42L42_REG_AMIC_VOLUME, 1);
+   codec_dbg(codec, "%s() vol() = %d\n", __func__, vol);
+   *valp++ = vol;
+   }
+   mutex_unlock(_i2c_mux);
+   break;
+   default:
+   break;
+   }
+   snd_hda_power_down(codec);
+   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);
+   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:
+   

[PATCH 2/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.

2021-03-03 Thread Vitaly Rodionov
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/pci:00/:00:1f.3/sound/card0/input8
input: HDA Intel PCH Headset Mic as 
/devices/pci:00/:00:1f.3/sound/card0/input9

Signed-off-by: Vitaly Rodionov 
---
 sound/pci/hda/patch_cirrus.c | 543 +++
 1 file changed, 543 insertions(+)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index f46204ab0b90..9d664982544f 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include "hda_local.h"
@@ -1219,6 +1220,547 @@ 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_NID0x34
+#define CS8409_CS42L42_DMIC_PIN_NID0x44
+
+#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(0x10

[PATCH 3/4] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec.

2021-03-03 Thread Vitaly Rodionov
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 
---
 sound/pci/hda/patch_cirrus.c | 335 +--
 1 file changed, 324 insertions(+), 11 deletions(-)

diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 9d664982544f..fa417f7adc7d 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -38,6 +39,13 @@ 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;
+
+   /* 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 +1237,13 @@ static int patch_cs4213(struct hda_codec *codec)
 #define CS8409_CS42L42_SPK_PIN_NID 0x2c
 #define CS8409_CS42L42_AMIC_PIN_NID0x34
 #define CS8409_CS42L42_DMIC_PIN_NID0x44
+#define CS8409_CS42L42_DMIC_ADC_PIN_NID0x22
+
+#define CS42L42_HSDET_AUTO_DONE0x02
+#define CS42L42_HSTYPE_MASK0x03
+
+#define CS42L42_JACK_INSERTED  0x0C
+#define CS42L42_JACK_REMOVED   0x00
 
 #define GPIO3_INT (1 << 3)
 #define GPIO4_INT (1 << 4)
@@ -1243,6 +1258,8 @@ static int patch_cs4213(struct hda_codec *codec)
 #define CIR_I2C_QWRITE 0x005D
 #define CIR_I2C_QREAD  0x005E
 
+static struct mutex cs8409_i2c_mux;
+
 struct cs8409_i2c_param {
unsigned int addr;
unsigned int reg;
@@ -1433,6 +1450,7 @@ static const struct cs8409_i2c_param 
cs42l42_init_reg_seq[] = {
{ 0x1C03, 0xC0 },
{ 0x1105, 0x00 },
{ 0x1112, 0xC0 },
+   { 0x1101, 0x02 },
{} /* Terminator */
 };
 
@@ -1580,21 +1598,180 @@ static void cs8409_cs42l42_reset(struct hda_codec 
*codec)
/* wait ~10ms */
usleep_range(1, 15000);
 
-   /* Clear interrupts status */
+   mutex_lock(_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(_i2c_mux);
+
+}
+
+/* Configure CS42L42 slave codec for jack autodetect */
+static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec)
+{
+   mutex_lock(_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(_i2c_mux);
+
+   return 0;
+}
+
+/* Enable and run CS42L42 slave codec jack auto detect */
+static void cs8409_cs42l42_run_jack_detect(struct hda_codec *codec)
+{
+   mutex_lock(_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(11, 20);
+   cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77, 1);
+   cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0, 1);
+   /* Wait ~10ms */
+   usleep_range(1, 25000);
+
+   mutex_unlock(_i2c_mux);
+
 }
 
 static void cs8409_cs42l42_reg_setup(struct hda_codec *codec)
 {
const struct cs8409_i2c_param *seq = cs42l42_

[PATCH 0/4] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec.

2021-03-03 Thread Vitaly Rodionov
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

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| 1033 +++
 3 files changed, 1035 insertions(+), 2 deletions(-)

-- 
2.25.1



[PATCH 1/4] ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18

2021-03-03 Thread Vitaly Rodionov
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 
---
 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