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 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 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 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 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 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 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 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 306 static void fsl_mqs_remove(struct platform_device *pdev) 307 { 308 pm_runtime_disable(&pdev->dev); 309 } 310 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 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