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