xref: /linux/sound/soc/fsl/fsl_mqs.c (revision 177bf8620cf4ed290ee170a6c5966adc0924b336)
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 
8 #include <linux/clk.h>
9 #include <linux/firmware/imx/sm.h>
10 #include <linux/module.h>
11 #include <linux/moduleparam.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
14 #include <linux/pm_runtime.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 
21 #define REG_MQS_CTRL		0x00
22 
23 #define MQS_EN_MASK			(0x1 << 28)
24 #define MQS_EN_SHIFT			(28)
25 #define MQS_SW_RST_MASK			(0x1 << 24)
26 #define MQS_SW_RST_SHIFT		(24)
27 #define MQS_OVERSAMPLE_MASK		(0x1 << 20)
28 #define MQS_OVERSAMPLE_SHIFT		(20)
29 #define MQS_CLK_DIV_MASK		(0xFF << 0)
30 #define MQS_CLK_DIV_SHIFT		(0)
31 
32 enum reg_type {
33 	TYPE_REG_OWN,  /* module own register space */
34 	TYPE_REG_GPR,  /* register in GPR space */
35 	TYPE_REG_SM,   /* System Manager controls the register */
36 };
37 
38 /**
39  * struct fsl_mqs_soc_data - soc specific data
40  *
41  * @type: control register space type
42  * @sm_index: index from definition in system manager
43  * @ctrl_off: control register offset
44  * @en_mask: enable bit mask
45  * @en_shift: enable bit shift
46  * @rst_mask: reset bit mask
47  * @rst_shift: reset bit shift
48  * @osr_mask: oversample bit mask
49  * @osr_shift: oversample bit shift
50  * @div_mask: clock divider mask
51  * @div_shift: clock divider bit shift
52  */
53 struct fsl_mqs_soc_data {
54 	enum reg_type type;
55 	int  sm_index;
56 	int  ctrl_off;
57 	int  en_mask;
58 	int  en_shift;
59 	int  rst_mask;
60 	int  rst_shift;
61 	int  osr_mask;
62 	int  osr_shift;
63 	int  div_mask;
64 	int  div_shift;
65 };
66 
67 /* codec private data */
68 struct fsl_mqs {
69 	struct regmap *regmap;
70 	struct clk *mclk;
71 	struct clk *ipg;
72 	const struct fsl_mqs_soc_data *soc;
73 
74 	unsigned int reg_mqs_ctrl;
75 };
76 
77 #define FSL_MQS_RATES	(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
78 #define FSL_MQS_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
79 
fsl_mqs_sm_read(void * context,unsigned int reg,unsigned int * val)80 static int fsl_mqs_sm_read(void *context, unsigned int reg, unsigned int *val)
81 {
82 	struct fsl_mqs *mqs_priv = context;
83 	int num = 1;
84 
85 	if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) &&
86 	    mqs_priv->soc->ctrl_off == reg)
87 		return scmi_imx_misc_ctrl_get(mqs_priv->soc->sm_index, &num, val);
88 
89 	return -EINVAL;
90 };
91 
fsl_mqs_sm_write(void * context,unsigned int reg,unsigned int val)92 static int fsl_mqs_sm_write(void *context, unsigned int reg, unsigned int val)
93 {
94 	struct fsl_mqs *mqs_priv = context;
95 
96 	if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) &&
97 	    mqs_priv->soc->ctrl_off == reg)
98 		return scmi_imx_misc_ctrl_set(mqs_priv->soc->sm_index, val);
99 
100 	return -EINVAL;
101 };
102 
fsl_mqs_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)103 static int fsl_mqs_hw_params(struct snd_pcm_substream *substream,
104 			     struct snd_pcm_hw_params *params,
105 			     struct snd_soc_dai *dai)
106 {
107 	struct snd_soc_component *component = dai->component;
108 	struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
109 	unsigned long mclk_rate;
110 	int div, res;
111 	int lrclk;
112 
113 	mclk_rate = clk_get_rate(mqs_priv->mclk);
114 	lrclk = params_rate(params);
115 
116 	/*
117 	 * mclk_rate / (oversample(32,64) * FS * 2 * divider ) = repeat_rate;
118 	 * if repeat_rate is 8, mqs can achieve better quality.
119 	 * oversample rate is fix to 32 currently.
120 	 */
121 	div = mclk_rate / (32 * lrclk * 2 * 8);
122 	res = mclk_rate % (32 * lrclk * 2 * 8);
123 
124 	if (res == 0 && div > 0 && div <= 256) {
125 		regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
126 				   mqs_priv->soc->div_mask,
127 				   (div - 1) << mqs_priv->soc->div_shift);
128 		regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
129 				   mqs_priv->soc->osr_mask, 0);
130 	} else {
131 		dev_err(component->dev, "can't get proper divider\n");
132 	}
133 
134 	return 0;
135 }
136 
fsl_mqs_set_dai_fmt(struct snd_soc_dai * dai,unsigned int fmt)137 static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
138 {
139 	/* Only LEFT_J & SLAVE mode is supported. */
140 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
141 	case SND_SOC_DAIFMT_LEFT_J:
142 		break;
143 	default:
144 		return -EINVAL;
145 	}
146 
147 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
148 	case SND_SOC_DAIFMT_NB_NF:
149 		break;
150 	default:
151 		return -EINVAL;
152 	}
153 
154 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
155 	case SND_SOC_DAIFMT_CBC_CFC:
156 		break;
157 	default:
158 		return -EINVAL;
159 	}
160 
161 	return 0;
162 }
163 
fsl_mqs_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)164 static int fsl_mqs_startup(struct snd_pcm_substream *substream,
165 			   struct snd_soc_dai *dai)
166 {
167 	struct snd_soc_component *component = dai->component;
168 	struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
169 
170 	regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
171 			   mqs_priv->soc->en_mask,
172 			   1 << mqs_priv->soc->en_shift);
173 	return 0;
174 }
175 
fsl_mqs_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)176 static void fsl_mqs_shutdown(struct snd_pcm_substream *substream,
177 			     struct snd_soc_dai *dai)
178 {
179 	struct snd_soc_component *component = dai->component;
180 	struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
181 
182 	regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
183 			   mqs_priv->soc->en_mask, 0);
184 }
185 
186 static const struct snd_soc_component_driver soc_codec_fsl_mqs = {
187 	.idle_bias_on = 1,
188 };
189 
190 static const struct snd_soc_dai_ops fsl_mqs_dai_ops = {
191 	.startup = fsl_mqs_startup,
192 	.shutdown = fsl_mqs_shutdown,
193 	.hw_params = fsl_mqs_hw_params,
194 	.set_fmt = fsl_mqs_set_dai_fmt,
195 };
196 
197 static struct snd_soc_dai_driver fsl_mqs_dai = {
198 	.name		= "fsl-mqs-dai",
199 	.playback	= {
200 		.stream_name	= "Playback",
201 		.channels_min	= 2,
202 		.channels_max	= 2,
203 		.rates		= FSL_MQS_RATES,
204 		.formats	= FSL_MQS_FORMATS,
205 	},
206 	.ops = &fsl_mqs_dai_ops,
207 };
208 
209 static const struct regmap_config fsl_mqs_regmap_config = {
210 	.reg_bits = 32,
211 	.reg_stride = 4,
212 	.val_bits = 32,
213 	.max_register = REG_MQS_CTRL,
214 	.cache_type = REGCACHE_NONE,
215 };
216 
217 static const struct regmap_config fsl_mqs_sm_regmap = {
218 	.reg_bits = 32,
219 	.val_bits = 32,
220 	.reg_read = fsl_mqs_sm_read,
221 	.reg_write = fsl_mqs_sm_write,
222 };
223 
fsl_mqs_probe(struct platform_device * pdev)224 static int fsl_mqs_probe(struct platform_device *pdev)
225 {
226 	struct device_node *np = pdev->dev.of_node;
227 	struct device_node *gpr_np = NULL;
228 	struct fsl_mqs *mqs_priv;
229 	void __iomem *regs;
230 	int ret;
231 
232 	mqs_priv = devm_kzalloc(&pdev->dev, sizeof(*mqs_priv), GFP_KERNEL);
233 	if (!mqs_priv)
234 		return -ENOMEM;
235 
236 	/* On i.MX6sx the MQS control register is in GPR domain
237 	 * But in i.MX8QM/i.MX8QXP the control register is moved
238 	 * to its own domain.
239 	 */
240 	mqs_priv->soc = of_device_get_match_data(&pdev->dev);
241 
242 	if (mqs_priv->soc->type == TYPE_REG_GPR) {
243 		gpr_np = of_parse_phandle(np, "gpr", 0);
244 		if (!gpr_np) {
245 			dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
246 			return -EINVAL;
247 		}
248 
249 		mqs_priv->regmap = syscon_node_to_regmap(gpr_np);
250 		of_node_put(gpr_np);
251 		if (IS_ERR(mqs_priv->regmap)) {
252 			dev_err(&pdev->dev, "failed to get gpr regmap\n");
253 			return PTR_ERR(mqs_priv->regmap);
254 		}
255 	} else if (mqs_priv->soc->type == TYPE_REG_SM) {
256 		mqs_priv->regmap = devm_regmap_init(&pdev->dev,
257 						    NULL,
258 						    mqs_priv,
259 						    &fsl_mqs_sm_regmap);
260 		if (IS_ERR(mqs_priv->regmap)) {
261 			dev_err(&pdev->dev, "failed to init regmap: %ld\n",
262 				PTR_ERR(mqs_priv->regmap));
263 			return PTR_ERR(mqs_priv->regmap);
264 		}
265 	} else {
266 		regs = devm_platform_ioremap_resource(pdev, 0);
267 		if (IS_ERR(regs))
268 			return PTR_ERR(regs);
269 
270 		mqs_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
271 							     "core",
272 							     regs,
273 							     &fsl_mqs_regmap_config);
274 		if (IS_ERR(mqs_priv->regmap)) {
275 			dev_err(&pdev->dev, "failed to init regmap: %ld\n",
276 				PTR_ERR(mqs_priv->regmap));
277 			return PTR_ERR(mqs_priv->regmap);
278 		}
279 
280 		mqs_priv->ipg = devm_clk_get(&pdev->dev, "core");
281 		if (IS_ERR(mqs_priv->ipg)) {
282 			dev_err(&pdev->dev, "failed to get the clock: %ld\n",
283 				PTR_ERR(mqs_priv->ipg));
284 			return PTR_ERR(mqs_priv->ipg);
285 		}
286 	}
287 
288 	mqs_priv->mclk = devm_clk_get(&pdev->dev, "mclk");
289 	if (IS_ERR(mqs_priv->mclk)) {
290 		dev_err(&pdev->dev, "failed to get the clock: %ld\n",
291 			PTR_ERR(mqs_priv->mclk));
292 		return PTR_ERR(mqs_priv->mclk);
293 	}
294 
295 	dev_set_drvdata(&pdev->dev, mqs_priv);
296 	pm_runtime_enable(&pdev->dev);
297 
298 	ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_fsl_mqs,
299 			&fsl_mqs_dai, 1);
300 	if (ret)
301 		return ret;
302 
303 	return 0;
304 }
305 
fsl_mqs_remove(struct platform_device * pdev)306 static void fsl_mqs_remove(struct platform_device *pdev)
307 {
308 	pm_runtime_disable(&pdev->dev);
309 }
310 
fsl_mqs_runtime_resume(struct device * dev)311 static int fsl_mqs_runtime_resume(struct device *dev)
312 {
313 	struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
314 	int ret;
315 
316 	ret = clk_prepare_enable(mqs_priv->ipg);
317 	if (ret) {
318 		dev_err(dev, "failed to enable ipg clock\n");
319 		return ret;
320 	}
321 
322 	ret = clk_prepare_enable(mqs_priv->mclk);
323 	if (ret) {
324 		dev_err(dev, "failed to enable mclk clock\n");
325 		clk_disable_unprepare(mqs_priv->ipg);
326 		return ret;
327 	}
328 
329 	regmap_write(mqs_priv->regmap, mqs_priv->soc->ctrl_off, mqs_priv->reg_mqs_ctrl);
330 	return 0;
331 }
332 
fsl_mqs_runtime_suspend(struct device * dev)333 static int fsl_mqs_runtime_suspend(struct device *dev)
334 {
335 	struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
336 
337 	regmap_read(mqs_priv->regmap, mqs_priv->soc->ctrl_off, &mqs_priv->reg_mqs_ctrl);
338 
339 	clk_disable_unprepare(mqs_priv->mclk);
340 	clk_disable_unprepare(mqs_priv->ipg);
341 
342 	return 0;
343 }
344 
345 static const struct dev_pm_ops fsl_mqs_pm_ops = {
346 	RUNTIME_PM_OPS(fsl_mqs_runtime_suspend, fsl_mqs_runtime_resume, NULL)
347 	SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
348 };
349 
350 static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = {
351 	.type = TYPE_REG_OWN,
352 	.ctrl_off = REG_MQS_CTRL,
353 	.en_mask  = MQS_EN_MASK,
354 	.en_shift = MQS_EN_SHIFT,
355 	.rst_mask = MQS_SW_RST_MASK,
356 	.rst_shift = MQS_SW_RST_SHIFT,
357 	.osr_mask = MQS_OVERSAMPLE_MASK,
358 	.osr_shift = MQS_OVERSAMPLE_SHIFT,
359 	.div_mask = MQS_CLK_DIV_MASK,
360 	.div_shift = MQS_CLK_DIV_SHIFT,
361 };
362 
363 static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = {
364 	.type = TYPE_REG_GPR,
365 	.ctrl_off = IOMUXC_GPR2,
366 	.en_mask  = IMX6SX_GPR2_MQS_EN_MASK,
367 	.en_shift = IMX6SX_GPR2_MQS_EN_SHIFT,
368 	.rst_mask = IMX6SX_GPR2_MQS_SW_RST_MASK,
369 	.rst_shift = IMX6SX_GPR2_MQS_SW_RST_SHIFT,
370 	.osr_mask  = IMX6SX_GPR2_MQS_OVERSAMPLE_MASK,
371 	.osr_shift = IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT,
372 	.div_mask  = IMX6SX_GPR2_MQS_CLK_DIV_MASK,
373 	.div_shift = IMX6SX_GPR2_MQS_CLK_DIV_SHIFT,
374 };
375 
376 static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = {
377 	.type = TYPE_REG_GPR,
378 	.ctrl_off = 0x20,
379 	.en_mask  = BIT(1),
380 	.en_shift = 1,
381 	.rst_mask = BIT(2),
382 	.rst_shift = 2,
383 	.osr_mask = BIT(3),
384 	.osr_shift = 3,
385 	.div_mask = GENMASK(15, 8),
386 	.div_shift = 8,
387 };
388 
389 static const struct fsl_mqs_soc_data fsl_mqs_imx95_aon_data = {
390 	.type = TYPE_REG_SM,
391 	.sm_index = SCMI_IMX95_CTRL_MQS1_SETTINGS,
392 	.ctrl_off = 0x88,
393 	.en_mask  = BIT(1),
394 	.en_shift = 1,
395 	.rst_mask = BIT(2),
396 	.rst_shift = 2,
397 	.osr_mask = BIT(3),
398 	.osr_shift = 3,
399 	.div_mask = GENMASK(15, 8),
400 	.div_shift = 8,
401 };
402 
403 static const struct fsl_mqs_soc_data fsl_mqs_imx95_netc_data = {
404 	.type = TYPE_REG_GPR,
405 	.ctrl_off = 0x0,
406 	.en_mask  = BIT(2),
407 	.en_shift = 2,
408 	.rst_mask = BIT(3),
409 	.rst_shift = 3,
410 	.osr_mask = BIT(4),
411 	.osr_shift = 4,
412 	.div_mask = GENMASK(16, 9),
413 	.div_shift = 9,
414 };
415 
416 static const struct fsl_mqs_soc_data fsl_mqs_imx943_aon_data = {
417 	.type = TYPE_REG_SM,
418 	.sm_index = SCMI_IMX94_CTRL_MQS1_SETTINGS,
419 	.ctrl_off = 0x88,
420 	.en_mask  = BIT(1),
421 	.en_shift = 1,
422 	.rst_mask = BIT(2),
423 	.rst_shift = 2,
424 	.osr_mask = BIT(3),
425 	.osr_shift = 3,
426 	.div_mask = GENMASK(15, 8),
427 	.div_shift = 8,
428 };
429 
430 static const struct fsl_mqs_soc_data fsl_mqs_imx943_wakeup_data = {
431 	.type = TYPE_REG_SM,
432 	.sm_index = SCMI_IMX94_CTRL_MQS2_SETTINGS,
433 	.ctrl_off = 0x10,
434 	.en_mask  = BIT(1),
435 	.en_shift = 1,
436 	.rst_mask = BIT(2),
437 	.rst_shift = 2,
438 	.osr_mask = BIT(3),
439 	.osr_shift = 3,
440 	.div_mask = GENMASK(15, 8),
441 	.div_shift = 8,
442 };
443 
444 static const struct of_device_id fsl_mqs_dt_ids[] = {
445 	{ .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data },
446 	{ .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data },
447 	{ .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data },
448 	{ .compatible = "fsl,imx95-aonmix-mqs", .data = &fsl_mqs_imx95_aon_data },
449 	{ .compatible = "fsl,imx95-netcmix-mqs", .data = &fsl_mqs_imx95_netc_data },
450 	{ .compatible = "fsl,imx943-aonmix-mqs", .data = &fsl_mqs_imx943_aon_data },
451 	{ .compatible = "fsl,imx943-wakeupmix-mqs", .data = &fsl_mqs_imx943_wakeup_data },
452 	{}
453 };
454 MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids);
455 
456 static struct platform_driver fsl_mqs_driver = {
457 	.probe		= fsl_mqs_probe,
458 	.remove		= fsl_mqs_remove,
459 	.driver		= {
460 		.name	= "fsl-mqs",
461 		.of_match_table = fsl_mqs_dt_ids,
462 		.pm = pm_ptr(&fsl_mqs_pm_ops),
463 	},
464 };
465 
466 module_platform_driver(fsl_mqs_driver);
467 
468 MODULE_AUTHOR("Shengjiu Wang <Shengjiu.Wang@nxp.com>");
469 MODULE_DESCRIPTION("MQS codec driver");
470 MODULE_LICENSE("GPL v2");
471 MODULE_ALIAS("platform:fsl-mqs");
472