ak5386.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * ALSA SoC driver for
  3. * Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
  4. *
  5. * (c) 2013 Daniel Mack <zonque@gmail.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/module.h>
  12. #include <linux/slab.h>
  13. #include <linux/of.h>
  14. #include <linux/of_gpio.h>
  15. #include <linux/of_device.h>
  16. #include <sound/soc.h>
  17. #include <sound/pcm.h>
  18. #include <sound/initval.h>
  19. struct ak5386_priv {
  20. int reset_gpio;
  21. };
  22. static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = {
  23. SND_SOC_DAPM_INPUT("AINL"),
  24. SND_SOC_DAPM_INPUT("AINR"),
  25. };
  26. static const struct snd_soc_dapm_route ak5386_dapm_routes[] = {
  27. { "Capture", NULL, "AINL" },
  28. { "Capture", NULL, "AINR" },
  29. };
  30. static struct snd_soc_codec_driver soc_codec_ak5386 = {
  31. .dapm_widgets = ak5386_dapm_widgets,
  32. .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets),
  33. .dapm_routes = ak5386_dapm_routes,
  34. .num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes),
  35. };
  36. static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
  37. unsigned int format)
  38. {
  39. struct snd_soc_codec *codec = codec_dai->codec;
  40. format &= SND_SOC_DAIFMT_FORMAT_MASK;
  41. if (format != SND_SOC_DAIFMT_LEFT_J &&
  42. format != SND_SOC_DAIFMT_I2S) {
  43. dev_err(codec->dev, "Invalid DAI format\n");
  44. return -EINVAL;
  45. }
  46. return 0;
  47. }
  48. static int ak5386_hw_params(struct snd_pcm_substream *substream,
  49. struct snd_pcm_hw_params *params,
  50. struct snd_soc_dai *dai)
  51. {
  52. struct snd_soc_codec *codec = dai->codec;
  53. struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
  54. /*
  55. * From the datasheet:
  56. *
  57. * All external clocks (MCLK, SCLK and LRCK) must be present unless
  58. * PDN pin = “L”. If these clocks are not provided, the AK5386 may
  59. * draw excess current due to its use of internal dynamically
  60. * refreshed logic. If the external clocks are not present, place
  61. * the AK5386 in power-down mode (PDN pin = “L”).
  62. */
  63. if (gpio_is_valid(priv->reset_gpio))
  64. gpio_set_value(priv->reset_gpio, 1);
  65. return 0;
  66. }
  67. static int ak5386_hw_free(struct snd_pcm_substream *substream,
  68. struct snd_soc_dai *dai)
  69. {
  70. struct snd_soc_codec *codec = dai->codec;
  71. struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
  72. if (gpio_is_valid(priv->reset_gpio))
  73. gpio_set_value(priv->reset_gpio, 0);
  74. return 0;
  75. }
  76. static const struct snd_soc_dai_ops ak5386_dai_ops = {
  77. .set_fmt = ak5386_set_dai_fmt,
  78. .hw_params = ak5386_hw_params,
  79. .hw_free = ak5386_hw_free,
  80. };
  81. static struct snd_soc_dai_driver ak5386_dai = {
  82. .name = "ak5386-hifi",
  83. .capture = {
  84. .stream_name = "Capture",
  85. .channels_min = 1,
  86. .channels_max = 2,
  87. .rates = SNDRV_PCM_RATE_8000_192000,
  88. .formats = SNDRV_PCM_FMTBIT_S8 |
  89. SNDRV_PCM_FMTBIT_S16_LE |
  90. SNDRV_PCM_FMTBIT_S24_LE |
  91. SNDRV_PCM_FMTBIT_S24_3LE,
  92. },
  93. .ops = &ak5386_dai_ops,
  94. };
  95. #ifdef CONFIG_OF
  96. static const struct of_device_id ak5386_dt_ids[] = {
  97. { .compatible = "asahi-kasei,ak5386", },
  98. { }
  99. };
  100. MODULE_DEVICE_TABLE(of, ak5386_dt_ids);
  101. #endif
  102. static int ak5386_probe(struct platform_device *pdev)
  103. {
  104. struct device *dev = &pdev->dev;
  105. struct ak5386_priv *priv;
  106. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  107. if (!priv)
  108. return -ENOMEM;
  109. priv->reset_gpio = -EINVAL;
  110. dev_set_drvdata(dev, priv);
  111. if (of_match_device(of_match_ptr(ak5386_dt_ids), dev))
  112. priv->reset_gpio = of_get_named_gpio(dev->of_node,
  113. "reset-gpio", 0);
  114. if (gpio_is_valid(priv->reset_gpio))
  115. if (devm_gpio_request_one(dev, priv->reset_gpio,
  116. GPIOF_OUT_INIT_LOW,
  117. "AK5386 Reset"))
  118. priv->reset_gpio = -EINVAL;
  119. return snd_soc_register_codec(dev, &soc_codec_ak5386,
  120. &ak5386_dai, 1);
  121. }
  122. static int ak5386_remove(struct platform_device *pdev)
  123. {
  124. snd_soc_unregister_codec(&pdev->dev);
  125. return 0;
  126. }
  127. static struct platform_driver ak5386_driver = {
  128. .probe = ak5386_probe,
  129. .remove = ak5386_remove,
  130. .driver = {
  131. .name = "ak5386",
  132. .owner = THIS_MODULE,
  133. .of_match_table = of_match_ptr(ak5386_dt_ids),
  134. },
  135. };
  136. module_platform_driver(ak5386_driver);
  137. MODULE_DESCRIPTION("ASoC driver for AK5386 ADC");
  138. MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
  139. MODULE_LICENSE("GPL");