1 // SPDX-License-Identifier: GPL-2.0-only 2 /* sound/soc/rockchip/rk_spdif.c 3 * 4 * ALSA SoC Audio Layer - Rockchip I2S Controller driver 5 * 6 * Copyright (c) 2014 Rockchip Electronics Co. Ltd. 7 * Author: Jianqun <jay.xu@rock-chips.com> 8 * Copyright (c) 2015 Collabora Ltd. 9 * Author: Sjoerd Simons <sjoerd.simons@collabora.co.uk> 10 */ 11 12 #include <linux/module.h> 13 #include <linux/delay.h> 14 #include <linux/clk.h> 15 #include <linux/pm_runtime.h> 16 #include <linux/mfd/syscon.h> 17 #include <linux/regmap.h> 18 #include <sound/pcm_params.h> 19 #include <sound/dmaengine_pcm.h> 20 21 #include "rockchip_spdif.h" 22 23 enum rk_spdif_type { 24 RK_SPDIF_RK3066, 25 RK_SPDIF_RK3188, 26 RK_SPDIF_RK3288, 27 RK_SPDIF_RK3366, 28 }; 29 30 #define RK3288_GRF_SOC_CON2 0x24c 31 32 struct rk_spdif_dev { 33 struct device *dev; 34 35 struct clk *mclk; 36 struct clk *hclk; 37 38 struct snd_dmaengine_dai_dma_data playback_dma_data; 39 40 struct regmap *regmap; 41 }; 42 43 static const struct of_device_id rk_spdif_match[] __maybe_unused = { 44 { .compatible = "rockchip,rk3066-spdif", 45 .data = (void *)RK_SPDIF_RK3066 }, 46 { .compatible = "rockchip,rk3188-spdif", 47 .data = (void *)RK_SPDIF_RK3188 }, 48 { .compatible = "rockchip,rk3228-spdif", 49 .data = (void *)RK_SPDIF_RK3366 }, 50 { .compatible = "rockchip,rk3288-spdif", 51 .data = (void *)RK_SPDIF_RK3288 }, 52 { .compatible = "rockchip,rk3328-spdif", 53 .data = (void *)RK_SPDIF_RK3366 }, 54 { .compatible = "rockchip,rk3366-spdif", 55 .data = (void *)RK_SPDIF_RK3366 }, 56 { .compatible = "rockchip,rk3368-spdif", 57 .data = (void *)RK_SPDIF_RK3366 }, 58 { .compatible = "rockchip,rk3399-spdif", 59 .data = (void *)RK_SPDIF_RK3366 }, 60 { .compatible = "rockchip,rk3568-spdif", 61 .data = (void *)RK_SPDIF_RK3366 }, 62 {}, 63 }; 64 MODULE_DEVICE_TABLE(of, rk_spdif_match); 65 66 static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev) 67 { 68 struct rk_spdif_dev *spdif = dev_get_drvdata(dev); 69 70 regcache_cache_only(spdif->regmap, true); 71 clk_disable_unprepare(spdif->mclk); 72 clk_disable_unprepare(spdif->hclk); 73 74 return 0; 75 } 76 77 static int __maybe_unused rk_spdif_runtime_resume(struct device *dev) 78 { 79 struct rk_spdif_dev *spdif = dev_get_drvdata(dev); 80 int ret; 81 82 ret = clk_prepare_enable(spdif->mclk); 83 if (ret) { 84 dev_err(spdif->dev, "mclk clock enable failed %d\n", ret); 85 return ret; 86 } 87 88 ret = clk_prepare_enable(spdif->hclk); 89 if (ret) { 90 clk_disable_unprepare(spdif->mclk); 91 dev_err(spdif->dev, "hclk clock enable failed %d\n", ret); 92 return ret; 93 } 94 95 regcache_cache_only(spdif->regmap, false); 96 regcache_mark_dirty(spdif->regmap); 97 98 ret = regcache_sync(spdif->regmap); 99 if (ret) { 100 clk_disable_unprepare(spdif->mclk); 101 clk_disable_unprepare(spdif->hclk); 102 } 103 104 return ret; 105 } 106 107 static int rk_spdif_hw_params(struct snd_pcm_substream *substream, 108 struct snd_pcm_hw_params *params, 109 struct snd_soc_dai *dai) 110 { 111 struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); 112 unsigned int val = SPDIF_CFGR_HALFWORD_ENABLE; 113 int srate, mclk; 114 int ret; 115 116 srate = params_rate(params); 117 mclk = srate * 128; 118 119 switch (params_format(params)) { 120 case SNDRV_PCM_FORMAT_S16_LE: 121 val |= SPDIF_CFGR_VDW_16; 122 break; 123 case SNDRV_PCM_FORMAT_S20_3LE: 124 val |= SPDIF_CFGR_VDW_20; 125 break; 126 case SNDRV_PCM_FORMAT_S24_LE: 127 val |= SPDIF_CFGR_VDW_24; 128 break; 129 default: 130 return -EINVAL; 131 } 132 133 /* Set clock and calculate divider */ 134 ret = clk_set_rate(spdif->mclk, mclk); 135 if (ret != 0) { 136 dev_err(spdif->dev, "Failed to set module clock rate: %d\n", 137 ret); 138 return ret; 139 } 140 141 ret = regmap_update_bits(spdif->regmap, SPDIF_CFGR, 142 SPDIF_CFGR_CLK_DIV_MASK | 143 SPDIF_CFGR_HALFWORD_ENABLE | 144 SDPIF_CFGR_VDW_MASK, val); 145 146 return ret; 147 } 148 149 static int rk_spdif_trigger(struct snd_pcm_substream *substream, 150 int cmd, struct snd_soc_dai *dai) 151 { 152 struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); 153 int ret; 154 155 switch (cmd) { 156 case SNDRV_PCM_TRIGGER_START: 157 case SNDRV_PCM_TRIGGER_RESUME: 158 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 159 ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR, 160 SPDIF_DMACR_TDE_ENABLE | 161 SPDIF_DMACR_TDL_MASK, 162 SPDIF_DMACR_TDE_ENABLE | 163 SPDIF_DMACR_TDL(16)); 164 165 if (ret != 0) 166 return ret; 167 168 ret = regmap_update_bits(spdif->regmap, SPDIF_XFER, 169 SPDIF_XFER_TXS_START, 170 SPDIF_XFER_TXS_START); 171 break; 172 case SNDRV_PCM_TRIGGER_SUSPEND: 173 case SNDRV_PCM_TRIGGER_STOP: 174 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 175 ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR, 176 SPDIF_DMACR_TDE_ENABLE, 177 SPDIF_DMACR_TDE_DISABLE); 178 179 if (ret != 0) 180 return ret; 181 182 ret = regmap_update_bits(spdif->regmap, SPDIF_XFER, 183 SPDIF_XFER_TXS_START, 184 SPDIF_XFER_TXS_STOP); 185 break; 186 default: 187 ret = -EINVAL; 188 break; 189 } 190 191 return ret; 192 } 193 194 static int rk_spdif_dai_probe(struct snd_soc_dai *dai) 195 { 196 struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); 197 198 snd_soc_dai_dma_data_set_playback(dai, &spdif->playback_dma_data); 199 200 return 0; 201 } 202 203 static const struct snd_soc_dai_ops rk_spdif_dai_ops = { 204 .probe = rk_spdif_dai_probe, 205 .hw_params = rk_spdif_hw_params, 206 .trigger = rk_spdif_trigger, 207 }; 208 209 static struct snd_soc_dai_driver rk_spdif_dai = { 210 .playback = { 211 .stream_name = "Playback", 212 .channels_min = 2, 213 .channels_max = 2, 214 .rates = (SNDRV_PCM_RATE_32000 | 215 SNDRV_PCM_RATE_44100 | 216 SNDRV_PCM_RATE_48000 | 217 SNDRV_PCM_RATE_96000 | 218 SNDRV_PCM_RATE_192000), 219 .formats = (SNDRV_PCM_FMTBIT_S16_LE | 220 SNDRV_PCM_FMTBIT_S20_3LE | 221 SNDRV_PCM_FMTBIT_S24_LE), 222 }, 223 .ops = &rk_spdif_dai_ops, 224 }; 225 226 static const struct snd_soc_component_driver rk_spdif_component = { 227 .name = "rockchip-spdif", 228 .legacy_dai_naming = 1, 229 }; 230 231 static bool rk_spdif_wr_reg(struct device *dev, unsigned int reg) 232 { 233 switch (reg) { 234 case SPDIF_CFGR: 235 case SPDIF_DMACR: 236 case SPDIF_INTCR: 237 case SPDIF_XFER: 238 case SPDIF_SMPDR: 239 return true; 240 default: 241 return false; 242 } 243 } 244 245 static bool rk_spdif_rd_reg(struct device *dev, unsigned int reg) 246 { 247 switch (reg) { 248 case SPDIF_CFGR: 249 case SPDIF_SDBLR: 250 case SPDIF_INTCR: 251 case SPDIF_INTSR: 252 case SPDIF_XFER: 253 case SPDIF_SMPDR: 254 return true; 255 default: 256 return false; 257 } 258 } 259 260 static bool rk_spdif_volatile_reg(struct device *dev, unsigned int reg) 261 { 262 switch (reg) { 263 case SPDIF_INTSR: 264 case SPDIF_SDBLR: 265 case SPDIF_SMPDR: 266 return true; 267 default: 268 return false; 269 } 270 } 271 272 static const struct regmap_config rk_spdif_regmap_config = { 273 .reg_bits = 32, 274 .reg_stride = 4, 275 .val_bits = 32, 276 .max_register = SPDIF_SMPDR, 277 .writeable_reg = rk_spdif_wr_reg, 278 .readable_reg = rk_spdif_rd_reg, 279 .volatile_reg = rk_spdif_volatile_reg, 280 .cache_type = REGCACHE_FLAT, 281 }; 282 283 static int rk_spdif_probe(struct platform_device *pdev) 284 { 285 struct device_node *np = pdev->dev.of_node; 286 struct rk_spdif_dev *spdif; 287 const struct of_device_id *match; 288 struct resource *res; 289 void __iomem *regs; 290 int ret; 291 292 match = of_match_node(rk_spdif_match, np); 293 if (match->data == (void *)RK_SPDIF_RK3288) { 294 struct regmap *grf; 295 296 grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 297 if (IS_ERR(grf)) { 298 dev_err(&pdev->dev, 299 "rockchip_spdif missing 'rockchip,grf'\n"); 300 return PTR_ERR(grf); 301 } 302 303 /* Select the 8 channel SPDIF solution on RK3288 as 304 * the 2 channel one does not appear to work 305 */ 306 regmap_write(grf, RK3288_GRF_SOC_CON2, BIT(1) << 16); 307 } 308 309 spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL); 310 if (!spdif) 311 return -ENOMEM; 312 313 spdif->hclk = devm_clk_get(&pdev->dev, "hclk"); 314 if (IS_ERR(spdif->hclk)) 315 return PTR_ERR(spdif->hclk); 316 317 spdif->mclk = devm_clk_get(&pdev->dev, "mclk"); 318 if (IS_ERR(spdif->mclk)) 319 return PTR_ERR(spdif->mclk); 320 321 regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 322 if (IS_ERR(regs)) 323 return PTR_ERR(regs); 324 325 spdif->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "hclk", regs, 326 &rk_spdif_regmap_config); 327 if (IS_ERR(spdif->regmap)) 328 return PTR_ERR(spdif->regmap); 329 330 spdif->playback_dma_data.addr = res->start + SPDIF_SMPDR; 331 spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 332 spdif->playback_dma_data.maxburst = 4; 333 334 spdif->dev = &pdev->dev; 335 dev_set_drvdata(&pdev->dev, spdif); 336 337 pm_runtime_enable(&pdev->dev); 338 if (!pm_runtime_enabled(&pdev->dev)) { 339 ret = rk_spdif_runtime_resume(&pdev->dev); 340 if (ret) 341 goto err_pm_runtime; 342 } 343 344 ret = devm_snd_soc_register_component(&pdev->dev, 345 &rk_spdif_component, 346 &rk_spdif_dai, 1); 347 if (ret) { 348 dev_err(&pdev->dev, "Could not register DAI\n"); 349 goto err_pm_suspend; 350 } 351 352 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 353 if (ret) { 354 dev_err(&pdev->dev, "Could not register PCM\n"); 355 goto err_pm_suspend; 356 } 357 358 return 0; 359 360 err_pm_suspend: 361 if (!pm_runtime_status_suspended(&pdev->dev)) 362 rk_spdif_runtime_suspend(&pdev->dev); 363 err_pm_runtime: 364 pm_runtime_disable(&pdev->dev); 365 366 return ret; 367 } 368 369 static void rk_spdif_remove(struct platform_device *pdev) 370 { 371 pm_runtime_disable(&pdev->dev); 372 if (!pm_runtime_status_suspended(&pdev->dev)) 373 rk_spdif_runtime_suspend(&pdev->dev); 374 } 375 376 static const struct dev_pm_ops rk_spdif_pm_ops = { 377 SET_RUNTIME_PM_OPS(rk_spdif_runtime_suspend, rk_spdif_runtime_resume, 378 NULL) 379 }; 380 381 static struct platform_driver rk_spdif_driver = { 382 .probe = rk_spdif_probe, 383 .remove_new = rk_spdif_remove, 384 .driver = { 385 .name = "rockchip-spdif", 386 .of_match_table = of_match_ptr(rk_spdif_match), 387 .pm = &rk_spdif_pm_ops, 388 }, 389 }; 390 module_platform_driver(rk_spdif_driver); 391 392 MODULE_ALIAS("platform:rockchip-spdif"); 393 MODULE_DESCRIPTION("ROCKCHIP SPDIF transceiver Interface"); 394 MODULE_AUTHOR("Sjoerd Simons <sjoerd.simons@collabora.co.uk>"); 395 MODULE_LICENSE("GPL v2"); 396