FILE
ak5386.c
File preview with syntax highlighting.
linux-6.19.14/sound/soc/codecs/ak5386.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * ALSA SoC driver for 4 * Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC 5 * 6 * (c) 2013 Daniel Mack <zonque@gmail.com> 7 */ 8 9#include <linux/device.h> 10#include <linux/dev_printk.h> 11#include <linux/err.h> 12#include <linux/gpio/consumer.h> 13#include <linux/module.h> 14#include <linux/regulator/consumer.h> 15#include <linux/slab.h> 16#include <sound/soc.h> 17#include <sound/pcm.h> 18#include <sound/initval.h> 19 20static const char * const supply_names[] = { 21 "va", "vd" 22}; 23 24struct ak5386_priv { 25 struct gpio_desc *reset_gpio; 26 struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; 27}; 28 29static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = { 30SND_SOC_DAPM_INPUT("AINL"), 31SND_SOC_DAPM_INPUT("AINR"), 32}; 33 34static const struct snd_soc_dapm_route ak5386_dapm_routes[] = { 35 { "Capture", NULL, "AINL" }, 36 { "Capture", NULL, "AINR" }, 37}; 38 39static int ak5386_soc_probe(struct snd_soc_component *component) 40{ 41 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 42 return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); 43} 44 45static void ak5386_soc_remove(struct snd_soc_component *component) 46{ 47 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 48 regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); 49} 50 51#ifdef CONFIG_PM 52static int ak5386_soc_suspend(struct snd_soc_component *component) 53{ 54 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 55 regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); 56 return 0; 57} 58 59static int ak5386_soc_resume(struct snd_soc_component *component) 60{ 61 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 62 return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); 63} 64#else 65#define ak5386_soc_suspend NULL 66#define ak5386_soc_resume NULL 67#endif /* CONFIG_PM */ 68 69static const struct snd_soc_component_driver soc_component_ak5386 = { 70 .probe = ak5386_soc_probe, 71 .remove = ak5386_soc_remove, 72 .suspend = ak5386_soc_suspend, 73 .resume = ak5386_soc_resume, 74 .dapm_widgets = ak5386_dapm_widgets, 75 .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets), 76 .dapm_routes = ak5386_dapm_routes, 77 .num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes), 78 .idle_bias_on = 1, 79 .use_pmdown_time = 1, 80 .endianness = 1, 81}; 82 83static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai, 84 unsigned int format) 85{ 86 struct snd_soc_component *component = codec_dai->component; 87 88 format &= SND_SOC_DAIFMT_FORMAT_MASK; 89 if (format != SND_SOC_DAIFMT_LEFT_J && 90 format != SND_SOC_DAIFMT_I2S) { 91 dev_err(component->dev, "Invalid DAI format\n"); 92 return -EINVAL; 93 } 94 95 return 0; 96} 97 98static int ak5386_hw_params(struct snd_pcm_substream *substream, 99 struct snd_pcm_hw_params *params, 100 struct snd_soc_dai *dai) 101{ 102 struct snd_soc_component *component = dai->component; 103 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 104 105 /* 106 * From the datasheet: 107 * 108 * All external clocks (MCLK, SCLK and LRCK) must be present unless 109 * PDN pin = āLā. If these clocks are not provided, the AK5386 may 110 * draw excess current due to its use of internal dynamically 111 * refreshed logic. If the external clocks are not present, place 112 * the AK5386 in power-down mode (PDN pin = āLā). 113 */ 114 115 gpiod_set_value(priv->reset_gpio, 1); 116 117 return 0; 118} 119 120static int ak5386_hw_free(struct snd_pcm_substream *substream, 121 struct snd_soc_dai *dai) 122{ 123 struct snd_soc_component *component = dai->component; 124 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 125 126 gpiod_set_value(priv->reset_gpio, 0); 127 128 return 0; 129} 130 131static const struct snd_soc_dai_ops ak5386_dai_ops = { 132 .set_fmt = ak5386_set_dai_fmt, 133 .hw_params = ak5386_hw_params, 134 .hw_free = ak5386_hw_free, 135}; 136 137static struct snd_soc_dai_driver ak5386_dai = { 138 .name = "ak5386-hifi", 139 .capture = { 140 .stream_name = "Capture", 141 .channels_min = 1, 142 .channels_max = 2, 143 .rates = SNDRV_PCM_RATE_8000_192000, 144 .formats = SNDRV_PCM_FMTBIT_S8 | 145 SNDRV_PCM_FMTBIT_S16_LE | 146 SNDRV_PCM_FMTBIT_S24_LE | 147 SNDRV_PCM_FMTBIT_S24_3LE, 148 }, 149 .ops = &ak5386_dai_ops, 150}; 151 152#ifdef CONFIG_OF 153static const struct of_device_id ak5386_dt_ids[] = { 154 { .compatible = "asahi-kasei,ak5386", }, 155 { } 156}; 157MODULE_DEVICE_TABLE(of, ak5386_dt_ids); 158#endif 159 160static int ak5386_probe(struct platform_device *pdev) 161{ 162 struct device *dev = &pdev->dev; 163 struct ak5386_priv *priv; 164 int ret, i; 165 166 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 167 if (!priv) 168 return -ENOMEM; 169 170 dev_set_drvdata(dev, priv); 171 172 for (i = 0; i < ARRAY_SIZE(supply_names); i++) 173 priv->supplies[i].supply = supply_names[i]; 174 175 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), 176 priv->supplies); 177 if (ret < 0) 178 return ret; 179 180 priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 181 if (IS_ERR(priv->reset_gpio)) 182 return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), 183 "Failed to get AK5386 reset GPIO\n"); 184 185 gpiod_set_consumer_name(priv->reset_gpio, "AK5386 Reset"); 186 187 return devm_snd_soc_register_component(dev, &soc_component_ak5386, 188 &ak5386_dai, 1); 189} 190 191static struct platform_driver ak5386_driver = { 192 .probe = ak5386_probe, 193 .driver = { 194 .name = "ak5386", 195 .of_match_table = of_match_ptr(ak5386_dt_ids), 196 }, 197}; 198 199module_platform_driver(ak5386_driver); 200 201MODULE_DESCRIPTION("ASoC driver for AK5386 ADC"); 202MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>"); 203MODULE_LICENSE("GPL");
~/
Read-only file preview.