Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 7cf143ca authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'asoc/topic/nau8825' and 'asoc/topic/nuc900' into asoc-next

Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ Optional properties:
  - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
  - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms

  - nuvoton,crosstalk-bypass: make crosstalk function bypass if set.
  - nuvoton,crosstalk-enable: make crosstalk function enable if set.

  - clocks: list of phandle and clock specifier pairs according to common clock bindings for the
      clocks described in clock-names
@@ -98,7 +98,7 @@ Example:
      nuvoton,short-key-debounce = <2>;
      nuvoton,jack-insert-debounce = <7>;
      nuvoton,jack-eject-debounce = <7>;
      nuvoton,crosstalk-bypass;
      nuvoton,crosstalk-enable;

      clock-names = "mclk";
      clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
+64 −37
Original line number Diff line number Diff line
@@ -194,10 +194,10 @@ static const struct reg_default nau8825_reg_defaults[] = {

/* register backup table when cross talk detection */
static struct reg_default nau8825_xtalk_baktab[] = {
	{ NAU8825_REG_ADC_DGAIN_CTRL, 0 },
	{ NAU8825_REG_ADC_DGAIN_CTRL, 0x00cf },
	{ NAU8825_REG_HSVOL_CTRL, 0 },
	{ NAU8825_REG_DACL_CTRL, 0 },
	{ NAU8825_REG_DACR_CTRL, 0 },
	{ NAU8825_REG_DACL_CTRL, 0x00cf },
	{ NAU8825_REG_DACR_CTRL, 0x02cf },
};

static const unsigned short logtable[256] = {
@@ -245,13 +245,14 @@ static const unsigned short logtable[256] = {
 * tasks are allowed to acquire the semaphore, calling this function will
 * put the task to sleep. If the semaphore is not released within the
 * specified number of jiffies, this function returns.
 * Acquires the semaphore without jiffies. If no more tasks are allowed
 * to acquire the semaphore, calling this function will put the task to
 * sleep until the semaphore is released.
 * If the semaphore is not released within the specified number of jiffies,
 * this function returns -ETIME.
 * If the sleep is interrupted by a signal, this function will return -EINTR.
 * It returns 0 if the semaphore was acquired successfully.
 * this function returns -ETIME. If the sleep is interrupted by a signal,
 * this function will return -EINTR. It returns 0 if the semaphore was
 * acquired successfully.
 *
 * Acquires the semaphore without jiffies. Try to acquire the semaphore
 * atomically. Returns 0 if the semaphore has been acquired successfully
 * or 1 if it it cannot be acquired.
 */
static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
{
@@ -262,8 +263,8 @@ static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
		if (ret < 0)
			dev_warn(nau8825->dev, "Acquire semaphore timeout\n");
	} else {
		ret = down_interruptible(&nau8825->xtalk_sem);
		if (ret < 0)
		ret = down_trylock(&nau8825->xtalk_sem);
		if (ret)
			dev_warn(nau8825->dev, "Acquire semaphore fail\n");
	}

@@ -454,22 +455,32 @@ static void nau8825_xtalk_backup(struct nau8825 *nau8825)
{
	int i;

	if (nau8825->xtalk_baktab_initialized)
		return;

	/* Backup some register values to backup table */
	for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++)
		regmap_read(nau8825->regmap, nau8825_xtalk_baktab[i].reg,
				&nau8825_xtalk_baktab[i].def);

	nau8825->xtalk_baktab_initialized = true;
}

static void nau8825_xtalk_restore(struct nau8825 *nau8825)
static void nau8825_xtalk_restore(struct nau8825 *nau8825, bool cause_cancel)
{
	int i, volume;

	if (!nau8825->xtalk_baktab_initialized)
		return;

	/* Restore register values from backup table; When the driver restores
	 * the headphone volumem, it needs recover to original level gradually
	 * with 3dB per step for less pop noise.
	 * the headphone volume in XTALK_DONE state, it needs recover to
	 * original level gradually with 3dB per step for less pop noise.
	 * Otherwise, the restore should do ASAP.
	 */
	for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++) {
		if (nau8825_xtalk_baktab[i].reg == NAU8825_REG_HSVOL_CTRL) {
		if (!cause_cancel && nau8825_xtalk_baktab[i].reg ==
			NAU8825_REG_HSVOL_CTRL) {
			/* Ramping up the volume change to reduce pop noise */
			volume = nau8825_xtalk_baktab[i].def &
				NAU8825_HPR_VOL_MASK;
@@ -479,6 +490,8 @@ static void nau8825_xtalk_restore(struct nau8825 *nau8825)
		regmap_write(nau8825->regmap, nau8825_xtalk_baktab[i].reg,
				nau8825_xtalk_baktab[i].def);
	}

	nau8825->xtalk_baktab_initialized = false;
}

static void nau8825_xtalk_prepare_dac(struct nau8825 *nau8825)
@@ -644,7 +657,7 @@ static void nau8825_xtalk_clean_adc(struct nau8825 *nau8825)
		NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_MASK, 0);
}

static void nau8825_xtalk_clean(struct nau8825 *nau8825)
static void nau8825_xtalk_clean(struct nau8825 *nau8825, bool cause_cancel)
{
	/* Enable internal VCO needed for interruptions */
	nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0);
@@ -660,7 +673,7 @@ static void nau8825_xtalk_clean(struct nau8825 *nau8825)
		NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK |
		NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_SLAVE);
	/* Restore value of specific register for cross talk */
	nau8825_xtalk_restore(nau8825);
	nau8825_xtalk_restore(nau8825, cause_cancel);
}

static void nau8825_xtalk_imm_start(struct nau8825 *nau8825, int vol)
@@ -779,7 +792,7 @@ static void nau8825_xtalk_measure(struct nau8825 *nau8825)
		dev_dbg(nau8825->dev, "cross talk sidetone: %x\n", sidetone);
		regmap_write(nau8825->regmap, NAU8825_REG_DAC_DGAIN_CTRL,
					(sidetone << 8) | sidetone);
		nau8825_xtalk_clean(nau8825);
		nau8825_xtalk_clean(nau8825, false);
		nau8825->xtalk_state = NAU8825_XTALK_DONE;
		break;
	default:
@@ -815,13 +828,14 @@ static void nau8825_xtalk_work(struct work_struct *work)

static void nau8825_xtalk_cancel(struct nau8825 *nau8825)
{
	/* If the xtalk_protect is true, that means the process is still
	 * on going. The driver forces to cancel the cross talk task and
	/* If the crosstalk is eanbled and the process is on going,
	 * the driver forces to cancel the crosstalk task and
	 * restores the configuration to original status.
	 */
	if (nau8825->xtalk_protect) {
	if (nau8825->xtalk_enable && nau8825->xtalk_state !=
		NAU8825_XTALK_DONE) {
		cancel_work_sync(&nau8825->xtalk_work);
		nau8825_xtalk_clean(nau8825);
		nau8825_xtalk_clean(nau8825, true);
	}
	/* Reset parameters for cross talk suppression function */
	nau8825_sema_reset(nau8825);
@@ -1246,8 +1260,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
		regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr);
		osr &= NAU8825_DAC_OVERSAMPLE_MASK;
		if (nau8825_clock_check(nau8825, substream->stream,
			params_rate(params), osr))
			params_rate(params), osr)) {
			nau8825_sema_release(nau8825);
			return -EINVAL;
		}
		regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
			NAU8825_CLK_DAC_SRC_MASK,
			osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT);
@@ -1255,8 +1271,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
		regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr);
		osr &= NAU8825_ADC_SYNC_DOWN_MASK;
		if (nau8825_clock_check(nau8825, substream->stream,
			params_rate(params), osr))
			params_rate(params), osr)) {
			nau8825_sema_release(nau8825);
			return -EINVAL;
		}
		regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
			NAU8825_CLK_ADC_SRC_MASK,
			osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT);
@@ -1273,8 +1291,10 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
			bclk_div = 1;
		else if (bclk_fs <= 128)
			bclk_div = 0;
		else
		else {
			nau8825_sema_release(nau8825);
			return -EINVAL;
		}
		regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
			NAU8825_I2S_LRC_DIV_MASK | NAU8825_I2S_BLK_DIV_MASK,
			((bclk_div + 1) << NAU8825_I2S_LRC_DIV_SFT) | bclk_div);
@@ -1294,6 +1314,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream,
		val_len |= NAU8825_I2S_DL_32;
		break;
	default:
		nau8825_sema_release(nau8825);
		return -EINVAL;
	}

@@ -1312,8 +1333,6 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
	struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
	unsigned int ctrl1_val = 0, ctrl2_val = 0;

	nau8825_sema_acquire(nau8825, 3 * HZ);

	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBM_CFM:
		ctrl2_val |= NAU8825_I2S_MS_MASTER;
@@ -1355,6 +1374,8 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
		return -EINVAL;
	}

	nau8825_sema_acquire(nau8825, 3 * HZ);

	regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1,
		NAU8825_I2S_DL_MASK | NAU8825_I2S_DF_MASK |
		NAU8825_I2S_BP_MASK | NAU8825_I2S_PCMB_MASK,
@@ -1687,7 +1708,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
	} else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) {
		if (nau8825_is_jack_inserted(regmap)) {
			event |= nau8825_jack_insert(nau8825);
			if (!nau8825->xtalk_bypass && !nau8825->high_imped) {
			if (nau8825->xtalk_enable && !nau8825->high_imped) {
				/* Apply the cross talk suppression in the
				 * headset without high impedance.
				 */
@@ -1701,12 +1722,15 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
					int ret;
					nau8825->xtalk_protect = true;
					ret = nau8825_sema_acquire(nau8825, 0);
					if (ret < 0)
					if (ret)
						nau8825->xtalk_protect = false;
				}
				/* Startup cross talk detection process */
				nau8825->xtalk_state = NAU8825_XTALK_PREPARE;
				if (nau8825->xtalk_protect) {
					nau8825->xtalk_state =
						NAU8825_XTALK_PREPARE;
					schedule_work(&nau8825->xtalk_work);
				}
			} else {
				/* The cross talk suppression shouldn't apply
				 * in the headset with high impedance. Thus,
@@ -1733,6 +1757,8 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
			nau8825->xtalk_event_mask = event_mask;
		}
	} else if (active_irq & NAU8825_IMPEDANCE_MEAS_IRQ) {
		/* crosstalk detection enable and process on going */
		if (nau8825->xtalk_enable && nau8825->xtalk_protect)
			schedule_work(&nau8825->xtalk_work);
		clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ;
	} else if ((active_irq & NAU8825_JACK_INSERTION_IRQ_MASK) ==
@@ -2382,7 +2408,7 @@ static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec)
	regcache_sync(nau8825->regmap);
	nau8825->xtalk_protect = true;
	ret = nau8825_sema_acquire(nau8825, 0);
	if (ret < 0)
	if (ret)
		nau8825->xtalk_protect = false;
	enable_irq(nau8825->irq);

@@ -2441,8 +2467,8 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825)
			nau8825->jack_insert_debounce);
	dev_dbg(dev, "jack-eject-debounce:  %d\n",
			nau8825->jack_eject_debounce);
	dev_dbg(dev, "crosstalk-bypass:     %d\n",
			nau8825->xtalk_bypass);
	dev_dbg(dev, "crosstalk-enable:     %d\n",
			nau8825->xtalk_enable);
}

static int nau8825_read_device_properties(struct device *dev,
@@ -2507,8 +2533,8 @@ static int nau8825_read_device_properties(struct device *dev,
		&nau8825->jack_eject_debounce);
	if (ret)
		nau8825->jack_eject_debounce = 0;
	nau8825->xtalk_bypass = device_property_read_bool(dev,
		"nuvoton,crosstalk-bypass");
	nau8825->xtalk_enable = device_property_read_bool(dev,
		"nuvoton,crosstalk-enable");

	nau8825->mclk = devm_clk_get(dev, "mclk");
	if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
@@ -2569,6 +2595,7 @@ static int nau8825_i2c_probe(struct i2c_client *i2c,
	 */
	nau8825->xtalk_state = NAU8825_XTALK_DONE;
	nau8825->xtalk_protect = false;
	nau8825->xtalk_baktab_initialized = false;
	sema_init(&nau8825->xtalk_sem, 1);
	INIT_WORK(&nau8825->xtalk_work, nau8825_xtalk_work);

+2 −1
Original line number Diff line number Diff line
@@ -476,7 +476,8 @@ struct nau8825 {
	int xtalk_event_mask;
	bool xtalk_protect;
	int imp_rms[NAU8825_XTALK_IMM];
	int xtalk_bypass;
	int xtalk_enable;
	bool xtalk_baktab_initialized; /* True if initialized. */
};

int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
+5 −6
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97,

	/* polling the AC_R_FINISH */
	while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH)
								&& timeout--)
								&& --timeout)
		mdelay(1);

	if (!timeout) {
@@ -121,7 +121,7 @@ static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg,

	/* polling the AC_W_FINISH */
	while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH)
								&& timeout--)
								&& --timeout)
		mdelay(1);

	if (!timeout)
@@ -345,11 +345,10 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
		goto out;
	}

	nuc900_audio->irq_num = platform_get_irq(pdev, 0);
	if (!nuc900_audio->irq_num) {
		ret = -EBUSY;
	ret = platform_get_irq(pdev, 0);
	if (ret < 0)
		goto out;
	}
	nuc900_audio->irq_num = ret;

	nuc900_ac97_data = nuc900_audio;