18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* sound/soc/rockchip/rockchip_i2s.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 */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 148c2ecf20Sopenharmony_ci#include <linux/of_device.h> 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 178c2ecf20Sopenharmony_ci#include <linux/regmap.h> 188c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 198c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "rockchip_i2s.h" 228c2ecf20Sopenharmony_ci#include "rockchip_pcm.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define DRV_NAME "rockchip-i2s" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct rk_i2s_pins { 278c2ecf20Sopenharmony_ci u32 reg_offset; 288c2ecf20Sopenharmony_ci u32 shift; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct rk_i2s_dev { 328c2ecf20Sopenharmony_ci struct device *dev; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci struct clk *hclk; 358c2ecf20Sopenharmony_ci struct clk *mclk; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data capture_dma_data; 388c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data playback_dma_data; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci struct regmap *regmap; 418c2ecf20Sopenharmony_ci struct regmap *grf; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * Used to indicate the tx/rx status. 458c2ecf20Sopenharmony_ci * I2S controller hopes to start the tx and rx together, 468c2ecf20Sopenharmony_ci * also to stop them when they are both try to stop. 478c2ecf20Sopenharmony_ci*/ 488c2ecf20Sopenharmony_ci bool tx_start; 498c2ecf20Sopenharmony_ci bool rx_start; 508c2ecf20Sopenharmony_ci bool is_master_mode; 518c2ecf20Sopenharmony_ci const struct rk_i2s_pins *pins; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int i2s_runtime_suspend(struct device *dev) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct rk_i2s_dev *i2s = dev_get_drvdata(dev); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci regcache_cache_only(i2s->regmap, true); 598c2ecf20Sopenharmony_ci clk_disable_unprepare(i2s->mclk); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int i2s_runtime_resume(struct device *dev) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct rk_i2s_dev *i2s = dev_get_drvdata(dev); 678c2ecf20Sopenharmony_ci int ret; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci ret = clk_prepare_enable(i2s->mclk); 708c2ecf20Sopenharmony_ci if (ret) { 718c2ecf20Sopenharmony_ci dev_err(i2s->dev, "clock enable failed %d\n", ret); 728c2ecf20Sopenharmony_ci return ret; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci regcache_cache_only(i2s->regmap, false); 768c2ecf20Sopenharmony_ci regcache_mark_dirty(i2s->regmap); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ret = regcache_sync(i2s->regmap); 798c2ecf20Sopenharmony_ci if (ret) 808c2ecf20Sopenharmony_ci clk_disable_unprepare(i2s->mclk); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return ret; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci return snd_soc_dai_get_drvdata(dai); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci unsigned int val = 0; 938c2ecf20Sopenharmony_ci int retry = 10; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (on) { 968c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_DMACR, 978c2ecf20Sopenharmony_ci I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_XFER, 1008c2ecf20Sopenharmony_ci I2S_XFER_TXS_START | I2S_XFER_RXS_START, 1018c2ecf20Sopenharmony_ci I2S_XFER_TXS_START | I2S_XFER_RXS_START); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci i2s->tx_start = true; 1048c2ecf20Sopenharmony_ci } else { 1058c2ecf20Sopenharmony_ci i2s->tx_start = false; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_DMACR, 1088c2ecf20Sopenharmony_ci I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (!i2s->rx_start) { 1118c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_XFER, 1128c2ecf20Sopenharmony_ci I2S_XFER_TXS_START | 1138c2ecf20Sopenharmony_ci I2S_XFER_RXS_START, 1148c2ecf20Sopenharmony_ci I2S_XFER_TXS_STOP | 1158c2ecf20Sopenharmony_ci I2S_XFER_RXS_STOP); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci udelay(150); 1188c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_CLR, 1198c2ecf20Sopenharmony_ci I2S_CLR_TXC | I2S_CLR_RXC, 1208c2ecf20Sopenharmony_ci I2S_CLR_TXC | I2S_CLR_RXC); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci regmap_read(i2s->regmap, I2S_CLR, &val); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Should wait for clear operation to finish */ 1258c2ecf20Sopenharmony_ci while (val) { 1268c2ecf20Sopenharmony_ci regmap_read(i2s->regmap, I2S_CLR, &val); 1278c2ecf20Sopenharmony_ci retry--; 1288c2ecf20Sopenharmony_ci if (!retry) { 1298c2ecf20Sopenharmony_ci dev_warn(i2s->dev, "fail to clear\n"); 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci unsigned int val = 0; 1408c2ecf20Sopenharmony_ci int retry = 10; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (on) { 1438c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_DMACR, 1448c2ecf20Sopenharmony_ci I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_XFER, 1478c2ecf20Sopenharmony_ci I2S_XFER_TXS_START | I2S_XFER_RXS_START, 1488c2ecf20Sopenharmony_ci I2S_XFER_TXS_START | I2S_XFER_RXS_START); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci i2s->rx_start = true; 1518c2ecf20Sopenharmony_ci } else { 1528c2ecf20Sopenharmony_ci i2s->rx_start = false; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_DMACR, 1558c2ecf20Sopenharmony_ci I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (!i2s->tx_start) { 1588c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_XFER, 1598c2ecf20Sopenharmony_ci I2S_XFER_TXS_START | 1608c2ecf20Sopenharmony_ci I2S_XFER_RXS_START, 1618c2ecf20Sopenharmony_ci I2S_XFER_TXS_STOP | 1628c2ecf20Sopenharmony_ci I2S_XFER_RXS_STOP); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci udelay(150); 1658c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_CLR, 1668c2ecf20Sopenharmony_ci I2S_CLR_TXC | I2S_CLR_RXC, 1678c2ecf20Sopenharmony_ci I2S_CLR_TXC | I2S_CLR_RXC); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci regmap_read(i2s->regmap, I2S_CLR, &val); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Should wait for clear operation to finish */ 1728c2ecf20Sopenharmony_ci while (val) { 1738c2ecf20Sopenharmony_ci regmap_read(i2s->regmap, I2S_CLR, &val); 1748c2ecf20Sopenharmony_ci retry--; 1758c2ecf20Sopenharmony_ci if (!retry) { 1768c2ecf20Sopenharmony_ci dev_warn(i2s->dev, "fail to clear\n"); 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, 1858c2ecf20Sopenharmony_ci unsigned int fmt) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct rk_i2s_dev *i2s = to_info(cpu_dai); 1888c2ecf20Sopenharmony_ci unsigned int mask = 0, val = 0; 1898c2ecf20Sopenharmony_ci int ret = 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci pm_runtime_get_sync(cpu_dai->dev); 1928c2ecf20Sopenharmony_ci mask = I2S_CKR_MSS_MASK; 1938c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 1948c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 1958c2ecf20Sopenharmony_ci /* Set source clock in Master mode */ 1968c2ecf20Sopenharmony_ci val = I2S_CKR_MSS_MASTER; 1978c2ecf20Sopenharmony_ci i2s->is_master_mode = true; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 2008c2ecf20Sopenharmony_ci val = I2S_CKR_MSS_SLAVE; 2018c2ecf20Sopenharmony_ci i2s->is_master_mode = false; 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci default: 2048c2ecf20Sopenharmony_ci ret = -EINVAL; 2058c2ecf20Sopenharmony_ci goto err_pm_put; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_CKR, mask, val); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci mask = I2S_CKR_CKP_MASK; 2118c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 2128c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 2138c2ecf20Sopenharmony_ci val = I2S_CKR_CKP_NEG; 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 2168c2ecf20Sopenharmony_ci val = I2S_CKR_CKP_POS; 2178c2ecf20Sopenharmony_ci break; 2188c2ecf20Sopenharmony_ci default: 2198c2ecf20Sopenharmony_ci ret = -EINVAL; 2208c2ecf20Sopenharmony_ci goto err_pm_put; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_CKR, mask, val); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci mask = I2S_TXCR_IBM_MASK | I2S_TXCR_TFS_MASK | I2S_TXCR_PBM_MASK; 2268c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 2278c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 2288c2ecf20Sopenharmony_ci val = I2S_TXCR_IBM_RSJM; 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 2318c2ecf20Sopenharmony_ci val = I2S_TXCR_IBM_LSJM; 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 2348c2ecf20Sopenharmony_ci val = I2S_TXCR_IBM_NORMAL; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: /* PCM delay 1 bit mode */ 2378c2ecf20Sopenharmony_ci val = I2S_TXCR_TFS_PCM | I2S_TXCR_PBM_MODE(1); 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: /* PCM no delay mode */ 2408c2ecf20Sopenharmony_ci val = I2S_TXCR_TFS_PCM; 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci default: 2438c2ecf20Sopenharmony_ci ret = -EINVAL; 2448c2ecf20Sopenharmony_ci goto err_pm_put; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_TXCR, mask, val); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci mask = I2S_RXCR_IBM_MASK | I2S_RXCR_TFS_MASK | I2S_RXCR_PBM_MASK; 2508c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 2518c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 2528c2ecf20Sopenharmony_ci val = I2S_RXCR_IBM_RSJM; 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 2558c2ecf20Sopenharmony_ci val = I2S_RXCR_IBM_LSJM; 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 2588c2ecf20Sopenharmony_ci val = I2S_RXCR_IBM_NORMAL; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: /* PCM delay 1 bit mode */ 2618c2ecf20Sopenharmony_ci val = I2S_RXCR_TFS_PCM | I2S_RXCR_PBM_MODE(1); 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: /* PCM no delay mode */ 2648c2ecf20Sopenharmony_ci val = I2S_RXCR_TFS_PCM; 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci default: 2678c2ecf20Sopenharmony_ci ret = -EINVAL; 2688c2ecf20Sopenharmony_ci goto err_pm_put; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_RXCR, mask, val); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cierr_pm_put: 2748c2ecf20Sopenharmony_ci pm_runtime_put(cpu_dai->dev); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return ret; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, 2808c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 2818c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct rk_i2s_dev *i2s = to_info(dai); 2848c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2858c2ecf20Sopenharmony_ci unsigned int val = 0; 2868c2ecf20Sopenharmony_ci unsigned int mclk_rate, bclk_rate, div_bclk, div_lrck; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (i2s->is_master_mode) { 2898c2ecf20Sopenharmony_ci mclk_rate = clk_get_rate(i2s->mclk); 2908c2ecf20Sopenharmony_ci bclk_rate = 2 * 32 * params_rate(params); 2918c2ecf20Sopenharmony_ci if (bclk_rate == 0 || mclk_rate % bclk_rate) 2928c2ecf20Sopenharmony_ci return -EINVAL; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci div_bclk = mclk_rate / bclk_rate; 2958c2ecf20Sopenharmony_ci div_lrck = bclk_rate / params_rate(params); 2968c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_CKR, 2978c2ecf20Sopenharmony_ci I2S_CKR_MDIV_MASK, 2988c2ecf20Sopenharmony_ci I2S_CKR_MDIV(div_bclk)); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_CKR, 3018c2ecf20Sopenharmony_ci I2S_CKR_TSD_MASK | 3028c2ecf20Sopenharmony_ci I2S_CKR_RSD_MASK, 3038c2ecf20Sopenharmony_ci I2S_CKR_TSD(div_lrck) | 3048c2ecf20Sopenharmony_ci I2S_CKR_RSD(div_lrck)); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci switch (params_format(params)) { 3088c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S8: 3098c2ecf20Sopenharmony_ci val |= I2S_TXCR_VDW(8); 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 3128c2ecf20Sopenharmony_ci val |= I2S_TXCR_VDW(16); 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S20_3LE: 3158c2ecf20Sopenharmony_ci val |= I2S_TXCR_VDW(20); 3168c2ecf20Sopenharmony_ci break; 3178c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 3188c2ecf20Sopenharmony_ci val |= I2S_TXCR_VDW(24); 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 3218c2ecf20Sopenharmony_ci val |= I2S_TXCR_VDW(32); 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci default: 3248c2ecf20Sopenharmony_ci return -EINVAL; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci switch (params_channels(params)) { 3288c2ecf20Sopenharmony_ci case 8: 3298c2ecf20Sopenharmony_ci val |= I2S_CHN_8; 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci case 6: 3328c2ecf20Sopenharmony_ci val |= I2S_CHN_6; 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci case 4: 3358c2ecf20Sopenharmony_ci val |= I2S_CHN_4; 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci case 2: 3388c2ecf20Sopenharmony_ci val |= I2S_CHN_2; 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci default: 3418c2ecf20Sopenharmony_ci dev_err(i2s->dev, "invalid channel: %d\n", 3428c2ecf20Sopenharmony_ci params_channels(params)); 3438c2ecf20Sopenharmony_ci return -EINVAL; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 3478c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_RXCR, 3488c2ecf20Sopenharmony_ci I2S_RXCR_VDW_MASK | I2S_RXCR_CSR_MASK, 3498c2ecf20Sopenharmony_ci val); 3508c2ecf20Sopenharmony_ci else 3518c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_TXCR, 3528c2ecf20Sopenharmony_ci I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK, 3538c2ecf20Sopenharmony_ci val); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (!IS_ERR(i2s->grf) && i2s->pins) { 3568c2ecf20Sopenharmony_ci regmap_read(i2s->regmap, I2S_TXCR, &val); 3578c2ecf20Sopenharmony_ci val &= I2S_TXCR_CSR_MASK; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci switch (val) { 3608c2ecf20Sopenharmony_ci case I2S_CHN_4: 3618c2ecf20Sopenharmony_ci val = I2S_IO_4CH_OUT_6CH_IN; 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci case I2S_CHN_6: 3648c2ecf20Sopenharmony_ci val = I2S_IO_6CH_OUT_4CH_IN; 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci case I2S_CHN_8: 3678c2ecf20Sopenharmony_ci val = I2S_IO_8CH_OUT_2CH_IN; 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci default: 3708c2ecf20Sopenharmony_ci val = I2S_IO_2CH_OUT_8CH_IN; 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci val <<= i2s->pins->shift; 3758c2ecf20Sopenharmony_ci val |= (I2S_IO_DIRECTION_MASK << i2s->pins->shift) << 16; 3768c2ecf20Sopenharmony_ci regmap_write(i2s->grf, i2s->pins->reg_offset, val); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, 3808c2ecf20Sopenharmony_ci I2S_DMACR_TDL(16)); 3818c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, 3828c2ecf20Sopenharmony_ci I2S_DMACR_RDL(16)); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci val = I2S_CKR_TRCM_TXRX; 3858c2ecf20Sopenharmony_ci if (dai->driver->symmetric_rates && rtd->dai_link->symmetric_rates) 3868c2ecf20Sopenharmony_ci val = I2S_CKR_TRCM_TXONLY; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci regmap_update_bits(i2s->regmap, I2S_CKR, 3898c2ecf20Sopenharmony_ci I2S_CKR_TRCM_MASK, 3908c2ecf20Sopenharmony_ci val); 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic int rockchip_i2s_trigger(struct snd_pcm_substream *substream, 3958c2ecf20Sopenharmony_ci int cmd, struct snd_soc_dai *dai) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci struct rk_i2s_dev *i2s = to_info(dai); 3988c2ecf20Sopenharmony_ci int ret = 0; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci switch (cmd) { 4018c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 4028c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 4038c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 4048c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 4058c2ecf20Sopenharmony_ci rockchip_snd_rxctrl(i2s, 1); 4068c2ecf20Sopenharmony_ci else 4078c2ecf20Sopenharmony_ci rockchip_snd_txctrl(i2s, 1); 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 4108c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 4118c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 4128c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 4138c2ecf20Sopenharmony_ci rockchip_snd_rxctrl(i2s, 0); 4148c2ecf20Sopenharmony_ci else 4158c2ecf20Sopenharmony_ci rockchip_snd_txctrl(i2s, 0); 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci default: 4188c2ecf20Sopenharmony_ci ret = -EINVAL; 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return ret; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, 4268c2ecf20Sopenharmony_ci unsigned int freq, int dir) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct rk_i2s_dev *i2s = to_info(cpu_dai); 4298c2ecf20Sopenharmony_ci int ret; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (freq == 0) 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci ret = clk_set_rate(i2s->mclk, freq); 4358c2ecf20Sopenharmony_ci if (ret) 4368c2ecf20Sopenharmony_ci dev_err(i2s->dev, "Fail to set mclk %d\n", ret); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return ret; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci dai->capture_dma_data = &i2s->capture_dma_data; 4468c2ecf20Sopenharmony_ci dai->playback_dma_data = &i2s->playback_dma_data; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { 4528c2ecf20Sopenharmony_ci .hw_params = rockchip_i2s_hw_params, 4538c2ecf20Sopenharmony_ci .set_sysclk = rockchip_i2s_set_sysclk, 4548c2ecf20Sopenharmony_ci .set_fmt = rockchip_i2s_set_fmt, 4558c2ecf20Sopenharmony_ci .trigger = rockchip_i2s_trigger, 4568c2ecf20Sopenharmony_ci}; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver rockchip_i2s_dai = { 4598c2ecf20Sopenharmony_ci .probe = rockchip_i2s_dai_probe, 4608c2ecf20Sopenharmony_ci .playback = { 4618c2ecf20Sopenharmony_ci .stream_name = "Playback", 4628c2ecf20Sopenharmony_ci .channels_min = 2, 4638c2ecf20Sopenharmony_ci .channels_max = 8, 4648c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 4658c2ecf20Sopenharmony_ci .formats = (SNDRV_PCM_FMTBIT_S8 | 4668c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | 4678c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | 4688c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | 4698c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE), 4708c2ecf20Sopenharmony_ci }, 4718c2ecf20Sopenharmony_ci .capture = { 4728c2ecf20Sopenharmony_ci .stream_name = "Capture", 4738c2ecf20Sopenharmony_ci .channels_min = 2, 4748c2ecf20Sopenharmony_ci .channels_max = 2, 4758c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 4768c2ecf20Sopenharmony_ci .formats = (SNDRV_PCM_FMTBIT_S8 | 4778c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | 4788c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | 4798c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | 4808c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE), 4818c2ecf20Sopenharmony_ci }, 4828c2ecf20Sopenharmony_ci .ops = &rockchip_i2s_dai_ops, 4838c2ecf20Sopenharmony_ci .symmetric_rates = 1, 4848c2ecf20Sopenharmony_ci}; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver rockchip_i2s_component = { 4878c2ecf20Sopenharmony_ci .name = DRV_NAME, 4888c2ecf20Sopenharmony_ci}; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci switch (reg) { 4938c2ecf20Sopenharmony_ci case I2S_TXCR: 4948c2ecf20Sopenharmony_ci case I2S_RXCR: 4958c2ecf20Sopenharmony_ci case I2S_CKR: 4968c2ecf20Sopenharmony_ci case I2S_DMACR: 4978c2ecf20Sopenharmony_ci case I2S_INTCR: 4988c2ecf20Sopenharmony_ci case I2S_XFER: 4998c2ecf20Sopenharmony_ci case I2S_CLR: 5008c2ecf20Sopenharmony_ci case I2S_TXDR: 5018c2ecf20Sopenharmony_ci return true; 5028c2ecf20Sopenharmony_ci default: 5038c2ecf20Sopenharmony_ci return false; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci switch (reg) { 5108c2ecf20Sopenharmony_ci case I2S_TXCR: 5118c2ecf20Sopenharmony_ci case I2S_RXCR: 5128c2ecf20Sopenharmony_ci case I2S_CKR: 5138c2ecf20Sopenharmony_ci case I2S_DMACR: 5148c2ecf20Sopenharmony_ci case I2S_INTCR: 5158c2ecf20Sopenharmony_ci case I2S_XFER: 5168c2ecf20Sopenharmony_ci case I2S_CLR: 5178c2ecf20Sopenharmony_ci case I2S_TXDR: 5188c2ecf20Sopenharmony_ci case I2S_RXDR: 5198c2ecf20Sopenharmony_ci case I2S_FIFOLR: 5208c2ecf20Sopenharmony_ci case I2S_INTSR: 5218c2ecf20Sopenharmony_ci return true; 5228c2ecf20Sopenharmony_ci default: 5238c2ecf20Sopenharmony_ci return false; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci switch (reg) { 5308c2ecf20Sopenharmony_ci case I2S_INTSR: 5318c2ecf20Sopenharmony_ci case I2S_CLR: 5328c2ecf20Sopenharmony_ci case I2S_FIFOLR: 5338c2ecf20Sopenharmony_ci case I2S_TXDR: 5348c2ecf20Sopenharmony_ci case I2S_RXDR: 5358c2ecf20Sopenharmony_ci return true; 5368c2ecf20Sopenharmony_ci default: 5378c2ecf20Sopenharmony_ci return false; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci switch (reg) { 5448c2ecf20Sopenharmony_ci case I2S_RXDR: 5458c2ecf20Sopenharmony_ci return true; 5468c2ecf20Sopenharmony_ci default: 5478c2ecf20Sopenharmony_ci return false; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic const struct reg_default rockchip_i2s_reg_defaults[] = { 5528c2ecf20Sopenharmony_ci {0x00, 0x0000000f}, 5538c2ecf20Sopenharmony_ci {0x04, 0x0000000f}, 5548c2ecf20Sopenharmony_ci {0x08, 0x00071f1f}, 5558c2ecf20Sopenharmony_ci {0x10, 0x001f0000}, 5568c2ecf20Sopenharmony_ci {0x14, 0x01f00000}, 5578c2ecf20Sopenharmony_ci}; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic const struct regmap_config rockchip_i2s_regmap_config = { 5608c2ecf20Sopenharmony_ci .reg_bits = 32, 5618c2ecf20Sopenharmony_ci .reg_stride = 4, 5628c2ecf20Sopenharmony_ci .val_bits = 32, 5638c2ecf20Sopenharmony_ci .max_register = I2S_RXDR, 5648c2ecf20Sopenharmony_ci .reg_defaults = rockchip_i2s_reg_defaults, 5658c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(rockchip_i2s_reg_defaults), 5668c2ecf20Sopenharmony_ci .writeable_reg = rockchip_i2s_wr_reg, 5678c2ecf20Sopenharmony_ci .readable_reg = rockchip_i2s_rd_reg, 5688c2ecf20Sopenharmony_ci .volatile_reg = rockchip_i2s_volatile_reg, 5698c2ecf20Sopenharmony_ci .precious_reg = rockchip_i2s_precious_reg, 5708c2ecf20Sopenharmony_ci .cache_type = REGCACHE_FLAT, 5718c2ecf20Sopenharmony_ci}; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic const struct rk_i2s_pins rk3399_i2s_pins = { 5748c2ecf20Sopenharmony_ci .reg_offset = 0xe220, 5758c2ecf20Sopenharmony_ci .shift = 11, 5768c2ecf20Sopenharmony_ci}; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic const struct of_device_id rockchip_i2s_match[] = { 5798c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3066-i2s", }, 5808c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3188-i2s", }, 5818c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3288-i2s", }, 5828c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3399-i2s", .data = &rk3399_i2s_pins }, 5838c2ecf20Sopenharmony_ci {}, 5848c2ecf20Sopenharmony_ci}; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int rockchip_i2s_probe(struct platform_device *pdev) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 5898c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 5908c2ecf20Sopenharmony_ci struct rk_i2s_dev *i2s; 5918c2ecf20Sopenharmony_ci struct snd_soc_dai_driver *soc_dai; 5928c2ecf20Sopenharmony_ci struct resource *res; 5938c2ecf20Sopenharmony_ci void __iomem *regs; 5948c2ecf20Sopenharmony_ci int ret; 5958c2ecf20Sopenharmony_ci int val; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); 5988c2ecf20Sopenharmony_ci if (!i2s) 5998c2ecf20Sopenharmony_ci return -ENOMEM; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci i2s->dev = &pdev->dev; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci i2s->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf"); 6048c2ecf20Sopenharmony_ci if (!IS_ERR(i2s->grf)) { 6058c2ecf20Sopenharmony_ci of_id = of_match_device(rockchip_i2s_match, &pdev->dev); 6068c2ecf20Sopenharmony_ci if (!of_id || !of_id->data) 6078c2ecf20Sopenharmony_ci return -EINVAL; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci i2s->pins = of_id->data; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* try to prepare related clocks */ 6138c2ecf20Sopenharmony_ci i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk"); 6148c2ecf20Sopenharmony_ci if (IS_ERR(i2s->hclk)) { 6158c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n"); 6168c2ecf20Sopenharmony_ci return PTR_ERR(i2s->hclk); 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci ret = clk_prepare_enable(i2s->hclk); 6198c2ecf20Sopenharmony_ci if (ret) { 6208c2ecf20Sopenharmony_ci dev_err(i2s->dev, "hclock enable failed %d\n", ret); 6218c2ecf20Sopenharmony_ci return ret; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); 6258c2ecf20Sopenharmony_ci if (IS_ERR(i2s->mclk)) { 6268c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); 6278c2ecf20Sopenharmony_ci ret = PTR_ERR(i2s->mclk); 6288c2ecf20Sopenharmony_ci goto err_clk; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 6328c2ecf20Sopenharmony_ci if (IS_ERR(regs)) { 6338c2ecf20Sopenharmony_ci ret = PTR_ERR(regs); 6348c2ecf20Sopenharmony_ci goto err_clk; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 6388c2ecf20Sopenharmony_ci &rockchip_i2s_regmap_config); 6398c2ecf20Sopenharmony_ci if (IS_ERR(i2s->regmap)) { 6408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 6418c2ecf20Sopenharmony_ci "Failed to initialise managed register map\n"); 6428c2ecf20Sopenharmony_ci ret = PTR_ERR(i2s->regmap); 6438c2ecf20Sopenharmony_ci goto err_clk; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci i2s->playback_dma_data.addr = res->start + I2S_TXDR; 6478c2ecf20Sopenharmony_ci i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 6488c2ecf20Sopenharmony_ci i2s->playback_dma_data.maxburst = 4; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci i2s->capture_dma_data.addr = res->start + I2S_RXDR; 6518c2ecf20Sopenharmony_ci i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 6528c2ecf20Sopenharmony_ci i2s->capture_dma_data.maxburst = 4; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, i2s); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 6578c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(&pdev->dev)) { 6588c2ecf20Sopenharmony_ci ret = i2s_runtime_resume(&pdev->dev); 6598c2ecf20Sopenharmony_ci if (ret) 6608c2ecf20Sopenharmony_ci goto err_pm_disable; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai, 6648c2ecf20Sopenharmony_ci sizeof(*soc_dai), GFP_KERNEL); 6658c2ecf20Sopenharmony_ci if (!soc_dai) { 6668c2ecf20Sopenharmony_ci ret = -ENOMEM; 6678c2ecf20Sopenharmony_ci goto err_pm_disable; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { 6718c2ecf20Sopenharmony_ci if (val >= 2 && val <= 8) 6728c2ecf20Sopenharmony_ci soc_dai->playback.channels_max = val; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { 6768c2ecf20Sopenharmony_ci if (val >= 2 && val <= 8) 6778c2ecf20Sopenharmony_ci soc_dai->capture.channels_max = val; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 6818c2ecf20Sopenharmony_ci &rockchip_i2s_component, 6828c2ecf20Sopenharmony_ci soc_dai, 1); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (ret) { 6858c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not register DAI\n"); 6868c2ecf20Sopenharmony_ci goto err_suspend; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci ret = rockchip_pcm_platform_register(&pdev->dev); 6908c2ecf20Sopenharmony_ci if (ret) { 6918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not register PCM\n"); 6928c2ecf20Sopenharmony_ci goto err_suspend; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return 0; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cierr_suspend: 6988c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 6998c2ecf20Sopenharmony_ci i2s_runtime_suspend(&pdev->dev); 7008c2ecf20Sopenharmony_cierr_pm_disable: 7018c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 7028c2ecf20Sopenharmony_cierr_clk: 7038c2ecf20Sopenharmony_ci clk_disable_unprepare(i2s->hclk); 7048c2ecf20Sopenharmony_ci return ret; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic int rockchip_i2s_remove(struct platform_device *pdev) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct rk_i2s_dev *i2s = dev_get_drvdata(&pdev->dev); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 7128c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 7138c2ecf20Sopenharmony_ci i2s_runtime_suspend(&pdev->dev); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci clk_disable_unprepare(i2s->hclk); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci return 0; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic const struct dev_pm_ops rockchip_i2s_pm_ops = { 7218c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, 7228c2ecf20Sopenharmony_ci NULL) 7238c2ecf20Sopenharmony_ci}; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic struct platform_driver rockchip_i2s_driver = { 7268c2ecf20Sopenharmony_ci .probe = rockchip_i2s_probe, 7278c2ecf20Sopenharmony_ci .remove = rockchip_i2s_remove, 7288c2ecf20Sopenharmony_ci .driver = { 7298c2ecf20Sopenharmony_ci .name = DRV_NAME, 7308c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(rockchip_i2s_match), 7318c2ecf20Sopenharmony_ci .pm = &rockchip_i2s_pm_ops, 7328c2ecf20Sopenharmony_ci }, 7338c2ecf20Sopenharmony_ci}; 7348c2ecf20Sopenharmony_cimodule_platform_driver(rockchip_i2s_driver); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface"); 7378c2ecf20Sopenharmony_ciMODULE_AUTHOR("jianqun <jay.xu@rock-chips.com>"); 7388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 7398c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME); 7408c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_i2s_match); 741