1 /* 2 * ADAU7002 Stereo PDM-to-I2S/TDM converter driver 3 * 4 * Copyright 2014-2016 Analog Devices 5 * Author: Lars-Peter Clausen <lars@metafoo.de> 6 * 7 * Licensed under the GPL-2. 8 */ 9 10 #include <linux/acpi.h> 11 #include <linux/delay.h> 12 #include <linux/init.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/platform_device.h> 16 17 #include <sound/soc.h> 18 19 struct adau7002_priv { 20 int wakeup_delay; 21 }; 22 23 static int adau7002_aif_event(struct snd_soc_dapm_widget *w, 24 struct snd_kcontrol *kcontrol, int event) 25 { 26 struct snd_soc_component *component = 27 snd_soc_dapm_to_component(w->dapm); 28 struct adau7002_priv *adau7002 = 29 snd_soc_component_get_drvdata(component); 30 31 switch (event) { 32 case SND_SOC_DAPM_POST_PMU: 33 if (adau7002->wakeup_delay) 34 msleep(adau7002->wakeup_delay); 35 break; 36 } 37 38 return 0; 39 } 40 41 static int adau7002_component_probe(struct snd_soc_component *component) 42 { 43 struct adau7002_priv *adau7002; 44 45 adau7002 = devm_kzalloc(component->dev, sizeof(*adau7002), 46 GFP_KERNEL); 47 if (!adau7002) 48 return -ENOMEM; 49 50 device_property_read_u32(component->dev, "wakeup-delay-ms", 51 &adau7002->wakeup_delay); 52 53 snd_soc_component_set_drvdata(component, adau7002); 54 55 return 0; 56 } 57 58 static const struct snd_soc_dapm_widget adau7002_widgets[] = { 59 SND_SOC_DAPM_AIF_OUT_E("ADAU AIF", "Capture", 0, 60 SND_SOC_NOPM, 0, 0, adau7002_aif_event, 61 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 62 SND_SOC_DAPM_INPUT("PDM_DAT"), 63 SND_SOC_DAPM_REGULATOR_SUPPLY("IOVDD", 0, 0), 64 }; 65 66 static const struct snd_soc_dapm_route adau7002_routes[] = { 67 { "ADAU AIF", NULL, "PDM_DAT"}, 68 { "Capture", NULL, "PDM_DAT" }, 69 { "Capture", NULL, "IOVDD" }, 70 }; 71 72 static struct snd_soc_dai_driver adau7002_dai = { 73 .name = "adau7002-hifi", 74 .capture = { 75 .stream_name = "Capture", 76 .channels_min = 2, 77 .channels_max = 2, 78 .rates = SNDRV_PCM_RATE_8000_96000, 79 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | 80 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | 81 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE, 82 .sig_bits = 20, 83 }, 84 }; 85 86 static const struct snd_soc_component_driver adau7002_component_driver = { 87 .probe = adau7002_component_probe, 88 .dapm_widgets = adau7002_widgets, 89 .num_dapm_widgets = ARRAY_SIZE(adau7002_widgets), 90 .dapm_routes = adau7002_routes, 91 .num_dapm_routes = ARRAY_SIZE(adau7002_routes), 92 .idle_bias_on = 1, 93 .use_pmdown_time = 1, 94 .endianness = 1, 95 .non_legacy_dai_naming = 1, 96 }; 97 98 static int adau7002_probe(struct platform_device *pdev) 99 { 100 return devm_snd_soc_register_component(&pdev->dev, 101 &adau7002_component_driver, 102 &adau7002_dai, 1); 103 } 104 105 static int adau7002_remove(struct platform_device *pdev) 106 { 107 return 0; 108 } 109 110 #ifdef CONFIG_OF 111 static const struct of_device_id adau7002_dt_ids[] = { 112 { .compatible = "adi,adau7002", }, 113 { } 114 }; 115 MODULE_DEVICE_TABLE(of, adau7002_dt_ids); 116 #endif 117 118 #ifdef CONFIG_ACPI 119 static const struct acpi_device_id adau7002_acpi_match[] = { 120 { "ADAU7002", 0 }, 121 {}, 122 }; 123 MODULE_DEVICE_TABLE(acpi, adau7002_acpi_match); 124 #endif 125 126 static struct platform_driver adau7002_driver = { 127 .driver = { 128 .name = "adau7002", 129 .of_match_table = of_match_ptr(adau7002_dt_ids), 130 .acpi_match_table = ACPI_PTR(adau7002_acpi_match), 131 }, 132 .probe = adau7002_probe, 133 .remove = adau7002_remove, 134 }; 135 module_platform_driver(adau7002_driver); 136 137 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 138 MODULE_DESCRIPTION("ADAU7002 Stereo PDM-to-I2S/TDM Converter driver"); 139 MODULE_LICENSE("GPL v2"); 140