ASoC: nau8825: add programmable biquad filter control
authorJohn Hsu <KCHSU0@nuvoton.com>
Tue, 31 May 2016 03:57:41 +0000 (11:57 +0800)
committerMark Brown <broonie@kernel.org>
Tue, 31 May 2016 17:38:59 +0000 (18:38 +0100)
Add programmable biquad filter configuration control for user space.
The filter is configurable for low pass filters, high pass filters,
Notch filter, etc in the ADC and DAC path.

Signed-off-by: John Hsu <KCHSU0@nuvoton.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/nau8825.c
sound/soc/codecs/nau8825.h

index e988f89ef715125da17d1d71a263dca93316c336..88e01f9376576e75f9d3029d0fb1c8d1c578a206 100644 (file)
@@ -217,6 +217,7 @@ static bool nau8825_volatile_reg(struct device *dev, unsigned int reg)
        case NAU8825_REG_SARDOUT_RAM_STATUS:
        case NAU8825_REG_CHARGE_PUMP_INPUT_READ:
        case NAU8825_REG_GENERAL_STATUS:
+       case NAU8825_REG_BIQ_CTRL ... NAU8825_REG_BIQ_COF10:
                return true;
        default:
                return false;
@@ -293,6 +294,54 @@ static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static int nau8825_biq_coeff_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+
+       if (!component->regmap)
+               return -EINVAL;
+
+       regmap_raw_read(component->regmap, NAU8825_REG_BIQ_COF1,
+               ucontrol->value.bytes.data, params->max);
+       return 0;
+}
+
+static int nau8825_biq_coeff_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+       void *data;
+
+       if (!component->regmap)
+               return -EINVAL;
+
+       data = kmemdup(ucontrol->value.bytes.data,
+               params->max, GFP_KERNEL | GFP_DMA);
+       if (!data)
+               return -ENOMEM;
+
+       regmap_update_bits(component->regmap, NAU8825_REG_BIQ_CTRL,
+               NAU8825_BIQ_WRT_EN, 0);
+       regmap_raw_write(component->regmap, NAU8825_REG_BIQ_COF1,
+               data, params->max);
+       regmap_update_bits(component->regmap, NAU8825_REG_BIQ_CTRL,
+               NAU8825_BIQ_WRT_EN, NAU8825_BIQ_WRT_EN);
+
+       kfree(data);
+       return 0;
+}
+
+static const char * const nau8825_biq_path[] = {
+       "ADC", "DAC"
+};
+
+static const struct soc_enum nau8825_biq_path_enum =
+       SOC_ENUM_SINGLE(NAU8825_REG_BIQ_CTRL, NAU8825_BIQ_PATH_SFT,
+               ARRAY_SIZE(nau8825_biq_path), nau8825_biq_path);
+
 static const char * const nau8825_adc_decimation[] = {
        "32", "64", "128", "256"
 };
@@ -329,6 +378,10 @@ static const struct snd_kcontrol_new nau8825_controls[] = {
 
        SOC_ENUM("ADC Decimation Rate", nau8825_adc_decimation_enum),
        SOC_ENUM("DAC Oversampling Rate", nau8825_dac_oversampl_enum),
+       /* programmable biquad filter */
+       SOC_ENUM("BIQ Path Select", nau8825_biq_path_enum),
+       SND_SOC_BYTES_EXT("BIQ Coefficeints", 20,
+                 nau8825_biq_coeff_get, nau8825_biq_coeff_put),
 };
 
 /* DAC Mux 0x33[9] and 0x34[9] */
index 9e6cb6262bf26b71a5018c84a34e6e971dd91b0c..1293d1bf80eb416a4a2c4ca76785907f266652e5 100644 (file)
 #define NAU8825_I2S_MS_MASTER  (1 << NAU8825_I2S_MS_SFT)
 #define NAU8825_I2S_MS_SLAVE   (0 << NAU8825_I2S_MS_SFT)
 
+/* BIQ_CTRL (0x20) */
+#define NAU8825_BIQ_WRT_SFT   4
+#define NAU8825_BIQ_WRT_EN     (1 << NAU8825_BIQ_WRT_SFT)
+#define NAU8825_BIQ_PATH_SFT   0
+#define NAU8825_BIQ_PATH_MASK  (1 << NAU8825_BIQ_PATH_SFT)
+#define NAU8825_BIQ_PATH_ADC   (0 << NAU8825_BIQ_PATH_SFT)
+#define NAU8825_BIQ_PATH_DAC   (1 << NAU8825_BIQ_PATH_SFT)
+
 /* ADC_RATE (0x2b) */
 #define NAU8825_ADC_SYNC_DOWN_SFT      0
 #define NAU8825_ADC_SYNC_DOWN_MASK     0x3