Signed-off-by: Andreas Irestål andire@axis.com --- .../devicetree/bindings/sound/adi,adau17x1.txt | 33 ++++++ include/dt-bindings/sound/adau17x1.h | 14 +++ sound/soc/codecs/adau1761.c | 131 +++++++++++++++++++++ sound/soc/codecs/adau1781.c | 57 +++++++++ 4 files changed, 235 insertions(+) create mode 100644 include/dt-bindings/sound/adau17x1.h
diff --git a/Documentation/devicetree/bindings/sound/adi,adau17x1.txt b/Documentation/devicetree/bindings/sound/adi,adau17x1.txt index 90f3ac3..296b417 100644 --- a/Documentation/devicetree/bindings/sound/adi,adau17x1.txt +++ b/Documentation/devicetree/bindings/sound/adi,adau17x1.txt @@ -12,10 +12,43 @@ Required properties: - reg: The i2c address. Value depends on the state of ADDR0 and ADDR1, as wired in hardware.
+Optional properties: + + - input-differential bool to set if the input is differential + - digital-microphone bool to set if there is a digital microphone connected + to the digmic/jackdet pin. + - micbias-vg Microphone bias voltage + MICBIAS_0_90_AVDD - 0.9 * AVDD + MICBIAS_0_65_AVDD - 0.65 * AVDD + +Optional properties (ADAU1361/ADAU1461/ADAU1761/ADAU1961 only) + + - jack-detection If present, configures codec to use the digmic/jackdet + pin for jack detection. must provide one of + JACKDETECT_ACTIVE_LO or JACKDETECT_ACTIVE_HI followed + by debounce time in ms, which must be 5, 10, 20, or 40. + + - lineout-mode Set output mode of the lineout pins. + - headphone-mode Set output mode of the headphone pins. + +The output mode must be one of: + OUTPUT_MODE_HEADPHONE - Headphone output + OUTPUT_MODE_HEADPHONE_CAPLESS - Capless headphone output + OUTPUT_MODE_LINE - Line output + + + Example: +#include <dt-bindings/sound/adau17x1.h> + i2c_bus { adau1361@38 { compatible = "adi,adau1361"; reg = <0x38>; + input-differential; + jack-detection = <JACKDETECT_ACTIVE_LO 40>; + lineout-mode = <OUTPUT_MODE_LINE>; + headphone-mode = <OUTPUT_MODE_HEADPHONE>; + micbias-vg = <MICBIAS_0_90_AVDD>; }; }; diff --git a/include/dt-bindings/sound/adau17x1.h b/include/dt-bindings/sound/adau17x1.h new file mode 100644 index 0000000..3152019 --- /dev/null +++ b/include/dt-bindings/sound/adau17x1.h @@ -0,0 +1,14 @@ +#ifndef __DT_ADAU17X1_H +#define __DT_ADAU17X1_H + +#define MICBIAS_0_90_AVDD 0 +#define MICBIAS_0_65_AVDD 1 + +#define OUTPUT_MODE_HEADPHONE 0 +#define OUTPUT_MODE_HEADPHONE_CAPLESS 1 +#define OUTPUT_MODE_LINE 2 + +#define JACKDETECT_ACTIVE_HI 0 +#define JACKDETECT_ACTIVE_LO 1 + +#endif diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 16fed36..22106b2 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -18,6 +18,7 @@ #include <sound/soc.h> #include <sound/tlv.h> #include <linux/platform_data/adau17x1.h> +#include <dt-bindings/sound/adau17x1.h>
#include "adau17x1.h" #include "adau1761.h" @@ -636,13 +637,143 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg) return adau17x1_readable_register(dev, reg); }
+#ifdef CONFIG_OF +static inline void adau1761_parse_of_outmode(struct snd_soc_codec *codec, + uint32_t of_val, + enum adau1761_output_mode *mode) +{ + switch (of_val) { + case OUTPUT_MODE_HEADPHONE: + *mode = ADAU1761_OUTPUT_MODE_HEADPHONE; + break; + case OUTPUT_MODE_HEADPHONE_CAPLESS: + *mode = ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS; + break; + case OUTPUT_MODE_LINE: + *mode = ADAU1761_OUTPUT_MODE_LINE; + break; + default: + dev_warn(codec->dev, "Invalid output mode %d\n", of_val); + *mode = ADAU1761_OUTPUT_MODE_LINE; + break; + } +} + +static void adau1761_pdata_from_of(struct snd_soc_codec *codec, + struct adau1761_platform_data *pdata) +{ + struct device_node *np = codec->dev->of_node; + uint32_t val; + uint32_t debounce_pars[2]; + + if (of_get_property(np, "input-differential", NULL)) + pdata->input_differential = 1; + else + pdata->input_differential = 0; + + if (of_get_property(np, "jack-detection", NULL)) { + pdata->digmic_jackdetect_pin_mode = + ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT; + if (!of_property_read_u32_array(np, "jack-detection", + debounce_pars, 2)) { + pdata->jackdetect_active_low = + debounce_pars[0] == JACKDETECT_ACTIVE_LO; + switch (debounce_pars[1]) { + case 5: + pdata->jackdetect_debounce_time = + ADAU1761_JACKDETECT_DEBOUNCE_5MS; + break; + case 10: + pdata->jackdetect_debounce_time = + ADAU1761_JACKDETECT_DEBOUNCE_10MS; + break; + case 20: + pdata->jackdetect_debounce_time = + ADAU1761_JACKDETECT_DEBOUNCE_20MS; + break; + case 40: + pdata->jackdetect_debounce_time = + ADAU1761_JACKDETECT_DEBOUNCE_40MS; + break; + default: + dev_warn(codec->dev, "Invalid debounce_time %d\n", + debounce_pars[1]); + pdata->jackdetect_debounce_time = + ADAU1761_JACKDETECT_DEBOUNCE_40MS; + break; + } + } else if (!of_property_read_u32_array(np, "jack-detection", + debounce_pars, 1)) { + dev_warn(codec->dev, "Debounce time not provided\n"); + pdata->jackdetect_active_low = + debounce_pars[0] == JACKDETECT_ACTIVE_LO; + } else { + dev_warn(codec->dev, "No jack detection settings found\n"); + pdata->jackdetect_active_low = 0; + pdata->jackdetect_debounce_time = + ADAU1761_JACKDETECT_DEBOUNCE_40MS; + } + } else if (of_get_property(np, "digital-microphone", NULL)) { + pdata->digmic_jackdetect_pin_mode = + ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC; + } else { + pdata->digmic_jackdetect_pin_mode = + ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE; + } + + if (!of_property_read_u32(np, "headphone-mode", &val)) + adau1761_parse_of_outmode(codec, val, &pdata->headphone_mode); + else + pdata->headphone_mode = ADAU1761_OUTPUT_MODE_LINE; + + if (!of_property_read_u32(np, "lineout-mode", &val)) + adau1761_parse_of_outmode(codec, val, &pdata->lineout_mode); + else + pdata->lineout_mode = ADAU1761_OUTPUT_MODE_LINE; + + if (!of_property_read_u32(np, "micbias-vg", &val)) { + switch (val) { + case MICBIAS_0_65_AVDD: + pdata->micbias_voltage = ADAU17X1_MICBIAS_0_65_AVDD; + break; + case MICBIAS_0_90_AVDD: + pdata->micbias_voltage = ADAU17X1_MICBIAS_0_90_AVDD; + break; + default: + dev_warn(codec->dev, "Invalid micbias voltage setting\n"); + pdata->micbias_voltage = ADAU17X1_MICBIAS_0_90_AVDD; + break; + } + } else { + pdata->micbias_voltage = ADAU17X1_MICBIAS_0_90_AVDD; + } +} +#else +static void adau1761_pdata_from_of(struct snd_soc_codec *codec, + struct adau1761_platform_data *pdata) +{ +} +#endif + static int adau1761_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct adau1761_platform_data *pdata = codec->dev->platform_data; struct adau *adau = snd_soc_codec_get_drvdata(codec); + struct device_node *np = codec->dev->of_node; + struct adau1761_platform_data *of_pdata; int ret;
+ if (!pdata && np && of_device_is_available(np)) { + of_pdata = devm_kzalloc(codec->dev, sizeof(*of_pdata), + GFP_KERNEL); + if (!of_pdata) + return -ENOMEM; + adau1761_pdata_from_of(codec, of_pdata); + pdata = of_pdata; + codec->dev->platform_data = pdata; + } + ret = adau17x1_add_widgets(codec); if (ret < 0) return ret; diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index bc1bb56..b207911 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -18,6 +18,7 @@ #include <sound/soc.h> #include <sound/tlv.h> #include <linux/platform_data/adau17x1.h> +#include <dt-bindings/sound/adau17x1.h>
#include "adau17x1.h" #include "adau1781.h" @@ -380,13 +381,69 @@ static int adau1781_set_input_mode(struct adau *adau, unsigned int reg, ADAU1781_INPUT_DIFFERNTIAL, val); }
+#ifdef CONFIG_OF +static void adau1781_pdata_from_of(struct snd_soc_codec *codec, + struct adau1781_platform_data *pdata) +{ + struct device_node *np = codec->dev->of_node; + uint32_t val; + + if (of_get_property(np, "input-differential", NULL)) { + pdata->left_input_differential = 1; + pdata->right_input_differential = 1; + } else { + pdata->left_input_differential = 0; + pdata->right_input_differential = 0; + } + + if (of_get_property(np, "digital-microphone", NULL)) + pdata->use_dmic = 1; + else + pdata->use_dmic = 0; + + if (!of_property_read_u32(np, "micbias-vg", &val)) { + switch (val) { + case MICBIAS_0_65_AVDD: + pdata->micbias_voltage = ADAU17X1_MICBIAS_0_65_AVDD; + break; + case MICBIAS_0_90_AVDD: + pdata->micbias_voltage = ADAU17X1_MICBIAS_0_90_AVDD; + break; + default: + dev_warn(codec->dev, "Invalid micbias voltage setting\n"); + pdata->micbias_voltage = ADAU17X1_MICBIAS_0_90_AVDD; + break; + } + } else { + pdata->micbias_voltage = ADAU17X1_MICBIAS_0_90_AVDD; + } +} +#else +static void adau1781_pdata_from_of(struct snd_soc_codec *codec, + struct adau1781_platform_data *pdata) +{ +} +#endif + static int adau1781_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); struct adau *adau = snd_soc_codec_get_drvdata(codec); + struct device_node *np = codec->dev->of_node; + struct adau1781_platform_data *of_pdata; int ret;
+ if (!pdata && np && of_device_is_available(np)) { + of_pdata = devm_kzalloc(codec->dev, sizeof(*of_pdata), + GFP_KERNEL); + if (!of_pdata) + return -ENOMEM; + adau1781_pdata_from_of(codec, of_pdata); + pdata = of_pdata; + codec->dev->platform_data = pdata; + } + ret = adau17x1_add_widgets(codec); if (ret) return ret;