fsl_mqs.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // ALSA SoC IMX MQS driver
  4. //
  5. // Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
  6. // Copyright 2019 NXP
  7. #include <linux/clk.h>
  8. #include <linux/module.h>
  9. #include <linux/moduleparam.h>
  10. #include <linux/mfd/syscon.h>
  11. #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
  12. #include <linux/of_device.h>
  13. #include <linux/pm_runtime.h>
  14. #include <linux/of.h>
  15. #include <linux/pm.h>
  16. #include <linux/slab.h>
  17. #include <sound/soc.h>
  18. #include <sound/pcm.h>
  19. #include <sound/initval.h>
  20. #define REG_MQS_CTRL 0x00
  21. #define MQS_EN_MASK (0x1 << 28)
  22. #define MQS_EN_SHIFT (28)
  23. #define MQS_SW_RST_MASK (0x1 << 24)
  24. #define MQS_SW_RST_SHIFT (24)
  25. #define MQS_OVERSAMPLE_MASK (0x1 << 20)
  26. #define MQS_OVERSAMPLE_SHIFT (20)
  27. #define MQS_CLK_DIV_MASK (0xFF << 0)
  28. #define MQS_CLK_DIV_SHIFT (0)
  29. /**
  30. * struct fsl_mqs_soc_data - soc specific data
  31. *
  32. * @use_gpr: control register is in General Purpose Register group
  33. * @ctrl_off: control register offset
  34. * @en_mask: enable bit mask
  35. * @en_shift: enable bit shift
  36. * @rst_mask: reset bit mask
  37. * @rst_shift: reset bit shift
  38. * @osr_mask: oversample bit mask
  39. * @osr_shift: oversample bit shift
  40. * @div_mask: clock divider mask
  41. * @div_shift: clock divider bit shift
  42. */
  43. struct fsl_mqs_soc_data {
  44. bool use_gpr;
  45. int ctrl_off;
  46. int en_mask;
  47. int en_shift;
  48. int rst_mask;
  49. int rst_shift;
  50. int osr_mask;
  51. int osr_shift;
  52. int div_mask;
  53. int div_shift;
  54. };
  55. /* codec private data */
  56. struct fsl_mqs {
  57. struct regmap *regmap;
  58. struct clk *mclk;
  59. struct clk *ipg;
  60. const struct fsl_mqs_soc_data *soc;
  61. unsigned int reg_mqs_ctrl;
  62. };
  63. #define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
  64. #define FSL_MQS_FORMATS SNDRV_PCM_FMTBIT_S16_LE
  65. static int fsl_mqs_hw_params(struct snd_pcm_substream *substream,
  66. struct snd_pcm_hw_params *params,
  67. struct snd_soc_dai *dai)
  68. {
  69. struct snd_soc_component *component = dai->component;
  70. struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
  71. unsigned long mclk_rate;
  72. int div, res;
  73. int lrclk;
  74. mclk_rate = clk_get_rate(mqs_priv->mclk);
  75. lrclk = params_rate(params);
  76. /*
  77. * mclk_rate / (oversample(32,64) * FS * 2 * divider ) = repeat_rate;
  78. * if repeat_rate is 8, mqs can achieve better quality.
  79. * oversample rate is fix to 32 currently.
  80. */
  81. div = mclk_rate / (32 * lrclk * 2 * 8);
  82. res = mclk_rate % (32 * lrclk * 2 * 8);
  83. if (res == 0 && div > 0 && div <= 256) {
  84. regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
  85. mqs_priv->soc->div_mask,
  86. (div - 1) << mqs_priv->soc->div_shift);
  87. regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
  88. mqs_priv->soc->osr_mask, 0);
  89. } else {
  90. dev_err(component->dev, "can't get proper divider\n");
  91. }
  92. return 0;
  93. }
  94. static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  95. {
  96. /* Only LEFT_J & SLAVE mode is supported. */
  97. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  98. case SND_SOC_DAIFMT_LEFT_J:
  99. break;
  100. default:
  101. return -EINVAL;
  102. }
  103. switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
  104. case SND_SOC_DAIFMT_NB_NF:
  105. break;
  106. default:
  107. return -EINVAL;
  108. }
  109. switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
  110. case SND_SOC_DAIFMT_CBC_CFC:
  111. break;
  112. default:
  113. return -EINVAL;
  114. }
  115. return 0;
  116. }
  117. static int fsl_mqs_startup(struct snd_pcm_substream *substream,
  118. struct snd_soc_dai *dai)
  119. {
  120. struct snd_soc_component *component = dai->component;
  121. struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
  122. regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
  123. mqs_priv->soc->en_mask,
  124. 1 << mqs_priv->soc->en_shift);
  125. return 0;
  126. }
  127. static void fsl_mqs_shutdown(struct snd_pcm_substream *substream,
  128. struct snd_soc_dai *dai)
  129. {
  130. struct snd_soc_component *component = dai->component;
  131. struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
  132. regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
  133. mqs_priv->soc->en_mask, 0);
  134. }
  135. static const struct snd_soc_component_driver soc_codec_fsl_mqs = {
  136. .idle_bias_on = 1,
  137. };
  138. static const struct snd_soc_dai_ops fsl_mqs_dai_ops = {
  139. .startup = fsl_mqs_startup,
  140. .shutdown = fsl_mqs_shutdown,
  141. .hw_params = fsl_mqs_hw_params,
  142. .set_fmt = fsl_mqs_set_dai_fmt,
  143. };
  144. static struct snd_soc_dai_driver fsl_mqs_dai = {
  145. .name = "fsl-mqs-dai",
  146. .playback = {
  147. .stream_name = "Playback",
  148. .channels_min = 2,
  149. .channels_max = 2,
  150. .rates = FSL_MQS_RATES,
  151. .formats = FSL_MQS_FORMATS,
  152. },
  153. .ops = &fsl_mqs_dai_ops,
  154. };
  155. static const struct regmap_config fsl_mqs_regmap_config = {
  156. .reg_bits = 32,
  157. .reg_stride = 4,
  158. .val_bits = 32,
  159. .max_register = REG_MQS_CTRL,
  160. .cache_type = REGCACHE_NONE,
  161. };
  162. static int fsl_mqs_probe(struct platform_device *pdev)
  163. {
  164. struct device_node *np = pdev->dev.of_node;
  165. struct device_node *gpr_np = NULL;
  166. struct fsl_mqs *mqs_priv;
  167. void __iomem *regs;
  168. int ret;
  169. mqs_priv = devm_kzalloc(&pdev->dev, sizeof(*mqs_priv), GFP_KERNEL);
  170. if (!mqs_priv)
  171. return -ENOMEM;
  172. /* On i.MX6sx the MQS control register is in GPR domain
  173. * But in i.MX8QM/i.MX8QXP the control register is moved
  174. * to its own domain.
  175. */
  176. mqs_priv->soc = of_device_get_match_data(&pdev->dev);
  177. if (mqs_priv->soc->use_gpr) {
  178. gpr_np = of_parse_phandle(np, "gpr", 0);
  179. if (!gpr_np) {
  180. dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
  181. return -EINVAL;
  182. }
  183. mqs_priv->regmap = syscon_node_to_regmap(gpr_np);
  184. of_node_put(gpr_np);
  185. if (IS_ERR(mqs_priv->regmap)) {
  186. dev_err(&pdev->dev, "failed to get gpr regmap\n");
  187. return PTR_ERR(mqs_priv->regmap);
  188. }
  189. } else {
  190. regs = devm_platform_ioremap_resource(pdev, 0);
  191. if (IS_ERR(regs))
  192. return PTR_ERR(regs);
  193. mqs_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
  194. "core",
  195. regs,
  196. &fsl_mqs_regmap_config);
  197. if (IS_ERR(mqs_priv->regmap)) {
  198. dev_err(&pdev->dev, "failed to init regmap: %ld\n",
  199. PTR_ERR(mqs_priv->regmap));
  200. return PTR_ERR(mqs_priv->regmap);
  201. }
  202. mqs_priv->ipg = devm_clk_get(&pdev->dev, "core");
  203. if (IS_ERR(mqs_priv->ipg)) {
  204. dev_err(&pdev->dev, "failed to get the clock: %ld\n",
  205. PTR_ERR(mqs_priv->ipg));
  206. return PTR_ERR(mqs_priv->ipg);
  207. }
  208. }
  209. mqs_priv->mclk = devm_clk_get(&pdev->dev, "mclk");
  210. if (IS_ERR(mqs_priv->mclk)) {
  211. dev_err(&pdev->dev, "failed to get the clock: %ld\n",
  212. PTR_ERR(mqs_priv->mclk));
  213. return PTR_ERR(mqs_priv->mclk);
  214. }
  215. dev_set_drvdata(&pdev->dev, mqs_priv);
  216. pm_runtime_enable(&pdev->dev);
  217. ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_fsl_mqs,
  218. &fsl_mqs_dai, 1);
  219. if (ret)
  220. return ret;
  221. return 0;
  222. }
  223. static int fsl_mqs_remove(struct platform_device *pdev)
  224. {
  225. pm_runtime_disable(&pdev->dev);
  226. return 0;
  227. }
  228. #ifdef CONFIG_PM
  229. static int fsl_mqs_runtime_resume(struct device *dev)
  230. {
  231. struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
  232. int ret;
  233. ret = clk_prepare_enable(mqs_priv->ipg);
  234. if (ret) {
  235. dev_err(dev, "failed to enable ipg clock\n");
  236. return ret;
  237. }
  238. ret = clk_prepare_enable(mqs_priv->mclk);
  239. if (ret) {
  240. dev_err(dev, "failed to enable mclk clock\n");
  241. clk_disable_unprepare(mqs_priv->ipg);
  242. return ret;
  243. }
  244. regmap_write(mqs_priv->regmap, mqs_priv->soc->ctrl_off, mqs_priv->reg_mqs_ctrl);
  245. return 0;
  246. }
  247. static int fsl_mqs_runtime_suspend(struct device *dev)
  248. {
  249. struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
  250. regmap_read(mqs_priv->regmap, mqs_priv->soc->ctrl_off, &mqs_priv->reg_mqs_ctrl);
  251. clk_disable_unprepare(mqs_priv->mclk);
  252. clk_disable_unprepare(mqs_priv->ipg);
  253. return 0;
  254. }
  255. #endif
  256. static const struct dev_pm_ops fsl_mqs_pm_ops = {
  257. SET_RUNTIME_PM_OPS(fsl_mqs_runtime_suspend,
  258. fsl_mqs_runtime_resume,
  259. NULL)
  260. SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
  261. pm_runtime_force_resume)
  262. };
  263. static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = {
  264. .use_gpr = false,
  265. .ctrl_off = REG_MQS_CTRL,
  266. .en_mask = MQS_EN_MASK,
  267. .en_shift = MQS_EN_SHIFT,
  268. .rst_mask = MQS_SW_RST_MASK,
  269. .rst_shift = MQS_SW_RST_SHIFT,
  270. .osr_mask = MQS_OVERSAMPLE_MASK,
  271. .osr_shift = MQS_OVERSAMPLE_SHIFT,
  272. .div_mask = MQS_CLK_DIV_MASK,
  273. .div_shift = MQS_CLK_DIV_SHIFT,
  274. };
  275. static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = {
  276. .use_gpr = true,
  277. .ctrl_off = IOMUXC_GPR2,
  278. .en_mask = IMX6SX_GPR2_MQS_EN_MASK,
  279. .en_shift = IMX6SX_GPR2_MQS_EN_SHIFT,
  280. .rst_mask = IMX6SX_GPR2_MQS_SW_RST_MASK,
  281. .rst_shift = IMX6SX_GPR2_MQS_SW_RST_SHIFT,
  282. .osr_mask = IMX6SX_GPR2_MQS_OVERSAMPLE_MASK,
  283. .osr_shift = IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT,
  284. .div_mask = IMX6SX_GPR2_MQS_CLK_DIV_MASK,
  285. .div_shift = IMX6SX_GPR2_MQS_CLK_DIV_SHIFT,
  286. };
  287. static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = {
  288. .use_gpr = true,
  289. .ctrl_off = 0x20,
  290. .en_mask = BIT(1),
  291. .en_shift = 1,
  292. .rst_mask = BIT(2),
  293. .rst_shift = 2,
  294. .osr_mask = BIT(3),
  295. .osr_shift = 3,
  296. .div_mask = GENMASK(15, 8),
  297. .div_shift = 8,
  298. };
  299. static const struct of_device_id fsl_mqs_dt_ids[] = {
  300. { .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data },
  301. { .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data },
  302. { .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data },
  303. {}
  304. };
  305. MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids);
  306. static struct platform_driver fsl_mqs_driver = {
  307. .probe = fsl_mqs_probe,
  308. .remove = fsl_mqs_remove,
  309. .driver = {
  310. .name = "fsl-mqs",
  311. .of_match_table = fsl_mqs_dt_ids,
  312. .pm = &fsl_mqs_pm_ops,
  313. },
  314. };
  315. module_platform_driver(fsl_mqs_driver);
  316. MODULE_AUTHOR("Shengjiu Wang <[email protected]>");
  317. MODULE_DESCRIPTION("MQS codec driver");
  318. MODULE_LICENSE("GPL v2");
  319. MODULE_ALIAS("platform:fsl-mqs");