Commit 8de4e5a6 authored by Lucas Tanure's avatar Lucas Tanure Committed by Takashi Iwai
Browse files

ALSA: hda/cs8409: Avoid re-setting the same page as the last access

parent d395fd78
Loading
Loading
Loading
Loading
+69 −55
Original line number Diff line number Diff line
@@ -170,18 +170,37 @@ 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
 * @i2c_reg: Page register
 *
 * Returns negative on error.
 */
static int cs8409_i2c_set_page(struct hda_codec *codec, unsigned int i2c_reg)
{
	struct cs8409_spec *spec = codec->spec;

	if (spec->paged && (spec->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;
	}

	return 0;
}

/**
 * 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)
static int cs8409_i2c_read(struct hda_codec *codec, unsigned int i2c_address, unsigned int i2c_reg)
{
	struct cs8409_spec *spec = codec->spec;
	unsigned int i2c_reg_data;
@@ -193,14 +212,11 @@ static int cs8409_i2c_read(struct hda_codec *codec, unsigned int i2c_address, un
	cs8409_enable_i2c_clock(codec);
	cs8409_set_i2c_dev_addr(codec, i2c_address);

	if (paged) {
		cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg >> 8);
		if (cs8409_i2c_wait_complete(codec) < 0) {
	if (cs8409_i2c_set_page(codec, i2c_reg)) {
		codec_err(codec, "%s() Paged Transaction Failed 0x%02x : 0x%04x\n",
			__func__, i2c_address, i2c_reg);
		return -EIO;
	}
	}

	i2c_reg_data = (i2c_reg << 8) & 0x0ffff;
	cs8409_vendor_coef_set(codec, CS8409_I2C_QREAD, i2c_reg_data);
@@ -222,13 +238,12 @@ static int cs8409_i2c_read(struct hda_codec *codec, unsigned int i2c_address, un
 * @i2c_address: I2C Address
 * @i2c_reg: Register to write to
 * @i2c_data: Data to write
 * @paged: Is a paged transaction
 *
 * 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 i2c_reg,
			    unsigned int i2c_data, unsigned int paged)
			    unsigned int i2c_data)
{
	struct cs8409_spec *spec = codec->spec;
	unsigned int i2c_reg_data;
@@ -239,14 +254,11 @@ static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, u
	cs8409_enable_i2c_clock(codec);
	cs8409_set_i2c_dev_addr(codec, i2c_address);

	if (paged) {
		cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg >> 8);
		if (cs8409_i2c_wait_complete(codec) < 0) {
	if (cs8409_i2c_set_page(codec, i2c_reg)) {
		codec_err(codec, "%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);
	cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg_data);
@@ -325,14 +337,14 @@ int cs8409_cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_va
		if (chs & BIT(0)) {
			spec->vol[ofs] = *valp;
			cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOL_CHA,
					 -(spec->vol[ofs]) & CS8409_CS42L42_REG_HS_VOL_MASK, 1);
					 -(spec->vol[ofs]) & CS8409_CS42L42_REG_HS_VOL_MASK);
		}
		if (chs & BIT(1)) {
			ofs++;
			valp++;
			spec->vol[ofs] = *valp;
			cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOL_CHB,
					 -(spec->vol[ofs]) & CS8409_CS42L42_REG_HS_VOL_MASK, 1);
					 -(spec->vol[ofs]) & CS8409_CS42L42_REG_HS_VOL_MASK);
		}
		mutex_unlock(&spec->cs8409_i2c_mux);
		break;
@@ -341,7 +353,7 @@ int cs8409_cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_va
		if (chs & BIT(0)) {
			spec->vol[ofs] = *valp;
			cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_AMIC_VOL,
					 spec->vol[ofs] & CS8409_CS42L42_REG_AMIC_VOL_MASK, 1);
					 spec->vol[ofs] & CS8409_CS42L42_REG_AMIC_VOL_MASK);
		}
		mutex_unlock(&spec->cs8409_i2c_mux);
		break;
@@ -367,14 +379,15 @@ static void cs8409_cs42l42_reset(struct hda_codec *codec)
	usleep_range(10000, 15000);

	spec->cs42l42_suspended = 0;
	spec->last_page = 0;

	mutex_lock(&spec->cs8409_i2c_mux);

	/* Clear interrupts, by reading interrupt status registers */
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F);

	mutex_unlock(&spec->cs8409_i2c_mux);

@@ -391,20 +404,20 @@ static void cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec)
	 * 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, 1);
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x0020);
	else
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x00a0, 1);
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x00a0);

	/* Clear WAKE# */
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x00C1, 1);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 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, 1);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x00C0);
	/* Clear interrupts status */
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f);
	/* Enable interrupt */
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xF3, 1);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xF3);

	mutex_unlock(&spec->cs8409_i2c_mux);
}
@@ -417,20 +430,20 @@ static void cs8409_cs42l42_run_jack_detect(struct hda_codec *codec)
	mutex_lock(&spec->cs8409_i2c_mux);

	/* Clear interrupts */
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b77, 1);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xFF, 1);
	cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 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, 0xFD, 1);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0x80, 1);
	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);
	/* Wait ~110ms*/
	usleep_range(110000, 200000);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77, 1);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0, 1);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0);
	/* Wait ~10ms */
	usleep_range(10000, 25000);

@@ -446,7 +459,7 @@ static void cs8409_cs42l42_reg_setup(struct hda_codec *codec)
	mutex_lock(&spec->cs8409_i2c_mux);

	for (; seq->addr; seq++)
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1);
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg);

	mutex_unlock(&spec->cs8409_i2c_mux);

@@ -480,9 +493,9 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)
	mutex_lock(&spec->cs8409_i2c_mux);

	/* Read jack detect status registers */
	reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1);
	reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1);
	reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1);
	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);

	mutex_unlock(&spec->cs8409_i2c_mux);

@@ -495,7 +508,7 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)

		mutex_lock(&spec->cs8409_i2c_mux);
		/* Disable HSDET_AUTO_DONE */
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0xFF, 1);
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0xFF);
		mutex_unlock(&spec->cs8409_i2c_mux);

		type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1);
@@ -522,7 +535,7 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res)

		mutex_lock(&spec->cs8409_i2c_mux);
		/* Re-Enable Tip Sense Interrupt */
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xF3, 1);
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0xF3);
		mutex_unlock(&spec->cs8409_i2c_mux);

	} else {
@@ -589,7 +602,7 @@ static int cs8409_suspend(struct hda_codec *codec)

	mutex_lock(&spec->cs8409_i2c_mux);
	/* Power down CS42L42 ASP/EQ/MIX/HP */
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1101, 0xfe, 1);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1101, 0xfe);
	mutex_unlock(&spec->cs8409_i2c_mux);

	spec->cs42l42_suspended = 1;
@@ -652,7 +665,7 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
	if (codec->fixup_id == CS8409_WARLOCK || codec->fixup_id == CS8409_CYBORG) {
		/* FULL_SCALE_VOL = 0 for Warlock / Cyborg */
		mutex_lock(&spec->cs8409_i2c_mux);
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01, 1);
		cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01);
		mutex_unlock(&spec->cs8409_i2c_mux);
		/* DMIC1_MO=00b, DMIC1/2_SR=1 */
		cs8409_vendor_coef_set(codec, 0x09, 0x0003);
@@ -661,11 +674,11 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
	/* Restore Volumes after Resume */
	mutex_lock(&spec->cs8409_i2c_mux);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOL_CHA,
			 -(spec->vol[1]) & CS8409_CS42L42_REG_HS_VOL_MASK, 1);
			 -(spec->vol[1]) & CS8409_CS42L42_REG_HS_VOL_MASK);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOL_CHB,
			 -(spec->vol[2]) & CS8409_CS42L42_REG_HS_VOL_MASK, 1);
			 -(spec->vol[2]) & CS8409_CS42L42_REG_HS_VOL_MASK);
	cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_AMIC_VOL,
			 spec->vol[0] & CS8409_CS42L42_REG_AMIC_VOL_MASK, 1);
			 spec->vol[0] & CS8409_CS42L42_REG_AMIC_VOL_MASK);
	mutex_unlock(&spec->cs8409_i2c_mux);

	cs8409_cs42l42_enable_jack_detect(codec);
@@ -771,6 +784,7 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
		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);
+2 −0
Original line number Diff line number Diff line
@@ -283,6 +283,8 @@ struct cs8409_spec {
	unsigned int i2c_clck_enabled;
	unsigned int dev_addr;
	struct delayed_work i2c_clk_work;
	unsigned int paged;
	unsigned int last_page;

	/* verb exec op override */
	int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags,