Currently, it is only possible to configure HW-specific options to the adau17x1 codecs by providing a platform data struct. With this patch, it is possible to provide the same data via DT instead.
Signed-off-by: Andreas Irestål andire@axis.com --- .../devicetree/bindings/sound/adi,adau17x1.txt | 31 +++++ include/dt-bindings/sound/adau17x1.h | 14 +++ sound/soc/codecs/adau1761.c | 127 +++++++++++++++++++++ sound/soc/codecs/adau1781.c | 48 ++++++++ 4 files changed, 220 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 8dbce0e..6050602 100644 --- a/Documentation/devicetree/bindings/sound/adi,adau17x1.txt +++ b/Documentation/devicetree/bindings/sound/adi,adau17x1.txt @@ -13,6 +13,32 @@ Required properties: - reg: The i2c address. Value depends on the state of ADDR0 and ADDR1, as wired in hardware.
+Optional properties: + + - adi,input-differential bool to set if the input is differential + - adi,digital-microphone bool to set if there is a digital microphone + connected to digmic/jackdet pin. + - adi,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) + + - adi,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. + + - adi,lineout-mode Set output mode of the lineout pins. + - adi,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 + + + Examples: #include <dt-bindings/sound/adau17x1.h>
@@ -20,5 +46,10 @@ Examples: adau1361@38 { compatible = "adi,adau1761"; 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..caba102 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" @@ -709,6 +710,122 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec) return 0; }
+#ifdef CONFIG_OF +static inline void adau1761_parse_of_outmode(struct device *dev, + 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(dev, "Invalid output mode %d\n", of_val); + *mode = ADAU1761_OUTPUT_MODE_LINE; + break; + } +} + +static void adau1761_pdata_from_of(struct device *dev, + struct adau1761_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + uint32_t val; + uint32_t debounce_pars[2]; + + pdata->input_differential = + of_property_read_bool(np, "adi,input-differential"); + + if (of_get_property(np, "adi,jack-detection", NULL)) { + pdata->digmic_jackdetect_pin_mode = + ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT; + if (!of_property_read_u32_array(np, "adi,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(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, "adi,jack-detection", + debounce_pars, 1)) { + dev_warn(dev, "Debounce time not provided\n"); + pdata->jackdetect_active_low = + debounce_pars[0] == JACKDETECT_ACTIVE_LO; + } else { + dev_warn(dev, "No jack detection settings found\n"); + pdata->jackdetect_active_low = 0; + pdata->jackdetect_debounce_time = + ADAU1761_JACKDETECT_DEBOUNCE_40MS; + } + } else if (of_property_read_bool(np, "adi,digital-microphone")) { + 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, "adi,headphone-mode", &val)) + adau1761_parse_of_outmode(dev, val, &pdata->headphone_mode); + else + pdata->headphone_mode = ADAU1761_OUTPUT_MODE_LINE; + + if (!of_property_read_u32(np, "adi,lineout-mode", &val)) + adau1761_parse_of_outmode(dev, val, &pdata->lineout_mode); + else + pdata->lineout_mode = ADAU1761_OUTPUT_MODE_LINE; + + if (!of_property_read_u32(np, "adi,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(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 device *dev, + struct adau1761_platform_data *pdata) +{ +} +#endif + static const struct snd_soc_codec_driver adau1761_codec_driver = { .probe = adau1761_codec_probe, .resume = adau17x1_resume, @@ -768,6 +885,8 @@ int adau1761_probe(struct device *dev, struct regmap *regmap, enum adau17x1_type type, void (*switch_mode)(struct device *dev)) { struct snd_soc_dai_driver *dai_drv; + struct adau1761_platform_data *of_pdata; + struct device_node *np = dev->of_node; const char *firmware_name; int ret;
@@ -779,6 +898,14 @@ int adau1761_probe(struct device *dev, struct regmap *regmap, firmware_name = ADAU1761_FIRMWARE; }
+ if (!dev->platform_data && np) { + of_pdata = devm_kzalloc(dev, sizeof(*of_pdata), GFP_KERNEL); + if (!of_pdata) + return -ENOMEM; + adau1761_pdata_from_of(dev, of_pdata); + dev->platform_data = of_pdata; + } + ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name); if (ret) return ret; diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index bc1bb56..401220e 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" @@ -426,6 +427,43 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) return 0; }
+#ifdef CONFIG_OF +static void adau1781_pdata_from_of(struct device *dev, + struct adau1781_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + uint32_t val; + + val = of_property_read_bool(np, "adi,input-differential"); + pdata->left_input_differential = val; + pdata->right_input_differential = val; + + of_property_read_bool(np, "adi,digital-microphone"); + + if (!of_property_read_u32(np, "adi,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(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 device *dev, + struct adau1781_platform_data *pdata) +{ +} +#endif + static const struct snd_soc_codec_driver adau1781_codec_driver = { .probe = adau1781_codec_probe, .resume = adau17x1_resume, @@ -479,6 +517,8 @@ int adau1781_probe(struct device *dev, struct regmap *regmap, enum adau17x1_type type, void (*switch_mode)(struct device *dev)) { const char *firmware_name; + struct adau1781_platform_data *of_pdata; + struct device_node *np = dev->of_node; int ret;
switch (type) { @@ -492,6 +532,14 @@ int adau1781_probe(struct device *dev, struct regmap *regmap, return -EINVAL; }
+ if (!dev->platform_data && np) { + of_pdata = devm_kzalloc(dev, sizeof(*of_pdata), GFP_KERNEL); + if (!of_pdata) + return -ENOMEM; + adau1781_pdata_from_of(dev, of_pdata); + dev->platform_data = of_pdata; + } + ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name); if (ret) return ret;