Merge remote-tracking branches 'asoc/topic/nau8824', 'asoc/topic/nau8825' and 'asoc...
authorMark Brown <broonie@kernel.org>
Fri, 5 Jan 2018 12:43:57 +0000 (12:43 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 5 Jan 2018 12:43:57 +0000 (12:43 +0000)
Documentation/devicetree/bindings/sound/nau8825.txt
sound/soc/codecs/nau8824.c
sound/soc/codecs/nau8825.c
sound/soc/codecs/nau8825.h
sound/soc/nuc900/nuc900-ac97.c

index 2f5e973285a648a3a7ea1bedb5d5cc9c79311589..d16d96839bcbf1a9aeb9c11fc5ffb79c25115c43 100644 (file)
@@ -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>;
index 0240759f951c7ea22b06004aa0e26320bba224fa..088e0cef4cb8d469f17c24f22941e045fbc5f1a8 100644 (file)
@@ -43,7 +43,7 @@ static bool nau8824_is_jack_inserted(struct nau8824 *nau8824);
 
 /* the parameter threshold of FLL */
 #define NAU_FREF_MAX 13500000
-#define NAU_FVCO_MAX 124000000
+#define NAU_FVCO_MAX 100000000
 #define NAU_FVCO_MIN 90000000
 
 /* scaling for mclk from sysclk_src output */
@@ -811,7 +811,8 @@ static void nau8824_eject_jack(struct nau8824 *nau8824)
                NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE);
 
        /* Close clock for jack type detection at manual mode */
-       nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
+       if (dapm->bias_level < SND_SOC_BIAS_PREPARE)
+               nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
 }
 
 static void nau8824_jdet_work(struct work_struct *work)
@@ -843,6 +844,11 @@ static void nau8824_jdet_work(struct work_struct *work)
        event_mask |= SND_JACK_HEADSET;
        snd_soc_jack_report(nau8824->jack, event, event_mask);
 
+       /* Enable short key press and release interruption. */
+       regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
+               NAU8824_IRQ_KEY_RELEASE_DIS |
+               NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0);
+
        nau8824_sema_release(nau8824);
 }
 
@@ -850,15 +856,15 @@ static void nau8824_setup_auto_irq(struct nau8824 *nau8824)
 {
        struct regmap *regmap = nau8824->regmap;
 
-       /* Enable jack ejection, short key press and release interruption. */
+       /* Enable jack ejection interruption. */
        regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING_1,
                NAU8824_IRQ_INSERT_EN | NAU8824_IRQ_EJECT_EN,
                NAU8824_IRQ_EJECT_EN);
        regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
-               NAU8824_IRQ_EJECT_DIS | NAU8824_IRQ_KEY_RELEASE_DIS |
-               NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0);
+               NAU8824_IRQ_EJECT_DIS, 0);
        /* Enable internal VCO needed for interruptions */
-       nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0);
+       if (nau8824->dapm->bias_level < SND_SOC_BIAS_PREPARE)
+               nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0);
        regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL,
                NAU8824_JD_SLEEP_MODE, 0);
 }
index e853a6dfd33b0ee7b8bf700dffea8b1e477f2d09..a1b697b6fb6483a357f68efa5818725a2a6e62e8 100644 (file)
@@ -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;
-                               schedule_work(&nau8825->xtalk_work);
+                               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,7 +1757,9 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
                        nau8825->xtalk_event_mask = event_mask;
                }
        } else if (active_irq & NAU8825_IMPEDANCE_MEAS_IRQ) {
-               schedule_work(&nau8825->xtalk_work);
+               /* 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) ==
                NAU8825_JACK_INSERTION_DETECTED) {
@@ -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);
 
index 8aee5c8647aee153f151ac09175dc3f6a9fd25da..f7e7321258825759d2adad0db15e84ced34f698e 100644 (file)
@@ -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,
index b6615affe5718b379df657f401cf34eeddc08dd1..81b09d740ed96ee39eeed88705305d46051c45da 100644 (file)
@@ -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;