sti-sas.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) STMicroelectronics SA 2015
  4. * Authors: Arnaud Pouliquen <[email protected]>
  5. * for STMicroelectronics.
  6. */
  7. #include <linux/io.h>
  8. #include <linux/module.h>
  9. #include <linux/regmap.h>
  10. #include <linux/reset.h>
  11. #include <linux/mfd/syscon.h>
  12. #include <sound/soc.h>
  13. #include <sound/soc-dapm.h>
  14. /* DAC definitions */
  15. /* stih407 DAC registers */
  16. /* sysconf 5041: Audio-Gue-Control */
  17. #define STIH407_AUDIO_GLUE_CTRL 0x000000A4
  18. /* sysconf 5042: Audio-DAC-Control */
  19. #define STIH407_AUDIO_DAC_CTRL 0x000000A8
  20. /* DAC definitions */
  21. #define STIH407_DAC_SOFTMUTE 0x0
  22. #define STIH407_DAC_STANDBY_ANA 0x1
  23. #define STIH407_DAC_STANDBY 0x2
  24. #define STIH407_DAC_SOFTMUTE_MASK BIT(STIH407_DAC_SOFTMUTE)
  25. #define STIH407_DAC_STANDBY_ANA_MASK BIT(STIH407_DAC_STANDBY_ANA)
  26. #define STIH407_DAC_STANDBY_MASK BIT(STIH407_DAC_STANDBY)
  27. /* SPDIF definitions */
  28. #define SPDIF_BIPHASE_ENABLE 0x6
  29. #define SPDIF_BIPHASE_IDLE 0x7
  30. #define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE)
  31. #define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE)
  32. enum {
  33. STI_SAS_DAI_SPDIF_OUT,
  34. STI_SAS_DAI_ANALOG_OUT,
  35. };
  36. static const struct reg_default stih407_sas_reg_defaults[] = {
  37. { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
  38. { STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
  39. };
  40. struct sti_dac_audio {
  41. struct regmap *regmap;
  42. struct regmap *virt_regmap;
  43. int mclk;
  44. };
  45. struct sti_spdif_audio {
  46. struct regmap *regmap;
  47. int mclk;
  48. };
  49. /* device data structure */
  50. struct sti_sas_dev_data {
  51. const struct regmap_config *regmap;
  52. const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */
  53. const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
  54. const int num_dapm_widgets; /* dapms declaration */
  55. const struct snd_soc_dapm_route *dapm_routes; /* route declaration */
  56. const int num_dapm_routes; /* route declaration */
  57. };
  58. /* driver data structure */
  59. struct sti_sas_data {
  60. struct device *dev;
  61. const struct sti_sas_dev_data *dev_data;
  62. struct sti_dac_audio dac;
  63. struct sti_spdif_audio spdif;
  64. };
  65. /* Read a register from the sysconf reg bank */
  66. static int sti_sas_read_reg(void *context, unsigned int reg,
  67. unsigned int *value)
  68. {
  69. struct sti_sas_data *drvdata = context;
  70. int status;
  71. u32 val;
  72. status = regmap_read(drvdata->dac.regmap, reg, &val);
  73. *value = (unsigned int)val;
  74. return status;
  75. }
  76. /* Read a register from the sysconf reg bank */
  77. static int sti_sas_write_reg(void *context, unsigned int reg,
  78. unsigned int value)
  79. {
  80. struct sti_sas_data *drvdata = context;
  81. return regmap_write(drvdata->dac.regmap, reg, value);
  82. }
  83. static int sti_sas_init_sas_registers(struct snd_soc_component *component,
  84. struct sti_sas_data *data)
  85. {
  86. int ret;
  87. /*
  88. * DAC and SPDIF are activated by default
  89. * put them in IDLE to save power
  90. */
  91. /* Initialise bi-phase formatter to disabled */
  92. ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
  93. SPDIF_BIPHASE_ENABLE_MASK, 0);
  94. if (!ret)
  95. /* Initialise bi-phase formatter idle value to 0 */
  96. ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
  97. SPDIF_BIPHASE_IDLE_MASK, 0);
  98. if (ret < 0) {
  99. dev_err(component->dev, "Failed to update SPDIF registers\n");
  100. return ret;
  101. }
  102. /* Init DAC configuration */
  103. /* init configuration */
  104. ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
  105. STIH407_DAC_STANDBY_MASK,
  106. STIH407_DAC_STANDBY_MASK);
  107. if (!ret)
  108. ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
  109. STIH407_DAC_STANDBY_ANA_MASK,
  110. STIH407_DAC_STANDBY_ANA_MASK);
  111. if (!ret)
  112. ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
  113. STIH407_DAC_SOFTMUTE_MASK,
  114. STIH407_DAC_SOFTMUTE_MASK);
  115. if (ret < 0) {
  116. dev_err(component->dev, "Failed to update DAC registers\n");
  117. return ret;
  118. }
  119. return ret;
  120. }
  121. /*
  122. * DAC
  123. */
  124. static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  125. {
  126. /* Sanity check only */
  127. if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
  128. dev_err(dai->component->dev,
  129. "%s: ERROR: Unsupported clocking 0x%x\n",
  130. __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
  131. return -EINVAL;
  132. }
  133. return 0;
  134. }
  135. static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
  136. SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
  137. STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
  138. SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL,
  139. STIH407_DAC_STANDBY, 1),
  140. SND_SOC_DAPM_OUTPUT("DAC Output"),
  141. };
  142. static const struct snd_soc_dapm_route stih407_sas_route[] = {
  143. {"DAC Output", NULL, "DAC standby ana"},
  144. {"DAC standby ana", NULL, "DAC standby"},
  145. };
  146. static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
  147. {
  148. struct snd_soc_component *component = dai->component;
  149. if (mute) {
  150. return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
  151. STIH407_DAC_SOFTMUTE_MASK,
  152. STIH407_DAC_SOFTMUTE_MASK);
  153. } else {
  154. return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
  155. STIH407_DAC_SOFTMUTE_MASK,
  156. 0);
  157. }
  158. }
  159. /*
  160. * SPDIF
  161. */
  162. static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
  163. unsigned int fmt)
  164. {
  165. if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
  166. dev_err(dai->component->dev,
  167. "%s: ERROR: Unsupported clocking mask 0x%x\n",
  168. __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
  169. return -EINVAL;
  170. }
  171. return 0;
  172. }
  173. /*
  174. * sti_sas_spdif_trigger:
  175. * Trigger function is used to ensure that BiPhase Formater is disabled
  176. * before CPU dai is stopped.
  177. * This is mandatory to avoid that BPF is stalled
  178. */
  179. static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
  180. struct snd_soc_dai *dai)
  181. {
  182. struct snd_soc_component *component = dai->component;
  183. switch (cmd) {
  184. case SNDRV_PCM_TRIGGER_START:
  185. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  186. return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
  187. SPDIF_BIPHASE_ENABLE_MASK,
  188. SPDIF_BIPHASE_ENABLE_MASK);
  189. case SNDRV_PCM_TRIGGER_RESUME:
  190. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  191. case SNDRV_PCM_TRIGGER_STOP:
  192. case SNDRV_PCM_TRIGGER_SUSPEND:
  193. return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
  194. SPDIF_BIPHASE_ENABLE_MASK,
  195. 0);
  196. default:
  197. return -EINVAL;
  198. }
  199. }
  200. static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
  201. {
  202. if (reg == STIH407_AUDIO_GLUE_CTRL)
  203. return true;
  204. return false;
  205. }
  206. /*
  207. * CODEC DAIS
  208. */
  209. /*
  210. * sti_sas_set_sysclk:
  211. * get MCLK input frequency to check that MCLK-FS ratio is coherent
  212. */
  213. static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
  214. unsigned int freq, int dir)
  215. {
  216. struct snd_soc_component *component = dai->component;
  217. struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
  218. if (dir == SND_SOC_CLOCK_OUT)
  219. return 0;
  220. if (clk_id != 0)
  221. return -EINVAL;
  222. switch (dai->id) {
  223. case STI_SAS_DAI_SPDIF_OUT:
  224. drvdata->spdif.mclk = freq;
  225. break;
  226. case STI_SAS_DAI_ANALOG_OUT:
  227. drvdata->dac.mclk = freq;
  228. break;
  229. }
  230. return 0;
  231. }
  232. static int sti_sas_prepare(struct snd_pcm_substream *substream,
  233. struct snd_soc_dai *dai)
  234. {
  235. struct snd_soc_component *component = dai->component;
  236. struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
  237. struct snd_pcm_runtime *runtime = substream->runtime;
  238. switch (dai->id) {
  239. case STI_SAS_DAI_SPDIF_OUT:
  240. if ((drvdata->spdif.mclk / runtime->rate) != 128) {
  241. dev_err(component->dev, "unexpected mclk-fs ratio\n");
  242. return -EINVAL;
  243. }
  244. break;
  245. case STI_SAS_DAI_ANALOG_OUT:
  246. if ((drvdata->dac.mclk / runtime->rate) != 256) {
  247. dev_err(component->dev, "unexpected mclk-fs ratio\n");
  248. return -EINVAL;
  249. }
  250. break;
  251. }
  252. return 0;
  253. }
  254. static const struct snd_soc_dai_ops stih407_dac_ops = {
  255. .set_fmt = sti_sas_dac_set_fmt,
  256. .mute_stream = stih407_sas_dac_mute,
  257. .prepare = sti_sas_prepare,
  258. .set_sysclk = sti_sas_set_sysclk,
  259. };
  260. static const struct regmap_config stih407_sas_regmap = {
  261. .reg_bits = 32,
  262. .val_bits = 32,
  263. .fast_io = true,
  264. .max_register = STIH407_AUDIO_DAC_CTRL,
  265. .reg_defaults = stih407_sas_reg_defaults,
  266. .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
  267. .volatile_reg = sti_sas_volatile_register,
  268. .cache_type = REGCACHE_RBTREE,
  269. .reg_read = sti_sas_read_reg,
  270. .reg_write = sti_sas_write_reg,
  271. };
  272. static const struct sti_sas_dev_data stih407_data = {
  273. .regmap = &stih407_sas_regmap,
  274. .dac_ops = &stih407_dac_ops,
  275. .dapm_widgets = stih407_sas_dapm_widgets,
  276. .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
  277. .dapm_routes = stih407_sas_route,
  278. .num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
  279. };
  280. static struct snd_soc_dai_driver sti_sas_dai[] = {
  281. {
  282. .name = "sas-dai-spdif-out",
  283. .id = STI_SAS_DAI_SPDIF_OUT,
  284. .playback = {
  285. .stream_name = "spdif_p",
  286. .channels_min = 2,
  287. .channels_max = 2,
  288. .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
  289. SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |
  290. SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
  291. SNDRV_PCM_RATE_192000,
  292. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  293. SNDRV_PCM_FMTBIT_S32_LE,
  294. },
  295. .ops = (struct snd_soc_dai_ops[]) {
  296. {
  297. .set_fmt = sti_sas_spdif_set_fmt,
  298. .trigger = sti_sas_spdif_trigger,
  299. .set_sysclk = sti_sas_set_sysclk,
  300. .prepare = sti_sas_prepare,
  301. }
  302. },
  303. },
  304. {
  305. .name = "sas-dai-dac",
  306. .id = STI_SAS_DAI_ANALOG_OUT,
  307. .playback = {
  308. .stream_name = "dac_p",
  309. .channels_min = 2,
  310. .channels_max = 2,
  311. .rates = SNDRV_PCM_RATE_8000_48000,
  312. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  313. SNDRV_PCM_FMTBIT_S32_LE,
  314. },
  315. },
  316. };
  317. #ifdef CONFIG_PM_SLEEP
  318. static int sti_sas_resume(struct snd_soc_component *component)
  319. {
  320. struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
  321. return sti_sas_init_sas_registers(component, drvdata);
  322. }
  323. #else
  324. #define sti_sas_resume NULL
  325. #endif
  326. static int sti_sas_component_probe(struct snd_soc_component *component)
  327. {
  328. struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
  329. return sti_sas_init_sas_registers(component, drvdata);
  330. }
  331. static struct snd_soc_component_driver sti_sas_driver = {
  332. .probe = sti_sas_component_probe,
  333. .resume = sti_sas_resume,
  334. .idle_bias_on = 1,
  335. .use_pmdown_time = 1,
  336. .endianness = 1,
  337. };
  338. static const struct of_device_id sti_sas_dev_match[] = {
  339. {
  340. .compatible = "st,stih407-sas-codec",
  341. .data = &stih407_data,
  342. },
  343. {},
  344. };
  345. MODULE_DEVICE_TABLE(of, sti_sas_dev_match);
  346. static int sti_sas_driver_probe(struct platform_device *pdev)
  347. {
  348. struct device_node *pnode = pdev->dev.of_node;
  349. struct sti_sas_data *drvdata;
  350. const struct of_device_id *of_id;
  351. /* Allocate device structure */
  352. drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data),
  353. GFP_KERNEL);
  354. if (!drvdata)
  355. return -ENOMEM;
  356. /* Populate data structure depending on compatibility */
  357. of_id = of_match_node(sti_sas_dev_match, pnode);
  358. if (!of_id->data) {
  359. dev_err(&pdev->dev, "data associated to device is missing\n");
  360. return -EINVAL;
  361. }
  362. drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data;
  363. /* Initialise device structure */
  364. drvdata->dev = &pdev->dev;
  365. /* Request the DAC & SPDIF registers memory region */
  366. drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata,
  367. drvdata->dev_data->regmap);
  368. if (IS_ERR(drvdata->dac.virt_regmap)) {
  369. dev_err(&pdev->dev, "audio registers not enabled\n");
  370. return PTR_ERR(drvdata->dac.virt_regmap);
  371. }
  372. /* Request the syscon region */
  373. drvdata->dac.regmap =
  374. syscon_regmap_lookup_by_phandle(pnode, "st,syscfg");
  375. if (IS_ERR(drvdata->dac.regmap)) {
  376. dev_err(&pdev->dev, "syscon registers not available\n");
  377. return PTR_ERR(drvdata->dac.regmap);
  378. }
  379. drvdata->spdif.regmap = drvdata->dac.regmap;
  380. sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
  381. /* Set dapms*/
  382. sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
  383. sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
  384. sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
  385. sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
  386. /* Store context */
  387. dev_set_drvdata(&pdev->dev, drvdata);
  388. return devm_snd_soc_register_component(&pdev->dev, &sti_sas_driver,
  389. sti_sas_dai,
  390. ARRAY_SIZE(sti_sas_dai));
  391. }
  392. static struct platform_driver sti_sas_platform_driver = {
  393. .driver = {
  394. .name = "sti-sas-codec",
  395. .of_match_table = sti_sas_dev_match,
  396. },
  397. .probe = sti_sas_driver_probe,
  398. };
  399. module_platform_driver(sti_sas_platform_driver);
  400. MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
  401. MODULE_AUTHOR("[email protected]");
  402. MODULE_LICENSE("GPL v2");