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/module.h> 10#include <linux/slab.h> 11#include <linux/of.h> 12#include <linux/of_gpio.h> 13#include <linux/regulator/consumer.h> 14#include <sound/soc.h> 15#include <sound/pcm.h> 16#include <sound/initval.h> 17 18static const char * const supply_names[] = { 19 "va", "vd" 20}; 21 22struct ak5386_priv { 23 int reset_gpio; 24 struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; 25}; 26 27static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = { 28SND_SOC_DAPM_INPUT("AINL"), 29SND_SOC_DAPM_INPUT("AINR"), 30}; 31 32static const struct snd_soc_dapm_route ak5386_dapm_routes[] = { 33 { "Capture", NULL, "AINL" }, 34 { "Capture", NULL, "AINR" }, 35}; 36 37static int ak5386_soc_probe(struct snd_soc_component *component) 38{ 39 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 40 return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); 41} 42 43static void ak5386_soc_remove(struct snd_soc_component *component) 44{ 45 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 46 regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); 47} 48 49#ifdef CONFIG_PM 50static int ak5386_soc_suspend(struct snd_soc_component *component) 51{ 52 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 53 regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); 54 return 0; 55} 56 57static int ak5386_soc_resume(struct snd_soc_component *component) 58{ 59 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 60 return regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); 61} 62#else 63#define ak5386_soc_suspend NULL 64#define ak5386_soc_resume NULL 65#endif /* CONFIG_PM */ 66 67static const struct snd_soc_component_driver soc_component_ak5386 = { 68 .probe = ak5386_soc_probe, 69 .remove = ak5386_soc_remove, 70 .suspend = ak5386_soc_suspend, 71 .resume = ak5386_soc_resume, 72 .dapm_widgets = ak5386_dapm_widgets, 73 .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets), 74 .dapm_routes = ak5386_dapm_routes, 75 .num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes), 76 .idle_bias_on = 1, 77 .use_pmdown_time = 1, 78 .endianness = 1, 79}; 80 81static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai, 82 unsigned int format) 83{ 84 struct snd_soc_component *component = codec_dai->component; 85 86 format &= SND_SOC_DAIFMT_FORMAT_MASK; 87 if (format != SND_SOC_DAIFMT_LEFT_J && 88 format != SND_SOC_DAIFMT_I2S) { 89 dev_err(component->dev, "Invalid DAI format\n"); 90 return -EINVAL; 91 } 92 93 return 0; 94} 95 96static int ak5386_hw_params(struct snd_pcm_substream *substream, 97 struct snd_pcm_hw_params *params, 98 struct snd_soc_dai *dai) 99{ 100 struct snd_soc_component *component = dai->component; 101 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 102 103 /* 104 * From the datasheet: 105 * 106 * All external clocks (MCLK, SCLK and LRCK) must be present unless 107 * PDN pin = ���L���. If these clocks are not provided, the AK5386 may 108 * draw excess current due to its use of internal dynamically 109 * refreshed logic. If the external clocks are not present, place 110 * the AK5386 in power-down mode (PDN pin = ���L���). 111 */ 112 113 if (gpio_is_valid(priv->reset_gpio)) 114 gpio_set_value(priv->reset_gpio, 1); 115 116 return 0; 117} 118 119static int ak5386_hw_free(struct snd_pcm_substream *substream, 120 struct snd_soc_dai *dai) 121{ 122 struct snd_soc_component *component = dai->component; 123 struct ak5386_priv *priv = snd_soc_component_get_drvdata(component); 124 125 if (gpio_is_valid(priv->reset_gpio)) 126 gpio_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 = of_get_named_gpio(dev->of_node, 181 "reset-gpio", 0); 182 183 if (gpio_is_valid(priv->reset_gpio)) 184 if (devm_gpio_request_one(dev, priv->reset_gpio, 185 GPIOF_OUT_INIT_LOW, 186 "AK5386 Reset")) 187 priv->reset_gpio = -EINVAL; 188 189 return devm_snd_soc_register_component(dev, &soc_component_ak5386, 190 &ak5386_dai, 1); 191} 192 193static struct platform_driver ak5386_driver = { 194 .probe = ak5386_probe, 195 .driver = { 196 .name = "ak5386", 197 .of_match_table = of_match_ptr(ak5386_dt_ids), 198 }, 199}; 200 201module_platform_driver(ak5386_driver); 202 203MODULE_DESCRIPTION("ASoC driver for AK5386 ADC"); 204MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>"); 205MODULE_LICENSE("GPL"); 206