summaryrefslogtreecommitdiff
path: root/sound/pci/hda/patch_cs8409.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_cs8409.c')
-rw-r--r--sound/pci/hda/patch_cs8409.c312
1 files changed, 155 insertions, 157 deletions
diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c
index 51776f843c7c..9d1a457c2696 100644
--- a/sound/pci/hda/patch_cs8409.c
+++ b/sound/pci/hda/patch_cs8409.c
@@ -177,20 +177,20 @@ static void cs8409_set_i2c_dev_addr(struct hda_codec *codec, unsigned int addr)
/**
* cs8409_i2c_set_page - CS8409 I2C set page register.
- * @codec: the codec instance
+ * @scodec: the codec instance
* @i2c_reg: Page register
*
* Returns negative on error.
*/
-static int cs8409_i2c_set_page(struct hda_codec *codec, unsigned int i2c_reg)
+static int cs8409_i2c_set_page(struct sub_codec *scodec, unsigned int i2c_reg)
{
- struct cs8409_spec *spec = codec->spec;
+ struct hda_codec *codec = scodec->codec;
- if (spec->paged && (spec->last_page != (i2c_reg >> 8))) {
+ if (scodec->paged && (scodec->last_page != (i2c_reg >> 8))) {
cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg >> 8);
if (cs8409_i2c_wait_complete(codec) < 0)
return -EIO;
- spec->last_page = i2c_reg >> 8;
+ scodec->last_page = i2c_reg >> 8;
}
return 0;
@@ -198,31 +198,27 @@ static int cs8409_i2c_set_page(struct hda_codec *codec, unsigned int i2c_reg)
/**
* cs8409_i2c_read - CS8409 I2C Read.
- * @codec: the codec instance
- * @i2c_address: I2C Address
+ * @scodec: the codec instance
* @addr: Register to read
*
- * 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 addr)
+static int cs8409_i2c_read(struct sub_codec *scodec, unsigned int addr)
{
+ struct hda_codec *codec = scodec->codec;
struct cs8409_spec *spec = codec->spec;
unsigned int i2c_reg_data;
unsigned int read_data;
- if (spec->cs42l42_suspended)
+ if (scodec->suspended)
return -EPERM;
mutex_lock(&spec->i2c_mux);
cs8409_enable_i2c_clock(codec);
- cs8409_set_i2c_dev_addr(codec, i2c_address);
+ cs8409_set_i2c_dev_addr(codec, scodec->addr);
- if (cs8409_i2c_set_page(codec, addr)) {
- codec_err(codec, "%s() Paged Transaction Failed 0x%02x : 0x%04x\n",
- __func__, i2c_address, addr);
- return -EIO;
- }
+ if (cs8409_i2c_set_page(scodec, addr))
+ goto error;
i2c_reg_data = (addr << 8) & 0x0ffff;
cs8409_vendor_coef_set(codec, CS8409_I2C_QREAD, i2c_reg_data);
@@ -237,34 +233,34 @@ static int cs8409_i2c_read(struct hda_codec *codec, unsigned int i2c_address, un
error:
mutex_unlock(&spec->i2c_mux);
- codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, i2c_address, addr);
+ codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr);
return -EIO;
}
/**
* cs8409_i2c_bulk_read - CS8409 I2C Read Sequence.
- * @codec: the codec instance
+ * @scodec: the codec instance
* @seq: Register Sequence to read
* @count: Number of registeres to read
*
* Returns negative on error, values are read into value element of cs8409_i2c_param sequence.
*/
-static int cs8409_i2c_bulk_read(struct hda_codec *codec, unsigned int i2c_address,
- struct cs8409_i2c_param *seq, int count)
+static int cs8409_i2c_bulk_read(struct sub_codec *scodec, struct cs8409_i2c_param *seq, int count)
{
+ struct hda_codec *codec = scodec->codec;
struct cs8409_spec *spec = codec->spec;
unsigned int i2c_reg_data;
int i;
- if (spec->cs42l42_suspended)
+ if (scodec->suspended)
return -EPERM;
mutex_lock(&spec->i2c_mux);
- cs8409_set_i2c_dev_addr(codec, i2c_address);
+ cs8409_set_i2c_dev_addr(codec, scodec->addr);
for (i = 0; i < count; i++) {
cs8409_enable_i2c_clock(codec);
- if (cs8409_i2c_set_page(codec, seq[i].addr))
+ if (cs8409_i2c_set_page(scodec, seq[i].addr))
goto error;
i2c_reg_data = (seq[i].addr << 8) & 0x0ffff;
@@ -282,39 +278,34 @@ static int cs8409_i2c_bulk_read(struct hda_codec *codec, unsigned int i2c_addres
error:
mutex_unlock(&spec->i2c_mux);
- codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", i2c_address);
+ codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr);
return -EIO;
}
/**
* cs8409_i2c_write - CS8409 I2C Write.
- * @codec: the codec instance
- * @i2c_address: I2C Address
+ * @scodec: the codec instance
* @addr: Register to write to
* @value: Data to write
*
- * CS8409 I2C Write.
* Returns negative on error, otherwise returns 0.
*/
-static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, unsigned int addr,
- unsigned int value)
+static int cs8409_i2c_write(struct sub_codec *scodec, unsigned int addr, unsigned int value)
{
+ struct hda_codec *codec = scodec->codec;
struct cs8409_spec *spec = codec->spec;
unsigned int i2c_reg_data;
- if (spec->cs42l42_suspended)
+ if (scodec->suspended)
return -EPERM;
mutex_lock(&spec->i2c_mux);
cs8409_enable_i2c_clock(codec);
- cs8409_set_i2c_dev_addr(codec, i2c_address);
+ cs8409_set_i2c_dev_addr(codec, scodec->addr);
- if (cs8409_i2c_set_page(codec, addr)) {
- codec_err(codec, "%s() Paged Transaction Failed 0x%02x : 0x%04x\n",
- __func__, i2c_address, addr);
- return -EIO;
- }
+ if (cs8409_i2c_set_page(scodec, addr))
+ goto error;
i2c_reg_data = ((addr << 8) & 0x0ff00) | (value & 0x0ff);
cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg_data);
@@ -327,34 +318,35 @@ static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, u
error:
mutex_unlock(&spec->i2c_mux);
- codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, i2c_address, addr);
+ codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr);
return -EIO;
}
/**
* cs8409_i2c_bulk_write - CS8409 I2C Write Sequence.
- * @codec: the codec instance
+ * @scodec: the codec instance
* @seq: Register Sequence to write
* @count: Number of registeres to write
*
* Returns negative on error.
*/
-static int cs8409_i2c_bulk_write(struct hda_codec *codec, unsigned int i2c_address,
- const struct cs8409_i2c_param *seq, int count)
+static int cs8409_i2c_bulk_write(struct sub_codec *scodec, const struct cs8409_i2c_param *seq,
+ int count)
{
+ struct hda_codec *codec = scodec->codec;
struct cs8409_spec *spec = codec->spec;
unsigned int i2c_reg_data;
int i;
- if (spec->cs42l42_suspended)
+ if (scodec->suspended)
return -EPERM;
mutex_lock(&spec->i2c_mux);
- cs8409_set_i2c_dev_addr(codec, i2c_address);
+ cs8409_set_i2c_dev_addr(codec, scodec->addr);
for (i = 0; i < count; i++) {
cs8409_enable_i2c_clock(codec);
- if (cs8409_i2c_set_page(codec, seq[i].addr))
+ if (cs8409_i2c_set_page(scodec, seq[i].addr))
goto error;
i2c_reg_data = ((seq[i].addr << 8) & 0x0ff00) | (seq[i].value & 0x0ff);
@@ -370,7 +362,7 @@ static int cs8409_i2c_bulk_write(struct hda_codec *codec, unsigned int i2c_addre
error:
mutex_unlock(&spec->i2c_mux);
- codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", i2c_address);
+ codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr);
return -EIO;
}
@@ -463,6 +455,7 @@ int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc
{
struct hda_codec *codec = snd_kcontrol_chip(kctrl);
struct cs8409_spec *spec = codec->spec;
+ struct sub_codec *cs42l42 = spec->scodecs[get_amp_index(kctrl)];
int chs = get_amp_channels(kctrl);
unsigned int ofs = get_amp_offset(kctrl);
long *valp = uctrl->value.integer.value;
@@ -470,13 +463,13 @@ int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc
switch (ofs) {
case CS42L42_VOL_DAC:
if (chs & BIT(0))
- *valp++ = spec->vol[ofs];
+ *valp++ = cs42l42->vol[ofs];
if (chs & BIT(1))
- *valp = spec->vol[ofs+1];
+ *valp = cs42l42->vol[ofs+1];
break;
case CS42L42_VOL_ADC:
if (chs & BIT(0))
- *valp = spec->vol[ofs];
+ *valp = cs42l42->vol[ofs];
break;
default:
break;
@@ -489,6 +482,7 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc
{
struct hda_codec *codec = snd_kcontrol_chip(kctrl);
struct cs8409_spec *spec = codec->spec;
+ struct sub_codec *cs42l42 = spec->scodecs[get_amp_index(kctrl)];
int chs = get_amp_channels(kctrl);
unsigned int ofs = get_amp_offset(kctrl);
long *valp = uctrl->value.integer.value;
@@ -496,23 +490,23 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc
switch (ofs) {
case CS42L42_VOL_DAC:
if (chs & BIT(0)) {
- spec->vol[ofs] = *valp;
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_HS_VOL_CHA,
- -(spec->vol[ofs]) & CS42L42_REG_HS_VOL_MASK);
+ cs42l42->vol[ofs] = *valp;
+ cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHA,
+ -(cs42l42->vol[ofs]) & CS42L42_REG_HS_VOL_MASK);
}
if (chs & BIT(1)) {
ofs++;
valp++;
- spec->vol[ofs] = *valp;
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_HS_VOL_CHB,
- -(spec->vol[ofs]) & CS42L42_REG_HS_VOL_MASK);
+ cs42l42->vol[ofs] = *valp;
+ cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHB,
+ -(cs42l42->vol[ofs]) & CS42L42_REG_HS_VOL_MASK);
}
break;
case CS42L42_VOL_ADC:
if (chs & BIT(0)) {
- spec->vol[ofs] = *valp;
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_AMIC_VOL,
- spec->vol[ofs] & CS42L42_REG_AMIC_VOL_MASK);
+ cs42l42->vol[ofs] = *valp;
+ cs8409_i2c_write(cs42l42, CS42L42_REG_AMIC_VOL,
+ cs42l42->vol[ofs] & CS42L42_REG_AMIC_VOL_MASK);
}
break;
default:
@@ -523,54 +517,45 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc
}
/* Configure CS42L42 slave codec for jack autodetect */
-static void cs42l42_enable_jack_detect(struct hda_codec *codec)
+static void cs42l42_enable_jack_detect(struct sub_codec *cs42l42)
{
- /* Set TIP_SENSE_EN for analog front-end of tip sense.
- * Additionally set HSBIAS_SENSE_EN for some variants.
- */
- if (codec->fixup_id == CS8409_WARLOCK || codec->fixup_id == CS8409_BULLSEYE)
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x0020);
- else
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x00a0);
-
+ cs8409_i2c_write(cs42l42, 0x1b70, cs42l42->hsbias_hiz);
/* Clear WAKE# */
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x00C1);
+ cs8409_i2c_write(cs42l42, 0x1b71, 0x00C1);
/* Wait ~2.5ms */
usleep_range(2500, 3000);
/* Set mode WAKE# output follows the combination logic directly */
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x00C0);
+ cs8409_i2c_write(cs42l42, 0x1b71, 0x00C0);
/* Clear interrupts status */
- cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f);
+ cs8409_i2c_read(cs42l42, 0x130f);
/* Enable interrupt */
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xF3);
+ cs8409_i2c_write(cs42l42, 0x1320, 0xF3);
}
/* Enable and run CS42L42 slave codec jack auto detect */
-static void cs42l42_run_jack_detect(struct hda_codec *codec)
+static void cs42l42_run_jack_detect(struct sub_codec *cs42l42)
{
/* Clear interrupts */
- cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308);
- cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b77);
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xFF);
- cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f);
-
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1102, 0x87);
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1f06, 0x86);
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b74, 0x07);
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0xFD);
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0x80);
+ cs8409_i2c_read(cs42l42, 0x1308);
+ cs8409_i2c_read(cs42l42, 0x1b77);
+ cs8409_i2c_write(cs42l42, 0x1320, 0xFF);
+ cs8409_i2c_read(cs42l42, 0x130f);
+
+ cs8409_i2c_write(cs42l42, 0x1102, 0x87);
+ cs8409_i2c_write(cs42l42, 0x1f06, 0x86);
+ cs8409_i2c_write(cs42l42, 0x1b74, 0x07);
+ cs8409_i2c_write(cs42l42, 0x131b, 0xFD);
+ cs8409_i2c_write(cs42l42, 0x1120, 0x80);
/* Wait ~110ms*/
usleep_range(110000, 200000);
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77);
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0);
+ cs8409_i2c_write(cs42l42, 0x111f, 0x77);
+ cs8409_i2c_write(cs42l42, 0x1120, 0xc0);
/* Wait ~10ms */
usleep_range(10000, 25000);
-
}
-static int cs42l42_jack_unsol_event(struct hda_codec *codec)
+static int cs42l42_jack_unsol_event(struct sub_codec *cs42l42)
{
- struct cs8409_spec *spec = codec->spec;
int status_changed = 0;
int reg_cdc_status;
int reg_hs_status;
@@ -578,9 +563,9 @@ static int cs42l42_jack_unsol_event(struct hda_codec *codec)
int type;
/* Read jack detect status registers */
- reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308);
- reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124);
- reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f);
+ reg_cdc_status = cs8409_i2c_read(cs42l42, 0x1308);
+ reg_hs_status = cs8409_i2c_read(cs42l42, 0x1124);
+ reg_ts_status = cs8409_i2c_read(cs42l42, 0x130f);
/* If status values are < 0, read error has occurred. */
if (reg_cdc_status < 0 || reg_hs_status < 0 || reg_ts_status < 0)
@@ -590,45 +575,45 @@ static int cs42l42_jack_unsol_event(struct hda_codec *codec)
if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) {
/* Disable HSDET_AUTO_DONE */
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0xFF);
+ cs8409_i2c_write(cs42l42, 0x131b, 0xFF);
type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
/* CS42L42 reports optical jack as type 4
* We don't handle optical jack
*/
if (type != 4) {
- if (!spec->cs42l42_hp_jack_in) {
+ if (!cs42l42->hp_jack_in) {
status_changed = 1;
- spec->cs42l42_hp_jack_in = 1;
+ cs42l42->hp_jack_in = 1;
}
/* type = 3 has no mic */
- if ((!spec->cs42l42_mic_jack_in) && (type != 3)) {
+ if ((!cs42l42->mic_jack_in) && (type != 3)) {
status_changed = 1;
- spec->cs42l42_mic_jack_in = 1;
+ cs42l42->mic_jack_in = 1;
}
} else {
- if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) {
+ if (cs42l42->hp_jack_in || cs42l42->mic_jack_in) {
status_changed = 1;
- spec->cs42l42_hp_jack_in = 0;
- spec->cs42l42_mic_jack_in = 0;
+ cs42l42->hp_jack_in = 0;
+ cs42l42->mic_jack_in = 0;
}
}
/* Re-Enable Tip Sense Interrupt */
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xF3);
+ cs8409_i2c_write(cs42l42, 0x1320, 0xF3);
} else {
/* TIP_SENSE INSERT/REMOVE */
switch (reg_ts_status) {
case CS42L42_JACK_INSERTED:
- cs42l42_run_jack_detect(codec);
+ cs42l42_run_jack_detect(cs42l42);
break;
case CS42L42_JACK_REMOVED:
- if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) {
+ if (cs42l42->hp_jack_in || cs42l42->mic_jack_in) {
status_changed = 1;
- spec->cs42l42_hp_jack_in = 0;
- spec->cs42l42_mic_jack_in = 0;
+ cs42l42->hp_jack_in = 0;
+ cs42l42->mic_jack_in = 0;
}
break;
@@ -642,10 +627,8 @@ static int cs42l42_jack_unsol_event(struct hda_codec *codec)
return status_changed;
}
-/* Assert/release RTS# line to CS42L42 */
-static void cs42l42_reset(struct hda_codec *codec)
+static void cs42l42_resume(struct sub_codec *cs42l42)
{
- struct cs8409_spec *spec = codec->spec;
struct cs8409_i2c_param irq_regs[] = {
{ 0x1308, 0x00 },
{ 0x1309, 0x00 },
@@ -653,27 +636,35 @@ static void cs42l42_reset(struct hda_codec *codec)
{ 0x130F, 0x00 },
};
- /* Assert RTS# line */
- snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, 0);
- /* wait ~10ms */
- usleep_range(10000, 15000);
- /* Release RTS# line */
- snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, CS8409_CS42L42_RESET);
- /* wait ~10ms */
- usleep_range(10000, 15000);
+ cs42l42->suspended = 0;
- spec->cs42l42_suspended = 0;
- spec->last_page = 0;
+ /* Initialize CS42L42 companion codec */
+ cs8409_i2c_bulk_write(cs42l42, cs42l42->init_seq, cs42l42->init_seq_num);
/* Clear interrupts, by reading interrupt status registers */
- cs8409_i2c_bulk_read(codec, CS42L42_I2C_ADDR, irq_regs, ARRAY_SIZE(irq_regs));
+ cs8409_i2c_bulk_read(cs42l42, irq_regs, ARRAY_SIZE(irq_regs));
+
+ /* Restore Volumes after Resume */
+ cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHA,
+ -(cs42l42->vol[1]) & CS42L42_REG_HS_VOL_MASK);
+ cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHB,
+ -(cs42l42->vol[2]) & CS42L42_REG_HS_VOL_MASK);
+ cs8409_i2c_write(cs42l42, CS42L42_REG_AMIC_VOL,
+ cs42l42->vol[0] & CS42L42_REG_AMIC_VOL_MASK);
+
+ if (cs42l42->full_scale_vol)
+ cs8409_i2c_write(cs42l42, 0x2001, 0x01);
+
+ cs42l42_enable_jack_detect(cs42l42);
}
#ifdef CONFIG_PM
-static void cs42l42_suspend(struct hda_codec *codec)
+static void cs42l42_suspend(struct sub_codec *cs42l42)
{
/* Power down CS42L42 ASP/EQ/MIX/HP */
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1101, 0xfe);
+ cs8409_i2c_write(cs42l42, 0x1101, 0xfe);
+ cs42l42->suspended = 1;
+ cs42l42->last_page = 0;
}
#endif
@@ -700,9 +691,10 @@ static void cs8409_free(struct hda_codec *codec)
* generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
* and then notify status via generic snd_hda_jack_unsol_event() call.
*/
-static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
+static void cs8409_cs42l42_jack_unsol_event(struct hda_codec *codec, unsigned int res)
{
struct cs8409_spec *spec = codec->spec;
+ struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
struct hda_jack_tbl *jk;
/* jack_unsol_event() will be called every time gpio line changing state.
@@ -710,12 +702,12 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
* registers in previous cs8409_jack_unsol_event() call.
* We don't need to handle this event, ignoring...
*/
- if (res & CS8409_CS42L42_INT)
+ if (res & cs42l42->irq_mask)
return;
- if (cs42l42_jack_unsol_event(codec)) {
+ if (cs42l42_jack_unsol_event(cs42l42)) {
snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
- spec->cs42l42_hp_jack_in ? 0 : PIN_OUT);
+ cs42l42->hp_jack_in ? 0 : PIN_OUT);
/* Report jack*/
jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
if (jk)
@@ -737,9 +729,7 @@ static int cs8409_cs42l42_suspend(struct hda_codec *codec)
cs8409_enable_ur(codec, 0);
- cs42l42_suspend(codec);
-
- spec->cs42l42_suspended = 1;
+ cs42l42_suspend(spec->scodecs[CS8409_CODEC0]);
/* Assert CS42L42 RTS# line */
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, 0);
@@ -762,6 +752,7 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg;
const struct cs8409_cir_param *seq_bullseye = cs8409_cs42l42_bullseye_atn;
struct cs8409_spec *spec = codec->spec;
+ struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
if (spec->gpio_mask) {
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_MASK,
@@ -775,33 +766,21 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
for (; seq->nid; seq++)
cs8409_vendor_coef_set(codec, seq->cir, seq->coeff);
- if (codec->fixup_id == CS8409_BULLSEYE)
+ if (codec->fixup_id == CS8409_BULLSEYE) {
for (; seq_bullseye->nid; seq_bullseye++)
cs8409_vendor_coef_set(codec, seq_bullseye->cir, seq_bullseye->coeff);
+ }
- /* Reset CS42L42 */
- cs42l42_reset(codec);
-
- /* Initialise CS42L42 companion codec */
- cs8409_i2c_bulk_write(codec, CS42L42_I2C_ADDR, cs42l42_init_reg_seq,
- CS42L42_INIT_REG_SEQ_SIZE);
-
- if (codec->fixup_id == CS8409_WARLOCK || codec->fixup_id == CS8409_CYBORG) {
- /* FULL_SCALE_VOL = 0 for Warlock / Cyborg */
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01);
- /* DMIC1_MO=00b, DMIC1/2_SR=1 */
+ /* DMIC1_MO=00b, DMIC1/2_SR=1 */
+ if (codec->fixup_id == CS8409_WARLOCK || codec->fixup_id == CS8409_CYBORG)
cs8409_vendor_coef_set(codec, 0x09, 0x0003);
- }
- /* Restore Volumes after Resume */
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_HS_VOL_CHA,
- -(spec->vol[1]) & CS42L42_REG_HS_VOL_MASK);
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_HS_VOL_CHB,
- -(spec->vol[2]) & CS42L42_REG_HS_VOL_MASK);
- cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_AMIC_VOL,
- spec->vol[0] & CS42L42_REG_AMIC_VOL_MASK);
+ /* Release RTS# line */
+ snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, CS8409_CS42L42_RESET);
+ /* wait ~10ms */
+ usleep_range(10000, 15000);
- cs42l42_enable_jack_detect(codec);
+ cs42l42_resume(cs42l42);
/* Enable Unsolicited Response */
cs8409_enable_ur(codec, 1);
@@ -812,7 +791,7 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
.build_pcms = snd_hda_gen_build_pcms,
.init = cs8409_init,
.free = cs8409_free,
- .unsol_event = cs8409_jack_unsol_event,
+ .unsol_event = cs8409_cs42l42_jack_unsol_event,
#ifdef CONFIG_PM
.suspend = cs8409_cs42l42_suspend,
#endif
@@ -823,6 +802,7 @@ static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, u
{
struct hda_codec *codec = container_of(dev, struct hda_codec, core);
struct cs8409_spec *spec = codec->spec;
+ struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
unsigned int nid = ((cmd >> 20) & 0x07f);
unsigned int verb = ((cmd >> 8) & 0x0fff);
@@ -835,18 +815,16 @@ static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, u
switch (nid) {
case CS8409_CS42L42_HP_PIN_NID:
if (verb == AC_VERB_GET_PIN_SENSE) {
- *res = (spec->cs42l42_hp_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+ *res = (cs42l42->hp_jack_in) ? AC_PINSENSE_PRESENCE : 0;
return 0;
}
break;
-
case CS8409_CS42L42_AMIC_PIN_NID:
if (verb == AC_VERB_GET_PIN_SENSE) {
- *res = (spec->cs42l42_mic_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+ *res = (cs42l42->mic_jack_in) ? AC_PINSENSE_PRESENCE : 0;
return 0;
}
break;
-
default:
break;
}
@@ -865,6 +843,9 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
spec->exec_verb = codec->core.exec_verb;
codec->core.exec_verb = cs8409_cs42l42_exec_verb;
+ spec->scodecs[CS8409_CODEC0] = &cs8409_cs42l42_codec;
+ spec->num_scodecs = 1;
+ spec->scodecs[CS8409_CODEC0]->codec = codec;
codec->patch_ops = cs8409_cs42l42_patch_ops;
spec->gen.suppress_auto_mute = 1;
@@ -872,21 +853,38 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
spec->gen.suppress_vmaster = 1;
/* GPIO 5 out, 3,4 in */
- spec->gpio_dir = CS8409_CS42L42_RESET;
+ spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio;
spec->gpio_data = 0;
spec->gpio_mask = 0x03f;
- spec->cs42l42_hp_jack_in = 0;
- spec->cs42l42_mic_jack_in = 0;
- spec->cs42l42_suspended = 1;
- spec->paged = 1;
-
/* Basic initial sequence for specific hw configuration */
snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs);
cs8409_fix_caps(codec, CS8409_CS42L42_HP_PIN_NID);
cs8409_fix_caps(codec, CS8409_CS42L42_AMIC_PIN_NID);
+ /* Set TIP_SENSE_EN for analog front-end of tip sense.
+ * Additionally set HSBIAS_SENSE_EN and Full Scale volume for some variants.
+ */
+ switch (codec->fixup_id) {
+ case CS8409_WARLOCK:
+ spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020;
+ spec->scodecs[CS8409_CODEC0]->full_scale_vol = 1;
+ break;
+ case CS8409_BULLSEYE:
+ spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020;
+ spec->scodecs[CS8409_CODEC0]->full_scale_vol = 0;
+ break;
+ case CS8409_CYBORG:
+ spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x00a0;
+ spec->scodecs[CS8409_CODEC0]->full_scale_vol = 1;
+ break;
+ default:
+ spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0003;
+ spec->scodecs[CS8409_CODEC0]->full_scale_vol = 1;
+ break;
+ }
+
break;
case HDA_FIXUP_ACT_PROBE:
/* Set initial DMIC volume to -26 dB */
@@ -910,7 +908,7 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
* been already plugged in.
* Run immediately after init.
*/
- cs42l42_run_jack_detect(codec);
+ cs42l42_run_jack_detect(spec->scodecs[CS8409_CODEC0]);
usleep_range(100000, 150000);
break;
default: