Commit 24f7ac3d authored by Lucas Tanure's avatar Lucas Tanure Committed by Takashi Iwai

ALSA: hda/cs8409: Move codec properties to its own struct

To accommodate move, cs42l42_resume has been added to mirror
the existing function cs42l42_suspend.
Function cs42l42_reset is no longer required, since cs42l42_resume
and cs42l42_suspend perform the same operations.
Signed-off-by: default avatarLucas Tanure <tanureal@opensource.cirrus.com>
Signed-off-by: default avatarVitaly Rodionov <vitalyr@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20210811185654.6837-19-vitalyr@opensource.cirrus.comSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 636eb9d2
...@@ -28,7 +28,7 @@ const struct snd_kcontrol_new cs42l42_dac_volume_mixer = { ...@@ -28,7 +28,7 @@ const struct snd_kcontrol_new cs42l42_dac_volume_mixer = {
.get = cs42l42_volume_get, .get = cs42l42_volume_get,
.put = cs42l42_volume_put, .put = cs42l42_volume_put,
.tlv = { .p = cs42l42_dac_db_scale }, .tlv = { .p = cs42l42_dac_db_scale },
.private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_TRANSMITTER_A, 3, 0, .private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_TRANSMITTER_A, 3, CS8409_CODEC0,
HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE
}; };
...@@ -41,89 +41,14 @@ const struct snd_kcontrol_new cs42l42_adc_volume_mixer = { ...@@ -41,89 +41,14 @@ const struct snd_kcontrol_new cs42l42_adc_volume_mixer = {
.get = cs42l42_volume_get, .get = cs42l42_volume_get,
.put = cs42l42_volume_put, .put = cs42l42_volume_put,
.tlv = { .p = cs42l42_adc_db_scale }, .tlv = { .p = cs42l42_adc_db_scale },
.private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_RECEIVER_A, 1, 0, .private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_RECEIVER_A, 1, CS8409_CODEC0,
HDA_INPUT, CS42L42_VOL_ADC) | HDA_AMP_VAL_MIN_MUTE HDA_INPUT, CS42L42_VOL_ADC) | HDA_AMP_VAL_MIN_MUTE
}; };
/* Dell Inspiron platforms /******************************************************************************
* with cs8409 bridge and cs42l42 codec * BULLSEYE / WARLOCK / CYBORG Specific Arrays
*/ * CS8409/CS42L42
const struct snd_pci_quirk cs8409_fixup_tbl[] = { ******************************************************************************/
SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A24, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A25, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A29, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A2A, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A2B, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0AB0, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB2, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB1, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB3, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB4, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB5, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AD9, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0ADA, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0ADB, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A7A, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A7D, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A7E, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A7F, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A80, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0ADF, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AE0, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AE1, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AE2, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AE9, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEA, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEB, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEC, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AED, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEE, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEF, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AF0, "Cyborg", CS8409_CYBORG),
{} /* terminator */
};
/* Dell Inspiron models with cs8409/cs42l42 */
const struct hda_model_fixup cs8409_models[] = {
{ .id = CS8409_BULLSEYE, .name = "bullseye" },
{ .id = CS8409_WARLOCK, .name = "warlock" },
{ .id = CS8409_CYBORG, .name = "cyborg" },
{}
};
const struct hda_fixup cs8409_fixups[] = {
[CS8409_BULLSEYE] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
.chain_id = CS8409_FIXUPS,
},
[CS8409_WARLOCK] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
.chain_id = CS8409_FIXUPS,
},
[CS8409_CYBORG] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
.chain_id = CS8409_FIXUPS,
},
[CS8409_FIXUPS] = {
.type = HDA_FIXUP_FUNC,
.v.func = cs8409_cs42l42_fixups,
},
};
const struct hda_verb cs8409_cs42l42_init_verbs[] = { const struct hda_verb cs8409_cs42l42_init_verbs[] = {
{ CS8409_PIN_AFG, AC_VERB_SET_GPIO_WAKE_MASK, 0x0018 }, /* WAKE from GPIO 3,4 */ { CS8409_PIN_AFG, AC_VERB_SET_GPIO_WAKE_MASK, 0x0018 }, /* WAKE from GPIO 3,4 */
...@@ -144,7 +69,7 @@ const struct hda_pintbl cs8409_cs42l42_pincfgs[] = { ...@@ -144,7 +69,7 @@ const struct hda_pintbl cs8409_cs42l42_pincfgs[] = {
}; };
/* Vendor specific HW configuration for CS42L42 */ /* Vendor specific HW configuration for CS42L42 */
const struct cs8409_i2c_param cs42l42_init_reg_seq[CS42L42_INIT_REG_SEQ_SIZE] = { static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
{ 0x1010, 0xB0 }, { 0x1010, 0xB0 },
{ 0x1D01, 0x00 }, { 0x1D01, 0x00 },
{ 0x1D02, 0x06 }, { 0x1D02, 0x06 },
...@@ -310,3 +235,97 @@ const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[] = { ...@@ -310,3 +235,97 @@ const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[] = {
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0x0000 }, { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0x0000 },
{} /* Terminator */ {} /* Terminator */
}; };
struct sub_codec cs8409_cs42l42_codec = {
.addr = CS42L42_I2C_ADDR,
.reset_gpio = CS8409_CS42L42_RESET,
.irq_mask = CS8409_CS42L42_INT,
.init_seq = cs42l42_init_reg_seq,
.init_seq_num = ARRAY_SIZE(cs42l42_init_reg_seq),
.hp_jack_in = 0,
.mic_jack_in = 0,
.paged = 1,
.suspended = 1,
};
/******************************************************************************
* CS8409 Patch Driver Structs
* Arrays Used for all projects using CS8409
******************************************************************************/
const struct snd_pci_quirk cs8409_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A24, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A25, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A29, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A2A, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0A2B, "Bullseye", CS8409_BULLSEYE),
SND_PCI_QUIRK(0x1028, 0x0AB0, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB2, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB1, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB3, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB4, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AB5, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AD9, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0ADA, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0ADB, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK),
SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A7A, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A7D, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A7E, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A7F, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0A80, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0ADF, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AE0, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AE1, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AE2, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AE9, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEA, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEB, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEC, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AED, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEE, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AEF, "Cyborg", CS8409_CYBORG),
SND_PCI_QUIRK(0x1028, 0x0AF0, "Cyborg", CS8409_CYBORG),
{} /* terminator */
};
/* Dell Inspiron models with cs8409/cs42l42 */
const struct hda_model_fixup cs8409_models[] = {
{ .id = CS8409_BULLSEYE, .name = "bullseye" },
{ .id = CS8409_WARLOCK, .name = "warlock" },
{ .id = CS8409_CYBORG, .name = "cyborg" },
{}
};
const struct hda_fixup cs8409_fixups[] = {
[CS8409_BULLSEYE] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
.chain_id = CS8409_FIXUPS,
},
[CS8409_WARLOCK] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
.chain_id = CS8409_FIXUPS,
},
[CS8409_CYBORG] = {
.type = HDA_FIXUP_PINS,
.v.pins = cs8409_cs42l42_pincfgs,
.chained = true,
.chain_id = CS8409_FIXUPS,
},
[CS8409_FIXUPS] = {
.type = HDA_FIXUP_FUNC,
.v.func = cs8409_cs42l42_fixups,
},
};
...@@ -177,20 +177,20 @@ static void cs8409_set_i2c_dev_addr(struct hda_codec *codec, unsigned int addr) ...@@ -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. * cs8409_i2c_set_page - CS8409 I2C set page register.
* @codec: the codec instance * @scodec: the codec instance
* @i2c_reg: Page register * @i2c_reg: Page register
* *
* Returns negative on error. * 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); cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg >> 8);
if (cs8409_i2c_wait_complete(codec) < 0) if (cs8409_i2c_wait_complete(codec) < 0)
return -EIO; return -EIO;
spec->last_page = i2c_reg >> 8; scodec->last_page = i2c_reg >> 8;
} }
return 0; return 0;
...@@ -198,31 +198,27 @@ static int cs8409_i2c_set_page(struct hda_codec *codec, unsigned int i2c_reg) ...@@ -198,31 +198,27 @@ static int cs8409_i2c_set_page(struct hda_codec *codec, unsigned int i2c_reg)
/** /**
* cs8409_i2c_read - CS8409 I2C Read. * cs8409_i2c_read - CS8409 I2C Read.
* @codec: the codec instance * @scodec: the codec instance
* @i2c_address: I2C Address
* @addr: Register to read * @addr: Register to read
* *
* CS8409 I2C Read.
* Returns negative on error, otherwise returns read value in bits 0-7. * 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; struct cs8409_spec *spec = codec->spec;
unsigned int i2c_reg_data; unsigned int i2c_reg_data;
unsigned int read_data; unsigned int read_data;
if (spec->cs42l42_suspended) if (scodec->suspended)
return -EPERM; return -EPERM;
mutex_lock(&spec->i2c_mux); mutex_lock(&spec->i2c_mux);
cs8409_enable_i2c_clock(codec); 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)) { if (cs8409_i2c_set_page(scodec, addr))
codec_err(codec, "%s() Paged Transaction Failed 0x%02x : 0x%04x\n", goto error;
__func__, i2c_address, addr);
return -EIO;
}
i2c_reg_data = (addr << 8) & 0x0ffff; i2c_reg_data = (addr << 8) & 0x0ffff;
cs8409_vendor_coef_set(codec, CS8409_I2C_QREAD, i2c_reg_data); 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 ...@@ -237,34 +233,34 @@ static int cs8409_i2c_read(struct hda_codec *codec, unsigned int i2c_address, un
error: error:
mutex_unlock(&spec->i2c_mux); 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; return -EIO;
} }
/** /**
* cs8409_i2c_bulk_read - CS8409 I2C Read Sequence. * cs8409_i2c_bulk_read - CS8409 I2C Read Sequence.
* @codec: the codec instance * @scodec: the codec instance
* @seq: Register Sequence to read * @seq: Register Sequence to read
* @count: Number of registeres to read * @count: Number of registeres to read
* *
* Returns negative on error, values are read into value element of cs8409_i2c_param sequence. * 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, static int cs8409_i2c_bulk_read(struct sub_codec *scodec, struct cs8409_i2c_param *seq, int count)
struct cs8409_i2c_param *seq, int count)
{ {
struct hda_codec *codec = scodec->codec;
struct cs8409_spec *spec = codec->spec; struct cs8409_spec *spec = codec->spec;
unsigned int i2c_reg_data; unsigned int i2c_reg_data;
int i; int i;
if (spec->cs42l42_suspended) if (scodec->suspended)
return -EPERM; return -EPERM;
mutex_lock(&spec->i2c_mux); 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++) { for (i = 0; i < count; i++) {
cs8409_enable_i2c_clock(codec); 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; goto error;
i2c_reg_data = (seq[i].addr << 8) & 0x0ffff; 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 ...@@ -282,39 +278,34 @@ static int cs8409_i2c_bulk_read(struct hda_codec *codec, unsigned int i2c_addres
error: error:
mutex_unlock(&spec->i2c_mux); 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; return -EIO;
} }
/** /**
* cs8409_i2c_write - CS8409 I2C Write. * cs8409_i2c_write - CS8409 I2C Write.
* @codec: the codec instance * @scodec: the codec instance
* @i2c_address: I2C Address
* @addr: Register to write to * @addr: Register to write to
* @value: Data to write * @value: Data to write
* *
* CS8409 I2C Write.
* Returns negative on error, otherwise returns 0. * Returns negative on error, otherwise returns 0.
*/ */
static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, unsigned int addr, static int cs8409_i2c_write(struct sub_codec *scodec, unsigned int addr, unsigned int value)
unsigned int value)
{ {
struct hda_codec *codec = scodec->codec;
struct cs8409_spec *spec = codec->spec; struct cs8409_spec *spec = codec->spec;
unsigned int i2c_reg_data; unsigned int i2c_reg_data;
if (spec->cs42l42_suspended) if (scodec->suspended)
return -EPERM; return -EPERM;
mutex_lock(&spec->i2c_mux); mutex_lock(&spec->i2c_mux);
cs8409_enable_i2c_clock(codec); 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)) { if (cs8409_i2c_set_page(scodec, addr))
codec_err(codec, "%s() Paged Transaction Failed 0x%02x : 0x%04x\n", goto error;
__func__, i2c_address, addr);
return -EIO;
}
i2c_reg_data = ((addr << 8) & 0x0ff00) | (value & 0x0ff); i2c_reg_data = ((addr << 8) & 0x0ff00) | (value & 0x0ff);
cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg_data); 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 ...@@ -327,34 +318,35 @@ static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, u
error: error:
mutex_unlock(&spec->i2c_mux); 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; return -EIO;
} }
/** /**
* cs8409_i2c_bulk_write - CS8409 I2C Write Sequence. * cs8409_i2c_bulk_write - CS8409 I2C Write Sequence.
* @codec: the codec instance * @scodec: the codec instance
* @seq: Register Sequence to write * @seq: Register Sequence to write
* @count: Number of registeres to write * @count: Number of registeres to write
* *
* Returns negative on error. * Returns negative on error.
*/ */
static int cs8409_i2c_bulk_write(struct hda_codec *codec, unsigned int i2c_address, static int cs8409_i2c_bulk_write(struct sub_codec *scodec, const struct cs8409_i2c_param *seq,
const struct cs8409_i2c_param *seq, int count) int count)
{ {
struct hda_codec *codec = scodec->codec;
struct cs8409_spec *spec = codec->spec; struct cs8409_spec *spec = codec->spec;
unsigned int i2c_reg_data; unsigned int i2c_reg_data;
int i; int i;
if (spec->cs42l42_suspended) if (scodec->suspended)
return -EPERM; return -EPERM;
mutex_lock(&spec->i2c_mux); 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++) { for (i = 0; i < count; i++) {
cs8409_enable_i2c_clock(codec); 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; goto error;
i2c_reg_data = ((seq[i].addr << 8) & 0x0ff00) | (seq[i].value & 0x0ff); 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 ...@@ -370,7 +362,7 @@ static int cs8409_i2c_bulk_write(struct hda_codec *codec, unsigned int i2c_addre
error: error:
mutex_unlock(&spec->i2c_mux); 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; return -EIO;
} }
...@@ -463,6 +455,7 @@ int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc ...@@ -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 hda_codec *codec = snd_kcontrol_chip(kctrl);
struct cs8409_spec *spec = codec->spec; struct cs8409_spec *spec = codec->spec;
struct sub_codec *cs42l42 = spec->scodecs[get_amp_index(kctrl)];
int chs = get_amp_channels(kctrl); int chs = get_amp_channels(kctrl);
unsigned int ofs = get_amp_offset(kctrl); unsigned int ofs = get_amp_offset(kctrl);
long *valp = uctrl->value.integer.value; long *valp = uctrl->value.integer.value;
...@@ -470,13 +463,13 @@ int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc ...@@ -470,13 +463,13 @@ int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc
switch (ofs) { switch (ofs) {
case CS42L42_VOL_DAC: case CS42L42_VOL_DAC:
if (chs & BIT(0)) if (chs & BIT(0))
*valp++ = spec->vol[ofs]; *valp++ = cs42l42->vol[ofs];
if (chs & BIT(1)) if (chs & BIT(1))
*valp = spec->vol[ofs+1]; *valp = cs42l42->vol[ofs+1];
break; break;
case CS42L42_VOL_ADC: case CS42L42_VOL_ADC:
if (chs & BIT(0)) if (chs & BIT(0))
*valp = spec->vol[ofs]; *valp = cs42l42->vol[ofs];
break; break;
default: default:
break; break;
...@@ -489,6 +482,7 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc ...@@ -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 hda_codec *codec = snd_kcontrol_chip(kctrl);
struct cs8409_spec *spec = codec->spec; struct cs8409_spec *spec = codec->spec;
struct sub_codec *cs42l42 = spec->scodecs[get_amp_index(kctrl)];
int chs = get_amp_channels(kctrl); int chs = get_amp_channels(kctrl);
unsigned int ofs = get_amp_offset(kctrl); unsigned int ofs = get_amp_offset(kctrl);
long *valp = uctrl->value.integer.value; long *valp = uctrl->value.integer.value;
...@@ -496,23 +490,23 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc ...@@ -496,23 +490,23 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc
switch (ofs) { switch (ofs) {
case CS42L42_VOL_DAC: case CS42L42_VOL_DAC:
if (chs & BIT(0)) { if (chs & BIT(0)) {
spec->vol[ofs] = *valp; cs42l42->vol[ofs] = *valp;
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_HS_VOL_CHA, cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHA,
-(spec->vol[ofs]) & CS42L42_REG_HS_VOL_MASK); -(cs42l42->vol[ofs]) & CS42L42_REG_HS_VOL_MASK);
} }
if (chs & BIT(1)) { if (chs & BIT(1)) {
ofs++; ofs++;
valp++; valp++;
spec->vol[ofs] = *valp; cs42l42->vol[ofs] = *valp;
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_HS_VOL_CHB, cs8409_i2c_write(cs42l42, CS42L42_REG_HS_VOL_CHB,
-(spec->vol[ofs]) & CS42L42_REG_HS_VOL_MASK); -(cs42l42->vol[ofs]) & CS42L42_REG_HS_VOL_MASK);
} }
break; break;
case CS42L42_VOL_ADC: case CS42L42_VOL_ADC:
if (chs & BIT(0)) { if (chs & BIT(0)) {
spec->vol[ofs] = *valp; cs42l42->vol[ofs] = *valp;
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_AMIC_VOL, cs8409_i2c_write(cs42l42, CS42L42_REG_AMIC_VOL,
spec->vol[ofs] & CS42L42_REG_AMIC_VOL_MASK); cs42l42->vol[ofs] & CS42L42_REG_AMIC_VOL_MASK);
} }
break; break;
default: default:
...@@ -523,54 +517,45 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc ...@@ -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 */ /* 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. cs8409_i2c_write(cs42l42, 0x1b70, cs42l42->hsbias_hiz);
* 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);
/* Clear WAKE# */ /* Clear WAKE# */
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x00C1); cs8409_i2c_write(cs42l42, 0x1b71, 0x00C1);
/* Wait ~2.5ms */ /* Wait ~2.5ms */
usleep_range(2500, 3000); usleep_range(2500, 3000);
/* Set mode WAKE# output follows the combination logic directly */ /* 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 */ /* Clear interrupts status */
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f); cs8409_i2c_read(cs42l42, 0x130f);
/* Enable interrupt */ /* 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 */ /* 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 */ /* Clear interrupts */
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308); cs8409_i2c_read(cs42l42, 0x1308);
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b77); cs8409_i2c_read(cs42l42, 0x1b77);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xFF); cs8409_i2c_write(cs42l42, 0x1320, 0xFF);
cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f); cs8409_i2c_read(cs42l42, 0x130f);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1102, 0x87); cs8409_i2c_write(cs42l42, 0x1102, 0x87);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1f06, 0x86); cs8409_i2c_write(cs42l42, 0x1f06, 0x86);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b74, 0x07); cs8409_i2c_write(cs42l42, 0x1b74, 0x07);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0xFD); cs8409_i2c_write(cs42l42, 0x131b, 0xFD);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0x80); cs8409_i2c_write(cs42l42, 0x1120, 0x80);
/* Wait ~110ms*/ /* Wait ~110ms*/
usleep_range(110000, 200000); usleep_range(110000, 200000);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77); cs8409_i2c_write(cs42l42, 0x111f, 0x77);
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0); cs8409_i2c_write(cs42l42, 0x1120, 0xc0);
/* Wait ~10ms */ /* Wait ~10ms */
usleep_range(10000, 25000); 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 status_changed = 0;
int reg_cdc_status; int reg_cdc_status;
int reg_hs_status; int reg_hs_status;
...@@ -578,9 +563,9 @@ static int cs42l42_jack_unsol_event(struct hda_codec *codec) ...@@ -578,9 +563,9 @@ static int cs42l42_jack_unsol_event(struct hda_codec *codec)
int type; int type;
/* Read jack detect status registers */ /* Read jack detect status registers */
reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308); reg_cdc_status = cs8409_i2c_read(cs42l42, 0x1308);
reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124); reg_hs_status = cs8409_i2c_read(cs42l42, 0x1124);
reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f); reg_ts_status = cs8409_i2c_read(cs42l42, 0x130f);
/* If status values are < 0, read error has occurred. */ /* If status values are < 0, read error has occurred. */
if (reg_cdc_status < 0 || reg_hs_status < 0 || reg_ts_status < 0) 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) ...@@ -590,45 +575,45 @@ static int cs42l42_jack_unsol_event(struct hda_codec *codec)
if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) { if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) {
/* Disable 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); type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
/* CS42L42 reports optical jack as type 4 /* CS42L42 reports optical jack as type 4
* We don't handle optical jack * We don't handle optical jack
*/ */
if (type != 4) { if (type != 4) {
if (!spec->cs42l42_hp_jack_in) { if (!cs42l42->hp_jack_in) {
status_changed = 1; status_changed = 1;
spec->cs42l42_hp_jack_in = 1; cs42l42->hp_jack_in = 1;
} }
/* type = 3 has no mic */ /* type = 3 has no mic */
if ((!spec->cs42l42_mic_jack_in) && (type != 3)) { if ((!cs42l42->mic_jack_in) && (type != 3)) {
status_changed = 1; status_changed = 1;
spec->cs42l42_mic_jack_in = 1; cs42l42->mic_jack_in = 1;
} }
} else { } else {
if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) { if (cs42l42->hp_jack_in || cs42l42->mic_jack_in) {
status_changed = 1; status_changed = 1;
spec->cs42l42_hp_jack_in = 0; cs42l42->hp_jack_in = 0;
spec->cs42l42_mic_jack_in = 0; cs42l42->mic_jack_in = 0;
} }
} }
/* Re-Enable Tip Sense Interrupt */ /* Re-Enable Tip Sense Interrupt */
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xF3); cs8409_i2c_write(cs42l42, 0x1320, 0xF3);
} else { } else {
/* TIP_SENSE INSERT/REMOVE */ /* TIP_SENSE INSERT/REMOVE */
switch (reg_ts_status) { switch (reg_ts_status) {
case CS42L42_JACK_INSERTED: case CS42L42_JACK_INSERTED:
cs42l42_run_jack_detect(codec); cs42l42_run_jack_detect(cs42l42);
break; break;
case CS42L42_JACK_REMOVED: 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; status_changed = 1;
spec->cs42l42_hp_jack_in = 0; cs42l42->hp_jack_in = 0;
spec->cs42l42_mic_jack_in = 0; cs42l42->mic_jack_in = 0;
} }
break; break;
...@@ -642,10 +627,8 @@ static int cs42l42_jack_unsol_event(struct hda_codec *codec) ...@@ -642,10 +627,8 @@ static int cs42l42_jack_unsol_event(struct hda_codec *codec)
return status_changed; return status_changed;
} }
/* Assert/release RTS# line to CS42L42 */ static void cs42l42_resume(struct sub_codec *cs42l42)
static void cs42l42_reset(struct hda_codec *codec)
{ {
struct cs8409_spec *spec = codec->spec;
struct cs8409_i2c_param irq_regs[] = { struct cs8409_i2c_param irq_regs[] = {
{ 0x1308, 0x00 }, { 0x1308, 0x00 },
{ 0x1309, 0x00 }, { 0x1309, 0x00 },
...@@ -653,27 +636,35 @@ static void cs42l42_reset(struct hda_codec *codec) ...@@ -653,27 +636,35 @@ static void cs42l42_reset(struct hda_codec *codec)
{ 0x130F, 0x00 }, { 0x130F, 0x00 },
}; };
/* Assert RTS# line */ cs42l42->suspended = 0;
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);
spec->cs42l42_suspended = 0; /* Initialize CS42L42 companion codec */
spec->last_page = 0; cs8409_i2c_bulk_write(cs42l42, cs42l42->init_seq, cs42l42->init_seq_num);
/* Clear interrupts, by reading interrupt status registers */ /* 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 #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 */ /* 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 #endif
...@@ -700,9 +691,10 @@ static void cs8409_free(struct hda_codec *codec) ...@@ -700,9 +691,10 @@ static void cs8409_free(struct hda_codec *codec)
* generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
* and then notify status via generic snd_hda_jack_unsol_event() call. * 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 cs8409_spec *spec = codec->spec;
struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
struct hda_jack_tbl *jk; struct hda_jack_tbl *jk;
/* jack_unsol_event() will be called every time gpio line changing state. /* 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) ...@@ -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. * registers in previous cs8409_jack_unsol_event() call.
* We don't need to handle this event, ignoring... * We don't need to handle this event, ignoring...
*/ */
if (res & CS8409_CS42L42_INT) if (res & cs42l42->irq_mask)
return; return;
if (cs42l42_jack_unsol_event(codec)) { if (cs42l42_jack_unsol_event(cs42l42)) {
snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID, 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*/ /* Report jack*/
jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0); jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
if (jk) if (jk)
...@@ -737,9 +729,7 @@ static int cs8409_cs42l42_suspend(struct hda_codec *codec) ...@@ -737,9 +729,7 @@ static int cs8409_cs42l42_suspend(struct hda_codec *codec)
cs8409_enable_ur(codec, 0); cs8409_enable_ur(codec, 0);
cs42l42_suspend(codec); cs42l42_suspend(spec->scodecs[CS8409_CODEC0]);
spec->cs42l42_suspended = 1;
/* Assert CS42L42 RTS# line */ /* Assert CS42L42 RTS# line */
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, 0); 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) ...@@ -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 = cs8409_cs42l42_hw_cfg;
const struct cs8409_cir_param *seq_bullseye = cs8409_cs42l42_bullseye_atn; const struct cs8409_cir_param *seq_bullseye = cs8409_cs42l42_bullseye_atn;
struct cs8409_spec *spec = codec->spec; struct cs8409_spec *spec = codec->spec;
struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
if (spec->gpio_mask) { if (spec->gpio_mask) {
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_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) ...@@ -775,33 +766,21 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
for (; seq->nid; seq++) for (; seq->nid; seq++)
cs8409_vendor_coef_set(codec, seq->cir, seq->coeff); 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++) for (; seq_bullseye->nid; seq_bullseye++)
cs8409_vendor_coef_set(codec, seq_bullseye->cir, seq_bullseye->coeff); 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); cs8409_vendor_coef_set(codec, 0x09, 0x0003);
}
/* Restore Volumes after Resume */ /* Release RTS# line */
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_HS_VOL_CHA, snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, CS8409_CS42L42_RESET);
-(spec->vol[1]) & CS42L42_REG_HS_VOL_MASK); /* wait ~10ms */
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS42L42_REG_HS_VOL_CHB, usleep_range(10000, 15000);
-(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);
cs42l42_enable_jack_detect(codec); cs42l42_resume(cs42l42);
/* Enable Unsolicited Response */ /* Enable Unsolicited Response */
cs8409_enable_ur(codec, 1); cs8409_enable_ur(codec, 1);
...@@ -812,7 +791,7 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { ...@@ -812,7 +791,7 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
.build_pcms = snd_hda_gen_build_pcms, .build_pcms = snd_hda_gen_build_pcms,
.init = cs8409_init, .init = cs8409_init,
.free = cs8409_free, .free = cs8409_free,
.unsol_event = cs8409_jack_unsol_event, .unsol_event = cs8409_cs42l42_jack_unsol_event,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = cs8409_cs42l42_suspend, .suspend = cs8409_cs42l42_suspend,
#endif #endif
...@@ -823,6 +802,7 @@ static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, u ...@@ -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 hda_codec *codec = container_of(dev, struct hda_codec, core);
struct cs8409_spec *spec = codec->spec; struct cs8409_spec *spec = codec->spec;
struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
unsigned int nid = ((cmd >> 20) & 0x07f); unsigned int nid = ((cmd >> 20) & 0x07f);
unsigned int verb = ((cmd >> 8) & 0x0fff); unsigned int verb = ((cmd >> 8) & 0x0fff);
...@@ -835,18 +815,16 @@ static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, u ...@@ -835,18 +815,16 @@ static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, u
switch (nid) { switch (nid) {
case CS8409_CS42L42_HP_PIN_NID: case CS8409_CS42L42_HP_PIN_NID:
if (verb == AC_VERB_GET_PIN_SENSE) { 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; return 0;
} }
break; break;
case CS8409_CS42L42_AMIC_PIN_NID: case CS8409_CS42L42_AMIC_PIN_NID:
if (verb == AC_VERB_GET_PIN_SENSE) { 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; return 0;
} }
break; break;
default: default:
break; break;
} }
...@@ -865,6 +843,9 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, ...@@ -865,6 +843,9 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
spec->exec_verb = codec->core.exec_verb; spec->exec_verb = codec->core.exec_verb;
codec->core.exec_verb = cs8409_cs42l42_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; codec->patch_ops = cs8409_cs42l42_patch_ops;
spec->gen.suppress_auto_mute = 1; spec->gen.suppress_auto_mute = 1;
...@@ -872,21 +853,38 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, ...@@ -872,21 +853,38 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
spec->gen.suppress_vmaster = 1; spec->gen.suppress_vmaster = 1;
/* GPIO 5 out, 3,4 in */ /* 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_data = 0;
spec->gpio_mask = 0x03f; 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 */ /* Basic initial sequence for specific hw configuration */
snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs);
cs8409_fix_caps(codec, CS8409_CS42L42_HP_PIN_NID); cs8409_fix_caps(codec, CS8409_CS42L42_HP_PIN_NID);
cs8409_fix_caps(codec, CS8409_CS42L42_AMIC_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; break;
case HDA_FIXUP_ACT_PROBE: case HDA_FIXUP_ACT_PROBE:
/* Set initial DMIC volume to -26 dB */ /* Set initial DMIC volume to -26 dB */
...@@ -910,7 +908,7 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, ...@@ -910,7 +908,7 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
* been already plugged in. * been already plugged in.
* Run immediately after init. * Run immediately after init.
*/ */
cs42l42_run_jack_detect(codec); cs42l42_run_jack_detect(spec->scodecs[CS8409_CODEC0]);
usleep_range(100000, 150000); usleep_range(100000, 150000);
break; break;
default: default:
......
...@@ -216,8 +216,8 @@ enum cs8409_coefficient_index_registers { ...@@ -216,8 +216,8 @@ enum cs8409_coefficient_index_registers {
/* CS42L42 Specific Definitions */ /* CS42L42 Specific Definitions */
#define CS8409_MAX_CODECS 8
#define CS42L42_VOLUMES (4U) #define CS42L42_VOLUMES (4U)
#define CS42L42_HP_VOL_REAL_MIN (-63) #define CS42L42_HP_VOL_REAL_MIN (-63)
#define CS42L42_HP_VOL_REAL_MAX (0) #define CS42L42_HP_VOL_REAL_MAX (0)
#define CS42L42_AMIC_VOL_REAL_MIN (-97) #define CS42L42_AMIC_VOL_REAL_MIN (-97)
...@@ -243,8 +243,6 @@ enum cs8409_coefficient_index_registers { ...@@ -243,8 +243,6 @@ enum cs8409_coefficient_index_registers {
#define CS8409_CS42L42_DMIC_PIN_NID CS8409_PIN_DMIC1_IN #define CS8409_CS42L42_DMIC_PIN_NID CS8409_PIN_DMIC1_IN
#define CS8409_CS42L42_DMIC_ADC_PIN_NID CS8409_PIN_DMIC1 #define CS8409_CS42L42_DMIC_ADC_PIN_NID CS8409_PIN_DMIC1
#define CS42L42_INIT_REG_SEQ_SIZE 59
enum { enum {
CS8409_BULLSEYE, CS8409_BULLSEYE,
CS8409_WARLOCK, CS8409_WARLOCK,
...@@ -252,6 +250,10 @@ enum { ...@@ -252,6 +250,10 @@ enum {
CS8409_FIXUPS, CS8409_FIXUPS,
}; };
enum {
CS8409_CODEC0,
};
enum { enum {
CS42L42_VOL_ADC, CS42L42_VOL_ADC,
CS42L42_VOL_DAC, CS42L42_VOL_DAC,
...@@ -268,25 +270,40 @@ struct cs8409_cir_param { ...@@ -268,25 +270,40 @@ struct cs8409_cir_param {
unsigned int coeff; unsigned int coeff;
}; };
struct sub_codec {
struct hda_codec *codec;
unsigned int addr;
unsigned int reset_gpio;
unsigned int irq_mask;
const struct cs8409_i2c_param *init_seq;
unsigned int init_seq_num;
unsigned int hp_jack_in:1;
unsigned int mic_jack_in:1;
unsigned int suspended:1;
unsigned int paged:1;
unsigned int last_page;
unsigned int hsbias_hiz;
unsigned int full_scale_vol:1;
s8 vol[CS42L42_VOLUMES];
};
struct cs8409_spec { struct cs8409_spec {
struct hda_gen_spec gen; struct hda_gen_spec gen;
struct hda_codec *codec; struct hda_codec *codec;
struct sub_codec *scodecs[CS8409_MAX_CODECS];
unsigned int num_scodecs;
unsigned int gpio_mask; unsigned int gpio_mask;
unsigned int gpio_dir; unsigned int gpio_dir;
unsigned int gpio_data; unsigned int gpio_data;
unsigned int cs42l42_hp_jack_in:1;
unsigned int cs42l42_mic_jack_in:1;
unsigned int cs42l42_suspended:1;
s8 vol[CS42L42_VOLUMES];
struct mutex i2c_mux; struct mutex i2c_mux;
unsigned int i2c_clck_enabled; unsigned int i2c_clck_enabled;
unsigned int dev_addr; unsigned int dev_addr;
struct delayed_work i2c_clk_work; struct delayed_work i2c_clk_work;
unsigned int paged;
unsigned int last_page;
/* verb exec op override */ /* verb exec op override */
int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags, int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
...@@ -305,9 +322,9 @@ extern const struct hda_model_fixup cs8409_models[]; ...@@ -305,9 +322,9 @@ extern const struct hda_model_fixup cs8409_models[];
extern const struct hda_fixup cs8409_fixups[]; extern const struct hda_fixup cs8409_fixups[];
extern const struct hda_verb cs8409_cs42l42_init_verbs[]; extern const struct hda_verb cs8409_cs42l42_init_verbs[];
extern const struct hda_pintbl cs8409_cs42l42_pincfgs[]; extern const struct hda_pintbl cs8409_cs42l42_pincfgs[];
extern const struct cs8409_i2c_param cs42l42_init_reg_seq[CS42L42_INIT_REG_SEQ_SIZE];
extern const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[]; extern const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[];
extern const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[]; extern const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[];
extern struct sub_codec cs8409_cs42l42_codec;
void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action); void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment