pcm1789.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Audio driver for PCM1789
  3. // Copyright (C) 2018 Bootlin
  4. // Mylène Josserand <mylene.josserand@bootlin.com>
  5. #include <linux/gpio/consumer.h>
  6. #include <linux/module.h>
  7. #include <linux/workqueue.h>
  8. #include <sound/pcm_params.h>
  9. #include <sound/soc.h>
  10. #include <sound/tlv.h>
  11. #include "pcm1789.h"
  12. #define PCM1789_MUTE_CONTROL 0x10
  13. #define PCM1789_FMT_CONTROL 0x11
  14. #define PCM1789_SOFT_MUTE 0x14
  15. #define PCM1789_DAC_VOL_LEFT 0x18
  16. #define PCM1789_DAC_VOL_RIGHT 0x19
  17. #define PCM1789_FMT_MASK 0x07
  18. #define PCM1789_MUTE_MASK 0x03
  19. #define PCM1789_MUTE_SRET 0x06
  20. struct pcm1789_private {
  21. struct regmap *regmap;
  22. unsigned int format;
  23. unsigned int rate;
  24. struct gpio_desc *reset;
  25. struct work_struct work;
  26. struct device *dev;
  27. };
  28. static const struct reg_default pcm1789_reg_defaults[] = {
  29. { PCM1789_FMT_CONTROL, 0x00 },
  30. { PCM1789_SOFT_MUTE, 0x00 },
  31. { PCM1789_DAC_VOL_LEFT, 0xff },
  32. { PCM1789_DAC_VOL_RIGHT, 0xff },
  33. };
  34. static bool pcm1789_accessible_reg(struct device *dev, unsigned int reg)
  35. {
  36. return reg >= PCM1789_MUTE_CONTROL && reg <= PCM1789_DAC_VOL_RIGHT;
  37. }
  38. static bool pcm1789_writeable_reg(struct device *dev, unsigned int reg)
  39. {
  40. return pcm1789_accessible_reg(dev, reg);
  41. }
  42. static int pcm1789_set_dai_fmt(struct snd_soc_dai *codec_dai,
  43. unsigned int format)
  44. {
  45. struct snd_soc_component *component = codec_dai->component;
  46. struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
  47. priv->format = format;
  48. return 0;
  49. }
  50. static int pcm1789_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
  51. {
  52. struct snd_soc_component *component = codec_dai->component;
  53. struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
  54. return regmap_update_bits(priv->regmap, PCM1789_SOFT_MUTE,
  55. PCM1789_MUTE_MASK,
  56. mute ? 0 : PCM1789_MUTE_MASK);
  57. }
  58. static int pcm1789_hw_params(struct snd_pcm_substream *substream,
  59. struct snd_pcm_hw_params *params,
  60. struct snd_soc_dai *codec_dai)
  61. {
  62. struct snd_soc_component *component = codec_dai->component;
  63. struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
  64. int val = 0, ret;
  65. priv->rate = params_rate(params);
  66. switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
  67. case SND_SOC_DAIFMT_RIGHT_J:
  68. switch (params_width(params)) {
  69. case 24:
  70. val = 2;
  71. break;
  72. case 16:
  73. val = 3;
  74. break;
  75. default:
  76. return -EINVAL;
  77. }
  78. break;
  79. case SND_SOC_DAIFMT_I2S:
  80. switch (params_width(params)) {
  81. case 16:
  82. case 24:
  83. case 32:
  84. val = 0;
  85. break;
  86. default:
  87. return -EINVAL;
  88. }
  89. break;
  90. case SND_SOC_DAIFMT_LEFT_J:
  91. switch (params_width(params)) {
  92. case 16:
  93. case 24:
  94. case 32:
  95. val = 1;
  96. break;
  97. default:
  98. return -EINVAL;
  99. }
  100. break;
  101. default:
  102. dev_err(component->dev, "Invalid DAI format\n");
  103. return -EINVAL;
  104. }
  105. ret = regmap_update_bits(priv->regmap, PCM1789_FMT_CONTROL,
  106. PCM1789_FMT_MASK, val);
  107. if (ret < 0)
  108. return ret;
  109. return 0;
  110. }
  111. static void pcm1789_work_queue(struct work_struct *work)
  112. {
  113. struct pcm1789_private *priv = container_of(work,
  114. struct pcm1789_private,
  115. work);
  116. /* Perform a software reset to remove codec from desynchronized state */
  117. if (regmap_update_bits(priv->regmap, PCM1789_MUTE_CONTROL,
  118. 0x3 << PCM1789_MUTE_SRET, 0) < 0)
  119. dev_err(priv->dev, "Error while setting SRET");
  120. }
  121. static int pcm1789_trigger(struct snd_pcm_substream *substream, int cmd,
  122. struct snd_soc_dai *dai)
  123. {
  124. struct snd_soc_component *component = dai->component;
  125. struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
  126. int ret = 0;
  127. switch (cmd) {
  128. case SNDRV_PCM_TRIGGER_START:
  129. case SNDRV_PCM_TRIGGER_RESUME:
  130. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  131. schedule_work(&priv->work);
  132. break;
  133. case SNDRV_PCM_TRIGGER_STOP:
  134. case SNDRV_PCM_TRIGGER_SUSPEND:
  135. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  136. break;
  137. default:
  138. ret = -EINVAL;
  139. }
  140. return ret;
  141. }
  142. static const struct snd_soc_dai_ops pcm1789_dai_ops = {
  143. .set_fmt = pcm1789_set_dai_fmt,
  144. .hw_params = pcm1789_hw_params,
  145. .mute_stream = pcm1789_mute,
  146. .trigger = pcm1789_trigger,
  147. .no_capture_mute = 1,
  148. };
  149. static const DECLARE_TLV_DB_SCALE(pcm1789_dac_tlv, -12000, 50, 1);
  150. static const struct snd_kcontrol_new pcm1789_controls[] = {
  151. SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1789_DAC_VOL_LEFT,
  152. PCM1789_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
  153. pcm1789_dac_tlv),
  154. };
  155. static const struct snd_soc_dapm_widget pcm1789_dapm_widgets[] = {
  156. SND_SOC_DAPM_OUTPUT("IOUTL+"),
  157. SND_SOC_DAPM_OUTPUT("IOUTL-"),
  158. SND_SOC_DAPM_OUTPUT("IOUTR+"),
  159. SND_SOC_DAPM_OUTPUT("IOUTR-"),
  160. };
  161. static const struct snd_soc_dapm_route pcm1789_dapm_routes[] = {
  162. { "IOUTL+", NULL, "Playback" },
  163. { "IOUTL-", NULL, "Playback" },
  164. { "IOUTR+", NULL, "Playback" },
  165. { "IOUTR-", NULL, "Playback" },
  166. };
  167. static struct snd_soc_dai_driver pcm1789_dai = {
  168. .name = "pcm1789-hifi",
  169. .playback = {
  170. .stream_name = "Playback",
  171. .channels_min = 2,
  172. .channels_max = 2,
  173. .rates = SNDRV_PCM_RATE_CONTINUOUS,
  174. .rate_min = 10000,
  175. .rate_max = 200000,
  176. .formats = PCM1789_FORMATS,
  177. },
  178. .ops = &pcm1789_dai_ops,
  179. };
  180. const struct regmap_config pcm1789_regmap_config = {
  181. .reg_bits = 8,
  182. .val_bits = 8,
  183. .max_register = PCM1789_DAC_VOL_RIGHT,
  184. .reg_defaults = pcm1789_reg_defaults,
  185. .num_reg_defaults = ARRAY_SIZE(pcm1789_reg_defaults),
  186. .writeable_reg = pcm1789_writeable_reg,
  187. .readable_reg = pcm1789_accessible_reg,
  188. };
  189. EXPORT_SYMBOL_GPL(pcm1789_regmap_config);
  190. static const struct snd_soc_component_driver soc_component_dev_pcm1789 = {
  191. .controls = pcm1789_controls,
  192. .num_controls = ARRAY_SIZE(pcm1789_controls),
  193. .dapm_widgets = pcm1789_dapm_widgets,
  194. .num_dapm_widgets = ARRAY_SIZE(pcm1789_dapm_widgets),
  195. .dapm_routes = pcm1789_dapm_routes,
  196. .num_dapm_routes = ARRAY_SIZE(pcm1789_dapm_routes),
  197. .idle_bias_on = 1,
  198. .use_pmdown_time = 1,
  199. .endianness = 1,
  200. .non_legacy_dai_naming = 1,
  201. };
  202. int pcm1789_common_init(struct device *dev, struct regmap *regmap)
  203. {
  204. struct pcm1789_private *pcm1789;
  205. pcm1789 = devm_kzalloc(dev, sizeof(struct pcm1789_private),
  206. GFP_KERNEL);
  207. if (!pcm1789)
  208. return -ENOMEM;
  209. pcm1789->regmap = regmap;
  210. pcm1789->dev = dev;
  211. dev_set_drvdata(dev, pcm1789);
  212. pcm1789->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
  213. if (IS_ERR(pcm1789->reset))
  214. return PTR_ERR(pcm1789->reset);
  215. gpiod_set_value_cansleep(pcm1789->reset, 0);
  216. msleep(300);
  217. INIT_WORK(&pcm1789->work, pcm1789_work_queue);
  218. return devm_snd_soc_register_component(dev, &soc_component_dev_pcm1789,
  219. &pcm1789_dai, 1);
  220. }
  221. EXPORT_SYMBOL_GPL(pcm1789_common_init);
  222. int pcm1789_common_exit(struct device *dev)
  223. {
  224. struct pcm1789_private *priv = dev_get_drvdata(dev);
  225. flush_work(&priv->work);
  226. return 0;
  227. }
  228. EXPORT_SYMBOL_GPL(pcm1789_common_exit);
  229. MODULE_DESCRIPTION("ASoC PCM1789 driver");
  230. MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
  231. MODULE_LICENSE("GPL");