18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* sound/soc/rockchip/rk_spdif.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * ALSA SoC Audio Layer - Rockchip I2S Controller driver 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2014 Rockchip Electronics Co. Ltd. 78c2ecf20Sopenharmony_ci * Author: Jianqun <jay.xu@rock-chips.com> 88c2ecf20Sopenharmony_ci * Copyright (c) 2015 Collabora Ltd. 98c2ecf20Sopenharmony_ci * Author: Sjoerd Simons <sjoerd.simons@collabora.co.uk> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 178c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 208c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "rockchip_spdif.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cienum rk_spdif_type { 258c2ecf20Sopenharmony_ci RK_SPDIF_RK3066, 268c2ecf20Sopenharmony_ci RK_SPDIF_RK3188, 278c2ecf20Sopenharmony_ci RK_SPDIF_RK3288, 288c2ecf20Sopenharmony_ci RK_SPDIF_RK3366, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define RK3288_GRF_SOC_CON2 0x24c 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct rk_spdif_dev { 348c2ecf20Sopenharmony_ci struct device *dev; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci struct clk *mclk; 378c2ecf20Sopenharmony_ci struct clk *hclk; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data playback_dma_data; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci struct regmap *regmap; 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic const struct of_device_id rk_spdif_match[] = { 458c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3066-spdif", 468c2ecf20Sopenharmony_ci .data = (void *)RK_SPDIF_RK3066 }, 478c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3188-spdif", 488c2ecf20Sopenharmony_ci .data = (void *)RK_SPDIF_RK3188 }, 498c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3228-spdif", 508c2ecf20Sopenharmony_ci .data = (void *)RK_SPDIF_RK3366 }, 518c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3288-spdif", 528c2ecf20Sopenharmony_ci .data = (void *)RK_SPDIF_RK3288 }, 538c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3328-spdif", 548c2ecf20Sopenharmony_ci .data = (void *)RK_SPDIF_RK3366 }, 558c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3366-spdif", 568c2ecf20Sopenharmony_ci .data = (void *)RK_SPDIF_RK3366 }, 578c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3368-spdif", 588c2ecf20Sopenharmony_ci .data = (void *)RK_SPDIF_RK3366 }, 598c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3399-spdif", 608c2ecf20Sopenharmony_ci .data = (void *)RK_SPDIF_RK3366 }, 618c2ecf20Sopenharmony_ci {}, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rk_spdif_match); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int __maybe_unused rk_spdif_runtime_suspend(struct device *dev) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct rk_spdif_dev *spdif = dev_get_drvdata(dev); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci regcache_cache_only(spdif->regmap, true); 708c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif->mclk); 718c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif->hclk); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int __maybe_unused rk_spdif_runtime_resume(struct device *dev) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct rk_spdif_dev *spdif = dev_get_drvdata(dev); 798c2ecf20Sopenharmony_ci int ret; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spdif->mclk); 828c2ecf20Sopenharmony_ci if (ret) { 838c2ecf20Sopenharmony_ci dev_err(spdif->dev, "mclk clock enable failed %d\n", ret); 848c2ecf20Sopenharmony_ci return ret; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spdif->hclk); 888c2ecf20Sopenharmony_ci if (ret) { 898c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif->mclk); 908c2ecf20Sopenharmony_ci dev_err(spdif->dev, "hclk clock enable failed %d\n", ret); 918c2ecf20Sopenharmony_ci return ret; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci regcache_cache_only(spdif->regmap, false); 958c2ecf20Sopenharmony_ci regcache_mark_dirty(spdif->regmap); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci ret = regcache_sync(spdif->regmap); 988c2ecf20Sopenharmony_ci if (ret) { 998c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif->mclk); 1008c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif->hclk); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return ret; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int rk_spdif_hw_params(struct snd_pcm_substream *substream, 1078c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 1088c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); 1118c2ecf20Sopenharmony_ci unsigned int val = SPDIF_CFGR_HALFWORD_ENABLE; 1128c2ecf20Sopenharmony_ci int srate, mclk; 1138c2ecf20Sopenharmony_ci int ret; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci srate = params_rate(params); 1168c2ecf20Sopenharmony_ci mclk = srate * 128; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci switch (params_format(params)) { 1198c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 1208c2ecf20Sopenharmony_ci val |= SPDIF_CFGR_VDW_16; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S20_3LE: 1238c2ecf20Sopenharmony_ci val |= SPDIF_CFGR_VDW_20; 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 1268c2ecf20Sopenharmony_ci val |= SPDIF_CFGR_VDW_24; 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci default: 1298c2ecf20Sopenharmony_ci return -EINVAL; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Set clock and calculate divider */ 1338c2ecf20Sopenharmony_ci ret = clk_set_rate(spdif->mclk, mclk); 1348c2ecf20Sopenharmony_ci if (ret != 0) { 1358c2ecf20Sopenharmony_ci dev_err(spdif->dev, "Failed to set module clock rate: %d\n", 1368c2ecf20Sopenharmony_ci ret); 1378c2ecf20Sopenharmony_ci return ret; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci ret = regmap_update_bits(spdif->regmap, SPDIF_CFGR, 1418c2ecf20Sopenharmony_ci SPDIF_CFGR_CLK_DIV_MASK | SPDIF_CFGR_HALFWORD_ENABLE | 1428c2ecf20Sopenharmony_ci SDPIF_CFGR_VDW_MASK, 1438c2ecf20Sopenharmony_ci val); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return ret; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic int rk_spdif_trigger(struct snd_pcm_substream *substream, 1498c2ecf20Sopenharmony_ci int cmd, struct snd_soc_dai *dai) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); 1528c2ecf20Sopenharmony_ci int ret; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci switch (cmd) { 1558c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 1568c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 1578c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1588c2ecf20Sopenharmony_ci ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR, 1598c2ecf20Sopenharmony_ci SPDIF_DMACR_TDE_ENABLE | 1608c2ecf20Sopenharmony_ci SPDIF_DMACR_TDL_MASK, 1618c2ecf20Sopenharmony_ci SPDIF_DMACR_TDE_ENABLE | 1628c2ecf20Sopenharmony_ci SPDIF_DMACR_TDL(16)); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (ret != 0) 1658c2ecf20Sopenharmony_ci return ret; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ret = regmap_update_bits(spdif->regmap, SPDIF_XFER, 1688c2ecf20Sopenharmony_ci SPDIF_XFER_TXS_START, 1698c2ecf20Sopenharmony_ci SPDIF_XFER_TXS_START); 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 1728c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 1738c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1748c2ecf20Sopenharmony_ci ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR, 1758c2ecf20Sopenharmony_ci SPDIF_DMACR_TDE_ENABLE, 1768c2ecf20Sopenharmony_ci SPDIF_DMACR_TDE_DISABLE); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (ret != 0) 1798c2ecf20Sopenharmony_ci return ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ret = regmap_update_bits(spdif->regmap, SPDIF_XFER, 1828c2ecf20Sopenharmony_ci SPDIF_XFER_TXS_START, 1838c2ecf20Sopenharmony_ci SPDIF_XFER_TXS_STOP); 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci default: 1868c2ecf20Sopenharmony_ci ret = -EINVAL; 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return ret; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int rk_spdif_dai_probe(struct snd_soc_dai *dai) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci dai->playback_dma_data = &spdif->playback_dma_data; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops rk_spdif_dai_ops = { 2038c2ecf20Sopenharmony_ci .hw_params = rk_spdif_hw_params, 2048c2ecf20Sopenharmony_ci .trigger = rk_spdif_trigger, 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver rk_spdif_dai = { 2088c2ecf20Sopenharmony_ci .probe = rk_spdif_dai_probe, 2098c2ecf20Sopenharmony_ci .playback = { 2108c2ecf20Sopenharmony_ci .stream_name = "Playback", 2118c2ecf20Sopenharmony_ci .channels_min = 2, 2128c2ecf20Sopenharmony_ci .channels_max = 2, 2138c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_32000 | 2148c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_44100 | 2158c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | 2168c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_96000 | 2178c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_192000), 2188c2ecf20Sopenharmony_ci .formats = (SNDRV_PCM_FMTBIT_S16_LE | 2198c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | 2208c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE), 2218c2ecf20Sopenharmony_ci }, 2228c2ecf20Sopenharmony_ci .ops = &rk_spdif_dai_ops, 2238c2ecf20Sopenharmony_ci}; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver rk_spdif_component = { 2268c2ecf20Sopenharmony_ci .name = "rockchip-spdif", 2278c2ecf20Sopenharmony_ci}; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic bool rk_spdif_wr_reg(struct device *dev, unsigned int reg) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci switch (reg) { 2328c2ecf20Sopenharmony_ci case SPDIF_CFGR: 2338c2ecf20Sopenharmony_ci case SPDIF_DMACR: 2348c2ecf20Sopenharmony_ci case SPDIF_INTCR: 2358c2ecf20Sopenharmony_ci case SPDIF_XFER: 2368c2ecf20Sopenharmony_ci case SPDIF_SMPDR: 2378c2ecf20Sopenharmony_ci return true; 2388c2ecf20Sopenharmony_ci default: 2398c2ecf20Sopenharmony_ci return false; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic bool rk_spdif_rd_reg(struct device *dev, unsigned int reg) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci switch (reg) { 2468c2ecf20Sopenharmony_ci case SPDIF_CFGR: 2478c2ecf20Sopenharmony_ci case SPDIF_SDBLR: 2488c2ecf20Sopenharmony_ci case SPDIF_INTCR: 2498c2ecf20Sopenharmony_ci case SPDIF_INTSR: 2508c2ecf20Sopenharmony_ci case SPDIF_XFER: 2518c2ecf20Sopenharmony_ci return true; 2528c2ecf20Sopenharmony_ci default: 2538c2ecf20Sopenharmony_ci return false; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic bool rk_spdif_volatile_reg(struct device *dev, unsigned int reg) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci switch (reg) { 2608c2ecf20Sopenharmony_ci case SPDIF_INTSR: 2618c2ecf20Sopenharmony_ci case SPDIF_SDBLR: 2628c2ecf20Sopenharmony_ci return true; 2638c2ecf20Sopenharmony_ci default: 2648c2ecf20Sopenharmony_ci return false; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic const struct regmap_config rk_spdif_regmap_config = { 2698c2ecf20Sopenharmony_ci .reg_bits = 32, 2708c2ecf20Sopenharmony_ci .reg_stride = 4, 2718c2ecf20Sopenharmony_ci .val_bits = 32, 2728c2ecf20Sopenharmony_ci .max_register = SPDIF_SMPDR, 2738c2ecf20Sopenharmony_ci .writeable_reg = rk_spdif_wr_reg, 2748c2ecf20Sopenharmony_ci .readable_reg = rk_spdif_rd_reg, 2758c2ecf20Sopenharmony_ci .volatile_reg = rk_spdif_volatile_reg, 2768c2ecf20Sopenharmony_ci .cache_type = REGCACHE_FLAT, 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int rk_spdif_probe(struct platform_device *pdev) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 2828c2ecf20Sopenharmony_ci struct rk_spdif_dev *spdif; 2838c2ecf20Sopenharmony_ci const struct of_device_id *match; 2848c2ecf20Sopenharmony_ci struct resource *res; 2858c2ecf20Sopenharmony_ci void __iomem *regs; 2868c2ecf20Sopenharmony_ci int ret; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci match = of_match_node(rk_spdif_match, np); 2898c2ecf20Sopenharmony_ci if (match->data == (void *)RK_SPDIF_RK3288) { 2908c2ecf20Sopenharmony_ci struct regmap *grf; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 2938c2ecf20Sopenharmony_ci if (IS_ERR(grf)) { 2948c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 2958c2ecf20Sopenharmony_ci "rockchip_spdif missing 'rockchip,grf' \n"); 2968c2ecf20Sopenharmony_ci return PTR_ERR(grf); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Select the 8 channel SPDIF solution on RK3288 as 3008c2ecf20Sopenharmony_ci * the 2 channel one does not appear to work 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ci regmap_write(grf, RK3288_GRF_SOC_CON2, BIT(1) << 16); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL); 3068c2ecf20Sopenharmony_ci if (!spdif) 3078c2ecf20Sopenharmony_ci return -ENOMEM; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci spdif->hclk = devm_clk_get(&pdev->dev, "hclk"); 3108c2ecf20Sopenharmony_ci if (IS_ERR(spdif->hclk)) 3118c2ecf20Sopenharmony_ci return PTR_ERR(spdif->hclk); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci spdif->mclk = devm_clk_get(&pdev->dev, "mclk"); 3148c2ecf20Sopenharmony_ci if (IS_ERR(spdif->mclk)) 3158c2ecf20Sopenharmony_ci return PTR_ERR(spdif->mclk); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3188c2ecf20Sopenharmony_ci regs = devm_ioremap_resource(&pdev->dev, res); 3198c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 3208c2ecf20Sopenharmony_ci return PTR_ERR(regs); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci spdif->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "hclk", regs, 3238c2ecf20Sopenharmony_ci &rk_spdif_regmap_config); 3248c2ecf20Sopenharmony_ci if (IS_ERR(spdif->regmap)) 3258c2ecf20Sopenharmony_ci return PTR_ERR(spdif->regmap); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci spdif->playback_dma_data.addr = res->start + SPDIF_SMPDR; 3288c2ecf20Sopenharmony_ci spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 3298c2ecf20Sopenharmony_ci spdif->playback_dma_data.maxburst = 4; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci spdif->dev = &pdev->dev; 3328c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, spdif); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 3358c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(&pdev->dev)) { 3368c2ecf20Sopenharmony_ci ret = rk_spdif_runtime_resume(&pdev->dev); 3378c2ecf20Sopenharmony_ci if (ret) 3388c2ecf20Sopenharmony_ci goto err_pm_runtime; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 3428c2ecf20Sopenharmony_ci &rk_spdif_component, 3438c2ecf20Sopenharmony_ci &rk_spdif_dai, 1); 3448c2ecf20Sopenharmony_ci if (ret) { 3458c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not register DAI\n"); 3468c2ecf20Sopenharmony_ci goto err_pm_suspend; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 3508c2ecf20Sopenharmony_ci if (ret) { 3518c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not register PCM\n"); 3528c2ecf20Sopenharmony_ci goto err_pm_suspend; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cierr_pm_suspend: 3588c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 3598c2ecf20Sopenharmony_ci rk_spdif_runtime_suspend(&pdev->dev); 3608c2ecf20Sopenharmony_cierr_pm_runtime: 3618c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return ret; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int rk_spdif_remove(struct platform_device *pdev) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 3698c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 3708c2ecf20Sopenharmony_ci rk_spdif_runtime_suspend(&pdev->dev); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic const struct dev_pm_ops rk_spdif_pm_ops = { 3768c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(rk_spdif_runtime_suspend, rk_spdif_runtime_resume, 3778c2ecf20Sopenharmony_ci NULL) 3788c2ecf20Sopenharmony_ci}; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic struct platform_driver rk_spdif_driver = { 3818c2ecf20Sopenharmony_ci .probe = rk_spdif_probe, 3828c2ecf20Sopenharmony_ci .remove = rk_spdif_remove, 3838c2ecf20Sopenharmony_ci .driver = { 3848c2ecf20Sopenharmony_ci .name = "rockchip-spdif", 3858c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(rk_spdif_match), 3868c2ecf20Sopenharmony_ci .pm = &rk_spdif_pm_ops, 3878c2ecf20Sopenharmony_ci }, 3888c2ecf20Sopenharmony_ci}; 3898c2ecf20Sopenharmony_cimodule_platform_driver(rk_spdif_driver); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:rockchip-spdif"); 3928c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ROCKCHIP SPDIF transceiver Interface"); 3938c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sjoerd Simons <sjoerd.simons@collabora.co.uk>"); 3948c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 395