Merge remote-tracking branches 'asoc/topic/inntel', 'asoc/topic/input', 'asoc/topic...
authorMark Brown <broonie@kernel.org>
Mon, 12 Dec 2016 15:53:03 +0000 (15:53 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 12 Dec 2016 15:53:03 +0000 (15:53 +0000)
drivers/input/misc/arizona-haptics.c
sound/soc/codecs/Kconfig
sound/soc/codecs/nau8825.c
sound/soc/codecs/nau8825.h

index 9829363345372add0e3a5fd6812ff49a6d527aba..07ec465f109587e48b946c9513f7b1fbc98a5619 100644 (file)
@@ -37,6 +37,8 @@ static void arizona_haptics_work(struct work_struct *work)
                                                       struct arizona_haptics,
                                                       work);
        struct arizona *arizona = haptics->arizona;
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(arizona->dapm);
        int ret;
 
        if (!haptics->arizona->dapm) {
@@ -66,7 +68,7 @@ static void arizona_haptics_work(struct work_struct *work)
                        return;
                }
 
-               ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
+               ret = snd_soc_component_enable_pin(component, "HAPTICS");
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
                                ret);
@@ -81,7 +83,7 @@ static void arizona_haptics_work(struct work_struct *work)
                }
        } else {
                /* This disable sequence will be a noop if already enabled */
-               ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
+               ret = snd_soc_component_disable_pin(component, "HAPTICS");
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
                                ret);
@@ -140,11 +142,14 @@ static int arizona_haptics_play(struct input_dev *input, void *data,
 static void arizona_haptics_close(struct input_dev *input)
 {
        struct arizona_haptics *haptics = input_get_drvdata(input);
+       struct snd_soc_component *component;
 
        cancel_work_sync(&haptics->work);
 
-       if (haptics->arizona->dapm)
-               snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");
+       if (haptics->arizona->dapm) {
+               component = snd_soc_dapm_to_component(haptics->arizona->dapm);
+               snd_soc_component_disable_pin(component, "HAPTICS");
+       }
 }
 
 static int arizona_haptics_probe(struct platform_device *pdev)
index 2aa709a0e87a8bffb5fe81b6b676cdfcbc54efb0..fb96959665fabe2f7f7c48e3c17f38c9b4364948 100644 (file)
@@ -85,6 +85,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MAX98095 if I2C
        select SND_SOC_MAX98357A if GPIOLIB
        select SND_SOC_MAX98371 if I2C
+       select SND_SOC_MAX98504 if I2C
        select SND_SOC_MAX9867 if I2C
        select SND_SOC_MAX98925 if I2C
        select SND_SOC_MAX98926 if I2C
index e643be91d7620f786803da5647b65932a4137785..efe3a44658d5a5e6d3a82d5f23ed8f8afd190d5a 100644 (file)
@@ -43,6 +43,8 @@
 #define GAIN_AUGMENT 22500
 #define SIDETONE_BASE 207000
 
+/* the maximum frequency of CLK_ADC and CLK_DAC */
+#define CLK_DA_AD_MAX 6144000
 
 static int nau8825_configure_sysclk(struct nau8825 *nau8825,
                int clk_id, unsigned int freq);
@@ -95,6 +97,27 @@ static const struct nau8825_fll_attr fll_pre_scalar[] = {
        { 8, 0x3 },
 };
 
+/* over sampling rate */
+struct nau8825_osr_attr {
+       unsigned int osr;
+       unsigned int clk_src;
+};
+
+static const struct nau8825_osr_attr osr_dac_sel[] = {
+       { 64, 2 },      /* OSR 64, SRC 1/4 */
+       { 256, 0 },     /* OSR 256, SRC 1 */
+       { 128, 1 },     /* OSR 128, SRC 1/2 */
+       { 0, 0 },
+       { 32, 3 },      /* OSR 32, SRC 1/8 */
+};
+
+static const struct nau8825_osr_attr osr_adc_sel[] = {
+       { 32, 3 },      /* OSR 32, SRC 1/8 */
+       { 64, 2 },      /* OSR 64, SRC 1/4 */
+       { 128, 1 },     /* OSR 128, SRC 1/2 */
+       { 256, 0 },     /* OSR 256, SRC 1 */
+};
+
 static const struct reg_default nau8825_reg_defaults[] = {
        { NAU8825_REG_ENA_CTRL, 0x00ff },
        { NAU8825_REG_IIC_ADDR_SET, 0x0 },
@@ -1179,15 +1202,64 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = {
        {"HPOR", NULL, "Class G"},
 };
 
+static int nau8825_clock_check(struct nau8825 *nau8825,
+       int stream, int rate, int osr)
+{
+       int osrate;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (osr >= ARRAY_SIZE(osr_dac_sel))
+                       return -EINVAL;
+               osrate = osr_dac_sel[osr].osr;
+       } else {
+               if (osr >= ARRAY_SIZE(osr_adc_sel))
+                       return -EINVAL;
+               osrate = osr_adc_sel[osr].osr;
+       }
+
+       if (!osrate || rate * osr > CLK_DA_AD_MAX) {
+               dev_err(nau8825->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int nau8825_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
        struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val_len = 0;
+       unsigned int val_len = 0, osr;
+
+       nau8825_sema_acquire(nau8825, 3 * HZ);
 
-       nau8825_sema_acquire(nau8825, 2 * HZ);
+       /* CLK_DAC or CLK_ADC = OSR * FS
+        * DAC or ADC clock frequency is defined as Over Sampling Rate (OSR)
+        * multiplied by the audio sample rate (Fs). Note that the OSR and Fs
+        * values must be selected such that the maximum frequency is less
+        * than 6.144 MHz.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               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))
+                       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);
+       } else {
+               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))
+                       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);
+       }
 
        switch (params_width(params)) {
        case 16:
@@ -1221,7 +1293,7 @@ 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, 2 * HZ);
+       nau8825_sema_acquire(nau8825, 3 * HZ);
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
@@ -1774,9 +1846,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
         * (audible hiss). Set it to something better.
         */
        regmap_update_bits(regmap, NAU8825_REG_ADC_RATE,
-               NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128);
+               NAU8825_ADC_SYNC_DOWN_MASK | NAU8825_ADC_SINC4_EN,
+               NAU8825_ADC_SYNC_DOWN_64);
        regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
-               NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128);
+               NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_64);
        /* Disable DACR/L power */
        regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,
                NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
@@ -1811,6 +1884,9 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
                NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_L);
        regmap_update_bits(nau8825->regmap, NAU8825_REG_DACR_CTRL,
                NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_R);
+       /* Disable short Frame Sync detection logic */
+       regmap_update_bits(regmap, NAU8825_REG_LEFT_TIME_SLOT,
+               NAU8825_DIS_FS_SHORT_DET, NAU8825_DIS_FS_SHORT_DET);
 }
 
 static const struct regmap_config nau8825_regmap_config = {
@@ -1919,8 +1995,10 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,
        regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
                NAU8825_CLK_SRC_MASK | NAU8825_CLK_MCLK_SRC_MASK,
                NAU8825_CLK_SRC_MCLK | fll_param->mclk_src);
+       /* Make DSP operate at high speed for better performance. */
        regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1,
-                       NAU8825_FLL_RATIO_MASK, fll_param->ratio);
+               NAU8825_FLL_RATIO_MASK | NAU8825_ICTRL_LATCH_MASK,
+               fll_param->ratio | (0x6 << NAU8825_ICTRL_LATCH_SFT));
        /* FLL 16-bit fractional input */
        regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac);
        /* FLL 10-bit integer input */
@@ -1936,19 +2014,22 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,
        regmap_update_bits(nau8825->regmap,
                NAU8825_REG_FLL6, NAU8825_DCO_EN, 0);
        if (fll_param->fll_frac) {
+               /* set FLL loop filter enable and cutoff frequency at 500Khz */
                regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
                        NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |
                        NAU8825_FLL_FTR_SW_MASK,
                        NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |
                        NAU8825_FLL_FTR_SW_FILTER);
                regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6,
-                       NAU8825_SDM_EN, NAU8825_SDM_EN);
+                       NAU8825_SDM_EN | NAU8825_CUTOFF500,
+                       NAU8825_SDM_EN | NAU8825_CUTOFF500);
        } else {
+               /* disable FLL loop filter and cutoff frequency */
                regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
                        NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |
                        NAU8825_FLL_FTR_SW_MASK, NAU8825_FLL_FTR_SW_ACCU);
-               regmap_update_bits(nau8825->regmap,
-                       NAU8825_REG_FLL6, NAU8825_SDM_EN, 0);
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6,
+                       NAU8825_SDM_EN | NAU8825_CUTOFF500, 0);
        }
 }
 
@@ -2014,6 +2095,9 @@ static void nau8825_configure_mclk_as_sysclk(struct regmap *regmap)
                NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_MCLK);
        regmap_update_bits(regmap, NAU8825_REG_FLL6,
                NAU8825_DCO_EN, 0);
+       /* Make DSP operate as default setting for power saving. */
+       regmap_update_bits(regmap, NAU8825_REG_FLL1,
+               NAU8825_ICTRL_LATCH_MASK, 0);
 }
 
 static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
@@ -2038,7 +2122,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                 * fered by cross talk process, the driver make the playback
                 * preparation halted until cross talk process finish.
                 */
-               nau8825_sema_acquire(nau8825, 2 * HZ);
+               nau8825_sema_acquire(nau8825, 3 * HZ);
                nau8825_configure_mclk_as_sysclk(regmap);
                /* MCLK not changed by clock tree */
                regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
@@ -2057,10 +2141,13 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                                NAU8825_DCO_EN, NAU8825_DCO_EN);
                        regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
                                NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO);
-                       /* Decrease the VCO frequency for power saving */
+                       /* Decrease the VCO frequency and make DSP operate
+                        * as default setting for power saving.
+                        */
                        regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
                                NAU8825_CLK_MCLK_SRC_MASK, 0xf);
                        regmap_update_bits(regmap, NAU8825_REG_FLL1,
+                               NAU8825_ICTRL_LATCH_MASK |
                                NAU8825_FLL_RATIO_MASK, 0x10);
                        regmap_update_bits(regmap, NAU8825_REG_FLL6,
                                NAU8825_SDM_EN, NAU8825_SDM_EN);
@@ -2083,9 +2170,14 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                 * fered by cross talk process, the driver make the playback
                 * preparation halted until cross talk process finish.
                 */
-               nau8825_sema_acquire(nau8825, 2 * HZ);
+               nau8825_sema_acquire(nau8825, 3 * HZ);
+               /* Higher FLL reference input frequency can only set lower
+                * gain error, such as 0000 for input reference from MCLK
+                * 12.288Mhz.
+                */
                regmap_update_bits(regmap, NAU8825_REG_FLL3,
-                       NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_MCLK);
+                       NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
+                       NAU8825_FLL_CLK_SRC_MCLK | 0);
                /* Release the semaphone. */
                nau8825_sema_release(nau8825);
 
@@ -2100,9 +2192,17 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                 * fered by cross talk process, the driver make the playback
                 * preparation halted until cross talk process finish.
                 */
-               nau8825_sema_acquire(nau8825, 2 * HZ);
+               nau8825_sema_acquire(nau8825, 3 * HZ);
+               /* If FLL reference input is from low frequency source,
+                * higher error gain can apply such as 0xf which has
+                * the most sensitive gain error correction threshold,
+                * Therefore, FLL has the most accurate DCO to
+                * target frequency.
+                */
                regmap_update_bits(regmap, NAU8825_REG_FLL3,
-                       NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_BLK);
+                       NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
+                       NAU8825_FLL_CLK_SRC_BLK |
+                       (0xf << NAU8825_GAIN_ERR_SFT));
                /* Release the semaphone. */
                nau8825_sema_release(nau8825);
 
@@ -2118,9 +2218,17 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                 * fered by cross talk process, the driver make the playback
                 * preparation halted until cross talk process finish.
                 */
-               nau8825_sema_acquire(nau8825, 2 * HZ);
+               nau8825_sema_acquire(nau8825, 3 * HZ);
+               /* If FLL reference input is from low frequency source,
+                * higher error gain can apply such as 0xf which has
+                * the most sensitive gain error correction threshold,
+                * Therefore, FLL has the most accurate DCO to
+                * target frequency.
+                */
                regmap_update_bits(regmap, NAU8825_REG_FLL3,
-                       NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_FS);
+                       NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
+                       NAU8825_FLL_CLK_SRC_FS |
+                       (0xf << NAU8825_GAIN_ERR_SFT));
                /* Release the semaphone. */
                nau8825_sema_release(nau8825);
 
index 1c63e2abafa99cddc7f9a2577e0e088803a68214..5d1704e732415dd04134f44ddab9971156c97de1 100644 (file)
 #define NAU8825_CLK_SRC_MASK                   (1 << NAU8825_CLK_SRC_SFT)
 #define NAU8825_CLK_SRC_VCO                    (1 << NAU8825_CLK_SRC_SFT)
 #define NAU8825_CLK_SRC_MCLK                   (0 << NAU8825_CLK_SRC_SFT)
+#define NAU8825_CLK_ADC_SRC_SFT                6
+#define NAU8825_CLK_ADC_SRC_MASK               (0x3 << NAU8825_CLK_ADC_SRC_SFT)
+#define NAU8825_CLK_DAC_SRC_SFT                4
+#define NAU8825_CLK_DAC_SRC_MASK               (0x3 << NAU8825_CLK_DAC_SRC_SFT)
 #define NAU8825_CLK_MCLK_SRC_MASK              (0xf << 0)
 
 /* FLL1 (0x04) */
+#define NAU8825_ICTRL_LATCH_SFT        10
+#define NAU8825_ICTRL_LATCH_MASK       (0x7 << NAU8825_ICTRL_LATCH_SFT)
 #define NAU8825_FLL_RATIO_MASK                 (0x7f << 0)
 
 /* FLL3 (0x06) */
+#define NAU8825_GAIN_ERR_SFT                   12
+#define NAU8825_GAIN_ERR_MASK                  (0xf << NAU8825_GAIN_ERR_SFT)
 #define NAU8825_FLL_INTEGER_MASK               (0x3ff << 0)
 #define NAU8825_FLL_CLK_SRC_SFT                10
 #define NAU8825_FLL_CLK_SRC_MASK               (0x3 << NAU8825_FLL_CLK_SRC_SFT)
 /* FLL6 (0x9) */
 #define NAU8825_DCO_EN                         (0x1 << 15)
 #define NAU8825_SDM_EN                         (0x1 << 14)
+#define NAU8825_CUTOFF500                      (0x1 << 13)
 
 /* HSD_CTRL (0xc) */
 #define NAU8825_HSD_AUTO_MODE  (1 << 6)
 #define NAU8825_I2S_MS_SLAVE   (0 << NAU8825_I2S_MS_SFT)
 #define NAU8825_I2S_BLK_DIV_MASK       0x7
 
+/* LEFT_TIME_SLOT (0x1e) */
+#define NAU8825_FS_ERR_CMP_SEL_SFT     14
+#define NAU8825_FS_ERR_CMP_SEL_MASK    (0x3 << NAU8825_FS_ERR_CMP_SEL_SFT)
+#define NAU8825_DIS_FS_SHORT_DET       (1 << 13)
+
 /* BIQ_CTRL (0x20) */
 #define NAU8825_BIQ_WRT_SFT   4
 #define NAU8825_BIQ_WRT_EN     (1 << NAU8825_BIQ_WRT_SFT)
 #define NAU8825_BIQ_PATH_DAC   (1 << NAU8825_BIQ_PATH_SFT)
 
 /* ADC_RATE (0x2b) */
+#define NAU8825_ADC_SINC4_SFT          4
+#define NAU8825_ADC_SINC4_EN           (1 << NAU8825_ADC_SINC4_SFT)
 #define NAU8825_ADC_SYNC_DOWN_SFT      0
 #define NAU8825_ADC_SYNC_DOWN_MASK     0x3
 #define NAU8825_ADC_SYNC_DOWN_32       0